Skip to content

Instantly share code, notes, and snippets.

@jerome-breton
Last active September 5, 2024 17:22
Show Gist options
  • Select an option

  • Save jerome-breton/986d1221ac062f77a35e51b976d131f1 to your computer and use it in GitHub Desktop.

Select an option

Save jerome-breton/986d1221ac062f77a35e51b976d131f1 to your computer and use it in GitHub Desktop.
Bookmarklet for removing played items from your Youtube Playlist
/** Minified version with https://dotmaui.com/jsminify/
javascript:(()=>{let e=window.location,t=document;if("www.youtube.com"!=e.host&&"/playlist"!=e.pathname)return void alert("You must be in a Youtube playlist !");let n=t.createElement("div");n.style="position:fixed;z-index:2999;top:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,0.8);",t.body.appendChild(n);let o=new URLSearchParams(e.search),i=t.createElement("iframe");i.src=e.origin+e.pathname+"?"+o.toString(),i.style="display:none",i.sandbox="allow-same-origin allow-scripts allow-top-navigation allow-presentation";let r="("+(e=>{function t(e){return new Promise(t=>{let n;if(n=document.querySelector(e))return t(n);const o=new MutationObserver(i=>{(n=document.querySelector(e))&&(t(n),o.disconnect())});o.observe(document.body,{childList:!0,subtree:!0})})}function n(e,r,l){var a;if(e.length){let o=e.pop().closest("ytd-playlist-video-renderer");o.querySelector("#menu #button").click(),t("tp-yt-iron-dropdown:not([id=dropdown])").then(t=>{(a=t,new Promise(e=>{if("none"!=a.style.display)return e(a);const t=new MutationObserver(n=>{"none"!=a.style.display&&(e(a),t.disconnect())});t.observe(a,{attributes:!0})})).then(()=>{[].slice.call(document.querySelectorAll("ytd-menu-service-item-renderer"))[3].click(),function(e){return new Promise(t=>{if(!e.isConnected)return t(e);const n=new MutationObserver(o=>{e.isConnected||(t(e),n.disconnect())});n.observe(e.parentNode,{childList:!0})})}(o).then(()=>{let t=100*(r-e.length)/r;i.postMessage({w:t+"%",i:Math.round(t)+"% ("+(r-e.length)+"/"+r+")"},"*"),window.setTimeout(()=>{n(e,r,l)},500)})})})}else if(i.postMessage({i:"Checking, please wait..."},"*"),l)console.log("Reload !");else{let e=/([?&])rnd=.*?(&|$)/i;o.location.search.match(e)?o.location=o.location.href.replace(e,"$1rnd="+Date.now()+"$2"):o.location=o.location.href+"&rnd="+Date.now()}}let o=document,i=window.parent;t("ytd-playlist-video-list-renderer").then(()=>{window.setTimeout(()=>{let t=Array.from(document.querySelectorAll("ytd-thumbnail-overlay-resume-playback-renderer"));t.length?n(t,t.length,e):(i.postMessage({i:"Refreshing, please wait..."},"*"),i.location.reload(!0))},2e3)})})+")(false)";window.trustedTypes&&trustedTypes.createPolicy&&(r=trustedTypes.createPolicy("noEscapePolicy",{createScript:e=>e}).createScript(r)),i.onload=(()=>{i.contentWindow.eval(r)}),t.body.appendChild(i);let l=t.createElement("div");l.style="position:absolute;left:0;right:0;top:0;bottom:0;width:830px;height:4px;margin:auto;background:#999;padding:0",n.appendChild(l);let a=t.createElement("div");a.style="height:4px;background:red;transition:width 1s ease 0s;width:0;",l.appendChild(a);let s=t.createElement("div");s.style="position:absolute;width:100%;height:100%;text-align:center;font-size:13px;color:white;line-height:30px;top:0;",s.innerText="Loading, please wait...",l.appendChild(s),window.addEventListener("message",e=>{let t=e.data;t.hasOwnProperty("w")&&(a.style.width=t.w),t.hasOwnProperty("i")&&(s.innerText=t.i)},!1)})();
**/
javascript:(() => {
let winloc = window.location;
let doc = document;
let debug = false;
let viewframe = debug || false;
if(debug) debugger;
if(winloc.host != 'www.youtube.com' && winloc.pathname != '/playlist'){
alert('You must be in a Youtube playlist !');
return;
}
/* Code being eval'ed in iframe */
let loop = (debug) => {
if(debug) debugger;
let doc = document;
let winpar = window.parent;
function waitForElm(selector) {
return new Promise(resolve => {
let elm;
if (elm = document.querySelector(selector)) {
return resolve(elm);
}
const observer = new MutationObserver(mutations => {
if (elm = document.querySelector(selector)) {
resolve(elm);
observer.disconnect();
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
});
}
function waitForVisible(elm) {
return new Promise(resolve => {
if (elm.style.display != 'none') {
return resolve(elm);
}
const observer = new MutationObserver(mutations => {
if (elm.style.display != 'none') {
resolve(elm);
observer.disconnect();
}
});
observer.observe(elm, {
attributes: true
});
});
}
function waitForDisconnected(elm) {
return new Promise(resolve => {
if (!elm.isConnected) {
return resolve(elm);
}
const observer = new MutationObserver(mutations => {
if (!elm.isConnected) {
resolve(elm);
observer.disconnect();
}
});
observer.observe(elm.parentNode, {
childList : true
});
});
}
function removeNext(c, max, debug){
if (!c.length) {
/* Job maybe done, reload iframe */
winpar.postMessage({ i: 'Checking, please wait...' }, '*');
if (debug) {
console.log('Reload !')
} else {
let regex = new RegExp("([?&])rnd=.*?(&|$)", "i");
if (doc.location.search.match(regex)) {
doc.location = doc.location.href.replace(regex, '$1rnd=' + Date.now() + '$2');
} else {
doc.location = doc.location.href + "&rnd=" + Date.now();
}
}
return;
} else {
/* Click menu */
let v = c.pop().closest("ytd-playlist-video-renderer");
v.querySelector("#menu #button").click();
waitForElm("tp-yt-iron-dropdown:not([id=dropdown])").then((m) => {
waitForVisible(m).then(() => {
/* Click 4th option */
let d = [].slice.call(document.querySelectorAll('ytd-menu-service-item-renderer'));
d[3].click()
waitForDisconnected(v).then(() => {
/* Update progress */
let pc = 100 * (max - c.length) / max;
winpar.postMessage({ w: pc + '%', i: Math.round(pc) + '% (' + (max - c.length) + '/' + max + ')' }, '*');
window.setTimeout(() => {
removeNext(c, max, debug);
}, 500);
});
});
});
}
}
waitForElm('ytd-playlist-video-list-renderer').then(() => {
window.setTimeout(() => {
/* Prevent real deletion and refreshing */
if(debug) debugger;
/* Get played */
let c = Array.from(document.querySelectorAll('ytd-thumbnail-overlay-resume-playback-renderer'));
if(!c.length){
/* Job done, reload parent ! */
winpar.postMessage({i: 'Refreshing, please wait...'}, '*');
winpar.location.reload(true);
} else {
removeNext(c, c.length, debug);
}
}, 2000);
});
};
/* Background color mask */
let ov = doc.createElement('div');
ov.style = 'position:fixed;z-index:2999;top:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,0.8);';
doc.body.appendChild(ov);
/* Iframe */
let urlParams = new URLSearchParams(winloc.search);
let ifr = doc.createElement('iframe');
ifr.src = winloc.origin + winloc.pathname + '?' + urlParams.toString();
ifr.style = viewframe ? 'display:block;z-index:4000;position:relative;top:0;left:0;width:100%;height:50vh' : 'display:none';
ifr.sandbox = "allow-same-origin allow-scripts allow-top-navigation allow-presentation"
/* Inject loop function in iframe */
let loopString = '(' + loop.toString() + ')(' + (debug?'true':'false') + ')';
if (window.trustedTypes && trustedTypes.createPolicy) {
loopString = trustedTypes.createPolicy('noEscapePolicy', { createScript: string => string }).createScript(loopString);
}
ifr.onload = () => { ifr.contentWindow.eval(loopString); };
doc.body.appendChild(ifr);
/* Progress bar background */
let bar = doc.createElement('div');
bar.style = 'position:absolute;left:0;right:0;top:0;bottom:0;width:830px;height:4px;margin:auto;background:#999;padding:0';
ov.appendChild(bar);
/* and front */
let pbar = doc.createElement('div');
pbar.style = 'height:4px;background:red;transition:width 1s ease 0s;width:0;';
bar.appendChild(pbar);
/* and text */
let bt = doc.createElement('div');
bt.style = 'position:absolute;width:100%;height:100%;text-align:center;font-size:13px;color:white;line-height:30px;top:0;';
bt.innerText = 'Loading, please wait...';
bar.appendChild(bt);
window.addEventListener("message", (event) => {
let data = event.data;
if(data.hasOwnProperty('w')){
pbar.style.width = data.w;
}
if(data.hasOwnProperty('i')){
bt.innerText = data.i;
}
}, false);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment