Image downloader for manga download scripts.
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/451810/1124333/ImageDownloaderLib.js
function ImageDownloader({
getImagePromises,
isOKToDownload = () => true,
title = `package_${Date.now()}`,
zipOptions = {},
imageSuffix = 'jpg',
cssVerticalDistance = 'top: 80px',
cssHorizontalDistance = 'left: 80px'
}) {
// create download button element
const dlBtn = document.createElement('button');
dlBtn.textContent = 'Download';
dlBtn.style = `
position: fixed;
${cssVerticalDistance};
${cssHorizontalDistance};
z-index: 9999999;
width: 128px;
height: 48px;
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
font-family: 'Consolas', 'Monaco', 'Microsoft YaHei';
color: #fff;
background-color: #0984e3;
border: none;
border-radius: 4px;
cursor: pointer;
`;
// setup click event callback
dlBtn.onclick = function () {
if (!isOKToDownload()) return;
dlBtn.disabled = true;
dlBtn.textContent = "Processing";
dlBtn.style.backgroundColor = '#aaa';
dlBtn.style.cursor = 'not-allowed';
download(getImagePromises, title, zipOptions);
}
// add button to body
document.body.appendChild(dlBtn);
// download
async function download(getImagePromises, title, zipOptions) {
// get promises of images
const imagePromises = getImagePromises();
// setup progress updater
setupProgressUpdater(imagePromises);
// wait until all promises are resolved
const images = await Promise.all(imagePromises);
// create zip
const zip = new JSZip(); // JSZip library should be imported already
const folder = zip.folder(title);
images.forEach((image, index) => {
const filename = `${String(index + 1).padStart(images.length >= 100 ? String(images.length).length : 2, '0')}.${imageSuffix}`;
folder.file(filename, image, zipOptions);
});
// pop up download window
const content = await zip.generateAsync({ type: "blob" });
saveAs(content, `${title}.zip`); // FileSaver library should be imported already
// change the text of download button
dlBtn.innerText = "Completed";
}
function setupProgressUpdater(imagePromises) {
const timer = setInterval(() => {
const statePromises = imagePromises.map(getPromiseState);
Promise
.all(statePromises)
.then(states => {
const fulfillCount = states.filter(state => state === 'fulfilled').length;
dlBtn.textContent = `Processing\n(${fulfillCount}/${states.length})`;
if (fulfillCount === states.length) {
dlBtn.textContent = "Zipping";
clearInterval(timer);
}
});
}, 200);
}
async function getPromiseState(targetPromise) {
const uniqueFlag = {};
return Promise.race([targetPromise, uniqueFlag]).then(
(raceResult) => raceResult === uniqueFlag ? 'pending' : 'fulfilled',
() => 'rejected'
);
}
}