Last active
June 15, 2023 15:03
-
-
Save Acendro/098f82e014a21ea18cad25af77d0bcff to your computer and use it in GitHub Desktop.
Removes watched videos from playlist either by %watched or removes all videos of that playlist // tampermonkey
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Youtube Playlist Cleanser 1.0 | |
// @namespace Youtube Playlist Cleanser 1.0 | |
// @version 1.0 | |
// @description Removes watched videos from playlist either by %watched or all | |
// @author Acendro | |
// @include http*://*.youtube.com/* | |
// @include http*://youtube.com/* | |
// @include http*://*.youtu.be/* | |
// @include http*://youtu.be/* | |
// @run-at document-end | |
// ==/UserScript== | |
// Config | |
var show_on_all = false; //Set to true do display buttons on all playlists; overwrites next option | |
var playlists = ["MyPlaylist1", "AnotherOne"]; //If option above == false then display buttons on those playlists only | |
var threshold = 90; //Delete if watched more or equal to % of video | |
var sleeptimer = 600; //Sleep interval for cleanse function (seems to need to be quite high for consistent results) | |
var sleeptimer_short = 50; //Sleep interval for Delete ALL function | |
// Config | |
const sleep = (timeout) => new Promise(res => setTimeout(res, timeout)) | |
function CreateButton(){ | |
var buttonDiv = document.createElement("div"); | |
buttonDiv.id = "CleanseButton"; | |
var cleanseButton = document.createElement("button"); | |
cleanseButton.textContent = 'Cleanse'; | |
//cleanseButton.appendChild(document.createTextNode("Cleanse")); | |
cleanseButton.style.width = "75px"; | |
cleanseButton.style.height = "100%"; | |
cleanseButton.style.backgroundColor = "#181717"; | |
cleanseButton.style.color = "white"; | |
cleanseButton.style.textAlign = "center"; | |
cleanseButton.style.fontSize = "14px"; | |
cleanseButton.style.border = "0"; | |
cleanseButton.style.cursor = "pointer"; | |
cleanseButton.style.borderRadius = "2px"; | |
cleanseButton.style.fontFamily = "Roboto, Arial, sans-serif"; | |
cleanseButton.style.borderRadius = "2px"; | |
cleanseButton.style.marginLeft = "10px"; | |
buttonDiv.appendChild(cleanseButton); | |
buttonDiv.addEventListener("click", function() { | |
playlist_cleanser(); | |
}); | |
var targetElement = document.querySelectorAll(".dropdown-trigger")[1]; | |
insertAfter(targetElement, buttonDiv); | |
var buttonDivTwo = document.createElement("div"); | |
buttonDivTwo.id = "CleanseButtonTwo"; | |
var cleanseButtonTwo = document.createElement("button"); | |
//cleanseButtonTwo.appendChild(document.createTextNode("All")); | |
cleanseButtonTwo.textContent = 'ALL'; | |
cleanseButtonTwo.style.width = "75px"; | |
cleanseButtonTwo.style.height = "100%"; | |
cleanseButtonTwo.style.backgroundColor = "#ff0000"; | |
cleanseButtonTwo.style.color = "white"; | |
cleanseButtonTwo.style.textAlign = "center"; | |
cleanseButtonTwo.style.fontSize = "14px"; | |
cleanseButtonTwo.style.border = "0"; | |
cleanseButtonTwo.style.cursor = "pointer"; | |
cleanseButtonTwo.style.borderRadius = "2px"; | |
cleanseButtonTwo.style.fontFamily = "Roboto, Arial, sans-serif"; | |
cleanseButtonTwo.style.borderRadius = "2px"; | |
cleanseButtonTwo.style.marginLeft = "10px"; | |
buttonDivTwo.appendChild(cleanseButtonTwo); | |
buttonDivTwo.addEventListener("click", function() { | |
console.log("clicked"); | |
delete_ALL(); | |
}); | |
insertAfter(buttonDiv, buttonDivTwo); | |
} | |
function insertAfter(referenceNode, newNode) { | |
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); | |
} | |
async function delete_ALL() { | |
console.log("delete_ALL"); | |
while(true){ | |
var logger = ''; | |
var playlist_title = document.querySelector('#display-dialog').querySelector('#text-displayed').innerHTML; | |
var elementList = document.querySelectorAll('#contents'); | |
var playlist = elementList[1]; | |
var real_playlist = playlist.querySelector('#contents'); | |
//console.log(real_playlist); | |
var video_one = document.querySelector('#index-container'); | |
//console.log(video_one); | |
if(!video_one) break; | |
var descendents = real_playlist.getElementsByTagName('*'); | |
var deleter = true; | |
for(var i=0; i<descendents.length; i++){ | |
var element = descendents[i]; | |
if(deleter == true){ | |
if (element.id == 'video-title'){ | |
var namer = element.innerHTML; | |
var link = element.href.split('&list')[0] | |
console.log("Deleting: " + namer + " -> " + link); | |
} | |
if(element.id == 'button'){ | |
await new Promise((resolve) => { | |
setTimeout(() => { | |
element.click(); | |
resolve(); | |
}, sleeptimer_short); | |
}); | |
//sleep(sleeptimer_short); | |
var menu = document.querySelectorAll('#contentWrapper')[2]; | |
var items = menu.getElementsByTagName('*'); | |
for(var y=0; y<items.length; y++){ | |
if(items[y].classList.contains("ytd-menu-popup-renderer")) var menu_deleteoption = items[y]; | |
if(items[y].innerHTML == playlist_title){ | |
await new Promise((resolve) => { | |
setTimeout(() => { | |
menu_deleteoption.click(); | |
deleter = false; | |
resolve(); | |
}, sleeptimer_short); | |
}); | |
//sleep(sleeptimer_short); | |
} | |
if(deleter == false){ | |
//console.log("break"); | |
break; | |
} | |
} | |
} | |
} | |
if(deleter == false){ | |
//console.log("break"); | |
break; | |
} | |
} | |
} | |
} | |
async function playlist_cleanser() { | |
console.log("playlist_cleanser"); | |
while(true){ | |
console.log("--------------------"); | |
var all_progress = document.querySelectorAll('#progress'); | |
var continue_on = false; | |
var value_check; | |
for (var z = 0; z < all_progress.length; z++) { | |
value_check = all_progress[z].style.cssText.substring(0, all_progress[z].style.cssText.length - 2).split('width: ')[1]; | |
//console.log(value_check); | |
if(value_check && value_check >= threshold){ | |
continue_on = true; | |
break; | |
} | |
} | |
if(continue_on == false){ | |
console.log("@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); | |
console.log(" DONE CLEANSING"); | |
console.log("@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); | |
console.log("--------------------"); | |
break; | |
} | |
console.log("Found videos in playlist that match threshold criteria"); | |
console.log("--------------------"); | |
var logger = ''; | |
var playlist_title = document.querySelector('#display-dialog').querySelector('#text-displayed').innerHTML; | |
var elementList = document.querySelectorAll('#contents'); | |
var playlist = elementList[1]; | |
var real_playlist = playlist.querySelector('#contents'); | |
var descendents = real_playlist.getElementsByTagName('*'); | |
var deleter = false; | |
for(var i=0; i<descendents.length; i++){ | |
var element = descendents[i]; | |
if(element.id == 'progress'){ | |
logger += "At least partly watched, checking if threshhold met"; | |
//console.log("At least partly watched, checking if threshhold met"); | |
var value = element.style.cssText.substring(0, element.style.cssText.length - 2).split('width: ')[1]; | |
//console.log("Watched for " + value + "%"); | |
logger += " | Watched for " + value + "%"; | |
if(value >= threshold){ | |
deleter = true; | |
logger += " | Threshhold met -> delete"; | |
//console.log(logger); | |
logger = ''; | |
//console.log("Threshhold met -> delete"); | |
} | |
else{ | |
deleter = false; | |
logger += " | Leave in watchlist"; | |
//console.log(logger); | |
logger = ''; | |
} | |
} | |
if(deleter == true){ | |
if (element.id == 'video-title'){ | |
var namer = element.innerHTML; | |
var link = element.href.split('&list')[0] | |
console.log("Deleting: " + namer + " -> " + link); | |
} | |
if(element.id == 'button'){ | |
await new Promise((resolve) => { | |
setTimeout(() => { | |
element.click(); | |
resolve(); | |
}, sleeptimer); | |
}); | |
sleep(sleeptimer); | |
var menu = document.querySelectorAll('#contentWrapper')[2]; | |
var items = menu.getElementsByTagName('*'); | |
for(var y=0; y<items.length; y++){ | |
if(items[y].classList.contains("ytd-menu-popup-renderer")) var menu_deleteoption = items[y]; | |
if(items[y].innerHTML == playlist_title){ | |
await new Promise((resolve) => { | |
setTimeout(() => { | |
menu_deleteoption.click(); | |
deleter = false; | |
resolve(); | |
}, sleeptimer); | |
}); | |
sleep(sleeptimer*2); | |
} | |
if(deleter == false){ | |
//console.log("break"); | |
break; | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
document.addEventListener("DOMContentLoaded", function(event) { | |
if(document.getElementById("polymer-app") || document.getElementById("masthead") || window.Polymer){ | |
setInterval(function(){ | |
if(window.location.href.indexOf("playlist?list=") < 0) return false; | |
var playlist_titler = document.querySelector('#display-dialog').querySelector('#text-displayed').innerHTML; | |
if(show_on_all == true){ | |
if(document.getElementById("CleanseButton") === null) CreateButton(); | |
} | |
else{ | |
if(playlists.includes(playlist_titler)){ | |
if(document.getElementById("CleanseButton") === null) CreateButton(); | |
} | |
else return false; | |
} | |
}, 100); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Cleaned it up and updated for latest YouTube version here: https://gist.github.com/js6pak/33bdefdefac09c387f55d08c5b9526fa