Google Play Music アカウントから曲のリスト(アーティスト、アルバム、評価、可能であれば再生回数と期間を含む)を印刷したい。
アプリからこれを行う簡単な方法はありません。曲の長いリストをページングしながら印刷画面を実行することはできません。
自分で操作できる標準形式(プレーンテキスト、CSV、XMLなど)へのデータのエクスポートに満足しています。
助言がありますか?
darkliquidの答え を変更して、複数のプレイリストを一度に保存できる以下を思いつきました。
JSON.stringify(tracklistObj, null, '\t')
(最小インデントが必要な場合は'\t'
を' '
に変更)またはtracklistObj
と入力できます。 JavaScriptオブジェクトで独自の方法で操作したいだけです。ソートする場合は、Object.values(tracklistObj).forEach(a => a.sort())
beforeコマンドを実行して、JSON.stringify
コマンドを呼び出します。やりたいことをすべて完了する前にページを更新しないように注意してください。さもないと、手順1から再起動する必要があります。
// Setup
var tracklistObj = {},
currentPlaylist,
checkIntervalTime = 100,
lastTime;
// Process the visible tracks
function getVisibleTracks() {
var playlist = document.querySelectorAll('.song-table tr.song-row');
for(var i = 0; i < playlist.length ; i++) {
var l = playlist[i];
var title = l.querySelector('td[data-col="title"] .column-content');
if(title !== null)
title = title.textContent;
var artist = l.querySelector('td[data-col="artist"] .column-content');
if(artist !== null)
artist = artist.textContent;
var duration = l.querySelector('td[data-col="duration"] span');
if(duration !== null)
duration = duration.textContent;
var album = l.querySelector('td[data-col="album"] .column-content');
if(album !== null)
album = album.textContent;
var playCount = l.querySelector('td[data-col="play-count"] span');
if(playCount !== null)
playCount = playCount.textContent;
var rating = l.querySelector('td[data-col="rating"]');
if(rating !== null)
rating = rating.textContent;
// Add it if it doesn't exist already
if(tracklistObj[currentPlaylist] && !tracklistObj[currentPlaylist].includes(artist + " - " + title)) {
tracklistObj[currentPlaylist].Push(artist + " - " + title);
if(printTracksToConsole) {
console.log(artist + ' - ' + title);
}
}
}
}
// Listen for page changes
window.onhashchange = function(e) {
currentPlaylist = null;
var doneLoading = setInterval(function() {
var playListName = document.querySelector('.gpm-detail-page-header h2[slot="title"]');
if(playListName != null) {
currentPlaylist = playListName.innerText;
if(tracklistObj[currentPlaylist] === undefined) {
tracklistObj[currentPlaylist] = [];
}
console.log("===================================");
console.log("Adding to playlist " + currentPlaylist);
getVisibleTracks();
clearInterval(doneLoading);
}
}, 100);
}
// Check for new tracks every so often
setInterval(function() {
getVisibleTracks();
}, checkIntervalTime);
// Whether or not to print the tracks obtained to the console
var printTracksToConsole = false;
printTracksToConsole
をtrue
に変更して、トラック名をコンソールに出力することもできます(手順3の前にこれを行う必要があります)。
コンソール内のすべてのGETおよびPOSTエラーを無視できる可能性があることに注意してください(これらはこのスクリプトではなく、Play Music自体によって生成されます)。
また、現在はArtist - Track name
を指定するように設定されているだけですが、tracklistObj[currentPlaylist].Push(artist + " - " + title);
を含む行はalbum
、playCount
、duration
、またはrating
、および/または任意のフォーマット(CSV形式を含む)で簡単に編集できますもしそうなら)。
出力例(現在持っているすべてのGoogle Playプレイリスト)とデフォルト設定。 32のプレイリストのそれぞれに移動し、それらを下にスクロールして、結果をテキストに変換するのに合計で約5分かかりました。
追伸私が見つけた Tune My Music というサイトを使用して、出力からYouTubeプレイリストを作成できます(ただし、YouTubeはプレイリストの作成を1日に10に制限します)。これを行う場合、おそらく TextMechanic のようなものを使用して、出力リストから引用符と.mp3
を削除する必要があります。
(2016-05-09更新、現在のトップアンサーより堅牢)
いくつかのプレイリストを保存する必要がある場合は、以下のJavascriptスニペットを使用できます。このスニペットは、ウェブページに表示されるすべてのリストを保存できるため、すべての曲/アルバム/アーティストのライブラリビューでも機能します。この回答の最後に、他の2つの選択肢をリストしました。
次へ移動します。 https://play.google.com/music/listen#/all (またはプレイリスト)
開発者コンソール(Chromeの場合はF12)を開きます。以下のコードをコンソールに貼り付けます。
すべてのスクレイピングされた曲はallsongs
オブジェクトに保存され、リストのテキストバージョンがクリップボードにコピーされます。その後、songsToText("all",true)
を実行して、完全なCSV情報を取得することをお勧めします。最初の試行でクリップボードのコピーが機能しなかった場合は、copy(outText)
を手動で実行します。
コード(最新バージョン2016年5月10日、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);
Github(Gist)の最新コードはこちら:https://Gist.github.com/jmiserez/c9a9a0f41e867e5ebb75
テキスト形式の出力が必要な場合は、songsToText()関数を呼び出すことができます。スタイルを選択し、形式を選択できます。いいね!/サムアップした曲のみをエクスポートする必要があります。結果のリストは、クリップボードに貼り付けられます。スタイルはall
、artist
、artistalbum
、artistsong
、artistalbumsong
です。 CSVはCSVファイルになり、省略できます(デフォルトはfalse)。 Likedonlyは省略可能(デフォルトはfalse)またはtrueに設定でき、5以上の評価を持つすべての曲をフィルタリングします。例:
songsToText("all",true,false)
は、すべての曲をCSV形式でエクスポートします。songsToText("all",true,true)
は、CSV形式のいいね!の曲のみをエクスポートします。songsToText("artistsong",false,false)
は、すべての曲をテキストとしてエクスポートします。好きな場所にデータを貼り付けることができます。たとえば、Spotifyアカウントに曲やアルバムを追加する場合は、 http://www.ivyishere.org/ に貼り付けます。 Ivyにフルアルバムを認識させるには、「artistalbum」スタイルを使用します。曲の場合は、「アーティストソング」スタイルを使用します。
スニペットについて:これはマイケル・スミスの元の答えに基づいていますが、もう少し堅牢です。次の改善を行いました。
プレイリストとライブラリで動作します。欠落している列は無視され、順序が計算されるため、Googleミュージック内のほぼすべての曲リストで機能するはずです。
一番下に達するか(スクロール位置を検出)、または指定されたタイムアウトの後に停止します。タイムアウトは、スクロール検出コードが数ピクセルずれている場合の無限ループを防ぐためにあります。
これははるかに高速です(1ミリ秒ごとの間隔)が、データの準備ができていない場合(指定されたタイムアウト、現在3秒まで)待機します。
操作中および出力で重複排除を行います。
評価を収集します:「未定義」は評価されず、「0」は評価されません(つまり、一度評価されてから削除されます)、「1」は不賛成、「5」は不賛成(いいね)です。
基本的な改善に加えて、テキストを適切にフォーマットし、クリップボードにコピーします。必要に応じて、songsToText
関数を2回実行して、CSVとしてデータを取得することもできます。
代替案:
Python APIが必要な場合は、 非公式のGoogle Music API プロジェクトをご覧ください。
たくさんのプレイリストがあり、それらすべてを一度にエクスポートしたい場合は、それを行うことができる gmusic-scripts プレイリストエクスポーターを試してください(Python、非公式APIプロジェクトを使用)。
ブラウザのデベロッパーコンソールでJavaScriptコードを少し実行してもかまわない場合は、次のようにしてページから情報を抽出できます(Chromeでのみテスト済み)。
var playlist = document.querySelectorAll('.song-table tr.song-row');
for(var i =0; i<playlist.length ; i++) {
var l = playlist[i];
var title = l.querySelector('td[data-col="title"] .column-content').textContent;
var artist = l.querySelector('td[data-col="artist"] .column-content').textContent;
var album = l.querySelector('td[data-col="album"] .column-content').textContent;
console.log(artist + ' --- ' + title + ' --- ' + album);
}
これにより、ウィンドウに現在表示されているほとんどの曲のリストがコンソールに出力されます。さらにスクロールするには、下にスクロールして再実行する必要があります。現時点では、情報を完全に把握する適切な方法はまだわかりませんが、この5分間の簡単なハックは、何もしないよりはましです。
(当時の)最上位の回答を使用して完全なソリューションを求めて、音楽リストをスクロールダウンしてJSONオブジェクトを配列に追加する次のコードを作成しました。
表示されている曲が正確にわからないため、コードはすべての曲を追加し、最後に重複を排除します。 (Chromeでのみテストされています。)
使用するには:ライブラリに移動して、曲の完全なリストを表示し、実行します
var total = [];
var interval = setInterval(function(){
var songs = document.querySelectorAll("table.song-table tbody tr.song-row");
for (var i = 0; i < songs.length; i++) {
total.Push({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
});
songs[i].scrollIntoView(true);
}
}, 800);
それがページの下部に到達したら、これを実行してスクロールを停止し、配列の重複を取り除き、JSONをクリップボードにコピーします。
clearInterval(interval);
for (var i = 0; i < total.length; i++) {
for (var j = i + 1; j < total.length; j++) {
if (total.hasOwnProperty(i) && total.hasOwnProperty(j) && total[i].name == total[j].name && total[j].artist == total[i].artist) {
total.splice(j,1);
}
}
}
copy(total);
コンソールに貼り付けることができる、はるかに短いJavaScriptがあります。コードを再実行する代わりに、下にスクロールするだけで、表示されるすべてのアルバムが追加されます。その後、プレイリストをスプレッドシートとしてダウンロードできます。
ここに移動: https://play.google.com/music/listen#/ap/auto-playlist-thumbs-up
Developer Tools(F12)を開き、以下のコードをConsoleに貼り付けますタブ
スクロールして、プレイリストの各アルバムが少なくとも1回表示されるようにします
ページのどこかをダブルクリックして、export-google-play.csv
をダウンロードします
Excelでexport-google-play.csv
を開きます。
alert("Please scroll through the playlist so that each album is visible once.\n" +
"Then double-click the page to export a spreadsheet.");
var albums = ["Artist,Album,Purchased"];
var addVisibleAlbums = function(){
[].forEach.call(document.querySelectorAll(".song-row"), function(e){
var albumNodes = [e.querySelector("td[data-col='artist']"),
e.querySelector("td[data-col='album']"),
e.querySelector("td[data-col='title'] .title-right-items")];
var albumString = albumNodes.map(function(s){
return s.innerText.trim().replace(/,/g,"");
}).join(",");
if(albums.indexOf(albumString) === -1){
albums.Push(albumString); console.log("Added: " + albumString)
}
});
}
var createCsv = function(){
var csv = "data:text/csv;charset=utf-8,";
albums.forEach(function(row){ csv += row + "\n"; });
var uri = encodeURI(csv);
var link = document.createElement("a");
link.setAttribute("href", uri);
link.setAttribute("download", "export-google-play.csv");
document.body.appendChild(link);
link.click();
alert("Download beginning!")
}
document.body.addEventListener("DOMNodeInserted", addVisibleAlbums, false);
document.body.addEventListener("dblclick", createCsv, false);
トップアンサーのアプローチを少し変更しました。これは、Ivyのコピー/貼り付け方法( http://www.ivyishere.org/ivy )のおかげで私にとってはうまくいきました。
ステップ1ChromeでGoogle Musicのプレイリストを開き、コンソールに貼り付けます:
document.querySelector('body.material').style.height = (document.querySelector('table.song-table tbody').getAttribute('data-count') * 100) + 'px';
これにより、一部だけではなく、プレイリスト全体がレンダリングされるはずです。
ステップ2このスクリプトをコンソールに貼り付けます:
var i, j, playlistString = '', playlist = document.querySelectorAll('.song-table tr.song-row');
for (i = 0, j = playlist.length; i < j; i++) {
var track = playlist[i];
var artist = track.querySelector('[href][aria-label]').textContent;
var title = track.querySelector('td[data-col="title"]').textContent;
playlistString += ('"' + artist + '", "' + title + '"\n');
}
console.log(playlistString);
ステップ3Ivy に進み、そこでステップ2に移動したら、[コピー/貼り付け]タブを選択し、コンソール出力を貼り付けますそこ。
編集
Alex Pedersen によって提案された更新されたスクリプト
Samurauturetskysの改良を繰り返します(彼の投稿にコメントするほどの評判はまだありません)。 Googleplayのスタイリングが更新されたため、下のスクリプトでもきれいな出力が得られると思います。
var i, j, playlistString = '', playlist = document.querySelectorAll('.song-table tr.song-row');
for (i = 0, j = playlist.length; i < j; i++) {
var track = playlist[i];
var artist = track.querySelector('[href][aria-label]').textContent;
var title = track.querySelector('span[class="column-content fade-out tooltip"]').textContent;
playlistString += ('"' + artist + '", "' + title + '"\n');
}
console.log(playlistString);