Skip to content

Instantly share code, notes, and snippets.

@spyesx
Last active March 27, 2024 18:58
Show Gist options
  • Star 25 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save spyesx/27cecbe9483c507b9b098d942e98d62b to your computer and use it in GitHub Desktop.
Save spyesx/27cecbe9483c507b9b098d942e98d62b to your computer and use it in GitHub Desktop.
Get URLs of your youtube watch later playlist
// Execute this in the console of on your own playlist
var videos = document.querySelectorAll('.yt-simple-endpoint.style-scope.ytd-playlist-video-renderer');
var r = [];
var json = [];
r.forEach.call(videos, function(video) {
var url = 'https://www.youtube.com' + video.getAttribute('href');
url = url.split('&list=WL&index=');
url = url[0];
json.push(url);
});
console.log(json)
## As @jwillmer said in the comment, we want to use bash, not sh
# chmod 744 youtube_watch_later.sh
# ./youtube_watch_later.sh
#!/bin/bash
declare -a videos=(
"https://www.youtube.com/watch?v=5dsGWM5XGdg"
"https://www.youtube.com/watch?v=2J5GzHoKl1Q"
)
for i in "${videos[@]}"
do
youtube-dl -i -c --write-thumbnail -f 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best' "$i"
done
@jwillmer
Copy link

jwillmer commented Nov 19, 2020

watch_later.sh: 3: watch_later.sh: Syntax error: "(" unexpected

Solution from StackExchange:

When you use ./scriptname.sh it executes with /bin/bash as in the first line with #!. But when you use sh scriptname.sh it executes sh, not bash.

@spyesx
Copy link
Author

spyesx commented Nov 20, 2020

Thx @jwillmer. I'm on MacOS I didn't face this issue. Anyway, now it's in a comment just in case.

@neon-dev
Copy link

neon-dev commented Jun 8, 2023

Thanks for this. I've simplified the JS to a oneliner that works on any playlist and outputs a block of text matching the expected format of your shell script variable:

console.log([...document.querySelectorAll('a.ytd-playlist-video-renderer')].map(e => '"' + e.href.split('&list=')[0] + '"').join('\n'))

@mckubisiak
Copy link

mckubisiak commented Jun 28, 2023

I've added title prior to URL

Original

var videos = document.querySelectorAll('.yt-simple-endpoint.style-scope.ytd-playlist-video-renderer');
var r = [];
var json = [];

r.forEach.call(videos, function(video) {
	var url = video.getAttribute('title') + "   " + 'https://www.youtube.com' + video.getAttribute('href') ;
	url = url.split('&list=WL&index=');
	url = url[0];
	json.push(url);
});
console.log(json)

Oneliner

console.log([...document.querySelectorAll('a.ytd-playlist-video-renderer')].map(e => e.title + '  ' + e.href.split('&list=')[0]  ).join('\n'))

@nielsbom
Copy link

I got duplicate URLs from the last script. I also didn't want to see the title, so here's my version.
(I added a block so it's easier to run multiple times)

{
  let videos = document.querySelectorAll('.yt-simple-endpoint.style-scope.ytd-playlist-video-renderer');
  let r = [];
  let result = new Set();

  r.forEach.call(videos, function (video) {
    let url = 'https://www.youtube.com' + video.getAttribute('href');
    url = url.split('&list=WL&index=')[0];
    result.add(url)
  });
  console.log(Array.from(result))
}

@zi3dAouidene
Copy link

I change it to a set of objects, each objects contains the title and url separately rather than just one string

  let videos = document.querySelectorAll('.yt-simple-endpoint.style-scope.ytd-playlist-video-renderer');
  let r = [];
  let result = new Set();

  r.forEach.call(videos, function (video) {
    let title = video.getAttribute('title') 
    let url = 'https://www.youtube.com' + video.getAttribute('href')
    url = url.split('&list=WL&index=')[0];

    result.add({title:title, url:url})

  });
  console.log(Array.from(result))

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