ImageDownloaderLib

Image downloader for manga download scripts.

当前为 2022-12-03 提交的版本,查看 最新版本

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

  1. function ImageDownloader({
  2. getImagePromises,
  3. isOKToDownload = () => true,
  4. title = `package_${Date.now()}`,
  5. zipOptions = {},
  6. imageSuffix = 'jpg',
  7. cssVerticalDistance = 'top: 80px',
  8. cssHorizontalDistance = 'left: 80px'
  9. }) {
  10. // create download button element
  11. const dlBtn = document.createElement('button');
  12. dlBtn.textContent = 'Download';
  13. dlBtn.style = `
  14. position: fixed;
  15. ${cssVerticalDistance};
  16. ${cssHorizontalDistance};
  17. z-index: 9999999;
  18.  
  19. width: 128px;
  20. height: 48px;
  21.  
  22. display: flex;
  23. justify-content: center;
  24. align-items: center;
  25.  
  26. font-size: 14px;
  27. font-family: 'Consolas', 'Monaco', 'Microsoft YaHei';
  28. color: #fff;
  29.  
  30. background-color: #0984e3;
  31. border: none;
  32. border-radius: 4px;
  33. cursor: pointer;
  34. `;
  35.  
  36. // setup click event callback
  37. dlBtn.onclick = function () {
  38. if (!isOKToDownload()) return;
  39.  
  40. dlBtn.disabled = true;
  41. dlBtn.textContent = "Processing";
  42. dlBtn.style.backgroundColor = '#aaa';
  43. dlBtn.style.cursor = 'not-allowed';
  44. download(getImagePromises, title, zipOptions);
  45. }
  46.  
  47. // add button to body
  48. document.body.appendChild(dlBtn);
  49.  
  50. // download
  51. async function download(getImagePromises, title, zipOptions) {
  52. // get promises of images
  53. const imagePromises = getImagePromises();
  54.  
  55. // setup progress updater
  56. setupProgressUpdater(imagePromises);
  57.  
  58. // wait until all promises are resolved
  59. const images = await Promise.all(imagePromises);
  60.  
  61. // create zip
  62. const zip = new JSZip(); // JSZip library should be imported already
  63. const folder = zip.folder(title);
  64. images.forEach((image, index) => {
  65. const filename = `${String(index + 1).padStart(images.length >= 100 ? String(images.length).length : 2, '0')}.${imageSuffix}`;
  66. folder.file(filename, image, zipOptions);
  67. });
  68.  
  69. // pop up download window
  70. const content = await zip.generateAsync({ type: "blob" });
  71. saveAs(content, `${title}.zip`); // FileSaver library should be imported already
  72.  
  73. // change the text of download button
  74. dlBtn.innerText = "Completed";
  75. }
  76.  
  77. function setupProgressUpdater(imagePromises) {
  78. const timer = setInterval(() => {
  79. const statePromises = imagePromises.map(getPromiseState);
  80. Promise
  81. .all(statePromises)
  82. .then(states => {
  83. const fulfillCount = states.filter(state => state === 'fulfilled').length;
  84. dlBtn.textContent = `Processing\n(${fulfillCount}/${states.length})`;
  85.  
  86. if (fulfillCount === states.length) {
  87. dlBtn.textContent = "Zipping";
  88. clearInterval(timer);
  89. }
  90. });
  91. }, 200);
  92. }
  93.  
  94. async function getPromiseState(targetPromise) {
  95. const uniqueFlag = {};
  96. return Promise.race([targetPromise, uniqueFlag]).then(
  97. (raceResult) => raceResult === uniqueFlag ? 'pending' : 'fulfilled',
  98. () => 'rejected'
  99. );
  100. }
  101. }