7

Script to remove all videos from Youtube Watch Later playlist

 1 year ago
source link: https://gist.github.com/astamicu/eb351ce10451f1a51b71a1287d36880f
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Script to remove all videos from Youtube Watch Later playlist · GitHub

Instantly share code, notes, and snippets.

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.

This will only work while you are watching the playlist:
you need to change the value of howManyToDelete to decide how many of the videos you want to delete

howManyToDelete = 5;
loopValue = 0;
new Promise((resolve1, reject) => {
  const loop = function () {
    if (++loopValue > howManyToDelete) {
      resolve1();
    } else {
      document.querySelector('#secondary button[aria-label="Action menu"]').click();
      new Promise((resolve) => setTimeout(() => resolve(), 200))
        .then(() => {
          document.querySelector('ytd-menu-service-item-renderer[aria-selected="false"]').click();
        })
        .then(new Promise((resolve) => setTimeout(() => resolve(), 200)))
        .then(loop)
        .catch((err) => console.log(err));
    }
  };
  loop();
});

Thank you, this is working for me at the moment! —SLG

Works perfect for me
Just suited to german

setInterval(function () {
// Changed "Action menu" to "Aktionsmenü" (DE)
  	document.querySelector('#primary button[aria-label="Aktionsmenü"]').click();
  	var things = document.evaluate(
// ... as well as "Remove from" to "Aus"
    '//span[contains(text(),"Aus")]',
    document,
    null,
    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
    null
  );
  for (var i = 0; i < things.snapshotLength; i++) {
    things.snapshotItem(i).click();
  }
},` 1000);

For all the french here, use this :
setInterval(function () { document.querySelector('#primary button[aria-label="Menu d\'actions"]').click(); var things = document.evaluate( '//span[contains(text(),"Supprimer de")]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); for (var i = 0; i < things.snapshotLength; i++) { things.snapshotItem(i).click(); } }, 1000);

It's insane to me that in 2022 this is still the only way to clear YouTube's Watch Later, and with much pain involved because you hit their stupid rate limit after 200 requests.

I have a Pi Hole and other blockers so YouTube can't tell when a video is 'watched'.

I have around 3,000 videos to clear. It always takes hours as it gets this way every few months.

It's insane to me that in 2022 this is still the only way to clear YouTube's Watch Later, and with much pain involved because you hit their stupid rate limit after 200 requests.

I have a Pi Hole and other blockers so YouTube can't tell when a video is 'watched'.

I have around 3,000 videos to clear. It always takes hours as it gets this way every few months.

Me too. I'm starting to wonder if this can be done through API calls too.

othyn

commented

May 3, 2022

edited

Checking the official YouTube API docs, it does seem possible. I'm yet to go through their official examples repo, but by the looks of it you could use the playlistitems list endpoint to grab all the video ID's in the playlist, then loop through them and send a delete request using the playlistitems delete endpoint.

The only limitation, and its a massive one, is that you are limited to 10,000 'units' per day, with playlist deletions costing 50 per request meaning you'd blow through the quota in just 200 video deletions, which is insane and according to YouTube is 'an amount sufficient for the majority of our API users'. In order to get more, they have to audit your project:

The YouTube Data API uses a quota system to ensure that developers use the service as intended and do not create API clients that unfairly reduce service quality or limit access for others.

Projects that enable the YouTube Data API have a default quota allocation of 10,000 units per day, an amount sufficient for the majority of our API users. You can see your quota usage on the Quotas page in the API Console.

If you would like to request additional quota beyond the default allocation, you must first complete an audit to show that your project is in compliance with the YouTube API Services Terms of Service. This gives YouTube visibility into the intended use cases of large projects and ensures that YouTube's API services are being used in a manner that is free from abuse. Visit this link for additional details on complying with YouTube’s Developer Policies.

I remember all this going down with 3rd party YouTube apps on the various mobile app stores, one by one slowly getting shutdown to force everyone to use the native apps and clients, with much more reduced functionality and rife with petty design (UX and software) decisions.

YouTube really, really needs a competitor.

@othyn seriously, it beggars belief that such a simple function takes this much work to accomplish, with strings attached. For each video on this specific playlist, remove it.

+1

dumpling

On May 3, 2022, at 16:25, Ben ***@***.***> wrote:

***@***.*** commented on this gist. +1

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you are subscribed to this thread.

For anyone from Czech Republic, you can use this modified function from a few comments above.

setInterval(() => {
  document.querySelector('#primary button[aria-label="Nabídka akcí"]').click();
  document.evaluate('//span[contains(text(),"Odstranit ze seznamu")]', document, null, 
   XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotItem(0).click();
}, 500);

@AwareWulf Thanks for sharing +1

For all the french here, use this :
setInterval(function () { document.querySelector('#primary button[aria-label="Menu d\'actions"]').click(); var things = document.evaluate( '//span[contains(text(),"Supprimer de")]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); for (var i = 0; i < things.snapshotLength; i++) { things.snapshotItem(i).click(); } }, 1000);

Merci beaucoup @DewasSquid ! Fonctionne au 02 juin 2022

This works great, thank you.

For everyone using a different language you have to update:

1: aria-label="HERE"

2: '//span[contains(text(),"HERE")]',


The second one is just the content of the "Remove from playlist button", press on the 3 dots and copy the text. Just some words is okay, e.g "Remove from" is totally fine.


Number 1 is a bit more tricky, to find it you have to inspect the 3 dots button (right click => inspect or something simillar)
It looks like this:
(Make sure to inspect the button not the icon, just inspect a bit on the side from the three dots.)

<button id="button" class="style-scope yt-icon-button" aria-label="Aktionsmenü"><yt-icon class="style-scope ytd-menu-renderer"</button>

From there you have to use the content of the aria-label

It worked just fine!!
I don't know why youtube does not include this feature, I had thousends of videos on the watch later section and I'm 100% that i'm actually not going to watch none of them :) but I want to use this feature of watch later but know in the proper way.
Anyways thank you very much and greetings from colombia +1

Works perfect for me Just suited to german

setInterval(function () {
// Changed "Action menu" to "Aktionsmenü" (DE)
  	document.querySelector('#primary button[aria-label="Aktionsmenü"]').click();
  	var things = document.evaluate(
// ... as well as "Remove from" to "Aus"
    '//span[contains(text(),"Aus")]',
    document,
    null,
    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
    null
  );
  for (var i = 0; i < things.snapshotLength; i++) {
    things.snapshotItem(i).click();
  }
},` 1000);

