Skip to content

Instantly share code, notes, and snippets.

@dcalacci
Forked from jmiserez/export_google_music.js
Last active August 2, 2022 15:15

Revisions

  1. dcalacci revised this gist Feb 23, 2016. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -87,8 +87,8 @@ var songsToText = function(style, csv, likedonly){
    curr = allsongs[i].artist + ",";
    curr += allsongs[i].album;
    } else if (style == "artistalbumsong") {
    curr = allsongs[i].artist + ",";
    curr += allsongs[i].album + ",";
    curr = allsongs[i].artist + "\t";
    curr += allsongs[i].album + "\t";
    curr += allsongs[i].title;
    } else {
    console.log("style not defined");
  2. @jmiserez jmiserez revised this gist Dec 16, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@
    //
    // A little bit of Javascript to let you export your Google Music library, playlists, and album track lists :)
    //
    // I posted this as an answer here: http://webapps.stackexchange.com/questions/50311/print-playlist-from-google-play
    // I posted this as an answer here: http://webapps.stackexchange.com/questions/50311/print-playlist-from-google-play-music
    //
    // 1. Go to: https://play.google.com/music/listen#/all (or your playlist)
    //
  3. @jmiserez jmiserez revised this gist Dec 16, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@
    //
    // A little bit of Javascript to let you export your Google Music library, playlists, and album track lists :)
    //
    // I posted this as an answer here:
    // I posted this as an answer here: http://webapps.stackexchange.com/questions/50311/print-playlist-from-google-play
    //
    // 1. Go to: https://play.google.com/music/listen#/all (or your playlist)
    //
  4. @jmiserez jmiserez revised this gist Dec 16, 2015. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -2,6 +2,8 @@
    //
    // A little bit of Javascript to let you export your Google Music library, playlists, and album track lists :)
    //
    // I posted this as an answer here:
    //
    // 1. Go to: https://play.google.com/music/listen#/all (or your playlist)
    //
    // 2. Open a developer console (F12 for Chrome). Paste
  5. @jmiserez jmiserez revised this gist Feb 13, 2015. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -1,8 +1,8 @@
    // Jeremie Miserez <jeremie@miserez.org>, 2015
    //
    // A little bit of Javascript to let you export your Google Music library :)
    // A little bit of Javascript to let you export your Google Music library, playlists, and album track lists :)
    //
    // 1. Go to: https://play.google.com/music/listen#/all
    // 1. Go to: https://play.google.com/music/listen#/all (or your playlist)
    //
    // 2. Open a developer console (F12 for Chrome). Paste
    // code below into the console.
    @@ -32,7 +32,7 @@
    // recognize full albums, use the "artistalbum" style. For
    // songs, use the "artistsong" style.

    // originally answered here: http://webapps.stackexchange.com/a/73791/77056
    // see my answer here for questions: http://webapps.stackexchange.com/a/73791/77056

    var allsongs = []
    var songsToText = function(style, csv, likedonly){
  6. @jmiserez jmiserez revised this gist Feb 12, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -190,4 +190,4 @@ var scrapeSongs = function(){
    }, intervalms);
    };
    scrapeSongs();
    // now you can call e.g. songsToText("all", false, false);
    // for the full CSV version you can now call songsToText("all", true);
  7. @jmiserez jmiserez revised this gist Feb 12, 2015. 1 changed file with 141 additions and 140 deletions.
    281 changes: 141 additions & 140 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -8,7 +8,8 @@
    // code below into the console.
    //
    // 3. All scraped songs are stored in the `allsongs` object
    // and a a CSV version of the list is copied to the clipboard.
    // and a text version of the list is copied to the clipboard. I recommend running
    // `songsToText("all",true)` afterwards to get the full CSV information.
    //
    // 4. If you would like the output in a text format, can call
    // the songsToText() function. You can select a style, choose
    @@ -33,160 +34,160 @@

    // originally answered here: http://webapps.stackexchange.com/a/73791/77056


    var allsongs = []
    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
    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");
    if (style === undefined){
    console.log("style is undefined.");
    return;
    }
    var csv = csv || false; // defaults to false
    var likedonly = likedonly || false; // defaults to false
    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");
    }
    var outText = "";
    if (csv) {
    if (style == "all") {
    //extra line
    outText = "index,artist,album,title,duration,playcount,rating" + "\n";
    } else if (style == "artist") {
    } else if (style == "artistsong") {
    } else if (style == "artistalbum") {
    } else if (style == "artistalbumsong") {
    } else {
    console.log("style not defined");
    }
    var outText = "";
    if (csv) {
    }
    var numEntries = 0;
    var seen = {};
    for (var i = 0; i < allsongs.length; i++) {
    var curr = "";
    if (!likedonly || (likedonly && allsongs[i].rating >= 5)){
    if (csv) {
    if (style == "all") {
    //extra line
    outText = "index,artist,album,title,duration,playcount,rating" + "\n";
    //extra line
    curr = allsongs[i].artist + ",";
    curr += allsongs[i].album + ",";
    curr += allsongs[i].title + ",";
    curr += allsongs[i].duration + ",";
    curr += allsongs[i].index + ",";
    curr += allsongs[i].playcount + ",";
    curr += allsongs[i].rating;
    } else if (style == "artist") {
    curr = allsongs[i].artist;
    } else if (style == "artistsong") {
    curr = allsongs[i].artist + ",";
    curr += allsongs[i].title;
    } else if (style == "artistalbum") {
    curr = allsongs[i].artist + ",";
    curr += allsongs[i].album;
    } else if (style == "artistalbumsong") {
    curr = allsongs[i].artist + ",";
    curr += allsongs[i].album + ",";
    curr += allsongs[i].title;
    } else {
    console.log("style not defined");
    console.log("style not defined");
    }
    }
    var numEntries = 0;
    var seen = {};
    for (var i = 0; i < allsongs.length; i++) {
    var curr = "";
    if (!likedonly || (likedonly && allsongs[i].rating >= 5)){
    if (csv) {
    if (style == "all") {
    //extra line
    curr = allsongs[i].index + ",";
    curr += allsongs[i].artist + ",";
    curr += allsongs[i].album + ",";
    curr += allsongs[i].title + ",";
    curr += allsongs[i].duration + ",";
    curr += allsongs[i].playcount + ",";
    curr += allsongs[i].rating;
    } else if (style == "artist") {
    curr = allsongs[i].artist;
    } else if (style == "artistsong") {
    curr = allsongs[i].artist + ",";
    curr += allsongs[i].title;
    } else if (style == "artistalbum") {
    curr = allsongs[i].artist + ",";
    curr += allsongs[i].album;
    } else if (style == "artistalbumsong") {
    curr = allsongs[i].artist + ",";
    curr += allsongs[i].album + ",";
    curr += allsongs[i].title;
    } else {
    console.log("style not defined");
    }
    } else {
    if (style == "all"){
    curr = "";
    curr += (allsongs[i].index.length > 0 ? allsongs[i].index + ". " : "");
    curr += allsongs[i].artist + " - ";
    curr += allsongs[i].album + " - ";
    curr += allsongs[i].title;
    } 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 + " - " + allsongs[i].title;
    } else if (style == "artistalbumsong"){
    curr = allsongs[i].artist + " - " + allsongs[i].album + " - " + allsongs[i].title;
    } 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);
    }
    } else {
    if (style == "all"){
    curr = "";
    curr += (allsongs[i].index.length > 0 ? allsongs[i].index + ". " : "");
    curr += allsongs[i].artist + " - ";
    curr += allsongs[i].album + " - ";
    curr += allsongs[i].title;
    } 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 + " - " + allsongs[i].title;
    } else if (style == "artistalbumsong"){
    curr = allsongs[i].artist + " - " + allsongs[i].album + " - " + allsongs[i].title;
    } 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);
    }
    }
    copy(outText);
    console.log("Done! " + numEntries + " lines copied to clipboard. Used " + numEntries + " songs out of " + allsongs.length + ".");
    }
    copy(outText);
    console.log("Done! " + numEntries + " lines copied to clipboard. Used " + numEntries + " songs 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 = "";
    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") == "playcount" ? 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("div#music-content");
    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("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].textContent : ""),
    }
    if (!seen.hasOwnProperty(curr.dataid)){ // hashset
    total.push(curr);
    seen[curr.id] = true;
    }
    }
    songs[songs.length-1].scrollIntoView(true); // go to next page
    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) {
    // 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") == "playcount" ? 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("div#music-content");
    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("all", false, 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].textContent : ""),
    }
    if (!seen.hasOwnProperty(curr.dataid)){ // hashset
    total.push(curr);
    seen[curr.id] = true;
    }
    }
    }, intervalms);
    songs[songs.length-1].scrollIntoView(true); // go to next page
    }
    }
    }, intervalms);
    };
    scrapeSongs();
    // now you can call e.g. songsToText("all", false, false);
  8. @jmiserez jmiserez revised this gist Feb 12, 2015. 1 changed file with 4 additions and 5 deletions.
    9 changes: 4 additions & 5 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -7,9 +7,8 @@
    // 2. Open a developer console (F12 for Chrome). Paste
    // 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.
    // 3. All scraped songs are stored in the `allsongs` object
    // and a a CSV version of the list is copied to the clipboard.
    //
    // 4. If you would like the output in a text format, can call
    // the songsToText() function. You can select a style, choose
    @@ -162,8 +161,8 @@ var scrapeSongs = function(){
    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 false, likedonly false: songsToText(\"all\", false).");
    songsToText("all", false, false);
    console.log("Calling songsToText with style all, csv flag true, likedonly false: songsToText(\"all\", false).");
    songsToText("all", true, false);
    }
    } else {
    retries = timeoutms / intervalms;
  9. @jmiserez jmiserez revised this gist Feb 12, 2015. 1 changed file with 135 additions and 55 deletions.
    190 changes: 135 additions & 55 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -12,14 +12,19 @@
    // 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 songsToText() function. You can select a style, choose
    // the format, and 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
    // Styles are ` all`, `artist`, `artistalbum`, `artistsong`,
    // `artistalbumsong`.
    // CSV will result in a CSV file and can be left out (defaults to false).
    // 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.
    // E.g:
    // - `songsToText("all",true,false)` will export all songs in csv format.
    // - `songsToText("all",true,true)` will export only liked songs in csv format.
    // - `songsToText("artistsong",false,false)` will export all songs as text.
    //
    // 5. You can then paste the data anywhere you like, for
    // example http://www.ivyishere.org/ if you want to add the
    @@ -30,8 +35,95 @@
    // originally answered here: http://webapps.stackexchange.com/a/73791/77056


    var allsongs = [];
    (function(){
    var allsongs = []
    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
    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");
    }
    var outText = "";
    if (csv) {
    if (style == "all") {
    //extra line
    outText = "index,artist,album,title,duration,playcount,rating" + "\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 = "";
    if (!likedonly || (likedonly && allsongs[i].rating >= 5)){
    if (csv) {
    if (style == "all") {
    //extra line
    curr = allsongs[i].index + ",";
    curr += allsongs[i].artist + ",";
    curr += allsongs[i].album + ",";
    curr += allsongs[i].title + ",";
    curr += allsongs[i].duration + ",";
    curr += allsongs[i].playcount + ",";
    curr += allsongs[i].rating;
    } else if (style == "artist") {
    curr = allsongs[i].artist;
    } else if (style == "artistsong") {
    curr = allsongs[i].artist + ",";
    curr += allsongs[i].title;
    } else if (style == "artistalbum") {
    curr = allsongs[i].artist + ",";
    curr += allsongs[i].album;
    } else if (style == "artistalbumsong") {
    curr = allsongs[i].artist + ",";
    curr += allsongs[i].album + ",";
    curr += allsongs[i].title;
    } else {
    console.log("style not defined");
    }
    } else {
    if (style == "all"){
    curr = "";
    curr += (allsongs[i].index.length > 0 ? allsongs[i].index + ". " : "");
    curr += allsongs[i].artist + " - ";
    curr += allsongs[i].album + " - ";
    curr += allsongs[i].title;
    } 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 + " - " + allsongs[i].title;
    } else if (style == "artistalbumsong"){
    curr = allsongs[i].artist + " - " + allsongs[i].album + " - " + allsongs[i].title;
    } 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);
    }
    }
    }
    copy(outText);
    console.log("Done! " + numEntries + " lines copied to clipboard. Used " + numEntries + " songs out of " + allsongs.length + ".");
    };
    var scrapeSongs = function(){
    var intervalms = 1; //in ms
    var timeoutms = 3000; //in ms
    var retries = timeoutms / intervalms;
    @@ -41,31 +133,54 @@ var allsongs = [];
    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") == "playcount" ? 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("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.");
    console.log("Got " + total.length + " songs and stored them in the allsongs variable.");
    console.log("Calling songsToText with style all, csv flag false, likedonly false: songsToText(\"all\", false).");
    songsToText("all", false, false);
    }
    } 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
    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].textContent : ""),
    }
    if (!seen.hasOwnProperty(curr.dataid)){ // hashset
    total.push(curr);
    seen[curr.id] = true;
    }
    @@ -74,40 +189,5 @@ var allsongs = [];
    }
    }
    }, 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].name;
    } else if (style == "artistalbumsong"){
    curr = allsongs[i].artist + " - " + allsongs[i].album + " - " + allsongs[i].name;
    } else {
    console.log("style not defined");
    }
    if (!seen.hasOwnProperty(curr)){ // hashset
    outText = outText + "\n" + curr;
    numEntries++;
    seen[curr] = true;
    } else {
    console.log("Skipping (duplicate) " + curr);
    }
    }
    }
    copy(outText);
    console.log("Done! " + numEntries + " lines copied to clipboard. Used " + numEntries + " songs out of " + allsongs.length + ".");
    }
    };
    scrapeSongs();
  10. @jmiserez jmiserez revised this gist Feb 11, 2015. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -103,6 +103,8 @@ var songsToText = function(style, likedonly){
    outText = outText + "\n" + curr;
    numEntries++;
    seen[curr] = true;
    } else {
    console.log("Skipping (duplicate) " + curr);
    }
    }
    }
  11. @jmiserez jmiserez revised this gist Feb 11, 2015. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -93,9 +93,9 @@ var songsToText = function(style, likedonly){
    } else if (style == "artistalbum"){
    curr = allsongs[i].artist + " - " + allsongs[i].album;
    } else if (style == "artistsong"){
    curr = allsongs[i].artist + " - " + allsongs[i].song;
    curr = allsongs[i].artist + " - " + allsongs[i].name;
    } else if (style == "artistalbumsong"){
    curr = allsongs[i].artist + " - " + allsongs[i].album + " - " + allsongs[i].song;
    curr = allsongs[i].artist + " - " + allsongs[i].album + " - " + allsongs[i].name;
    } else {
    console.log("style not defined");
    }
  12. @jmiserez jmiserez revised this gist Feb 11, 2015. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -82,11 +82,11 @@ var songsToText = function(style, likedonly){
    if (likedonly) {
    console.log("Only selecting liked songs");
    }
    var outText = ""
    var outText = "";
    var numEntries = 0;
    var seen = {};
    for (var i = 0; i < allsongs.length; i++) {
    var curr = ""
    var curr = "";
    if (!likedonly || (likedonly && allsongs[i].rating >= 5)){
    if (style == "artist"){
    curr = allsongs[i].artist;
  13. @jmiserez jmiserez revised this gist Feb 11, 2015. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,5 @@
    // Jeremie Miserez <jeremie@miserez.org>, 2015
    //
    // A little bit of Javascript to let you export your Google Music library :)
    //
    // 1. Go to: https://play.google.com/music/listen#/all
  14. @jmiserez jmiserez revised this gist Feb 11, 2015. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,5 @@
    // A little bit of Javascript to let you export your Google Music library :)
    //
    // 1. Go to: https://play.google.com/music/listen#/all
    //
    // 2. Open a developer console (F12 for Chrome). Paste
  15. @jmiserez jmiserez revised this gist Feb 11, 2015. 1 changed file with 19 additions and 4 deletions.
    23 changes: 19 additions & 4 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -1,12 +1,27 @@
    // 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.
    // 2. Open a developer console (F12 for Chrome). Paste
    // 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.
    // 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.
    // 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.
    // 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

  16. @jmiserez jmiserez revised this gist Feb 11, 2015. 1 changed file with 11 additions and 4 deletions.
    15 changes: 11 additions & 4 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -1,12 +1,17 @@
    // 1. Go to: https://play.google.com/music/listen#/all
    // 2. Paste the code below into a Chrome developer console
    // 3. A JS object will then be pasted into the clipboard containing all songs in the order they were listed
    // 4. After everything is processed, and you would like the output in a friendlier text format, you 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 to 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" option.
    //
    // 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
    @@ -25,6 +30,7 @@
    if (isAtBottom || retries <= 0) {
    clearInterval(interval); //done
    copy(total);
    allsongs = total;
    console.log("Done! " + total.length + " songs copied to clipboard.");
    }
    } else {
    @@ -51,6 +57,7 @@
    }, intervalms);
    }());


    var songsToText = function(style, likedonly){
    var likedonly = likedonly || false; // defaults to false
    if (likedonly) {
  17. @jmiserez jmiserez revised this gist Feb 11, 2015. 1 changed file with 6 additions and 9 deletions.
    15 changes: 6 additions & 9 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -1,12 +1,9 @@
    // go to: https://play.google.com/music/listen#/all
    // and paste this into a Chrome developer console
    // A JS object will then be pasted into the clipboard containing all songs in the order they were listed
    //
    // After everything is processed, and you would like the output in a friendlier text
    // format, you 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.
    //
    // 1. Go to: https://play.google.com/music/listen#/all
    // 2. Paste the code below into a Chrome developer console
    // 3. A JS object will then be pasted into the clipboard containing all songs in the order they were listed
    // 4. After everything is processed, and you would like the output in a friendlier text format, you 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 to 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" option.

    // originally answered here: http://webapps.stackexchange.com/a/73791/77056


  18. @jmiserez jmiserez revised this gist Feb 11, 2015. 1 changed file with 40 additions and 2 deletions.
    42 changes: 40 additions & 2 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,11 @@
    // go to: https://play.google.com/music/listen#/all
    // and paste this into a Chrome developer console
    // the songs will be pasted into the clipboard in the order they appear in the list
    // A JS object will then be pasted into the clipboard containing all songs in the order they were listed
    //
    // After everything is processed, and you would like the output in a friendlier text
    // format, you 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.
    //
    // originally answered here: http://webapps.stackexchange.com/a/73791/77056

    @@ -47,4 +52,37 @@
    }
    }
    }, 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 + ".");
    }
  19. @jmiserez jmiserez created this gist Feb 11, 2015.
    50 changes: 50 additions & 0 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,50 @@
    // go to: https://play.google.com/music/listen#/all
    // and paste this into a Chrome developer console
    // the songs will be pasted into the clipboard in the order they appear in the list
    //
    // originally answered here: http://webapps.stackexchange.com/a/73791/77056


    (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);
    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);
    }());