// 1. Go to: https://play.google.com/music/listen#/all // // 2. Open a developer console (F12 for Chrome). Paste the code below into the console. // // 3. All scraped songs are stored in the `allSongs` object and copied to the clipboard. I'd recommend saving this somewhere for future use. // // 4. If you would like the output in a text format, can call the songsToText() function. You can select a style and choose if only liked/thumbed up songs should be exported. The resulting list will then be pasted into the clipboard. Styles are `artist`, `artistalbum`, `artistsong`, `artistalbumsong`. Likedonly can be left out (defaults to false) or set to true, and will filter all songs with ratings greater or equal to 5. E.g: `songsToText("artistsong",true)` will export all liked songs. // // 5. You can then paste the data anywhere you like, for example http://www.ivyishere.org/ if you want to add the songs or albums to your Spotify account. To make Ivy recognize full albums, use the "artistalbum" style. For songs, use the "artistsong" style. // originally answered here: http://webapps.stackexchange.com/a/73791/77056 var allsongs = []; (function(){ var intervalms = 1; //in ms var timeoutms = 3000; //in ms var retries = timeoutms / intervalms; var total = []; var seen = {}; var topId = ""; var interval = setInterval(function(){ var songs = document.querySelectorAll("table.song-table tbody tr.song-row"); if (songs.length > 0) { var currId = songs[0].getAttribute("data-id"); if (currId == topId){ // page has not yet changed retries--; scrollDiv = document.querySelector("div#music-content"); isAtBottom = scrollDiv.scrollTop == (scrollDiv.scrollHeight - scrollDiv.offsetHeight) if (isAtBottom || retries <= 0) { clearInterval(interval); //done copy(total); allsongs = total; console.log("Done! " + total.length + " songs copied to clipboard."); } } else { retries = timeoutms / intervalms; topId = currId; // read page for (var i = 0; i < songs.length; i++) { var curr = {name: songs[i].childNodes[0].textContent, length: songs[i].childNodes[1].textContent, artist: songs[i].childNodes[2].textContent, album: songs[i].childNodes[3].textContent, plays: songs[i].childNodes[4].textContent, rating: songs[i].childNodes[5].getAttribute("data-rating"), id: songs[i].getAttribute("data-id") } if (!seen.hasOwnProperty(curr.id)){ // hashset total.push(curr); seen[curr.id] = true; } } songs[songs.length-1].scrollIntoView(true); // go to next page } } }, intervalms); }()); var songsToText = function(style, likedonly){ var likedonly = likedonly || false; // defaults to false if (likedonly) { console.log("Only selecting liked songs"); } var outText = "" var numEntries = 0; var seen = {}; for (var i = 0; i < allsongs.length; i++) { var curr = "" if (!likedonly || (likedonly && allsongs[i].rating >= 5)){ if (style == "artist"){ curr = allsongs[i].artist; } else if (style == "artistalbum"){ curr = allsongs[i].artist + " - " + allsongs[i].album; } else if (style == "artistsong"){ curr = allsongs[i].artist + " - " + allsongs[i].song; } else if (style == "artistalbumsong"){ curr = allsongs[i].artist + " - " + allsongs[i].album + " - " + allsongs[i].song; } else { console.log("style not defined"); } if (!seen.hasOwnProperty(curr)){ // hashset outText = outText + "\n" + curr; numEntries++; seen[curr] = true; } } } copy(outText); console.log("Done! " + numEntries + " lines copied to clipboard. Used " + numEntries + " songs out of " + allsongs.length + "."); }