Skip to main content

📜 BookmarkLETS

This is a collection of JavaScript bookmarklets to assist in everyday life copy pasting.

Download YouTube Subtitles

Opens a new tab to download subtitles for the current YouTube video.

Name:

📥 Download YouTube Subtitles

Revision:

  • 2024-09-29 - initial
Code:
javascript:(function(){
/* Check if the current site is YouTube and has a video ID */
if (window.location.hostname.includes('youtube.com') && new URLSearchParams(window.location.search).has('v')) {
/* Get the current page URL */
var currentUrl = window.location.href;
/* Encode the URL */
var encodedUrl = encodeURIComponent(currentUrl);
/* Construct the target URL */
var targetUrl = 'https://www.downloadyoutubesubtitles.com/?u=' + encodedUrl;
/* Open the target URL in a new tab */
window.open(targetUrl, '_blank');
} else {
/* Alert the user if not on a YouTube video page */
alert('This bookmarklet works only on YouTube video pages.');
}
})();


javascript:(function(){if(window.location.hostname.includes('youtube.com')&&new URLSearchParams(window.location.search).has('v')){var currentUrl=window.location.href;var encodedUrl=encodeURIComponent(currentUrl);var targetUrl='https://www.downloadyoutubesubtitles.com/?u='+encodedUrl;window.open(targetUrl,'_blank');}else{alert('This bookmarklet works only on YouTube video pages.');}})();

Copies link to the current page in clipboard in Markdown format:

