您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a button to download all images from a gallery for postimg.cc (postimages.org).
// ==UserScript== // @name Batch Download for postimg.cc (postimages.org) // @namespace http://tampermonkey.net/ // @version 2024-11-02 // @description Adds a button to download all images from a gallery for postimg.cc (postimages.org). // @match *://postimg.cc/gallery/* // @author xskutsu (Discord: @xskt) // @license Creative Commons Attribution-NonCommercial 4.0 International License // @require https://cdnjs.cloudflare.com/ajax/libs/jszip/3.9.1/jszip.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // ==/UserScript== (function() { "use strict"; GM_registerMenuCommand("Compression Level", function () { const value = parseInt(prompt("What level of compression should be used?\nany integer between 0 (best speed) and 9 (best compression)\nDefault: 5")); if (isNaN(value) || value !== Math.floor(value) || value < 0 || value > 9) { alert(`${value} is not valid!`); } else { GM_setValue("compressionLevel", value); } }); GM_registerMenuCommand("Sleep Time", function () { const value = parseInt(prompt("How much time (in ms) should we sleep between downloading original file blobs?\Default: 100ms")); if (isNaN(value) || value !== Math.floor(value) || value < 0 || value > 10000) { alert(`${value} is not valid!`); } else { GM_setValue("sleepTime", value); } }); async function getAllImages(album) { const result = []; let page = 1; while (true) { const response = await fetch("https://postimg.cc/json", { "headers": { "content-type": "application/x-www-form-urlencoded; charset=UTF-8", }, "referrer": `https://postimg.cc/gallery/${album}`, "referrerPolicy": "strict-origin-when-cross-origin", "body": `action=list&album=${album}&page=${page++}`, "method": "POST", "mode": "cors", "credentials": "omit" }); const data = await response.json(); for (let i = 0; i < data.images.length; i++) { result.push(data.images[i]); } if (!data.has_page_next) { break; } } return result; } async function fetchOriginalImageURL(code, album) { const response = await fetch(`https://postimg.cc/${code}`, { "referrer": `https://postimg.cc/gallery/${album}`, "referrerPolicy": "strict-origin-when-cross-origin", "body": null, "method": "GET", "mode": "cors", "credentials": "omit" }); const data = await response.text(); const parser = new DOMParser(); const doc = parser.parseFromString(data, "text/html"); return doc.getElementById("download").href; } window.addEventListener("load", function () { const collapseShareElement = document.getElementById("collapse_share"); const downloadGalleryElement = collapseShareElement.cloneNode(true); downloadGalleryElement.style.color = "#c57f15"; downloadGalleryElement.style.borderColor = "#c57f15"; downloadGalleryElement.childNodes[0].classList.remove("fa-codes"); downloadGalleryElement.childNodes[0].classList.add("fa-download"); const textNode = downloadGalleryElement.childNodes[1]; textNode.textContent = "Download Gallery"; downloadGalleryElement.addEventListener("click", async function () { try { const album = window.location.pathname.split("/").slice(-1)[0]; textNode.textContent = "Fetching pages..."; const images = await getAllImages(album); const imageURLs = []; for (let i = 0; i < images.length; i++) { textNode.textContent = `Fetching original URLs... (${i + 1}/${images.length})`; const originalURL = await fetchOriginalImageURL(images[i][0], album); imageURLs.push(originalURL.replace(/\?dl=1$/, "")); } const blobs = []; const sleepTime = GM_getValue("sleepTime", 100); for (let i = 0; i < images.length; i++) { textNode.textContent = `Fetching original image blobs... (${i + 1}/${images.length})`; const url = imageURLs[i]; const response = await fetch(url); const blob = await response.blob(); const fileName = url.split("/").pop(); blobs.push(fileName, blob); if (i < imageURLs.length - 1) { await new Promise(resolve => setTimeout(resolve, sleepTime)); } } const zip = new JSZip(); for (let i = 0; i < blobs.length; i += 2) { textNode.textContent = `Adding files to zip... (${i / 2 + 1}/${images.length})`; zip.file(blobs[i], blobs[i + 1]); } textNode.textContent = `Starting zip...`; const compressionLevel = GM_getValue("compressionLevel", 5); const content = await zip.generateAsync({ type: "blob", compression: compressionLevel === 0 ? "STORE" : "DEFLATE", comment: `Images from album ${album} on postimg.cc (postimages.org)`, compressionOptions: { level: compressionLevel } }, function (metadata) { if (metadata.currentFile) { textNode.textContent = `Zipping images... (${metadata.percent.toFixed(2)}%)`; } }); textNode.textContent = `Download finished!`; saveAs(content, "gallery_SC2ZHmR.zip"); textNode.textContent = `Download Gallery`; } catch (error) { alert("An error has occurred while downloading the gallery. Check logs for more information."); console.error(error); } }); collapseShareElement.parentNode.prepend(downloadGalleryElement); }); })();