Skip to content

Instantly share code, notes, and snippets.

@jcisio
Last active October 16, 2025 16:10
Show Gist options
  • Select an option

  • Save jcisio/b173edab440ef636aebc9df3b7b8d93f to your computer and use it in GitHub Desktop.

Select an option

Save jcisio/b173edab440ef636aebc9df3b7b8d93f to your computer and use it in GitHub Desktop.
Download all links in selected text
(async () => {
// Defaults that usually work, but change to fit your need.
const delayMs = 1000; // delay between links (milliseconds), it should be at least 1/3 the time to download a file
const allow = /\.(pdf|zip|mp3)(\?|#|$)/i; // Restrict to certain file types
// === Nothing to change after this ===
const sel = window.getSelection();
if (!sel || sel.rangeCount === 0) {
alert('Select some content on the page first.');
return;
}
// Clone the selection to a detached fragment so we can safely query it
const frag = sel.getRangeAt(0).cloneContents();
// 1) Links from <a.
const anchorUrls = Array.from(frag.querySelectorAll('a[href]'))
.map(a => a.href);
// 2) Plain-text URLs inside the selection (e.g., “https://example.com/file.pdf”)
const text = (frag.textContent || '');
const plainUrls = Array.from(text.matchAll(/\bhttps?:\/\/[^\s"'<>]+/gi)).map(m => m[0]);
// Merge & de-duplicate
const urls = Array.from(new Set([...anchorUrls, ...plainUrls]))
.filter(u => /^https?:\/\//i.test(u));
if (urls.length === 0) {
alert('No links found in the selection.');
return;
}
const urlsFiltered = urls.filter(u => allow.test(u));
const targets = urlsFiltered.length ? urlsFiltered : urls;
const inferName = (url, i) => {
const raw = url.split('/').pop().split('#')[0].split('?')[0];
const name = decodeURIComponent(raw || '');
return name || `download-${i + 1}`;
};
// Try to trigger download via <a download>. This generally works best for
// same-origin or when the server allows it; some cross-origin links may open in a tab.
const sleep = (ms) => new Promise(res => setTimeout(res, ms));
let ok = 0;
for (let i = 0; i < urls.length; i++) {
const url = urls[i];
const a = document.createElement('a');
a.href = url;
a.download = inferName(url, i); // browsers may ignore for cross-origin, but it's a hint
a.rel = 'noopener';
a.style.display = 'none';
document.body.appendChild(a);
// Trigger the download
a.click();
a.remove();
ok++;
// Wait between downloads
await sleep(delayMs);
}
console.log(`Attempted downloads: ${count}, but sometimes you can only download about 20 files each time.\n`, targets);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment