(Cập nhật 2016-05-09, mạnh mẽ hơn câu trả lời hàng đầu hiện tại)
Nếu bạn chỉ cần lưu một vài danh sách phát, bạn có thể sử dụng đoạn mã Javascript của tôi bên dưới. Đoạn mã này có thể lưu mọi danh sách khi nó được hiển thị trên trang web, do đó, nó cũng hoạt động cho tất cả các lượt xem thư viện bài hát / album / nghệ sĩ. Tôi đã liệt kê hai lựa chọn thay thế khác ở cuối câu trả lời này.
Truy cập: https://play.google.com/music/listen#/all (hoặc danh sách phát của bạn)
Mở bảng điều khiển dành cho nhà phát triển (F12 cho Chrome). Dán mã dưới đây vào bàn điều khiển.
Tất cả các bài hát bị loại bỏ được lưu trữ trong allsongs
đối tượng và một phiên bản văn bản của danh sách được sao chép vào bảng tạm. Tôi khuyên bạn nên chạy
songsToText("all",true)
sau đó để có được thông tin CSV đầy đủ. Chạy copy(outText)
thủ công nếu sao chép clipboard không hoạt động trong lần thử đầu tiên.
Mã (phiên bản mới nhất ngày 10 tháng 5 năm 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);
Mã mới nhất trên Github (Gist) tại đây: https://gist.github.com/jmiserez/c9a9a0f41e867e5ebb75
Nếu bạn muốn đầu ra ở định dạng văn bản, có thể gọi hàm testsToText (). Bạn có thể chọn một kiểu, chọn định dạng và nếu chỉ xuất các bài hát thích / bật ngón tay cái lên. Danh sách kết quả sau đó sẽ được dán vào bảng tạm. Styles là all
, artist
, artistalbum
, artistsong
,
artistalbumsong
. CSV sẽ dẫn đến một tệp CSV và có thể bị bỏ qua (mặc định là sai). Likedonly có thể bị bỏ qua (mặc định là false) hoặc được đặt thành true và sẽ lọc tất cả các bài hát có xếp hạng lớn hơn hoặc bằng 5. Ví dụ:
songsToText("all",true,false)
sẽ xuất tất cả các bài hát ở định dạng csv.
songsToText("all",true,true)
sẽ chỉ xuất các bài hát thích ở định dạng csv.
songsToText("artistsong",false,false)
sẽ xuất tất cả các bài hát dưới dạng văn bản.
Sau đó, bạn có thể dán dữ liệu vào bất cứ nơi nào bạn thích, ví dụ: http://www.ivyishere.org/ nếu bạn muốn thêm các bài hát hoặc album vào tài khoản Spotify của mình. Để làm cho Ivy nhận ra album đầy đủ, hãy sử dụng phong cách "artistalbum". Đối với các bài hát, sử dụng phong cách "artistong".
Về đoạn trích:
Điều này dựa trên câu trả lời ban đầu của Michael Smith, nhưng mạnh mẽ hơn một chút. Tôi đã thực hiện các cải tiến sau:
Hoạt động trên danh sách phát cũng như thư viện. Bất kỳ cột bị thiếu nào đều bị bỏ qua và thứ tự được tìm ra, do đó, nó sẽ hoạt động trên hầu hết mọi danh sách bài hát trong Google Music.
Nó dừng hoặc khi chạm đến đáy (phát hiện vị trí cuộn) hoặc sau khi hết thời gian đã chỉ định. Thời gian chờ là có để ngăn chặn một vòng lặp vô tận trong trường hợp mã phát hiện cuộn bị tắt bởi một vài pixel.
Nó nhanh hơn nhiều (khoảng cách mỗi 1ms), nhưng chờ đợi nếu dữ liệu chưa sẵn sàng (tối đa là thời gian chờ đã chỉ định, hiện tại là 3 giây).
Không trùng lặp trong quá trình hoạt động và trên đầu ra.
Xếp hạng tập hợp: "không xác định" không bao giờ được xếp hạng, "0" không được xếp hạng (nghĩa là một khi được xếp hạng nhưng sau đó bị xóa), "1" là ngón tay cái xuống và "5" là ngón tay cái lên (thích).
Ngoài những cải tiến cơ bản, nó cũng định dạng văn bản độc đáo và sao chép nó vào bảng tạm. Bạn cũng có thể lấy dữ liệu dưới dạng CSV nếu muốn, bằng cách chạy songsToText
chức năng lần thứ hai.
Lựa chọn thay thế:
Nếu bạn cần API Python, hãy xem dự án Google Music API không chính thức .
Nếu bạn có hàng tấn danh sách phát và muốn xuất tất cả chúng trong một lần, hãy thử trình xuất danh sách phát gmusic-scripts có thể làm điều đó (Python, sử dụng dự án API không chính thức).