Skip to content

Instantly share code, notes, and snippets.

@astamicu
Last active December 17, 2024 01:31
Show Gist options
  • Save astamicu/eb351ce10451f1a51b71a1287d36880f to your computer and use it in GitHub Desktop.
Save astamicu/eb351ce10451f1a51b71a1287d36880f to your computer and use it in GitHub Desktop.
Script to remove all videos from Youtube Watch Later playlist

UPDATED 22.11.2022

It's been two years since the last update, so here's the updated working script as per the comments below.

Thanks to BryanHaley for this.

setInterval(function () {
    video = document.getElementsByTagName('ytd-playlist-video-renderer')[0];

    video.querySelector('#primary button[aria-label="Action menu"]').click();

    var things = document.evaluate(
        '//span[contains(text(),"Remove from")]',
        document,
        null,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
        null
    );

    for (var i = 0; i < things.snapshotLength; i++) 
    {
        things.snapshotItem(i).click();
    }
}, 500);

Non-english users will need to change "Action menu" and "Remove from" to what YouTube uses for their localization.

@BIRTAX38
Copy link

BIRTAX38 commented May 1, 2024

Polska wersja:

setInterval(function () {
    video = document.getElementsByTagName('ytd-playlist-video-renderer')[0];

    video.querySelector('#primary button[aria-label="Menu czynności"]').click();

    var things = document.evaluate(
        '//span[contains(text(),"Usuń z")]',
        document,
        null,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
        null
    );

    for (var i = 0; i < things.snapshotLength; i++) 
    {
        things.snapshotItem(i).click();
    }
}, 400);

@jeduardobras
Copy link

Brazilian Portuguese version:

setInterval(function () {
    video = document.getElementsByTagName('ytd-playlist-video-renderer')[0];

    video.querySelector('#primary button[aria-label="Menu de ações"]').click();

    var things = document.evaluate(
        '//span[contains(text(),"Remover de")]',
        document,
        null,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
        null
    );

    for (var i = 0; i < things.snapshotLength; i++) 
    {
        things.snapshotItem(i).click();
    }
}, 500);

Works for the European Portuguese version of YouTube as well. Thanks!

@John-nata
Copy link

John-nata commented Aug 14, 2024

