Forked from qoomon/youtube_clean_watch_later_videos.js
Last active
March 11, 2023 19:41
-
-
Save udovichenko/295357dc6b504e4ce3dd540ad6c368a4 to your computer and use it in GitHub Desktop.
Clean YouTube Watch Later Videos with Limit and Random Delay
This file contains hidden or 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
(async function() { | |
const REMOVE_BUTTON_TEXT = 'Remove from Watch later' | |
// de-DE: const REMOVE_BUTTON_TEXT = 'Aus "Später ansehen" entfernen' | |
// pt-BR: const REMOVE_BUTTON_TEXT = 'Remover de Assistir mais tarde' | |
// swe-SE: const REMOVE_BUTTON_TEXT = 'Ta bort från Titta senare' | |
// zh-Hans-CN: const REMOVE_BUTTON_TEXT = '从稍后观看中移除' | |
// ru-RU: const REMOVE_BUTTON_TEXT = 'Удалить из плейлиста "Смотреть позже"' | |
const playlistName = document.querySelector('#title a').text | |
const limit = +prompt(`How many videos do you want to remove from ${playlistName}?`) | |
if (!limit) return | |
console.info('start...') | |
let count = 0 | |
while (true) { | |
const videos = document.querySelectorAll('#primary ytd-playlist-video-renderer') | |
if (videos.length == 0) break | |
for (const videoElement of videos) { | |
const videoTitle = videoElement.querySelector('a#video-title') | |
console.info(`Remove Video\n` + ` Title: ${videoTitle.innerText}\n` + ` URL: ${videoTitle.href}`) | |
const actionMenuButton = videoElement.querySelector('#menu #button') | |
console.debug('click actionMenuButton', actionMenuButton) | |
actionMenuButton.click() | |
const removeButton = await untilDefined(() => { | |
for (const actionMenu of [...document.querySelectorAll('ytd-popup-container > tp-yt-iron-dropdown')]) { | |
if ((actionMenu) => actionMenu.style.display !== 'none') { | |
for (const actionButton of [...actionMenu.querySelectorAll('tp-yt-paper-item')]) { | |
if (actionButton.innerText.trim().toLowerCase() === REMOVE_BUTTON_TEXT.toLowerCase()) { | |
return actionButton | |
} | |
} | |
} | |
} | |
console.debug('wait for removeButton') | |
}) | |
console.debug('click removeButton', removeButton) | |
removeButton.click() | |
count++ | |
if (count >= limit) break | |
const randDelay = 1000 + Math.random() * 400 | |
await sleep(randDelay) | |
} | |
if (count >= limit) break | |
} | |
console.info('done!') | |
// === util functions ======================================================== | |
async function sleep(timeout) { | |
return new Promise((res) => setTimeout(res, timeout)) | |
} | |
async function untilDefined(factory, checkInterval = 100) { | |
while (true) { | |
const value = factory() | |
if (value != null) return value | |
await sleep(checkInterval) | |
} | |
} | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment