Skip to content

Instantly share code, notes, and snippets.

@BrianLincoln
Last active March 15, 2024 15:50
Show Gist options
  • Star 28 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save BrianLincoln/982bd121c4414d89ff3785af93f65c7a to your computer and use it in GitHub Desktop.
Save BrianLincoln/982bd121c4414d89ff3785af93f65c7a to your computer and use it in GitHub Desktop.
YouTube Music Likes to Playlist

Copy Likes to a playlist in YouTube Music

This is a very hacky solution to copy Liked songs to a playlist since YTM still doesn't have the functionality. I'm using this to copy songs out of YTM to another service, then unsubscribing. Thus, I won't be maintaining it (or ever using it again). It will only work while the YTM interface is the same as it is today (3/6/21) and will break once they make updates.

Steps to use:

  1. Create a new playlist
  2. Go to your Likes page (in chrome, on a desktop or laptop). Scroll to the bottom so all songs are loaded
  3. Open Chrome's dev tools (F12 on windows), go to the console
  4. Paste the script below. Edit the first line, replace "YOUR_PLAYLIST_NAME" with your playlist's name
  5. Press enter

If it's working, you will see it log out the song titles and (1 of x).

let TARGET_PLAYLIST = "YOUR_PLAYLIST_NAME";

let songElements = document.querySelectorAll(
  "#contents > .ytmusic-playlist-shelf-renderer"
);
let addToPlaylistXpath = "//yt-formatted-string[text()='Add to playlist']";
let playlistXpath = `//yt-formatted-string[text()='${TARGET_PLAYLIST}']`;

function isHidden(element) {
  return element.offsetParent === null;
}

function waitForElementToDisplay(xpath, callback) {
  const timeout = 5000
  const checkFrequency = 30

  var startTimeInMs = Date.now();
  (function loopSearch() {
    const element = document.evaluate(
      xpath,
      document,
      null,
      XPathResult.FIRST_ORDERED_NODE_TYPE,
      null
    ).singleNodeValue;

    if (element && !isHidden(element)) {
      callback(element);
      return;
    } else {
      setTimeout(function () {
        if (timeout && Date.now() - startTimeInMs > timeout) return;
        loopSearch();
      }, checkFrequency);
    }
  })();
}

function copySong(songElement, index) {
  const dotsElement = songElement.querySelector("#button");
  const songTitle = songElement.querySelector(".yt-simple-endpoint").textContent;

  console.log(`Copying: ${songTitle} (${index} of ${songElements.length})`);

  // click dot action menu
  dotsElement.click();

  waitForElementToDisplay(addToPlaylistXpath, (addToPlaylistElement) => {
    // click "Add to playlist"
    addToPlaylistElement.click();

    waitForElementToDisplay(playlistXpath, (playlistElement) => {
      // click target playlist
      playlistElement.click();

      document.body.click();

      // call function again
      if (index <= songElements.length) {
        const nextIndex = index + 1;
        copySong(songElements[nextIndex], nextIndex);
      }
    });
  });
}

copySong(songElements[0], 0)
@andrewright
Copy link

Uncaught TypeError: Cannot read properties of undefined (reading 'querySelector')
    at copySong (<anonymous>:40:37)
    at <anonymous>:67:1

It looks like you go through all steps or not correct copy all the code:

  1. Create a new playlist
  2. Go to your Likes page (in chrome, on a desktop or laptop). Scroll to the bottom so all songs are loaded
  3. Open Chrome's dev tools (F12 on windows), go to the console
  4. Paste the script below. Edit the first line, replace "YOUR_PLAYLIST_NAME" with your playlist's name
  5. Press enter

@dehartNex
Copy link

As of 2022-10-10 seeing the same error as schweppes. Chrome Version 106.0.5249.103 (Official Build) (64-bit)

@gavinayling
Copy link

gavinayling commented Oct 20, 2022

Interesting. It worked for me today using Edge (the updated code further down the page). Am using this to get it to Apple Music because of the YouTube Premium price hike. Thank you so much OP.

@dwolrdcojp
Copy link

This is only copying the first song from my liked playlist into a new playlist.

Version 107.0.5304.87 (Official Build) (arm64)

@vitaminac
Copy link

vitaminac commented Nov 13, 2022

updated

let TARGET_PLAYLIST = "YOUR_PLAYLIST_NAME";

let songElements = document.querySelectorAll(
    "#contents > .ytmusic-playlist-shelf-renderer"
);
let addToPlaylistXpath = "//yt-formatted-string[text()='Add to playlist']";
let playlistXpath = `//yt-formatted-string[@title='${TARGET_PLAYLIST}']`;

function isHidden(element) {
    return element.offsetParent === null;
}

function waitForElementToDisplay(xpath, callback) {
    const timeout = 5000
    const checkFrequency = 30

    var startTimeInMs = Date.now();
    (function loopSearch() {
        const element = document.evaluate(
            xpath,
            document,
            null,
            XPathResult.FIRST_ORDERED_NODE_TYPE,
            null
        ).singleNodeValue;

        if (element && !isHidden(element)) {
            callback(element);
            return;
        } else {
            setTimeout(function () {
                if (timeout && Date.now() - startTimeInMs > timeout) return;
                loopSearch();
            }, checkFrequency);
        }
    })();
}

function copySong(index, callback) {
    songElement = songElements[index]
    const dotsElement = songElement.querySelector("#button");
    const songTitle = songElement.querySelector(".yt-simple-endpoint").textContent;
    console.log(`Started copying: ${songTitle} (${index + 1} of ${songElements.length})`);

    // click dot action menu
    dotsElement.click();
    waitForElementToDisplay(addToPlaylistXpath, (addToPlaylistElement) => {
        // click "Add to playlist"
        addToPlaylistElement.click();

        waitForElementToDisplay(playlistXpath, (playlistElement) => {
            // click target playlist
            playlistElement.click();

            document.body.click();

            console.log(`Completed copying: ${songTitle} (${index + 1} of ${songElements.length})`)
            callback();
        });
    });

}

function copySongs(index) {
    copySong(index, () => {
        const nextIndex = index + 1;
        if (nextIndex < songElements.length) {
            copySongs(nextIndex);
        }
    })
}

copySongs(0)

and to remove like from all songs of my new playlist

let likeButtons = document.querySelectorAll("ytmusic-like-button-renderer.ytmusic-menu-renderer yt-button-shape.like.ytmusic-like-button-renderer[aria-pressed='true'] > button");
function turnOffAllLike(index) {
    console.log(`turning off ${index}th like`);
    const node = likeButtons[index]
    node.click();
    const nextIndex = index + 1;
    if (nextIndex < likeButtons.length) {
        setTimeout(() => turnOffAllLike(nextIndex), 1000)
    }
}

turnOffAllLike(0);

@SharpieMay
Copy link

updated

let TARGET_PLAYLIST = "YOUR_PLAYLIST_NAME";

let songElements = document.querySelectorAll(
    "#contents > .ytmusic-playlist-shelf-renderer"
);
let addToPlaylistXpath = "//yt-formatted-string[text()='Add to playlist']";
let playlistXpath = `//yt-formatted-string[@title='${TARGET_PLAYLIST}']`;

function isHidden(element) {
    return element.offsetParent === null;
}

function waitForElementToDisplay(xpath, callback) {
    const timeout = 5000
    const checkFrequency = 30

    var startTimeInMs = Date.now();
    (function loopSearch() {
        const element = document.evaluate(
            xpath,
            document,
            null,
            XPathResult.FIRST_ORDERED_NODE_TYPE,
            null
        ).singleNodeValue;

        if (element && !isHidden(element)) {
            callback(element);
            return;
        } else {
            setTimeout(function () {
                if (timeout && Date.now() - startTimeInMs > timeout) return;
                loopSearch();
            }, checkFrequency);
        }
    })();
}

function copySong(index, callback) {
    songElement = songElements[index]
    const dotsElement = songElement.querySelector("#button");
    const songTitle = songElement.querySelector(".yt-simple-endpoint").textContent;
    console.log(`Started copying: ${songTitle} (${index + 1} of ${songElements.length})`);

    // click dot action menu
    dotsElement.click();
    waitForElementToDisplay(addToPlaylistXpath, (addToPlaylistElement) => {
        // click "Add to playlist"
        addToPlaylistElement.click();

        waitForElementToDisplay(playlistXpath, (playlistElement) => {
            // click target playlist
            playlistElement.click();

            document.body.click();

            console.log(`Completed copying: ${songTitle} (${index + 1} of ${songElements.length})`)
            callback();
        });
    });

}

function copySongs(index) {
    copySong(index, () => {
        const nextIndex = index + 1;
        if (nextIndex < songElements.length) {
            copySongs(nextIndex);
        }
    })
}

copySongs(0)

and to remove like from all songs of my new playlist

let likeButtons = document.querySelectorAll("ytmusic-like-button-renderer.ytmusic-menu-renderer yt-button-shape.like.ytmusic-like-button-renderer[aria-pressed='true'] > button");
function turnOffAllLike(index) {
    console.log(`turning off ${index}th like`);
    const node = likeButtons[index]
    node.click();
    const nextIndex = index + 1;
    if (nextIndex < likeButtons.length) {
        setTimeout(() => turnOffAllLike(nextIndex), 1000)
    }
}

turnOffAllLike(0);

You are brilliant, thank you!

@keekeh007
Copy link

It only allows for maximum of 100, is there a work around as I have over 700 items in my likes.

@alyalbright
Copy link

Any way around this?
yt music

@Thatguystoner
Copy link

It doesn't work properly for me, it stops after the 10th song

  • you have to scroll all the way to the bottom of your liked songs first

@Thatguystoner
Copy link

It only allows for maximum of 100, is there a work around as I have over 700 items in my likes.

You have to scroll all the way down your liked songs first

@prometheus247
Copy link

prometheus247 commented Dec 23, 2022

I love the general idea, but for some reasons I am not able to get it done its magic:
image

Electric is ofc the first title. Not sure how to debug further now.
The Playlist Test123 is set to global if this makes any difference, I deactivated all addons preventing scripts.

With Verbose activated, I see this:
image

@cormac22
Copy link

cormac22 commented Jan 7, 2023

This works to an extent. I have 3500 songs in my "Likes" playlist. When I run this code, many of the songs are copied but it always "bails out" before being half way done. Here are the errors that I am getting.

image

@ChrisPrefect
Copy link

This would be so great if it worked! Especially since the youtube app does not show the likes-playlist reliably anymore. But I just get this error:

Uncaught TypeError: Cannot read properties of undefined (reading 'querySelector') at copySong (<anonymous>:41:37) at copySongs (<anonymous>:65:5) at <anonymous>:73:1

I am in the playlist-view and not on the video player page with the playlist, correct?

image

@BrianLincoln
Copy link
Author

This would be so great if it worked! Especially since the youtube app does not show the likes-playlist reliably anymore.

Hey @ChrisPrefect! I made this for YouTube Music, not YouTube. I would not expect this to work on YouTube since the script looks for specific HTML to interact with and that would vary between the apps (I'm not even sure if it is working for YTM anymore).

Sorry this won't work for what you need, good luck!

@capulido
Copy link

@prometheus247

I love the general idea, but for some reasons I am not able to get it done its magic:

Your youtube music is in a different language than english.

You need to change the addToPlaylistXpath to match your language, so probably something like (not tested):

let addToPlaylistXpath = "//yt-formatted-string[text()='Zu Playlist hinzufügen']";

@peterboivin
Copy link

I can't seem to download the new playlist. Did youtube music change?

@peterboivin
Copy link

I created a solution that has worked for me. And it is all free. https://peterboivin.substack.com/p/how-to-get-liked-music-playlist-from?sd=pf

@senecaso
Copy link

senecaso commented May 5, 2023

This didn't work for me, and the steps outlined in the comment above involved running some Java code. I decided to try my own thing, and here is what worked for me: https://gist.github.com/senecaso/784e740f343f12ccc0b4a896f59a5f03

It involves running a small python script though, but it very quickly copied my entire set of likes songs to a new playlist (< 5s).

@peterboivin
Copy link

This didn't work for me, and the steps outlined in the comment above involved running some Java code. I decided to try my own thing, and here is what worked for me: https://gist.github.com/senecaso/784e740f343f12ccc0b4a896f59a5f03

It involves running a small python script though, but it very quickly copied my entire set of likes songs to a new playlist (< 5s).

Your script does roughly what the above script does. However, the problem is that now YM will not allow you to export your playlist. My steps do that. The program will match your songs in your hard drive to the songs from your YM Like playlist to create a new playlist locally.

@mshannongit
Copy link

mshannongit commented Jun 21, 2023

Here is one I hacked together for regular youtube (not youtube music) - to essentially add liked videos to a playlist. This way I can create a semi-public playlist with associated hyperlink, which can in turn be added to the iphone using the shortcuts app to be automatically launched via siri and/or a home button.

https://gist.github.com/mshannongit/81b722ab71d3b85a372412af51e12eac

@DeamonDan
Copy link

This didn't work for me, and the steps outlined in the comment above involved running some Java code. I decided to try my own thing, and here is what worked for me: https://gist.github.com/senecaso/784e740f343f12ccc0b4a896f59a5f03

It involves running a small python script though, but it very quickly copied my entire set of likes songs to a new playlist (< 5s).

it does the work but songs gets shuffled in the created playlist.

To get it as it is:
https://gist.github.com/Redbyte1/1e88e0bfbe97584792b7fbb89207b5fe
use this
use oauth.json instead of headers_auth.json
and increase the liked song counter from 500 to your desires num

@MeSeTLeN
Copy link

MeSeTLeN commented Jul 26, 2023

  1. Go YM app
  2. Play song from "Liked"
  3. Press "Up next" (button in left bottom corner)
  4. Top right corner will be the button "Save"
  5. Wait until all songs load
  6. Press "Save"

P.S. It won't add all songs by one try, do multiple times

@MeSeTLeN
Copy link

Or u can make script to "mark" all songs in "Liked" and then press button in the center "save to playlist"

@Mrkas121
Copy link

Mrkas121 commented Aug 5, 2023

I guess this doesn't work anymore? I keep getting an undefined and it sits at 1 of x

@Tom-Whi
Copy link

Tom-Whi commented Aug 16, 2023

I guess this doesn't work anymore? I keep getting an undefined and it sits at 1 of x

Yeah same here

image

@MeSeTLeN
Copy link

I guess this doesn't work anymore? I keep getting an undefined and it sits at 1 of x

This work Liked music to playlist

@Tom-Whi
Copy link

Tom-Whi commented Aug 20, 2023

I guess this doesn't work anymore? I keep getting an undefined and it sits at 1 of x

This work Liked music to playlist

I have too many tracks in my Liked Music so your "nice but manual" method won't work for me, but thanks for the hint. I'll keep looking for a scripted way to automate the full list.

@DwiBlackList
Copy link

@Tom-Whi @Mrkas121 (sorry for tag)

Hey i found treasure

go to https://chrome.google.com/webstore/detail/multiselect-for-youtube/gpgbiinpmelaihndlegbgfkmnpofgfei/related
Download , install , and eneble

image

go to the playlist , scroll to bottom , select all videos , three dots , save to playlist
and done

@Tom-Whi
Copy link

Tom-Whi commented Sep 25, 2023

Hey i found treasure

You are an absolute treasure...!!! Thank you so much for sharing. That worked so much easier than I was expecting :-)

@dangerousdan
Copy link

You can just select the checkbox next to the first song, scroll to the bottom, then shift click on the last. Then add to playlist. No plugin or reverse engineering needed.

It seems as though you have to click on a playlist from the "All playlists" list though. If you try to add to a playlist from the "Recent" list, then it doesn't work

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