Skip to content

Instantly share code, notes, and snippets.

@anadius
Last active April 22, 2025 00:44
Show Gist options
  • Save anadius/94a218da5262735b431eb2b4b3f20d5d to your computer and use it in GitHub Desktop.
Save anadius/94a218da5262735b431eb2b4b3f20d5d to your computer and use it in GitHub Desktop.
Patreon bulk attachment downloader
// ==UserScript==
// @name Patreon bulk attachment downloader
// @author anadius
// @namespace anadius.su
// @match https://www.patreon.com/posts/*
// @version 1.0.2
// @grant none
// @require https://cdn.jsdelivr.net/npm/[email protected]/dist/jszip.min.js
// @require https://cdn.jsdelivr.net/npm/[email protected]/FileSaver.min.js
// @run-at document-end
// ==/UserScript==
window.addEventListener("load", () => {
const ATTACHMENTS = document.querySelector("[data-tag=post-attachments]");
const DOWNLOAD_BUTTON = document.createElement("button");
const TITLE = document.querySelector("[data-tag=post-title]").textContent;
const makeCheckbox = (attachment) => {
const cb = document.createElement("input");
cb.type = "checkbox";
if(attachment !== null) {
cb.filename = attachment.textContent;
cb.url = attachment.href;
cb.style.height = "1.35rem";
cb.classList.add("attachment");
}
return cb;
};
const getCheckboxes = () => ATTACHMENTS.querySelectorAll("input.attachment[type=checkbox]");
const readAsBinaryString = blob => new Promise(resolve => {
const reader = new FileReader();
reader.onload = function(event) {
resolve(event.target.result);
};
reader.readAsBinaryString(blob);
});
const download = async e => {
e.preventDefault();
const zip = new JSZip();
DOWNLOAD_BUTTON.disabled = "disabled";
for(const cb of getCheckboxes()) {
if(cb.checked) {
const response = await fetch(cb.url);
const blob = await response.blob();
cb.classList.add("downloaded");
zip.file(cb.filename, await readAsBinaryString(blob), {binary: true});
}
}
zip.generateAsync({type:"blob"})
.then(function(content) {
saveAs(content, `${TITLE}.zip`);
});
DOWNLOAD_BUTTON.disabled = "";
};
for(const attachment of ATTACHMENTS.querySelectorAll("[data-tag=post-attachment-link]")) {
attachment.before(makeCheckbox(attachment));
}
const div = document.createElement("div");
const toggleAll = makeCheckbox(null);
toggleAll.addEventListener("click", () => {
for(const cb of getCheckboxes()) {
cb.checked = toggleAll.checked;
}
});
DOWNLOAD_BUTTON.innerHTML = "Download";
DOWNLOAD_BUTTON.addEventListener("click", download);
const label = document.createElement("label");
label.innerHTML = " Toggle all ";
label.prepend(toggleAll);
div.append(label, DOWNLOAD_BUTTON);
ATTACHMENTS.append(div);
document.styleSheets[0].addRule("input.attachment.downloaded[type=checkbox] + a:after",'content: "✅"');
})();
@legendarygamer2022
Copy link

I think the problem is actually Tampermonkey and Violentmonkey. I tried with both Tampermonkey and Violentmonkey on Zen, a FF fork, and on Edge. With either extension, the toggle and download all button appear, but if I click the button, it greys out and nothing downloads. I tested with this post, this post and the post you linked. Then I tried with Greasemonkey on FF, and everything works as it should.

Thank you for clarifying the issue. I tested it on mac and windows and both of them freezed. The box and download button didnt show up on mac. Greasemonkey only downloads the first file. Anadius couldnt even realize the problem because he always has a shitty ego.

@anadius
Copy link
Author

anadius commented Oct 6, 2024

@legendarygamer2022 are you dumb? They clearly said that it works fine in Firefox with Greasemonkey. So if it doesn't work for you - that's on your side. You haven't even provided ANY FUCKING LINKS yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment