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);
});
})();