Works perfect! Just suited to pt-br

setInterval(function () {
  	document.querySelector('#primary button[aria-label="Menu de ações"]').click();
  	var things = document.evaluate(
    '//span[contains(text(),"Remover")]',
    document,
    null,
    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
    null
  );
  for (var i = 0; i < things.snapshotLength; i++) {
    things.snapshotItem(i).click();
  }
}, 1000);

@othyn, unfortunately you can't do this at all with the YouTube API, because it will not return the contents of the Watch Later playlist: https://developers.google.com/youtube/v3/revision_history#september-15,-2016

Suited for PL:

setInterval(function () {
    document.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();
    }
}, 500);

Action menu changed to Menu czynności
Remove from changed to Usuń z

For Arabic:

setInterval(function () {
  document.querySelector('#primary button[aria-label="قائمة الإجراءات"]').click();
  var things = document.evaluate(
    '//span[contains(text(),"إزالة من")]',
    document,
    null,
    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
    null
  );
  for (var i = 0; i < things.snapshotLength; i++) {
    things.snapshotItem(i).click();
  }
}, 200);

With the latest redesign of the Watch Later page, none of the previous solutions work. I think we're going to have to search for the textContent of spans, for example: Array.from(document.querySelectorAll('span.style-scope.yt-formatted-string')).find(el => el.textContent === 'Remove from ');

this code worked....:)

Thanks worked like a charm! Had to translate the aria-label and text for dutch:

setInterval(function () {
  document.querySelector('#primary button[aria-label="Actiemenu"]').click();
  var things = document.evaluate(
    '//span[contains(text(),"Verwijderen uit")]',
    document,
    null,
    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
    null
  );
  for (var i = 0; i < things.snapshotLength; i++) {
    things.snapshotItem(i).click();
  }
}, 1000);

Here's my take on 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);

Working as of 11/21/2022. Just let it run in the background. Non-english users will need to change "Action menu" and "Remove from" to what YouTube uses for their localization.

If you need it to clear hidden videos this is the tweak to do that (I had like 200) - click options menu and show hidden videos then run this

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

    video.querySelector('#button > yt-icon').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);

This is a lifesaver for me. Thanks.

Türkler için

setInterval(() => {
  document.querySelector('#primary button[aria-label="İşlem menüsü"]').click();
  document
    .evaluate(
      '//span[contains(text(),"Daha sonra")]',
      document,
      null,
      XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
      null
    )
    .snapshotItem(0)
    .click();
}, 100);

Hızlandırılmış hali

setInterval(() => {
  document.querySelector('#primary button[aria-label="İşlem menüsü"]').click();
  document
    .evaluate(
      '//span[contains(text(),"Daha sonra")]',
      document,
      null,
      XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
      null
    )
    .snapshotItem(0)
    .click();
}, 50);

Korean version, if someone needs it
한국어 환경에서 유튜브 나중에 볼 동영상 전부 지우기

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

    video.querySelector('#primary button[aria-label="작업 메뉴"]').click();

    var things = document.evaluate(
        '//span[contains(text(),"에서 삭제")]',
        document,
        null,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
        null
    );

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

Russian version

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

    video.querySelector('#primary button[aria-label="Меню действий"]').click();

    var things = document.evaluate(
        '//span[contains(text(),"Удалить из плейлиста")]',
        document,
        null,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
        null
    );

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

Swedish version:


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

    video.querySelector('#primary button[aria-label="Åtgärdsmeny"]').click();

    var things = document.evaluate(
        '//span[contains(text(),"Ta bort från")]',
        document,
        null,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
        null
    );

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

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK