Skip to content

Instantly share code, notes, and snippets.

@DavidMetcalfe
Forked from jmiserez/export_google_music.js
Last active May 5, 2018 23:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DavidMetcalfe/520858b7a8678c89e11780f54d41e08f to your computer and use it in GitHub Desktop.
Save DavidMetcalfe/520858b7a8678c89e11780f54d41e08f to your computer and use it in GitHub Desktop.
Modified and minified version in bookmarklet form of https://gist.github.com/jmiserez/c9a9a0f41e867e5ebb75
javascript: (function () {
var allsongs = [];
var outText = "";
var songsToText = function (style, csv, likedonly) {
if (style === undefined) {
console.log("style is undefined.");
return;
}
var csv = csv || false; // defaults to false
var likedonly = likedonly || false; // defaults to false
var playlistName = document.querySelector('.gpm-detail-page-header h2[slot="title"]').innerText;
if (likedonly) {
console.log("Only selecting liked songs");
}
if (style == "all" && !csv) {
console.log("Duration, ratings, and playcount will only be exported with the CSV flag");
}
outText = "";
if (csv) {
if (style == "all") {
//extra line
outText = "artist,album,title,duration,playcount,rating,rating_interpretation" + "\n";
} else if (style == "artist") {} else if (style == "artistsong") {} else if (style == "artistalbum") {} else if (style == "artistalbumsong") {} else {
console.log("style not defined");
}
}
var numEntries = 0;
var seen = {};
for (var i = 0; i < allsongs.length; i++) {
var curr = "";
var properTitle = allsongs[i].title.replace(/[\n\r!]/g, '').trim();
if (!likedonly || (likedonly && allsongs[i].rating >= 5)) {
if (csv) {
if (style == "all") {
//extra line
curr += '"' + allsongs[i].artist.replace(/"/g, '""').trim() + '"' + ",";
curr += '"' + properTitle.replace(/"/g, '""').trim() + '"' + ",";
curr += '"' + allsongs[i].album.replace(/"/g, '""').trim() + '"' + ",";
curr += '"' + allsongs[i].duration.replace(/"/g, '""').trim() + '"' + ",";
curr += '"' + allsongs[i].playcount.replace(/"/g, '""').trim() + '"' + ",";
curr += '"' + allsongs[i].rating.replace(/"/g, '""').trim() + '"' + ",";
curr += '"' + allsongs[i].rating_interpretation.replace(/"/g, '""').trim() + '"';
} else if (style == "artist") {
curr += '"' + allsongs[i].artist.replace(/"/g, '""').trim() + '"';
} else if (style == "artistsong") {
curr += '"' + allsongs[i].artist.replace(/"/g, '""').trim() + '"' + ",";
curr += '"' + properTitle.replace(/"/g, '""').trim() + '"';
} else if (style == "artistalbum") {
curr += '"' + allsongs[i].artist.replace(/"/g, '""').trim() + '"' + ",";
curr += '"' + allsongs[i].album.replace(/"/g, '""').trim() + '"';
} else if (style == "artistsongalbum") {
curr += '"' + allsongs[i].artist.replace(/"/g, '""').trim() + '"' + ",";
curr += '"' + properTitle.replace(/"/g, '""').trim() + '"';
curr += '"' + allsongs[i].album.replace(/"/g, '""').trim() + '"' + ",";
} else {
console.log("style not defined");
}
} else {
if (style == "all") {
curr = allsongs[i].artist + " - " + allsongs[i].album + " - " + properTitle + " [[playcount: " + allsongs[i].playcount + ", rating: " + allsongs[i].rating_interpretation + "]]";
} else 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 + " - " + properTitle;
} else if (style == "artistalbumsong") {
curr = allsongs[i].artist + " - " + allsongs[i].album + " - " + properTitle;
} else {
console.log("style not defined");
}
}
if (!seen.hasOwnProperty(curr)) { // hashset
outText = outText + curr + "\n";
numEntries++;
seen[curr] = true;
} else {
//console.log("Skipping (duplicate) " + curr);
}
}
}
console.log("=============================================================");
console.log(outText);
console.log("=============================================================");
try {
downloadCSVFile(playlistName, "text/csv", outText);
console.log("Export to CSV succeeded.");
} catch (e) {
console.log(e);
console.log("Export to CSV failed. Please type copy(outText) on the console or copy the log output above.");
}
console.log("Done! " + numEntries + " lines in output. Used " + numEntries + " unique entries out of " + allsongs.length + ".");
};
var scrapeSongs = function () {
var intervalms = 1; //in ms
var timeoutms = 3000; //in ms
var retries = timeoutms / intervalms;
var total = [];
var seen = {};
var topId = "";
document.querySelector("#mainContainer").scrollTop = 0; //scroll to top
var interval = setInterval(function () {
var songs = document.querySelectorAll("table.song-table tbody tr.song-row");
if (songs.length > 0) {
// detect order
var colNames = {
index: -1,
title: -1,
duration: -1,
artist: -1,
album: -1,
playcount: -1,
rating: -1
};
for (var i = 0; i < songs[0].childNodes.length; i++) {
colNames.index = songs[0].childNodes[i].getAttribute("data-col") == "index" ? i : colNames.index;
colNames.title = songs[0].childNodes[i].getAttribute("data-col") == "title" ? i : colNames.title;
colNames.duration = songs[0].childNodes[i].getAttribute("data-col") == "duration" ? i : colNames.duration;
colNames.artist = songs[0].childNodes[i].getAttribute("data-col") == "artist" ? i : colNames.artist;
colNames.album = songs[0].childNodes[i].getAttribute("data-col") == "album" ? i : colNames.album;
colNames.playcount = songs[0].childNodes[i].getAttribute("data-col") == "play-count" ? i : colNames.playcount;
colNames.rating = songs[0].childNodes[i].getAttribute("data-col") == "rating" ? i : colNames.rating;
}
// check if page has updated/scrolled
var currId = songs[0].getAttribute("data-id");
if (currId == topId) { // page has not yet changed
retries--;
scrollDiv = document.querySelector("#mainContainer");
isAtBottom = scrollDiv.scrollTop == (scrollDiv.scrollHeight - scrollDiv.offsetHeight)
if (isAtBottom || retries <= 0) {
clearInterval(interval); //done
allsongs = total;
console.log("Got " + total.length + " songs and stored them in the allsongs variable.");
console.log("Calling songsToText with style all, csv flag true, likedonly false: songsToText(\"all\", false).");
// songsToText("artistsongalbum", true, false);
songsToText("all", true, false);
}
} else {
retries = timeoutms / intervalms;
topId = currId;
// read page
for (var i = 0; i < songs.length; i++) {
var curr = {
dataid: songs[i].getAttribute("data-id"),
index: (colNames.index != -1 ? songs[i].childNodes[colNames.index].textContent : ""),
title: (colNames.title != -1 ? songs[i].childNodes[colNames.title].textContent : ""),
duration: (colNames.duration != -1 ? songs[i].childNodes[colNames.duration].textContent : ""),
artist: (colNames.artist != -1 ? songs[i].childNodes[colNames.artist].textContent : ""),
album: (colNames.album != -1 ? songs[i].childNodes[colNames.album].textContent : ""),
playcount: (colNames.playcount != -1 ? songs[i].childNodes[colNames.playcount].textContent : ""),
rating: (colNames.rating != -1 ? songs[i].childNodes[colNames.rating].getAttribute("data-rating") : ""),
rating_interpretation: "",
}
if (curr.rating == "undefined") {
curr.rating_interpretation = "never-rated"
}
if (curr.rating == "0") {
curr.rating_interpretation = "not-rated"
}
if (curr.rating == "1") {
curr.rating_interpretation = "thumbs-down"
}
if (curr.rating == "5") {
curr.rating_interpretation = "thumbs-up"
}
if (!seen.hasOwnProperty(curr.dataid)) { // hashset
total.push(curr);
seen[curr.dataid] = true;
}
}
songs[songs.length - 1].scrollIntoView(true); // go to next page
}
}
}, intervalms);
};
function downloadCSVFile(filename, mime, text) {
var f = document.createElement('a');
f.setAttribute('href', 'data:' + mime + ';charset=utf-8,' + encodeURIComponent(text));
f.setAttribute('download', filename);
document.body.appendChild(f);
f.click();
document.body.removeChild(f);
}
var urlcheck = "https://play.google.com/music/listen#/pl/";
urlcheck = urlcheck.replace(/([\/])/g, "\\$1");
urlcheck = RegExp(urlcheck);
// Confirm we're in a Google Music playlist.
if (urlcheck.test(window.location.href)) {
scrapeSongs();
// for the full CSV version you can now call songsToText("all", true);
}
})();
javascript: (function () {var allsongs=[],outText="",songsToText=function(t,e,l){if(void 0!==t){e=e||!1,l=l||!1;var o=document.querySelector('.gpm-detail-page-header h2[slot="title"]').innerText;l&&console.log("Only selecting liked songs"),"all"!=t||e||console.log("Duration, ratings, and playcount will only be exported with the CSV flag"),outText="",e&&("all"==t?outText="artist,album,title,duration,playcount,rating,rating_interpretation\n":"artist"==t||"artistsong"==t||"artistalbum"==t||"artistalbumsong"==t||console.log("style not defined"));for(var a=0,n={},i=0;i<allsongs.length;i++){var r="",s=allsongs[i].title.replace(/[\n\r!]/g,"").trim();(!l||l&&allsongs[i].rating>=5)&&(e?"all"==t?(r+='"'+allsongs[i].artist.replace(/"/g,'""').trim()+'",',r+='"'+s.replace(/"/g,'""').trim()+'",',r+='"'+allsongs[i].album.replace(/"/g,'""').trim()+'",',r+='"'+allsongs[i].duration.replace(/"/g,'""').trim()+'",',r+='"'+allsongs[i].playcount.replace(/"/g,'""').trim()+'",',r+='"'+allsongs[i].rating.replace(/"/g,'""').trim()+'",',r+='"'+allsongs[i].rating_interpretation.replace(/"/g,'""').trim()+'"'):"artist"==t?r+='"'+allsongs[i].artist.replace(/"/g,'""').trim()+'"':"artistsong"==t?(r+='"'+allsongs[i].artist.replace(/"/g,'""').trim()+'",',r+='"'+s.replace(/"/g,'""').trim()+'"'):"artistalbum"==t?(r+='"'+allsongs[i].artist.replace(/"/g,'""').trim()+'",',r+='"'+allsongs[i].album.replace(/"/g,'""').trim()+'"'):"artistsongalbum"==t?(r+='"'+allsongs[i].artist.replace(/"/g,'""').trim()+'",',r+='"'+s.replace(/"/g,'""').trim()+'"',r+='"'+allsongs[i].album.replace(/"/g,'""').trim()+'",'):console.log("style not defined"):"all"==t?r=allsongs[i].artist+" - "+allsongs[i].album+" - "+s+" [[playcount: "+allsongs[i].playcount+", rating: "+allsongs[i].rating_interpretation+"]]":"artist"==t?r=allsongs[i].artist:"artistalbum"==t?r=allsongs[i].artist+" - "+allsongs[i].album:"artistsong"==t?r=allsongs[i].artist+" - "+s:"artistalbumsong"==t?r=allsongs[i].artist+" - "+allsongs[i].album+" - "+s:console.log("style not defined"),n.hasOwnProperty(r)||(outText=outText+r+"\n",a++,n[r]=!0))}console.log("============================================================="),console.log(outText),console.log("=============================================================");try{downloadCSVFile(o,"text/csv",outText),console.log("Export to CSV succeeded.")}catch(t){console.log(t),console.log("Export to CSV failed. Please type copy(outText) on the console or copy the log output above.")}console.log("Done! "+a+" lines in output. Used "+a+" unique entries out of "+allsongs.length+".")}else console.log("style is undefined.")},scrapeSongs=function(){var t=3e3,e=[],l={},o="";document.querySelector("#mainContainer").scrollTop=0;var a=setInterval(function(){var n=document.querySelectorAll("table.song-table tbody tr.song-row");if(n.length>0){for(var i={index:-1,title:-1,duration:-1,artist:-1,album:-1,playcount:-1,rating:-1},r=0;r<n[0].childNodes.length;r++)i.index="index"==n[0].childNodes[r].getAttribute("data-col")?r:i.index,i.title="title"==n[0].childNodes[r].getAttribute("data-col")?r:i.title,i.duration="duration"==n[0].childNodes[r].getAttribute("data-col")?r:i.duration,i.artist="artist"==n[0].childNodes[r].getAttribute("data-col")?r:i.artist,i.album="album"==n[0].childNodes[r].getAttribute("data-col")?r:i.album,i.playcount="play-count"==n[0].childNodes[r].getAttribute("data-col")?r:i.playcount,i.rating="rating"==n[0].childNodes[r].getAttribute("data-col")?r:i.rating;var s=n[0].getAttribute("data-id");if(s==o)t--,scrollDiv=document.querySelector("#mainContainer"),isAtBottom=scrollDiv.scrollTop==scrollDiv.scrollHeight-scrollDiv.offsetHeight,(isAtBottom||t<=0)&&(clearInterval(a),allsongs=e,console.log("Got "+e.length+" songs and stored them in the allsongs variable."),console.log('Calling songsToText with style all, csv flag true, likedonly false: songsToText("all", false).'),songsToText("all",!0,!1));else{t=3e3,o=s;for(r=0;r<n.length;r++){var g={dataid:n[r].getAttribute("data-id"),index:-1!=i.index?n[r].childNodes[i.index].textContent:"",title:-1!=i.title?n[r].childNodes[i.title].textContent:"",duration:-1!=i.duration?n[r].childNodes[i.duration].textContent:"",artist:-1!=i.artist?n[r].childNodes[i.artist].textContent:"",album:-1!=i.album?n[r].childNodes[i.album].textContent:"",playcount:-1!=i.playcount?n[r].childNodes[i.playcount].textContent:"",rating:-1!=i.rating?n[r].childNodes[i.rating].getAttribute("data-rating"):"",rating_interpretation:""};"undefined"==g.rating&&(g.rating_interpretation="never-rated"),"0"==g.rating&&(g.rating_interpretation="not-rated"),"1"==g.rating&&(g.rating_interpretation="thumbs-down"),"5"==g.rating&&(g.rating_interpretation="thumbs-up"),l.hasOwnProperty(g.dataid)||(e.push(g),l[g.dataid]=!0)}n[n.length-1].scrollIntoView(!0)}}},1)};function downloadCSVFile(t,e,l){var o=document.createElement("a");o.setAttribute("href","data:"+e+";charset=utf-8,"+encodeURIComponent(l)),o.setAttribute("download",t),document.body.appendChild(o),o.click(),document.body.removeChild(o)}var urlcheck="https://play.google.com/music/listen#/pl/";urlcheck=urlcheck.replace(/([\/])/g,"\\$1"),(urlcheck=RegExp(urlcheck)).test(window.location.href)&&scrapeSongs();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment