MyDownloader

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

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/515674/1581960/MyDownloader.js

  1. // ==UserScript==
  2. // @name MyDownloader
  3. // @version 2025.05.03
  4. // @description 包含多种下载方法的下载库
  5. // @author You
  6. // @grant none
  7. // @grant GM_getValue
  8. // @grant GM_setValue
  9. // @grant GM_deleteValue
  10. // @grant GM_download
  11. // @require https://update.greasyfork.org/scripts/480132/1476440/Get_all_img_Library.js
  12. // @require https://update.greasyfork.org/scripts/522187/1511410/Kquery.js
  13. // ==/UserScript==
  14. // 2025.01.07 更新了download text
  15. // 2025.01.07.02 更新了download text(src,name)
  16. // 2025.01.07.03 修复了download text(src,name)没有传入name的bug
  17. // 2025.05.03 修复isnowpage的bug
  18. /**
  19. * 包含多种下载方法的下载类
  20. * @example
  21. const downloader = new Downloader();
  22. downloader.Download_img(imgs);
  23. */
  24. function Downloader(){
  25. let downloading = 0;
  26. let downloaded = [];
  27. let downloadError = [];
  28. let imgs = null;
  29. let maxDownloadingCounts = 10;
  30. let timeout = null;
  31. let downloadType = ""
  32. let checkSrc = false;
  33. /**
  34. * @example Download_img(imgs)
  35. */
  36. this.Download_img = async (imgs)=>{
  37. Set_download(imgs)
  38. if(downloadType==""){
  39. Download_obo("GM_download");return;
  40. }
  41. console.log(downloadType);
  42. if(downloadType=="GM_download"){
  43. Download_obo("GM_download");
  44. }else if(downloadType=="atag"){
  45. Download_obo("atag");
  46. console.log('download atag')
  47. }else if(downloadType=="blob"){
  48. Download_obo("blob");
  49. }else{
  50. alert("no this donwload type");
  51. }
  52. }
  53. this.Set_downloadType = v => downloadType = v;
  54. this.Set_maxDownloadingCounts = v => maxDownloadingCounts = v;
  55. this.Set_timeout = v => timeout = v;
  56. this.Set_checkSrc = v => checkSrc = v;
  57. /**
  58. * @example OneSuccess((success_img)=>{...})
  59. */
  60. function OneSuccess(img){}
  61. this.OneSuccess = foo=>OneSuccess = foo;
  62. /**
  63. * @example OneError((error_img)=>{...})
  64. */
  65. function OneError(img){}
  66. this.OneError = foo=>OneError = foo;
  67. /**
  68. * @example AllComplete(()=>{...})
  69. */
  70. function AllComplete(){}
  71. this.AllComplete = foo=>AllComplete = foo;
  72. this.Set_download = (iimgs)=>{Set_download(iimgs);}
  73. function Set_download(iimgs){
  74. downloaded = [];
  75. downloading = 0;
  76. downloadError = [];
  77. imgs = iimgs;
  78. }
  79. function Download_obo(dtype){
  80. async function Download_one(i){
  81. if(i>=imgs.length){AllComplete();return;}
  82. if(downloading>=maxDownloadingCounts){setTimeout(()=>{Download_one(i)},1000);return;}
  83. const img = imgs.eq(i);
  84. downloading++;
  85. function success(img){
  86. OneSuccess(img);
  87. downloading--;
  88. downloaded.push(img);
  89. ConsoleWrite((downloaded.length+downloadError.length)+"/"+imgs.length)
  90. }
  91. function error(img){
  92. OneError(img);
  93. downloading--;
  94. downloadError.push(img);
  95. }
  96. switch(dtype){
  97. case "GM_download":
  98. Donwload_img_by_GM(img)
  99. .then(img=>success(img))
  100. .catch(img=>{
  101. dtype = "blob"
  102. Download_one(i);
  103. });
  104. break;
  105. case "blob":
  106. Download_img_by_blob(img)
  107. .then(img=>success(img))
  108. .catch(img=>{
  109. dtype = "atagIfram";
  110. Download_one(i);
  111. });
  112. break;
  113. case "atagIfram":
  114. Download_img_by_atag(img)
  115. .then(img=>success(img))
  116. .catch(img=>{
  117. error(img);
  118. dtype = "GM_download";
  119. });
  120. break;
  121. }
  122. Download_one(++i);
  123. }
  124. Download_one(0);
  125. }
  126. function ConsoleWrite(mass){
  127. if(window.GAIL){
  128. window.GAIL.showmass(mass);
  129. }
  130. }
  131. this.ConsoleWrite = foo=>ConsoleWrite = foo;
  132. this.Donwload_img_by_GM = img=>{Donwload_img_by_GM(img);}
  133. function Donwload_img_by_GM(img){
  134. return new Promise(async(resolve,reject)=>{
  135. if(!img){alert("img is empty");reject(img);return;}
  136. if(!GM_download){alert("GM_download is undefind");reject(img);return;}
  137. let name = '';
  138. let src = '';
  139. try{
  140. await Check_and_get_nameAndsrc({img:img,checkSrc:checkSrc})
  141. .then((m)=>{
  142. name = m.name;
  143. src = m.src;
  144. console.log(m);
  145. });
  146. }catch(error){
  147. reject(img);
  148. return;
  149. }
  150. console.log(name)
  151. console.log(src)
  152. GM_download({
  153. url:src,
  154. name:name,
  155. onload:function(){
  156. resolve(img);
  157. },
  158. onerror:function(){
  159. reject(img);
  160. },
  161. onprogress:function(){
  162. }
  163. });
  164. if(timeout){
  165. setTimeout(()=>{
  166. reject(img);
  167. },timeout);
  168. }
  169. })
  170. }
  171. this.Download_img_by_blob = (img)=>{Download_img_by_blob(img);}
  172. function Download_img_by_blob(img){
  173. return new Promise(async(rs,rj)=>{
  174. if(!img){alert("imgs is empty");rj(img);return;}
  175. let name = '';
  176. let src = '';
  177. try{
  178. await Check_and_get_nameAndsrc({img:img,checkSrc:checkSrc})
  179. .then((m)=>{
  180. name = m.name;
  181. src = m.src;
  182. console.log(m);
  183. });
  184. }catch(error){
  185. rj(img);
  186. return;
  187. }
  188. UrlToBlob({url:src,timeout:timeout})
  189. .then(blob=>{
  190. let a = $('<a></a>').attr({
  191. download:name,
  192. href:blob
  193. })
  194. a[0].click();
  195. rs(img);
  196. })
  197. .catch(er=>{
  198. console.log(er);
  199. rj(img);
  200. });
  201. if(timeout){
  202. setTimeout(()=>{
  203. rj(img);
  204. },timeout)
  205. }
  206. })
  207. }
  208. this.Download_img_by_atag = (img,nowIsImgPage)=>{Download_img_by_atag(img,nowIsImgPage);}
  209. async function Download_img_by_atag(img,nowIsImgPage) {
  210. return new Promise(async(resolve,reject)=>{
  211. if(!img){alert("imgs is empty");reject(img);return;}
  212. if(!GM_setValue){alert("GM_setValue is underfind");reject(img);return;}
  213. if (!nowIsImgPage) {
  214. let name = '';
  215. let src = '';
  216. try{
  217. await Check_and_get_nameAndsrc({img:img,checkSrc:checkSrc})
  218. .then((m)=>{
  219. name = m.name;
  220. src = m.src;
  221. console.log(m);
  222. });
  223. }catch(error){
  224. reject(img);
  225. return;
  226. }
  227. GM_setValue("downloadType", "start");
  228. GM_setValue("downloadName", name);
  229. GM_setValue("downloadSrc", src);
  230. let mi = new My_iframe();
  231. let iframe;
  232. let isTimeout = false;
  233. if(timeout){
  234. setTimeout(()=>{isTimeout = true;},timeout)
  235. }
  236. await mi.Add_iframe(src).then(ifr=>iframe = ifr);
  237. const checkDownload = setInterval(() => {
  238. if (GM_getValue("downloadType") === "end") {
  239. $(iframe).remove();
  240. resolve(img);
  241. clearInterval(checkDownload);
  242. return;
  243. }
  244. if(isTimeout){
  245. reject(img);
  246. }
  247. }, 100);
  248. }else {
  249. const newimg = $("img").attr({
  250. name:GM_getValue("downloadName"),
  251. })
  252. await Check_and_get_nameAndsrc({img:newimg,checkSrc:true})
  253. .then((m)=>{
  254. let name = m.name;
  255. let src = m.src;
  256. $('<a></a>').attr({
  257. 'href': src,
  258. 'download': name,
  259. })[0].click();
  260. });
  261. await new Promise(resolve => setTimeout(resolve, 1000));
  262. GM_setValue("downloadType", "end");
  263. window.close();
  264. }
  265. })
  266. }
  267. this.Listening_Download_by_atag = ()=>{
  268. const locationHref = window.location.href;
  269. const GM_downloadSrc = GM_getValue("downloadSrc");
  270. if(!GM_downloadSrc){return;}
  271. if(GM_downloadSrc == locationHref|| locationHref.indexOf(GM_downloadSrc)>=0 || GM_downloadSrc.indexOf(locationHref)>=0 ){
  272. Download_img_by_atag($("img"),true);
  273. }
  274. }
  275. /**
  276. * @example Urls({url:url,timeout : 100})
  277. */
  278. this.UrlToBlob = (args)=>{UrlToBlob(args);}
  279. async function UrlToBlob(args) {
  280. return new Promise((resolve,reject)=>{
  281. if(!args.url){reject("no url");}
  282. if(args.timeout){
  283. const timeout = setTimeout(function() {reject("fetch timeout")}, args.timeout);
  284. }
  285. fetch(args.url)
  286. .then(response => {
  287. const contentLength = response.headers.get('Content-Length');
  288. const total = parseInt(contentLength, 10);
  289. let loaded = 0;
  290. // 克隆响应以便分别读取流和获得 Blob
  291. const clonedResponse = response.clone();
  292. const reader = clonedResponse.body.getReader();
  293. // 更新进度的函数
  294. function updateProgress({ done, value }) {
  295. if (done) {
  296. return; // 如果读取完毕,直接返回
  297. }
  298. loaded += value.byteLength; // 累加已加载字节
  299. const progress = (loaded / total) * 100; // 计算进度百分比
  300. console.log(`Loading: ${progress.toFixed(2)}%`);
  301. FetchShowProgress(progress);
  302. // 继续读取下一块数据
  303. return reader.read().then(updateProgress);
  304. }
  305. // 开始读取流以更新进度
  306. return reader.read().then(updateProgress).then(() => {
  307. // 完成后返回原始响应的 Blob
  308. return response.blob();
  309. });
  310. })
  311. .then(blob => {
  312. const blobUrl = URL.createObjectURL(blob);
  313. resolve(blobUrl);
  314. })
  315. .catch(error => {
  316. console.error('Error caching video:', error);
  317. reject(error);
  318. });
  319. });
  320. }
  321. this.FetchShowProgress = (pro)=>{FetchShowProgress(pro);}
  322. function FetchShowProgress(pro){
  323. if(this.maxDownloadingCounts==1 && this.imgs.length==1){
  324. window.GAIL.showmass(pro);
  325. $(".mass_top").css('font-size',"10vmin");
  326. }
  327. }
  328. this.Check_and_get_nameAndsrc = (args)=>{Check_and_get_nameAndsrc(args);}
  329. function Check_and_get_nameAndsrc(args){
  330. return new Promise(async (resolve,reject)=>{
  331. if(!args || !args.img){return reject();}
  332. let src = args.img.attr('big_src')||args.img.attr('big-src');
  333. if(!src){src = args.img.attr('src');}
  334. if(!src){src = args.img.attr('small_src')||args.img.attr('small-src');}
  335. if(!src){reject();}
  336. //console.log("check:"+src)
  337. if(args.checkSrc){
  338. try{
  339. await check_src_is_right(src);
  340. }catch(error){
  341. reject();
  342. }
  343. }
  344. let ext = src.match(/\.jpg|\.png|\.webp|\.gif|\.bmp/g);
  345. if(!ext){ext = '.png';}else{ext = ext[0];}
  346. let name = args.img.attr('name');
  347. if(!name){name = document.title + new Date().getTime() + Math.floor(Math.random()*100) + ext;}
  348. resolve({name:name,src:src,img:args.img});
  349. });
  350. }
  351. function generateUUID() {
  352. return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
  353. (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
  354. );
  355. }
  356.  
  357. this.check_src_is_right = (src)=>{check_src_is_right(src);}
  358. function check_src_is_right(src){
  359. return new Promise((resolve,reject)=>{
  360. let iimg = new Image();
  361. iimg.onload = function(){
  362. if(this.width*this.height*this.naturalWidth*this.naturalHeight==0){reject();}else{resolve();}
  363. }
  364. iimg.onerror = function(){reject();}
  365. iimg.src = src;
  366. setTimeout(function() {reject();}, 2000);
  367. })
  368. }
  369. function downloadText(text,name) {
  370. // 创建 Blob 对象
  371. var blob = new Blob([text], { type: "text/plain" });
  372. // 创建下载链接
  373. var url = URL.createObjectURL(blob);
  374. // 创建下载按钮
  375. var a = document.createElement("a");
  376. a.href = url;
  377. a.download = name?name:"downloaded_text"+new Date().getTime()+".txt"; // 文件名
  378. document.body.appendChild(a);
  379. // 模拟点击下载
  380. a.click();
  381. // 清理
  382. window.URL.revokeObjectURL(url);
  383. document.body.removeChild(a);
  384. }
  385. this.Download_to_text = (url,name)=>{downloadText(url,name);}
  386. }
  387. $(function(){
  388. let dd = new Downloader()
  389. dd.Listening_Download_by_atag()
  390. })
  391. window.Downloader = Downloader;