Hi guys!
Just wanna share my userscript (inspired by @colejd's script) to helps you tidy up your YT playlists : YT-Playlist-Cleaner

Here are the key features :
-Customisable settings for deletion criteria
-Auto-scroll functionality to process large playlists
-Improved user interface with progress bar and status updates
-Pause and resume functionality
-Configurable delays between deletions to avoid rate limiting

screenshot

Tbh, I received some helpful suggestions from Claude AI to optimize some parts of my script before uploading it online.
Let me know what you think!

@Someone117
Copy link

I created a similar script that works by just clicking the 3 dots and then on the "Remove from playlist" button. By default, this script removes 100 videos, but that is also adjustable

This should work for all languages, so paste the script into your console and run.

YT might change their UI and you may have different screen resolution, so you may need to adjust the click x and y for each. You may also need to increase the delay if videos don't load fast enough (you can also run it multiple times).

function simulateClick(x, y) {
    // What acually does the clicking
    var event = new MouseEvent('click', {
        view: window,
        bubbles: true,
        cancelable: true,
        clientX: x,
        clientY: y
    });
    document.elementFromPoint(x, y).dispatchEvent(event);
}

function performClicks() {
    let count = 0;

    function clickSequence() {
        // change this number to remove more videos
        if (count >= 100) {
            console.log("Completed 100 click sequences.");
            return;
        }

        // change this when the UI changes, this should be the location of the 3 dots
        simulateClick(1872, 256);
        console.log(`Click sequence ${count + 1} pt 1`);

        setTimeout(function() {
            // change this when the UI changes, this should be the location of the "Remove From Playlist" button
            simulateClick(1784, 333);
            console.log(`Click sequence ${count + 1} pt 2`);

            count++;

            // Wait 100ms, you may want to set this to more time to let the next video load
            setTimeout(clickSequence, 100);
        // Wait 100ms, you may want to set this to more time to let the next video load
        }, 100);
    }

    // Start
    clickSequence();
}

// Execute the click sequences
performClicks();

This code prints your mouse location to the console so you can tailor the script

document.addEventListener('mousemove', function(event) {
    let x = event.clientX;
    let y = event.clientY;
    console.log(`Mouse position: X: ${x}, Y: ${y}`);
});

@BIRTAX38
Copy link

BIRTAX38 commented Oct 14, 2024

Universal version for all languages:

setInterval(function () {
    video = document.getElementsByTagName('ytd-playlist-video-renderer')[0];

    video.querySelector(`#primary button[aria-label="${window.ytcfg.msgs["VIDEO_ACTION_MENU"]}"]`).click();

    var things = document.evaluate(
        `//span[contains(text(),"${document.querySelector('meta[name="title"]')?.content}")]`,
        document,
        null,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
        null
    );

    for (var i = 0; i < things.snapshotLength; i++) 
    {
        things.snapshotItem(i).click();
    }
}, 400);

@jstrocel
Copy link

window.ytcfg

This object returns an undefined object for me when I tried it in english.

@nightbasilisk
Copy link

To remove hidden videos. Click the dots in Watch Later playlist and select "Show unavailable videos" then run this version of the script:

setInterval(function () {
    video = document.getElementsByTagName('ytd-playlist-video-renderer')[0];

    video.querySelector('#primary button').click();

    var things = document.evaluate(
        '//span[contains(text(),"Remove from")]',
        document,
        null,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
        null
    );

    for (var i = 0; i < things.snapshotLength; i++) 
    {
        things.snapshotItem(i).click();
    }
}, 1000);

@secbug
Copy link

secbug commented Nov 17, 2024

@nightbasilisk That worked perfect for me, but the timeout seemed really long. So I added a little something extra to randomize the clicking, but shorten the average up a little bit.

const getRandomMillis = (min, max) => {
  return Math.random() * (max - min) + min
}

setInterval(function () {
    video = document.getElementsByTagName('ytd-playlist-video-renderer')[0];

    video.querySelector('#primary button').click();

    var things = document.evaluate(
        '//span[contains(text(),"Remove from")]',
        document,
        null,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
        null
    );

    for (var i = 0; i < things.snapshotLength; i++) 
    {
        things.snapshotItem(i).click();
    }
}, getRandomMillis(700, 1100));

@JaiganeshKumaran
Copy link

JaiganeshKumaran commented Nov 26, 2024

No longer works for me. It deletes the first one, and then the menu gets stuck at the top-left corner.

@anhtuan219
Copy link

anhtuan219 commented Dec 5, 2024

Thanks @vinivosh
Here's Vietnamese version, including removing the hidden videos and clearing the interval after the playlist is empty

  1. Go to Youtube Watch Later playlist
  2. Ctrl + Shift + I to open chrome devtools -> Choose the Console tab
  3. Type 'allow pasting' in the console
  4. Paste this into the console
var deleteInterval = setInterval(function () {
    video = document.getElementsByTagName('ytd-playlist-video-renderer')[0];

    if(!video) {
         clearInterval(deleteInterval);
         return;
    }

    video.querySelector('#primary button[aria-label="Menu tác vụ"]').click();

    var things = document.evaluate(
        '//span[contains(text(),"Xóa khỏi")]',
        document,
        null,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
        null
    );

    for (var i = 0; i < things.snapshotLength; i++) 
    {
        things.snapshotItem(i).click();
    }
}, 1000);
  1. Paste this into the console to remove the hidden videos
// Show hidden videos
var btnListWL = document.querySelector('.metadata-buttons-wrapper.style-scope.ytd-playlist-header-renderer');
btnListWL.lastElementChild.lastElementChild.lastElementChild.click();
setTimeout(() => {
     var showHiddenVideoLink = document.querySelector('a[href="/playlist?list=WL"]').click();
}, 500);

// Remove the hidden videos
setTimeout(() => {
var deleteHiddenVideosInterval = setInterval(function () {
    video = document.getElementsByTagName('ytd-playlist-video-renderer')[0];

    if(!video) {
         clearInterval(deleteHiddenVideosInterval);
         return;
    }

    video.querySelector('button').click();

    var things = document.evaluate(
        '//span[contains(text(),"Xóa khỏi")]',
        document,
        null,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
        null
    );

    for (var i = 0; i < things.snapshotLength; i++) 
    {
        things.snapshotItem(i).click();
    }
}, 1000);
}, 1000);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment