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

hi anadius, it dosent work anymore. could you please fix it?

@anadius
Copy link
Author

anadius commented Oct 1, 2024

Just tested on a random post I used for testing in the past: https://www.patreon.com/posts/83804756

Works perfectly fine. Maybe you have some outdated version of the script.

@legendarygamer2022
Copy link

legendarygamer2022 commented Oct 4, 2024

Just tested on a random post I used for testing in the past: https://www.patreon.com/posts/83804756

Works perfectly fine. Maybe you have some outdated version of the script.

i have just tested it on chrome and firefox but both of them didnt work. The extension still worked for me 3 weeks ago. (i use tampermonkey)
when i try Greasemonkey, it only downloads the first file. Violentmonkey also doesnt work

@anadius
Copy link
Author

anadius commented Oct 4, 2024

"didnt work" doesn't tell me shit. I sent a link to a post that works perfectly fine for me in Firefox with Greasemonkey and the newest version (1.0.2) of this script. I don't know what you're trying to download. You didn't provide any link, you didn't specify if you tested the link I sent or something else. Send one more useless comment and I'm blocking you.

@119z
Copy link

119z commented Oct 4, 2024

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.

@anadius
Copy link
Author

anadius commented Oct 4, 2024

You're right. It doesn't work in Tampermonkey and Violentmonkey. There were some issues with downloading, but it's nothing a GM.xmlHttpRequest can't solve. The real problem is that the code responsible for generating the ZIP file doesn't work. I don't know why. It doesn't throw any errors for me to read. I assume it may be a combination of Tampermonkey/Violentmonkey working differently than Greasemonkey and Patreon adding some content policy rules, that broke TM/VM. I'm not going to dive into the jszip code because I don't have time and that's not really something I'm going to fix anyway - since it's not my script's fault. It works in Firefox + Greasemonkey. Use that.

@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