Skip to content

Instantly share code, notes, and snippets.

@jmiserez
Last active December 20, 2023 01:45
Show Gist options
  • Save jmiserez/c9a9a0f41e867e5ebb75 to your computer and use it in GitHub Desktop.
Save jmiserez/c9a9a0f41e867e5ebb75 to your computer and use it in GitHub Desktop.

Revisions

  1. jmiserez revised this gist Jan 16, 2018. 1 changed file with 6 additions and 1 deletion.
    7 changes: 6 additions & 1 deletion export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,9 @@
    // Jeremie Miserez <[email protected]>, 2016
    // Copyright 2016 Jeremie Miserez <[email protected]>
    //
    // MIT License
    // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
    // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    //
    // A little bit of Javascript to let you export your Google Music library, playlists, and album track lists :)
    //
  2. jmiserez revised this gist Jan 26, 2017. 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
    @@ -34,7 +34,7 @@
    // recognize full albums, use the "artistalbum" style. For
    // songs, use the "artistsong" style.

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

    var allsongs = []
    var outText = "";
  3. jmiserez revised this gist May 11, 2016. No changes.
  4. jmiserez revised this gist May 10, 2016. 1 changed file with 20 additions and 6 deletions.
    26 changes: 20 additions & 6 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -55,7 +55,7 @@ var songsToText = function(style, csv, likedonly){
    if (csv) {
    if (style == "all") {
    //extra line
    outText = "artist,album,title,duration,playcount,rating" + "\n";
    outText = "artist,album,title,duration,playcount,rating,rating_interpretation" + "\n";
    } else if (style == "artist") {
    } else if (style == "artistsong") {
    } else if (style == "artistalbum") {
    @@ -78,7 +78,8 @@ var songsToText = function(style, csv, likedonly){
    curr += '"' + properTitle.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.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") {
    @@ -96,7 +97,7 @@ var songsToText = function(style, csv, likedonly){
    }
    } else {
    if (style == "all"){
    curr = allsongs[i].artist + " - " + allsongs[i].album + " - " + properTitle;
    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"){
    @@ -157,7 +158,7 @@ var scrapeSongs = function(){
    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.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
    @@ -171,7 +172,7 @@ var scrapeSongs = function(){
    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);
    songsToText("artistalbumsong", false, false);
    }
    } else {
    retries = timeoutms / intervalms;
    @@ -186,8 +187,21 @@ var scrapeSongs = function(){
    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 : ""),
    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;
  5. jmiserez revised this gist May 10, 2016. 1 changed file with 17 additions and 21 deletions.
    38 changes: 17 additions & 21 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -55,7 +55,7 @@ var songsToText = function(style, csv, likedonly){
    if (csv) {
    if (style == "all") {
    //extra line
    outText = "index,artist,album,title,duration,playcount,rating" + "\n";
    outText = "artist,album,title,duration,playcount,rating" + "\n";
    } else if (style == "artist") {
    } else if (style == "artistsong") {
    } else if (style == "artistalbum") {
    @@ -73,35 +73,30 @@ var songsToText = function(style, csv, likedonly){
    if (csv) {
    if (style == "all") {
    //extra line
    curr = allsongs[i].artist + ",";
    curr += allsongs[i].album + ",";
    curr += properTitle + ",";
    curr += allsongs[i].duration + ",";
    curr += allsongs[i].index + ",";
    curr += allsongs[i].playcount + ",";
    curr += allsongs[i].rating;
    curr += '"' + allsongs[i].artist.replace(/"/g, '""').trim() + '"' + ",";
    curr += '"' + allsongs[i].album.replace(/"/g, '""').trim() + '"' + ",";
    curr += '"' + properTitle.replace(/"/g, '""').trim() + '"' + ",";
    curr += '"' + allsongs[i].duration.replace(/"/g, '""').trim() + '"' + ",";
    curr += '"' + allsongs[i].playcount.replace(/"/g, '""').trim() + '"' + ",";
    curr += '"' + allsongs[i].rating.replace(/"/g, '""').trim() + '"';
    } else if (style == "artist") {
    curr = allsongs[i].artist;
    curr += '"' + allsongs[i].artist.replace(/"/g, '""').trim() + '"';
    } else if (style == "artistsong") {
    curr = allsongs[i].artist + ",";
    curr += properTitle;
    curr += '"' + allsongs[i].artist.replace(/"/g, '""').trim() + '"' + ",";
    curr += '"' + properTitle.replace(/"/g, '""').trim() + '"';
    } else if (style == "artistalbum") {
    curr = allsongs[i].artist + ",";
    curr += allsongs[i].album;
    curr += '"' + allsongs[i].artist.replace(/"/g, '""').trim() + '"' + ",";
    curr += '"' + allsongs[i].album.replace(/"/g, '""').trim() + '"';
    } else if (style == "artistalbumsong") {
    curr = allsongs[i].artist + ",";
    curr += allsongs[i].album + ",";
    curr += properTitle;
    curr += '"' + allsongs[i].artist.replace(/"/g, '""').trim() + '"' + ",";
    curr += '"' + allsongs[i].album.replace(/"/g, '""').trim() + '"' + ",";
    curr += '"' + properTitle.replace(/"/g, '""').trim() + '"';
    } 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 += properTitle;
    curr = allsongs[i].artist + " - " + allsongs[i].album + " - " + properTitle;
    } else if (style == "artist"){
    curr = allsongs[i].artist;
    } else if (style == "artistalbum"){
    @@ -128,6 +123,7 @@ var songsToText = function(style, csv, likedonly){
    console.log("=============================================================");
    try {
    copy(outText);
    console.log("copy(outText) to clipboard succeeded.");
    } catch (e) {
    console.log(e);
    console.log("copy(outText) to clipboard failed, please type copy(outText) on the console or copy the log output above.");
  6. jmiserez revised this gist May 10, 2016. 1 changed file with 5 additions and 2 deletions.
    7 changes: 5 additions & 2 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -35,7 +35,9 @@
    // songs, use the "artistsong" style.

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

    var allsongs = []
    var outText = "";
    var songsToText = function(style, csv, likedonly){
    if (style === undefined){
    console.log("style is undefined.");
    @@ -49,7 +51,7 @@ var songsToText = function(style, csv, likedonly){
    if (style == "all" && !csv){
    console.log("Duration, ratings, and playcount will only be exported with the CSV flag");
    }
    var outText = "";
    outText = "";
    if (csv) {
    if (style == "all") {
    //extra line
    @@ -127,7 +129,8 @@ var songsToText = function(style, csv, likedonly){
    try {
    copy(outText);
    } catch (e) {
    console.log("copy() to clipboard failed, please copy output manually.");
    console.log(e);
    console.log("copy(outText) to clipboard 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 + ".");
    };
  7. jmiserez revised this gist May 10, 2016. 1 changed file with 0 additions and 56 deletions.
    56 changes: 0 additions & 56 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -35,62 +35,6 @@
    // songs, use the "artistsong" style.

    // see my answer here for questions: http://webapps.stackexchange.com/a/73791/77056
    var copyTextToClipboard = function(text) {
    var textArea = document.createElement("textarea");

    //
    // *** This styling is an extra step which is likely not required. ***
    //
    // Why is it here? To ensure:
    // 1. the element is able to have focus and selection.
    // 2. if element was to flash render it has minimal visual impact.
    // 3. less flakyness with selection and copying which **might** occur if
    // the textarea element is not visible.
    //
    // The likelihood is the element won't even render, not even a flash,
    // so some of these are just precautions. However in IE the element
    // is visible whilst the popup box asking the user for permission for
    // the web page to copy to the clipboard.
    //

    // Place in top-left corner of screen regardless of scroll position.
    textArea.style.position = 'fixed';
    textArea.style.top = 0;
    textArea.style.left = 0;

    // Ensure it has a small width and height. Setting to 1px / 1em
    // doesn't work as this gives a negative w/h on some browsers.
    textArea.style.width = '2em';
    textArea.style.height = '2em';

    // We don't need padding, reducing the size if it does flash render.
    textArea.style.padding = 0;

    // Clean up any borders.
    textArea.style.border = 'none';
    textArea.style.outline = 'none';
    textArea.style.boxShadow = 'none';

    // Avoid flash of white box if rendered for any reason.
    textArea.style.background = 'transparent';


    textArea.value = text;

    document.body.appendChild(textArea);

    textArea.select();

    try {
    var successful = document.execCommand('copy');
    var msg = successful ? 'successful' : 'unsuccessful';
    console.log('Copying text command was ' + msg);
    } catch (err) {
    console.log('Oops, unable to copy');
    }

    document.body.removeChild(textArea);
    };
    var allsongs = []
    var songsToText = function(style, csv, likedonly){
    if (style === undefined){
  8. jmiserez revised this gist May 10, 2016. 1 changed file with 61 additions and 2 deletions.
    63 changes: 61 additions & 2 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -35,7 +35,62 @@
    // songs, use the "artistsong" style.

    // see my answer here for questions: http://webapps.stackexchange.com/a/73791/77056
    var copyTextToClipboard = function(text) {
    var textArea = document.createElement("textarea");

    //
    // *** This styling is an extra step which is likely not required. ***
    //
    // Why is it here? To ensure:
    // 1. the element is able to have focus and selection.
    // 2. if element was to flash render it has minimal visual impact.
    // 3. less flakyness with selection and copying which **might** occur if
    // the textarea element is not visible.
    //
    // The likelihood is the element won't even render, not even a flash,
    // so some of these are just precautions. However in IE the element
    // is visible whilst the popup box asking the user for permission for
    // the web page to copy to the clipboard.
    //

    // Place in top-left corner of screen regardless of scroll position.
    textArea.style.position = 'fixed';
    textArea.style.top = 0;
    textArea.style.left = 0;

    // Ensure it has a small width and height. Setting to 1px / 1em
    // doesn't work as this gives a negative w/h on some browsers.
    textArea.style.width = '2em';
    textArea.style.height = '2em';

    // We don't need padding, reducing the size if it does flash render.
    textArea.style.padding = 0;

    // Clean up any borders.
    textArea.style.border = 'none';
    textArea.style.outline = 'none';
    textArea.style.boxShadow = 'none';

    // Avoid flash of white box if rendered for any reason.
    textArea.style.background = 'transparent';


    textArea.value = text;

    document.body.appendChild(textArea);

    textArea.select();

    try {
    var successful = document.execCommand('copy');
    var msg = successful ? 'successful' : 'unsuccessful';
    console.log('Copying text command was ' + msg);
    } catch (err) {
    console.log('Oops, unable to copy');
    }

    document.body.removeChild(textArea);
    };
    var allsongs = []
    var songsToText = function(style, csv, likedonly){
    if (style === undefined){
    @@ -125,8 +180,12 @@ var songsToText = function(style, csv, likedonly){
    console.log("=============================================================");
    console.log(outText);
    console.log("=============================================================");
    console.log("Done! " + numEntries + " lines copied to clipboard. Used " + numEntries + " songs out of " + allsongs.length + ".");
    copy(outText); //doesn't work on the first call... "copy() is not defined"?
    try {
    copy(outText);
    } catch (e) {
    console.log("copy() to clipboard failed, please copy output manually.");
    }
    console.log("Done! " + numEntries + " lines in output. Used " + numEntries + " unique entries out of " + allsongs.length + ".");
    };
    var scrapeSongs = function(){
    var intervalms = 1; //in ms
  9. jmiserez revised this gist May 9, 2016. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -122,9 +122,11 @@ var songsToText = function(style, csv, likedonly){
    }
    }
    }
    //copy(outText); //doesn't work on the first call... "copy() is not defined"? Opening a dialog window instead:
    window.prompt("Copy to clipboard: Ctrl+C, Enter", outText);
    console.log("=============================================================");
    console.log(outText);
    console.log("=============================================================");
    console.log("Done! " + numEntries + " lines copied to clipboard. Used " + numEntries + " songs out of " + allsongs.length + ".");
    copy(outText); //doesn't work on the first call... "copy() is not defined"?
    };
    var scrapeSongs = function(){
    var intervalms = 1; //in ms
  10. jmiserez revised this gist May 9, 2016. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -133,6 +133,7 @@ var scrapeSongs = function(){
    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) {
  11. jmiserez revised this gist May 9, 2016. 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
    @@ -1,4 +1,4 @@
    // Jeremie Miserez <[email protected]>, 2015
    // Jeremie Miserez <[email protected]>, 2016
    //
    // A little bit of Javascript to let you export your Google Music library, playlists, and album track lists :)
    //
  12. jmiserez revised this gist May 9, 2016. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -122,7 +122,8 @@ var songsToText = function(style, csv, likedonly){
    }
    }
    }
    copy(outText);
    //copy(outText); //doesn't work on the first call... "copy() is not defined"? Opening a dialog window instead:
    window.prompt("Copy to clipboard: Ctrl+C, Enter", outText);
    console.log("Done! " + numEntries + " lines copied to clipboard. Used " + numEntries + " songs out of " + allsongs.length + ".");
    };
    var scrapeSongs = function(){
  13. jmiserez revised this gist May 9, 2016. 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
    @@ -118,7 +118,7 @@ var songsToText = function(style, csv, likedonly){
    numEntries++;
    seen[curr] = true;
    } else {
    console.log("Skipping (duplicate) " + curr);
    //console.log("Skipping (duplicate) " + curr);
    }
    }
    }
  14. jmiserez revised this gist May 9, 2016. 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
    @@ -184,7 +184,7 @@ var scrapeSongs = function(){
    }
    if (!seen.hasOwnProperty(curr.dataid)){ // hashset
    total.push(curr);
    seen[curr.id] = true;
    seen[curr.dataid] = true;
    }
    }
    songs[songs.length-1].scrollIntoView(true); // go to next page
  15. jmiserez revised this gist May 9, 2016. 1 changed file with 8 additions and 7 deletions.
    15 changes: 8 additions & 7 deletions export_google_music.js
    Original file line number Diff line number Diff line change
    @@ -67,13 +67,14 @@ var songsToText = function(style, csv, likedonly){
    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 + ",";
    curr += allsongs[i].album + ",";
    curr += allsongs[i].title + ",";
    curr += properTitle + ",";
    curr += allsongs[i].duration + ",";
    curr += allsongs[i].index + ",";
    curr += allsongs[i].playcount + ",";
    @@ -82,14 +83,14 @@ var songsToText = function(style, csv, likedonly){
    curr = allsongs[i].artist;
    } else if (style == "artistsong") {
    curr = allsongs[i].artist + ",";
    curr += allsongs[i].title;
    curr += properTitle;
    } 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;
    curr += properTitle;
    } else {
    console.log("style not defined");
    }
    @@ -99,15 +100,15 @@ var songsToText = function(style, csv, likedonly){
    curr += (allsongs[i].index.length > 0 ? allsongs[i].index + ". " : "");
    curr += allsongs[i].artist + " - ";
    curr += allsongs[i].album + " - ";
    curr += allsongs[i].title;
    curr += properTitle;
    } 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;
    curr = allsongs[i].artist + " - " + properTitle;
    } else if (style == "artistalbumsong"){
    curr = allsongs[i].artist + " - " + allsongs[i].album + " - " + allsongs[i].title;
    curr = allsongs[i].artist + " - " + allsongs[i].album + " - " + properTitle;
    } else {
    console.log("style not defined");
    }
    @@ -157,7 +158,7 @@ var scrapeSongs = function(){
    var currId = songs[0].getAttribute("data-id");
    if (currId == topId){ // page has not yet changed
    retries--;
    scrollDiv = document.querySelector("div#music-content");
    scrollDiv = document.querySelector("#mainContainer");
    isAtBottom = scrollDiv.scrollTop == (scrollDiv.scrollHeight - scrollDiv.offsetHeight)
    if (isAtBottom || retries <= 0) {
    clearInterval(interval); //done
  16. 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)
    //
  17. 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)
    //
  18. 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
  19. 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 <[email protected]>, 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){
  20. 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);
  21. 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);
  22. 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;
  23. 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();
  24. 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);
    }
    }
    }
  25. 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");
    }
  26. 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;
  27. 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 <[email protected]>, 2015
    //
    // A little bit of Javascript to let you export your Google Music library :)
    //
    // 1. Go to: https://play.google.com/music/listen#/all
  28. 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
  29. 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

  30. 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) {