Adds a download button to Bluesky images and videos. Built off coredumperror's script with a few improvements.
< Feedback on Bluesky Image Download Button
I wouldn't really call it a massive improvement, but thank you xD
I hadn't really run through all your code, I only did the "at a glance" stuff that I would personally handle differently, but in no way could I have written this myself. I'm more of a tinkerer than a respectable creator, so I am grateful for all your hard work in laying down the foundation.
I hadn't run into that situation yet, so I wasn't aware of that bug, I'll see where I can spot an alternative method for obtaining the post data.
Spotted, L304 and L388, we do a check to see if we're on a post page and don't do any further verification. So this would apply to literally any reply to a post while on the page of a post. I'll try to think of a clever way to get the post id, probably some query shenanigans or stripping the entire post to raw HTML and matching the post regex to that.
Yeah, querying the root of the reply and doing a simple raw regex match just pops it out easy. When I get to actually testing the code (not at 1AM LMAO), I hope in practice it won't actually be straining on the browser at all.
To remind me later:
$(reply_root).innerHTML.match(post_url_regex)
Alright, I believe I fixed it. Keep me informed of any other bugs you come across!
Oh! Something else I forgot to mention. I can't get the download filename format setting to work, probably because your code that renders the button on the Bluesky Settings page uses jQuery, and for whatever reason it's not installing for me on Bluesky. I had assumed the "requires" statement at the top of the file would do that, but I guess not?
Not entirely sure what's up, but switching to raw Javascript might be the best solution. The web is generally moving away from jQuery these days, anyway, since browsers now reliably implement all the useful functionality the same way (goodbye, Internet Explorer! Your rotting corpse will not be missed!!!). If you're not familiar with raw JS, try ChatGPT. I've found that it's surprisingly good at converting jQuery code to raw JS.
I've never heard of things moving away from JQuery, but I can see that happening, the only reason I used it is because JQuery is just simply cleaner. I'll do a quick rewrite without JQuery since it's not really required to accomplish what we need.
The settings was missing for a short bit because Bsky changed their settings page, I updated it earlier this morning.
For example:
function filenamingSettings(node) {
let topbar = $(node);
let settings = $('<input>').attr("id", "filename-input-space").css({
"display": "flex",
"align-items": "center",
"justify-content": "center",
"margin-top": "10px",
"text-align": "center"
}).hide().keypress((e) => {
if (e.which == 13) {
settings.hide();
button.show();
filename_template = settings.val();
GM_setValue('filename', settings.val());
}
});
let button = $('<a>').attr("id", "filename-input-button").text('Download Button Filename Template').css({
"display": "flex",
"align-items": "center",
"justify-content": "center",
"margin-top": "10px",
"border" : "2px solid",
"cursor": "pointer"
}).on('click', (e) => {
e.preventDefault();
button.hide();
settings.show().focus();
settings.val(filename_template);
});
topbar.before(button).before(settings);
}
becomes
function filenamingSettings(node) {
// Create the input element
let settings = document.createElement('input');
settings.id = 'filename-input-space';
settings.style.display = 'flex';
settings.style.alignItems = 'center';
settings.style.justifyContent = 'center';
settings.style.marginTop = '10px';
settings.style.textAlign = 'center';
settings.style.display = 'none'; // Hide initially
// Add event listener for Enter key press
settings.addEventListener('keypress', (e) => {
if (e.which === 13) {
settings.style.display = 'none';
button.style.display = 'flex';
filename_template = settings.value;
GM_setValue('filename', settings.value);
}
});
// Create the button element
let button = document.createElement('a');
button.id = 'filename-input-button';
button.textContent = 'Download Button Filename Template';
button.style.display = 'flex';
button.style.alignItems = 'center';
button.style.justifyContent = 'center';
button.style.marginTop = '10px';
button.style.border = '2px solid';
button.style.cursor = 'pointer';
// Add click event listener to the button
button.addEventListener('click', (e) => {
e.preventDefault();
button.style.display = 'none';
settings.style.display = 'flex';
settings.focus();
settings.value = filename_template;
});
// Insert the elements before the topbar
node.parentNode.insertBefore(button, node);
node.parentNode.insertBefore(settings, button);
}
It's just so much extra wordage to accomplish the same thing, but I guess it better than loading another resource. It's the Python coder in me that thinks it's just trying too hard to be hyper-specific. Like topbar.before(button).before(settings);
becoming two lines where it has to step up to the parent and specify the element being added and the element we just parented from for each individual element is just ugly and overcomplicating the who issue. The JQuery design philosophy follows the Promise and ES 2024 design philosophy so much more than the raw JS methods.
You're not wrong though, I used JQuery on instinct instead of looking what the modern suggested frameworks are, looks like people want React these days. In any case, I'll drop an update dropping JQuery for raw JS and take the time to learn one of those other frameworks for fun.
Love it! Massive improvement to my original script. Use this one, folks!
That said, there's a bug in my original that persist in this one. If you go to a Bluesky post that has a self-reply with more images in it, the image files get named after the original post, rather than the reply they're actually in.
I'm not entirely sure how to deal with this, but I imagine that a different algorithm for determining the post ID is necessary.