(Aktualisiert am 09.05.2016, robuster als die aktuelle Top-Antwort)
Wenn Sie nur ein paar Wiedergabelisten speichern müssen, können Sie einfach mein Javascript-Snippet unten verwenden. Mit diesem Snippet kann jede Liste so gespeichert werden, wie sie auf der Webseite angezeigt wird, sodass es auch für alle Ansichten der Musik- / Album- / Künstlerbibliothek funktioniert. Ich habe am Ende dieser Antwort zwei weitere Alternativen aufgelistet.
Gehen Sie zu: https://play.google.com/music/listen#/all (oder Ihrer Wiedergabeliste)
Öffnen Sie eine Entwicklerkonsole (F12 für Chrome). Fügen Sie den folgenden Code in die Konsole ein.
Alle gescrapten Songs werden im allsongs
Objekt gespeichert und eine Textversion der Liste wird in die Zwischenablage kopiert. Ich empfehle,
songsToText("all",true)
danach auszuführen, um die vollständigen CSV-Informationen zu erhalten. Führen Sie copy(outText)
manuell , wenn die Zwischenablage kopiert nicht beim ersten Versuch nicht funktioniert.
Code (neueste Version 10. Mai 2016, Rev. 30):
var allsongs = []
var outText = "";
var songsToText = function(style, csv, likedonly){
if (style === undefined){
console.log("style is undefined.");
return;
}
var csv = csv || false; // defaults to false
var likedonly = likedonly || false; // defaults to false
if (likedonly) {
console.log("Only selecting liked songs");
}
if (style == "all" && !csv){
console.log("Duration, ratings, and playcount will only be exported with the CSV flag");
}
outText = "";
if (csv) {
if (style == "all") {
//extra line
outText = "artist,album,title,duration,playcount,rating,rating_interpretation" + "\n";
} else if (style == "artist") {
} else if (style == "artistsong") {
} else if (style == "artistalbum") {
} else if (style == "artistalbumsong") {
} else {
console.log("style not defined");
}
}
var numEntries = 0;
var seen = {};
for (var i = 0; i < allsongs.length; i++) {
var curr = "";
var properTitle = allsongs[i].title.replace(/[\n\r!]/g, '').trim();
if (!likedonly || (likedonly && allsongs[i].rating >= 5)){
if (csv) {
if (style == "all") {
//extra line
curr += '"' + allsongs[i].artist.replace(/"/g, '""').trim() + '"' + ",";
curr += '"' + 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() + '"' + ",";
curr += '"' + allsongs[i].rating_interpretation.replace(/"/g, '""').trim() + '"';
} else if (style == "artist") {
curr += '"' + allsongs[i].artist.replace(/"/g, '""').trim() + '"';
} else if (style == "artistsong") {
curr += '"' + allsongs[i].artist.replace(/"/g, '""').trim() + '"' + ",";
curr += '"' + properTitle.replace(/"/g, '""').trim() + '"';
} else if (style == "artistalbum") {
curr += '"' + allsongs[i].artist.replace(/"/g, '""').trim() + '"' + ",";
curr += '"' + allsongs[i].album.replace(/"/g, '""').trim() + '"';
} else if (style == "artistalbumsong") {
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 = allsongs[i].artist + " - " + allsongs[i].album + " - " + properTitle + " [[playcount: " + allsongs[i].playcount + ", rating: " + allsongs[i].rating_interpretation + "]]" ;
} else if (style == "artist"){
curr = allsongs[i].artist;
} else if (style == "artistalbum"){
curr = allsongs[i].artist + " - " + allsongs[i].album;
} else if (style == "artistsong"){
curr = allsongs[i].artist + " - " + properTitle;
} else if (style == "artistalbumsong"){
curr = allsongs[i].artist + " - " + allsongs[i].album + " - " + properTitle;
} else {
console.log("style not defined");
}
}
if (!seen.hasOwnProperty(curr)){ // hashset
outText = outText + curr + "\n";
numEntries++;
seen[curr] = true;
} else {
//console.log("Skipping (duplicate) " + curr);
}
}
}
console.log("=============================================================");
console.log(outText);
console.log("=============================================================");
try {
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.");
}
console.log("Done! " + numEntries + " lines in output. Used " + numEntries + " unique entries out of " + allsongs.length + ".");
};
var scrapeSongs = function(){
var intervalms = 1; //in ms
var timeoutms = 3000; //in ms
var retries = timeoutms / intervalms;
var total = [];
var seen = {};
var topId = "";
document.querySelector("#mainContainer").scrollTop = 0; //scroll to top
var interval = setInterval(function(){
var songs = document.querySelectorAll("table.song-table tbody tr.song-row");
if (songs.length > 0) {
// detect order
var colNames = {
index: -1,
title: -1,
duration: -1,
artist: -1,
album: -1,
playcount: -1,
rating: -1
};
for (var i = 0; i < songs[0].childNodes.length; i++) {
colNames.index = songs[0].childNodes[i].getAttribute("data-col") == "index" ? i : colNames.index;
colNames.title = songs[0].childNodes[i].getAttribute("data-col") == "title" ? i : colNames.title;
colNames.duration = songs[0].childNodes[i].getAttribute("data-col") == "duration" ? i : colNames.duration;
colNames.artist = songs[0].childNodes[i].getAttribute("data-col") == "artist" ? i : colNames.artist;
colNames.album = songs[0].childNodes[i].getAttribute("data-col") == "album" ? i : colNames.album;
colNames.playcount = songs[0].childNodes[i].getAttribute("data-col") == "play-count" ? i : colNames.playcount;
colNames.rating = songs[0].childNodes[i].getAttribute("data-col") == "rating" ? i : colNames.rating;
}
// check if page has updated/scrolled
var currId = songs[0].getAttribute("data-id");
if (currId == topId){ // page has not yet changed
retries--;
scrollDiv = document.querySelector("#mainContainer");
isAtBottom = scrollDiv.scrollTop == (scrollDiv.scrollHeight - scrollDiv.offsetHeight)
if (isAtBottom || retries <= 0) {
clearInterval(interval); //done
allsongs = total;
console.log("Got " + total.length + " songs and stored them in the allsongs variable.");
console.log("Calling songsToText with style all, csv flag true, likedonly false: songsToText(\"all\", false).");
songsToText("artistalbumsong", 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].getAttribute("data-rating") : ""),
rating_interpretation: "",
}
if(curr.rating == "undefined") {
curr.rating_interpretation = "never-rated"
}
if(curr.rating == "0") {
curr.rating_interpretation = "not-rated"
}
if(curr.rating == "1") {
curr.rating_interpretation = "thumbs-down"
}
if(curr.rating == "5") {
curr.rating_interpretation = "thumbs-up"
}
if (!seen.hasOwnProperty(curr.dataid)){ // hashset
total.push(curr);
seen[curr.dataid] = true;
}
}
songs[songs.length-1].scrollIntoView(true); // go to next page
}
}
}, intervalms);
};
scrapeSongs();
// for the full CSV version you can now call songsToText("all", true);
Letzter Code für Github (Gist) hier: https://gist.github.com/jmiserez/c9a9a0f41e867e5ebb75
Wenn Sie die Ausgabe in einem Textformat wünschen, können Sie die Funktion songsToText () aufrufen. Sie können einen Style auswählen, das Format auswählen und wenn Sie möchten, sollten nur Songs exportiert werden. Die resultierende Liste wird dann in die Zwischenablage eingefügt. Styles sind all
, artist
, artistalbum
, artistsong
,
artistalbumsong
. CSV führt zu einer CSV-Datei und kann weggelassen werden (standardmäßig false). Likedonly kann weggelassen werden (Standard ist false) oder auf true gesetzt werden und filtert alle Songs mit Bewertungen größer oder gleich 5. Beispiel:
songsToText("all",true,false)
exportiert alle songs im csv format.
songsToText("all",true,true)
exportiert nur beliebte songs im csv format.
songsToText("artistsong",false,false)
exportiert alle Lieder als Text.
Sie können die Daten dann an einer beliebigen Stelle einfügen, z. B. http://www.ivyishere.org/, wenn Sie die Titel oder Alben zu Ihrem Spotify-Konto hinzufügen möchten. Verwenden Sie den "artistalbum" -Stil, damit Ivy vollständige Alben erkennt. Verwenden Sie für Songs den "artistsong" -Stil.
Über das Snippet:
Dies basiert auf der ursprünglichen Antwort von Michael Smith, ist jedoch etwas robuster. Ich habe folgende Verbesserungen vorgenommen:
Funktioniert sowohl mit Wiedergabelisten als auch mit der Bibliothek. Fehlende Spalten werden ignoriert und die Reihenfolge wird ermittelt. Daher sollte dies in fast jeder Songliste in Google Music funktionieren.
Es stoppt entweder am unteren Rand (erkennt die Bildlaufposition) oder nach dem angegebenen Timeout. Das Timeout verhindert eine Endlosschleife, falls der Bildlauferkennungscode um einige Pixel abweicht.
Es ist viel schneller (Intervall alle 1 ms), wartet aber, wenn die Daten nicht bereit sind (bis zum angegebenen Timeout, derzeit 3s).
Deduplizierung während des Betriebs und auf der Ausgabe.
Sammelt Bewertungen: "undefined" wird nie bewertet, "0" wird nicht bewertet (dh einmal bewertet, aber dann entfernt), "1" ist Daumen nach unten und "5" ist Daumen nach oben (gefällt).
Neben den grundlegenden Verbesserungen wird auch der Text schön formatiert und in die Zwischenablage kopiert. Sie können die Daten auch als CSV abrufen, indem Sie die songsToText
Funktion ein zweites Mal ausführen.
Alternativen:
Wenn Sie eine Python-API benötigen, lesen Sie das inoffizielle Google Music-API- Projekt.
Wenn Sie Unmengen von Wiedergabelisten haben und alle auf einmal exportieren möchten, probieren Sie den gmusic-scripts- Exporter für Wiedergabelisten aus, der dies ermöglicht (Python verwendet das inoffizielle API-Projekt).