MyDownloader

包含多种下载方法的下载库

目前為 2025-01-07 提交的版本,檢視 最新版本

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.cn-greasyfork.org/scripts/515674/1516722/MyDownloader.js

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         MyDownloader
// @version      2025.01.07.03
// @description  包含多种下载方法的下载库
// @author       You
// @grant        none
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @grant        GM_download
// @require https://update.greasyfork.org/scripts/480132/1476440/Get_all_img_Library.js
// @require https://update.greasyfork.org/scripts/522187/1511410/Kquery.js
// ==/UserScript==
// 2025.01.07 更新了download text
// 2025.01.07.02 更新了download text(src,name)
// 2025.01.07.03 修复了download text(src,name)没有传入name的bug


/**
 * 包含多种下载方法的下载类
 * @example
 const downloader = new Downloader();
 downloader.Download_img(imgs);
*/
function Downloader(){
	
	let downloading = 0;
	let downloaded = [];
	let downloadError = [];
	let imgs = null;
	let maxDownloadingCounts = 10;
	let timeout = null;
	let AllComplete = null;
	let OneSuccess = null;
	let OneError = null;
	let downloadType = ""
	
	
	/**
	 * @example Download_img(imgs)
	 */
	this.Download_img = async (imgs)=>{
		if(downloadType==""){
			await Test_downloadType(imgs.eq(0));
		}
		
		Set_download(imgs)
		console.log(downloadType);
		if(downloadType=="GM_download"){
			Donwload_img_by_GM();
		}else if(downloadType=="atag"){
			Donwload_img_by_atag();
		}else if(downloadType=="blob"){
			Donwload_img_by_blob();
		}else{
			alert("no this donwload type");
		}
	}
	/**
	 * @example downloadType.value = "GM_download" || "atag" || "blob"
	 */
	this.downloadType = {get value(){return downloadType;},set value(v){downloadType = v;}};
	/**
	 * @example maxDownloadingCounts.value = 100
	 */
	this.maxDownloadingCounts = {get value(){return maxDownloadingCounts;},set value(v){maxDownloadingCounts = v}};
	/**
	 * @example timeout.value = 1000
	 */
	this.timeout = {get value(){return timeout;},set value(v){timeout = v}};
	/**
	 * @example OneSuccess((success_img)=>{...})
	 */
	this.OneSuccess = foo=>OneSuccess = foo;
	/**
	 * @example OneError((error_img)=>{...})
	 */
	this.OneError = foo=>OneError = foo;
	/**
	 * @example AllComplete(()=>{...})
	 */
	this.AllComplete = foo=>AllComplete = foo;
	
	this.Test_downloadType = (img)=>{Test_downloadType(img);}
	async function Test_downloadType(img){
		return new Promise((resolve)=>{
			let timeout = 3000;
			let isOk = false;
			GM_download({
				url:img[0].src,
				name:"test.png",
				onload:()=>{isOk = true;downloadType = "GM_download";resolve()},
			})
			setTimeout(()=>{
				if(!isOk){downloadType = "atag";}
				resolve()
			},timeout)
		})
	}
	this.Set_download = (iimgs)=>{Set_download(iimgs);}
	function Set_download(iimgs){
		downloaded = [];
		downloading = 0;
		downloadError = [];
		imgs = iimgs;
	}
	
	this.Donwload_img_by_GM = ()=>{Donwload_img_by_GM();}
	function Donwload_img_by_GM(){
		if(!imgs || imgs.length == 0){alert("imgs is empty");return;}
		async function Download_one(i){
			if(i>=imgs.length){if(AllComplete){AllComplete()};return;}
			if(downloading>=maxDownloadingCounts){setTimeout(()=>{Download_one(i)},1000);return;}
			
			let name = '';
			let src = '';
			downloading++;
			try{
				await Check_and_get_nameAndsrc({img:imgs.eq(i),checkSrc:true})
						.then((m)=>{
							name = m.name;
							src = m.src;
						});
			}catch(error){
				console.log(error)
				console.log('imgsrc is error:');
				downloadError.push(i);
				downloading--;
				Download_one(i+1);
				return;
			}
			console.log(name)
			console.log(document.title)
			let timeout = false;
			setTimeout(() => {timeout = true;},10000);
			const donwimg = imgs.eq(i);
			GM_download({
				url:src,
				name:name,
				onload:function(){
					downloaded.push(downimg);
					downloading--;
					if(window.GAIL.showmass){
						window.GAIL.showmass((downloaded.length+downloadError.length)+"/"+imgs.length);
					}
					imgs.eq(i).remove();
					
					if(OneSuccess){OneSuccess(downimg);}
				},
				onerror:function(){
					downloading--;
					downloadError.push(downimg);
					if(OnError){OnError(downimg);}
				},
				onprogress:function(){
					if(timeout){return false;}
				}
			});
			setTimeout(function() {Download_one(i+1);}, 10);
		}
		Download_one(0);
	}
	
	this.Donwload_img_by_atag = (nowIsImgPage)=>{Donwload_img_by_atag(nowIsImgPage);}
	async function Donwload_img_by_atag(nowIsImgPage) {
		if (!nowIsImgPage) {
			if(!imgs || imgs.length==0){alert("imgs is empty");return;}
			GM_setValue("downloadName", document.title);
			for (let i = 0; i < imgs.length; i++) {
				GM_setValue("downloadType", "start");
				let name;
				let src;
				await Check_and_get_nameAndsrc({img:imgs.eq(i),checkSrc:false})
						.then((m)=>{
							name = m.name;
							src = m.src;
						});
				GM_setValue("downloadSrc", src);
				let mi = new My_iframe();
				let iframe;
				await mi.Add_iframe(src).then(ifr=>iframe = ifr);
				//const myWindow = window.open(src, '_blank');
				
				await new Promise(resolve => {
					const checkDownload = setInterval(() => {
						if (GM_getValue("downloadType") === "end") {
							resolve();
							clearInterval(checkDownload);
						}
					}, 100);
				});
				$(iframe).remove();
				OneSuccess(imgs.eq(i));
				downloaded.push(imgs.eq(i));
				window.GAIL.showmass((downloaded.length+downloadError.length)+"/"+imgs.length);
				$(".mass_top").css({'font-size':'6vmin'});
			}
			AllComplete();
		} else {
			await Check_and_get_nameAndsrc({img:$("img"),checkSrc:true})
					.then((m)=>{
						let name = m.name;
						let src = m.src;
						$('<a></a>').attr({
							'href': src,
							'download': name,
						})[0].click();
					});
			await new Promise(resolve => setTimeout(resolve, 1000));
			GM_setValue("downloadType", "end");
			window.close();
		}
	}
	this.Listening_Download_by_atag = ()=>{
		const locationHref = window.location.href;
		const GM_downloadSrc = GM_getValue("downloadSrc");
		if(!GM_downloadSrc){return;}
		if(GM_downloadSrc == locationHref|| locationHref.indexOf(GM_downloadSrc)>=0 || GM_downloadSrc.indexOf(locationHref)>=0 ){
			Donwload_img_by_atag(true);
		}
	}
	
	this.Donwload_img_by_blob = ()=>{Donwload_img_by_blob();}
	function Donwload_img_by_blob(){
		if(!imgs || imgs.length==0){alert("imgs is empty");return;}

		const obo = (i)=>{
			if(i>=imgs.length){return;}
			if(maxDownloadingCounts>1 && downloading >= maxDownloadingCounts){
				setTimeout(function() {obo(i)}, 1000);
			}
			let src = imgs.eq(i).attr('big_src');
			if(!src){src = imgs.eq(i).attr('src');}
			const checkimg = imgs.eq(i);
			downloading++;
			UrlToBlob({url:src,timeout:timeout})
				.then(blob=>{
					Check_and_get_nameAndsrc({img:checkimg}).then(args=>{
						const name = args.name;
						let a = $('<a></a>').attr({
							download:name,
							href:blob
						})
						a[0].click();
						downloaded.push(checkimg);
						downloading--;
						checkimg.attr('src',blob);
						OneSuccess(checkimg);
					})
					
					if(maxDownloadingCounts==1){
						obo(++i);
					}else{
						window.GAIL.showmass((downloaded.length+downloadError.length)+"/"+imgs.length);
					}
				})
				.catch(er=>{
					console.log(er);
					downloadError.push(imgs.eq(i));
					downloading--;
					if(maxDownloadingCounts==1){
						obo(++i);
					}else{
						window.GAIL.showmass((downloaded.length+downloadError.length)+"/"+imgs.length);
					}
				});
			if(maxDownloadingCounts>1){
				setTimeout(function() {obo(++i);}, 10);
			}
		}
		obo(0);
	}
	/**
	 * @example Urls({url:url,timeout : 100})
    */
   this.UrlToBlob = (args)=>{UrlToBlob(args);}
	async function UrlToBlob(args) {
		return new Promise((resolve,reject)=>{
			if(!args.url){reject("no url");}
			if(args.timeout){
				const timeout = setTimeout(function() {reject("fetch timeout")}, args.timeout);
			}
			fetch(args.url)
					.then(response => {
						const contentLength = response.headers.get('Content-Length');
						const total = parseInt(contentLength, 10);
						let loaded = 0;
			
						// 克隆响应以便分别读取流和获得 Blob
						const clonedResponse = response.clone();
						const reader = clonedResponse.body.getReader();
			
						// 更新进度的函数
						function updateProgress({ done, value }) {
							if (done) {
								return; // 如果读取完毕,直接返回
							}
							loaded += value.byteLength; // 累加已加载字节
							const progress = (loaded / total) * 100; // 计算进度百分比
							console.log(`Loading: ${progress.toFixed(2)}%`);
							FetchShowProgress(progress);
							// 继续读取下一块数据
							return reader.read().then(updateProgress);
						}
			
						// 开始读取流以更新进度
						return reader.read().then(updateProgress).then(() => {
							// 完成后返回原始响应的 Blob
							return response.blob();
						});
					})
					.then(blob => {
						const blobUrl = URL.createObjectURL(blob);
						resolve(blobUrl);
					})
					.catch(error => {
						console.error('Error caching video:', error);
						reject(error);
					});
		});
	}
	this.FetchShowProgress = (pro)=>{FetchShowProgress(pro);}
	function FetchShowProgress(pro){
		if(this.maxDownloadingCounts==1 && this.imgs.length==1){
			window.GAIL.showmass(pro);
			$(".mass_top").css('font-size',"10vmin");
		}
	}
	
	this.Check_and_get_nameAndsrc = (args)=>{Check_and_get_nameAndsrc(args);}
	function Check_and_get_nameAndsrc(args){
		return new Promise(async (resolve,reject)=>{
			if(!args || !args.img){return reject();}
			let src = args.img.attr('big_src');
			if(!src){src = args.img.attr('src');}
			if(!src){src = args.img.attr('small_src');}
			if(!src){reject();}
			//console.log("check:"+src)
			if(args.checkSrc){
				try{
					await check_src_is_right(src);
				}catch(error){
					reject();
				}
			}
			let ext = src.match(/\.jpg|\.png|\.webp|\.gif|\.bmp/g);
			if(!ext){ext = '.png';}else{ext = ext[0];}
			let name = args.img.attr('name');
			if(!name){name = document.title + new Date().getTime() + ext;}
			resolve({name:name,src:src});
		});
	}
	
	this.check_src_is_right = (src)=>{check_src_is_right(src);}
	function check_src_is_right(src){
		return new Promise((resolve,reject)=>{
			let iimg = new Image();
			iimg.onload = function(){
				if(this.width*this.height*this.naturalWidth*this.naturalHeight==0){reject();}else{resolve();}
			}
			iimg.onerror = function(){reject();}
			iimg.src = src;
			setTimeout(function() {iimg.abort();reject();}, 2000);
		})
	}
	
	function downloadText(text,name) {
	 
	    // 创建 Blob 对象
	    var blob = new Blob([text], { type: "text/plain" });
	 
	    // 创建下载链接
	    var url = URL.createObjectURL(blob);
	 
	    // 创建下载按钮
	    var a = document.createElement("a");
	    a.href = url;
	    a.download = name?name:"downloaded_text"+new Date().getTime()+".txt"; // 文件名
	    document.body.appendChild(a);
	 
	    // 模拟点击下载
	    a.click();
	 
	    // 清理
	    window.URL.revokeObjectURL(url);
	    document.body.removeChild(a);
	}
	this.Download_to_text = (url,name)=>{downloadText(url,name);}
}
$(function(){
	let dd = new Downloader()
	dd.Listening_Download_by_atag()
})

window.Downloader = Downloader;