2023-03-12 [Hello from Dmytro Zharii | Dmytro Zharii](https://blog.zharii.com/)

2023-03-12 Hello from Dmytro Zharii | Dmytro Zharii

Name:

🥧 Copy as MD Link

Revision:

  • 2023-03-12 - initial
  • 2024-08-17 - add domain as in "{ domain.com }"
Code:
javascript:(function() {
function showToast(message, textColor, backgroundColor) {
var toast = document.createElement("div");
toast.style.cssText = "position: fixed; top: 0; left: 0; background-color: " + backgroundColor + "; color: " + textColor + "; padding: 10px; font-family: Arial, Verdana; font-size: 16px; font-weight: bold; z-index: 9999; opacity: 0; transition: opacity 0.3s ease-in-out;";
toast.innerHTML = message;
document.body.appendChild(toast);
setTimeout(function() {
toast.style.opacity = 1;
}, 100);
setTimeout(function() {
toast.style.opacity = 0;
}, 3000);
}

document.body.focus();
var title = document.title;
/* remove [ and ] from title */
title = title.replace(/[\[\]]/g, ' ');

var url = window.location.href;
/* remove utm parameters from url */
url = url.replace(/utm_[^&]+&?/g, '');
/* remove final /? from url */
url = url.replace(/\/\?$/g, '/');
url = url.replace(/\?$/g, '/');

var date = new Date().toISOString().slice(0, 10);
var markdownLink = date + " [" + title + "](" + url + ")";

try {
var urlObject = new URL(url);
var domain = urlObject.hostname;
markdownLink += " { " + domain + " }";
} catch (e) {
console.error("Failed to parse domain name: ", e);
}

setTimeout(function() {
navigator.clipboard.writeText(markdownLink).then(function() {
showToast("Copied to clipboard", "lime", "#333");
}, function() {
showToast("Failed to copy to clipboard", "white", "darkred");
});
}, 100);
})();

Name:

🥧 Copy as ORG Link

Revision:

2024-05-13

Code:
javascript:(function() {
function showToast(message, textColor, backgroundColor) {
var toast = document.createElement("div");
toast.style.cssText = "position: fixed; top: 0; left: 0; background-color: " + backgroundColor + "; color: " + textColor + "; padding: 10px; font-family: Arial, Verdana; font-size: 16px; font-weight: bold; z-index: 9999; opacity: 0; transition: opacity 0.3s ease-in-out;";
toast.innerHTML = message;
document.body.appendChild(toast);
setTimeout(function() {
toast.style.opacity = 1;
}, 100);
setTimeout(function() {
toast.style.opacity = 0;
document.body.removeChild(toast);
}, 3000);
}

document.body.focus();
var title = document.title;
/* remove [ and ] from title */
title = title.replace(/[\[\]]/g, ' ');

var url = window.location.href;
/* remove utm parameters from url */
url = url.replace(/utm_[^&]+&?/g, '');
/* clean up unnecessary trailing characters */
url = url.replace(/\/?\?$/g, '');
url = url.replace(/\?$/g, '/');

var date = new Date().toISOString().slice(0, 10);
var orgModeLink = "[[" + url + "][" + date + " " + title + "]]";

try {
var urlObject = new URL(url);
var domain = urlObject.hostname;
orgModeLink += " =" + domain + "=";
} catch (e) {
console.error("Failed to parse domain name: ", e);
}

setTimeout(function() {
navigator.clipboard.writeText(orgModeLink).then(function() {
showToast("Copied to clipboard", "lime", "#333");
}, function() {
showToast("Failed to copy to clipboard", "white", "darkred");
});
}, 100);
})();

RSS Feed Finder 2

Name:

📶 Find RSS II

Revision:

2025-03-04

Code:
javascript:(async () => {
const pageUrl = document.location.href;
let feedUrls = [];

try {
const resp = await fetch(pageUrl);
const body = await resp.text();
const parser = new DOMParser();
const doc = parser.parseFromString(body, 'text/html');

/* Get standard RSS and Atom feed links */
const linkSelectors = [
'link[type="application/rss+xml"]',
'link[type="application/atom+xml"]',
'link[rel="alternate"][type*="rss"]',
'link[rel="alternate"][type*="atom"]'
];
linkSelectors.forEach(selector => {
const links = Array.from(doc.querySelectorAll(selector));
links.forEach(link => {
const url = link.getAttribute('href');
if (url) feedUrls.push(url);
});
});
} catch (error) {
console.error('Error fetching page source:', error);
}

/* Define site-specific heuristics */
const siteSpecificFeeds = {
'reddit.com': (url, doc) => {
const subredditMatch = url.match(/reddit\.com\/r\/([^\/]+)\/?/);
if (subredditMatch) {
return [`https://www.reddit.com/r/${subredditMatch[1]}/.rss`];
}
return ['https://www.reddit.com/.rss'];
},
'youtube.com': (url, doc) => {
const channelMatch = url.match(/youtube\.com\/channel\/([^\/]+)/);
if (channelMatch) {
return [`https://www.youtube.com/feeds/videos.xml?channel_id=${channelMatch[1]}`];
}
const userMatch = url.match(/youtube\.com\/user\/([^\/]+)/);
if (userMatch) {
return [`https://www.youtube.com/feeds/videos.xml?user=${userMatch[1]}`];
}
return [];
},
'medium.com': (url, doc) => {
return url.endsWith('/feed') ? [] : [`${url.replace(/\/$/, '')}/feed`];
},
'blogspot.com': (url, doc) => {
return [`${url.replace(/\/$/, '')}/feeds/posts/default?alt=rss`];
}
/* Additional sites can be added here */
};

/* Extract the hostname from the current page URL */
const hostname = new URL(pageUrl).hostname;

/* Check and add site-specific feeds if applicable */
Object.keys(siteSpecificFeeds).forEach(domain => {
if (hostname.includes(domain)) {
const siteFeeds = siteSpecificFeeds[domain](pageUrl, document);
feedUrls = feedUrls.concat(siteFeeds);
}
});

/* Convert any relative URLs to absolute URLs using the current page URL as base */
feedUrls = feedUrls.map(url => {
try {
return new URL(url, pageUrl).href;
} catch (e) {
console.error('Invalid URL found:', url);
return url;
}
});

/* Remove duplicates */
feedUrls = [...new Set(feedUrls)];

/* Create the dialog to display the results */
createDialog(feedUrls);

function createDialog(feedUrls) {
const dialog = document.createElement('div');
styleDialog(dialog, feedUrls.length > 0);
document.body.appendChild(dialog);

/* Create a header strip to indicate status */
const headerStrip = document.createElement('div');
headerStrip.style.height = '5px';
headerStrip.style.width = '100%';
headerStrip.style.backgroundColor = feedUrls.length > 0 ? '#4CAF50' : '#f44336';
dialog.appendChild(headerStrip);

/* Create a content container */
const content = document.createElement('div');
content.style.padding = '15px';

if (feedUrls.length > 0) {
const ul = document.createElement('ul');
ul.style.listStyle = 'none';
ul.style.padding = '0';
ul.style.margin = '0 0 10px 0';
feedUrls.forEach(url => {
const li = document.createElement('li');
li.style.marginBottom = '10px';
li.style.display = 'flex';
li.style.justifyContent = 'space-between';
li.style.alignItems = 'center';
li.style.borderBottom = '1px solid #eee';
li.style.paddingBottom = '5px';

const span = document.createElement('span');
span.textContent = url;
span.style.wordBreak = 'break-all';
li.appendChild(span);

const copyBtn = createCopyButton(url);
li.appendChild(copyBtn);
ul.appendChild(li);
});
content.appendChild(ul);
} else {
const message = document.createElement('div');
message.textContent = 'No RSS Feed found';
message.style.textAlign = 'center';
message.style.padding = '10px';
content.appendChild(message);
setTimeout(() => fadeAndRemove(dialog), 3000);
}

const closeBtn = createCloseButton(dialog);
content.appendChild(closeBtn);
dialog.appendChild(content);
}

function styleDialog(dialog, hasFeeds) {
dialog.style.position = 'fixed';
dialog.style.top = '20px';
dialog.style.left = '50%';
dialog.style.transform = 'translateX(-50%)';
dialog.style.backgroundColor = 'white';
dialog.style.borderRadius = '5px';
dialog.style.boxShadow = '0 2px 10px rgba(0,0,0,0.1)';
dialog.style.fontFamily = 'Arial, sans-serif';
dialog.style.fontSize = '14px';
dialog.style.color = '#333';
dialog.style.minWidth = '300px';
dialog.style.overflow = 'hidden';
dialog.style.zIndex = '10000';
}

function createCopyButton(text) {
const button = document.createElement('button');
button.textContent = 'Copy';
button.style.padding = '5px 10px';
button.style.marginLeft = '10px';
button.style.border = 'none';
button.style.borderRadius = '3px';
button.style.backgroundColor = '#eee';
button.style.cursor = 'pointer';
button.onclick = () => {
navigator.clipboard.writeText(text).then(() =>
fadeAndRemove(button.closest('div'))
);
};
return button;
}

function createCloseButton(dialog) {
const button = document.createElement('button');
button.textContent = 'Close';
button.style.padding = '5px 10px';
button.style.border = 'none';
button.style.borderRadius = '3px';
button.style.backgroundColor = '#ddd';
button.style.cursor = 'pointer';
button.style.display = 'block';
button.style.margin = '10px auto 0 auto';
button.onclick = () => dialog.remove();
return button;
}

function fadeAndRemove(element) {
element.style.transition = 'opacity 0.5s';
element.style.opacity = '0';
setTimeout(() => element.remove(), 500);
}
})();


RSS Feed Finder

Name:

📶 Find RSS

Revision:

2024-01-01

Code:
javascript:(async () => {
const pageUrl = document.location.href;

try {
const resp = await fetch(pageUrl);
const body = await resp.text();
const parser = new DOMParser();
const doc = parser.parseFromString(body, 'text/html');
const rssLinks = doc.querySelectorAll('link[type="application/rss+xml"]');
createDialog(Array.from(rssLinks).map(link => link.getAttribute('href')));
} catch (error) {
console.error('Error fetching page source:', error);
createDialog([]);
}

function createDialog(feedUrls) {
const dialog = document.createElement('div');
styleDialog(dialog, feedUrls.length > 0);
document.body.appendChild(dialog);

if (feedUrls.length > 0) {
const ul = document.createElement('ul');
feedUrls.forEach(url => {
const li = document.createElement('li');
li.textContent = url;
const copyBtn = createCopyButton(url);
li.appendChild(copyBtn);
ul.appendChild(li);
});
dialog.appendChild(ul);
} else {
dialog.textContent = 'No RSS Feed found';
setTimeout(() => fadeAndRemove(dialog), 3000);
}

const closeBtn = createCloseButton(dialog);
dialog.appendChild(closeBtn);
}

function styleDialog(dialog, hasFeeds) {
dialog.style.position = 'fixed';
dialog.style.top = '20px';
dialog.style.left = '50%';
dialog.style.transform = 'translateX(-50%)';
dialog.style.backgroundColor = hasFeeds ? 'green' : 'red';
dialog.style.padding = '20px';
dialog.style.zIndex = '10000';
dialog.style.color = 'white';
dialog.style.borderRadius = '5px';
dialog.style.fontSize = '16px';
}

function createCopyButton(text) {
const button = document.createElement('button');
button.textContent = 'Copy to Clipboard';
button.style.marginLeft = '10px';
button.onclick = () => {
navigator.clipboard.writeText(text).then(() => fadeAndRemove(button.parentElement.parentElement.parentElement));
};
return button;
}

function createCloseButton(dialog) {
const button = document.createElement('button');
button.textContent = 'Close';
button.style.display = 'block';
button.style.marginTop = '10px';
button.onclick = () => dialog.remove();
return button;
}

function fadeAndRemove(element) {
element.style.transition = 'opacity 0.5s';
element.style.opacity = '0';
setTimeout(() => element.remove(), 500);
}
})();

Open ChatGPT Summary Prompt

Name:

🔎 Open ChatGPT with Summary Prompt

Revision:

2025-03-23

Code:
javascript:(function() {
var currentUrl = window.location.href;
var prompt = [
"Begin your response with 'Tags:' followed by up to 10 meaningful tags that capture the main ideas of the article. ",
"Then, in 30 words or fewer, provide the article's main idea (without labeling it). ",
"After that, present key sub-ideas or secondary points that should not be missed, but do not include a heading for that section. ",
"Finally, conclude with a brief note (1-2 sentences) on why this article is interesting or important, also without a heading. ",
"Search the web / use webtool to find the content by url: \"" + currentUrl + "\""
].join('');
var newUrl = "https://chatgpt.com/?q=" + encodeURIComponent(prompt);
window.open(newUrl, "_blank");
})();

Leetcode copy submission

Name:

✨ Leetcode get submission url

Revision:

2024-05-07

Code:

Code snippet for ✨ Leetcode get submission url
javascript:(function(){
function transformURL(url) {
const regex = /https:\/\/leetcode\.com\/problems\/.+?\/submissions\/(\d+)/;
const match = url.match(regex);
if (match && match[1]) {
return `https://leetcode.com/submissions/detail/${match[1]}/`;
}
return null;
}

function copyToClipboard(text) {
const textarea = document.createElement('textarea');
textarea.value = text;
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
}

function showToast(message) {
const toast = document.createElement('div');
toast.textContent = message;
toast.style.position = 'fixed';
toast.style.bottom = '20px';
toast.style.left = '50%';
toast.style.transform = 'translateX(-50%)';
toast.style.backgroundColor = 'black';
toast.style.color = 'white';
toast.style.padding = '10px 20px';
toast.style.borderRadius = '5px';
toast.style.zIndex = '10000';
document.body.appendChild(toast);
setTimeout(() => {
toast.style.transition = 'opacity 0.5s ease';
toast.style.opacity = '0';
setTimeout(() => document.body.removeChild(toast), 500);
}, 2000);
}

function triggerFireworks() {
const emojis = ['🎉', '🎊', '✨', '🌟'];
const maxParticles = 20;
for (let i = 0; i < maxParticles; i++) {
const particle = document.createElement('div');
particle.textContent = emojis[Math.floor(Math.random() * emojis.length)];
particle.style.position = 'fixed';
particle.style.fontSize = '24px';
particle.style.animation = 'firework 2s linear forwards';
particle.style.left = `${Math.random() * window.innerWidth}px`;
particle.style.bottom = '0px';
document.body.appendChild(particle);
particle.addEventListener('animationend', () => document.body.removeChild(particle));
}
}

const style = document.createElement('style');
document.head.appendChild(style);
style.sheet.insertRule(`@keyframes firework {
0% { transform: translateY(0); opacity: 1; }
100% { transform: translateY(-300px); opacity: 0; }
}`, 0);

const newUrl = transformURL(window.location.href);
if (newUrl) {
copyToClipboard(newUrl);
showToast('URL copied to clipboard!');
triggerFireworks();
} else {
showToast('No matching URL found!');
}
})();

Content editable

Flips contentEditable on body to make copy-paste on laptop from keyboard easier.

Name:

🔛 Content Editable

Revision:

2023-03-12

Code:

javascript: document.body.contentEditable = (document.body.contentEditable === 'true') ? false : true;

Helpful for podcast sites

Name:

🧓 Silver Links

Revision:

2023-05-31

Code:

javascript:(function() {
var newStylesheet = document.createElement('style');
document.head.appendChild(newStylesheet);
newStylesheet.sheet.insertRule('a:visited { color: silver !important }', 0);
})();

Wake lock

Through the browser api, and while the current browser page is active, forces the screen to never lock or go sleep.

Name:

👀 Wake Lock

Revision:

2023-06-28

Code:

javascript:(async function() {
let statusElem = document.createElement('div');
statusElem.style.position = 'fixed';
statusElem.style.bottom = '0';
statusElem.style.right = '0';
statusElem.style.background = 'lightgray';
statusElem.style.padding = '10px';
document.body.appendChild(statusElem);

let wakeLock = null;
try {
wakeLock = await navigator.wakeLock.request('screen');
statusElem.textContent = 'Wake Lock is active!';
} catch (err) {
statusElem.textContent = `${err.name}, ${err.message}`;
}
})();

Next, please!

Placeholder.