// ==UserScript== // @name CloudMusic - Show all songs on the playlist // @name:zh-CN 网易云音乐 - 显示歌单中的所有歌曲 // @namespace https://greasyfork.org/zh-CN/users/193133-pana // @homepage https://www.sailboatweb.com // @version 1.0.3 // @description Show all songs in the playlist // @description:zh-CN 显示歌单中的所有歌曲 // @author pana // @license GNU General Public License v3.0 or later // @match *://music.163.com/* // @connect api.imjad.cn // @connect music.163.com // @grant GM_xmlhttpRequest // @downloadURL none // ==/UserScript== (function() { 'use strict'; class Basic_Obj { constructor(id, name) { this.id = id; this.name = name; } getId() { return this.id; } getName() { return this.name; } } class Song_Obj extends Basic_Obj { constructor(song_id, song_name, play_time, mvid = 0, no_copyright_rcmd = null, alias = null, trans_name = null) { super(song_id, song_name); this.playTime = play_time; this.mvid = mvid; this.noCopyrightRcmd = no_copyright_rcmd; this.alias = alias; this.transName = trans_name; } getPlayTime() { let time = ''; let seconds = Math.round(this.playTime / 1000); if ((seconds / 3600) >= 1) { time += Math.floor(seconds / 3600) + ":"; } seconds %= 3600; if ((seconds / 60) >= 1) { if ((seconds / 60) > 9) { time += Math.floor(seconds / 60) + ":"; } else { time += "0" + Math.floor(seconds / 60).toString() + ":"; } } seconds %= 60; if (seconds >= 10) { time += seconds; } else { time += "0" + seconds.toString(); } return time; } getMvid() { return this.mvid; } getAliasName() { if (this.alias) { return this.alias[0]; } return null; } getTransName() { return this.transName; } isExistsMv() { if (this.mvid > 0) { return true; } return false; } isNoCopyright() { if (this.noCopyrightRcmd) { return true; } return false; } } class Aritst_Obj extends Basic_Obj { constructor(aritst_id, aritst_name) { super(aritst_id, aritst_name); } } class Album_Obj extends Basic_Obj { constructor(album_id, album_name, pic_url) { super(album_id, album_name); this.picUrl = pic_url; } getPicUrl() { return this.picUrl; } } class Music_Obj { constructor(playlist_id, song_obj, aritst_arr, album_obj) { this.playlistId = playlist_id; this.song = song_obj; this.aritst = aritst_arr; this.album = album_obj; } createTableItem(position, is_even = false) { let tr = document.createElement('tr'); tr.id = this.song.getId().toString() + Date.now().toString(); if (is_even) { tr.classList.add('even'); } if (this.song.isNoCopyright()) { tr.classList.add('js-dis'); } let aritst_name = ''; this.aritst.forEach((item) => { if (aritst_name) { aritst_name += "/" + item.getName(); } else { aritst_name = item.getName(); } }); let td_0 = document.createElement('td'); td_0.className = 'left'; let td_0_div = document.createElement('div'); td_0_div.className = 'hd'; let td_0_div_span_0 = document.createElement('span'); td_0_div_span_0.className = 'ply'; td_0_div_span_0.setAttribute('data-res-id', this.song.getId()); td_0_div_span_0.setAttribute('data-res-type', '18'); td_0_div_span_0.setAttribute('data-res-action', 'play'); td_0_div_span_0.setAttribute('data-res-from', '13'); td_0_div_span_0.setAttribute('data-res-data', this.playlistId); let td_0_div_span_1 = document.createElement('span'); td_0_div_span_1.className = 'num'; td_0_div_span_1.textContent = position; td_0_div.appendChild(td_0_div_span_0); td_0_div.appendChild(td_0_div_span_1); td_0.appendChild(td_0_div); let alias_name = ''; let song_title = ''; if (this.song.isExistsMv()) { song_title = this.song.getName(); } else if (this.song.getTransName()) { alias_name = this.song.getTransName(); song_title = this.song.getName() + ' - (' + this.song.getTransName() + ')'; } else if (this.song.getAliasName()) { alias_name = this.song.getAliasName(); song_title = this.song.getName() + ' - (' + this.song.getAliasName() + ')'; } else { song_title = this.song.getName(); } let td_1 = document.createElement('td'); let td_1_div = document.createElement('div'); td_1_div.className = 'f-cb'; let td_1_div_div = document.createElement('div'); td_1_div_div.className = 'tt'; let td_1_div_div_div = document.createElement('div'); td_1_div_div_div.className = 'ttc'; let td_1_div_div_div_span = document.createElement('span'); td_1_div_div_div_span.className = 'txt'; let td_1_div_div_div_span_a = document.createElement('a'); td_1_div_div_div_span_a.href = '/song?id=' + this.song.getId(); let td_1_div_div_div_span_a_b = document.createElement('b'); td_1_div_div_div_span_a_b.textContent = this.song.getName(); td_1_div_div_div_span_a_b.title = song_title; td_1_div_div_div_span_a.appendChild(td_1_div_div_div_span_a_b); td_1_div_div_div_span.appendChild(td_1_div_div_div_span_a); td_1_div_div_div.appendChild(td_1_div_div_div_span); td_1_div_div.appendChild(td_1_div_div_div); td_1_div.appendChild(td_1_div_div); td_1.appendChild(td_1_div); if (this.song.isExistsMv()) { let td_1_div_div_div_span_span = document.createElement('span'); td_1_div_div_div_span_span.className = 'mv'; td_1_div_div_div_span_span.textContent = 'MV'; td_1_div_div_div_span_span.title = '播放mv'; td_1_div_div_div_span_span.setAttribute('data-res-id', this.song.getId()); td_1_div_div_div_span_span.setAttribute('data-res-action', 'mv'); td_1_div_div_div_span_span.addEventListener('click', () => { window.parent.location.href = '/mv?id=' + this.song.getMvid(); }); td_1_div_div_div_span.appendChild(td_1_div_div_div_span_span); } else if (alias_name) { let td_1_div_div_div_span_span = document.createElement('span'); td_1_div_div_div_span_span.className = 's-fc8'; td_1_div_div_div_span_span.title = alias_name; td_1_div_div_div_span_span.textContent = ' - (' + alias_name + ')'; td_1_div_div_div_span.appendChild(td_1_div_div_div_span_span); } let td_2 = document.createElement('td'); td_2.className = 's-fc3'; let td_2_span = document.createElement('span'); td_2_span.className = 'u-dur'; td_2_span.textContent = this.song.getPlayTime(); let td_2_div = document.createElement('div'); td_2_div.className = 'opt hshow'; let td_2_div_a = document.createElement('a'); td_2_div_a.className = 'u-icn u-icn-81 icn-add'; td_2_div_a.href = 'javascript:;'; td_2_div_a.title = '添加到播放列表'; td_2_div_a.setAttribute('hidefocus', 'true'); td_2_div_a.setAttribute('data-res-type', '18'); td_2_div_a.setAttribute('data-res-id', this.song.getId()); td_2_div_a.setAttribute('data-res-action', 'addto'); td_2_div_a.setAttribute('data-res-from', '13'); td_2_div_a.setAttribute('data-res-data', this.playlistId); let td_2_div_span_0 = document.createElement('span'); td_2_div_span_0.className = 'icn icn-fav'; td_2_div_span_0.title = '收藏'; td_2_div_span_0.setAttribute('data-res-id', this.song.getId()); td_2_div_span_0.setAttribute('data-res-type', '18'); td_2_div_span_0.setAttribute('data-res-action', 'fav'); let td_2_div_span_1 = document.createElement('span'); td_2_div_span_1.className = 'icn icn-share'; td_2_div_span_1.title = '分享'; td_2_div_span_1.textContent = '分享'; td_2_div_span_1.setAttribute('data-res-id', this.song.getId()); td_2_div_span_1.setAttribute('data-res-type', '18'); td_2_div_span_1.setAttribute('data-res-action', 'share'); td_2_div_span_1.setAttribute('data-res-name', this.song.getName()); td_2_div_span_1.setAttribute('data-res-author', aritst_name); td_2_div_span_1.setAttribute('data-res-pic', this.album.getPicUrl()); let td_2_div_span_2 = document.createElement('span'); td_2_div_span_2.className = 'icn icn-dl'; td_2_div_span_2.title = '下载'; td_2_div_span_2.setAttribute('data-res-id', this.song.getId()); td_2_div_span_2.setAttribute('data-res-type', '18'); td_2_div_span_2.setAttribute('data-res-action', 'download'); td_2_div.appendChild(td_2_div_a); td_2_div.appendChild(td_2_div_span_0); td_2_div.appendChild(td_2_div_span_1); td_2_div.appendChild(td_2_div_span_2); td_2.appendChild(td_2_span); td_2.appendChild(td_2_div); let td_3 = document.createElement('td'); let td_3_div = document.createElement('div'); td_3_div.className = 'text'; td_3_div.title = aritst_name; let td_3_div_span = document.createElement('span'); td_3_div_span.title = aritst_name; this.aritst.forEach((item, index) => { let td_3_div_span_a = document.createElement('a'); td_3_div_span_a.href = '/aritst?id=' + item.getId(); td_3_div_span_a.textContent = item.getName(); td_3_div_span_a.setAttribute('hidefocus', 'true'); td_3_div_span.appendChild(td_3_div_span_a); if (index > 0) { td_3_div_span_a.before("/"); } }); td_3_div.appendChild(td_3_div_span); td_3.appendChild(td_3_div); let td_4 = document.createElement('td'); let td_4_div = document.createElement('div'); td_4_div.className = 'text'; let td_4_div_a = document.createElement('a'); td_4_div_a.title = this.album.getName(); td_4_div_a.textContent = this.album.getName(); td_4_div_a.href = '/album?id=' + this.album.getId(); td_4_div.appendChild(td_4_div_a); td_4.appendChild(td_4_div); tr.appendChild(td_0); tr.appendChild(td_1); tr.appendChild(td_2); tr.appendChild(td_3); tr.appendChild(td_4); return tr; } } function get_Music_Info(music_id) { return new Promise(function(resolve, _reject) { let music_details = { 'method': 'GET', 'url': 'http://music.163.com/api/song/detail/?id=' + music_id + '&ids=%5B' + music_id + '%5D', 'headers': { 'Content-Type': 'application/x-www-form-urlencoded' }, 'responseType': 'json', 'onload': function(res) { if (res.status == 200 && res.readyState == 4) { resolve(res.response); } else { console.warn('返回的歌曲信息状态码异常。code: ' + res.status + ' readyState: ' + res.readyState); resolve(null); } }, 'onerror': function() { console.error('获取歌曲信息出错!id:', music_id); resolve(null); } }; GM_xmlhttpRequest(music_details); }); } async function main_Cloud_Music(playlist_id, playlist_obj, callback) { let record_arr = []; document.querySelectorAll('#song-list-pre-cache tbody tr').forEach((item) => { record_arr.push(item.id.replace(/\d{13}$/, '')); }); let position = record_arr.length; let show_num = null; if (document.querySelector('.n-songtb .sub.s-fc3')) { show_num = document.createElement('span'); show_num.id = 'cloudMusicShowNum'; show_num.textContent = '(已经加载' + position + '首歌)'; document.querySelector('.n-songtb .sub.s-fc3').appendChild(show_num); } if (document.querySelector('#song-list-pre-cache tbody')) { let tbody = document.querySelector('#song-list-pre-cache tbody'); for (let ele of playlist_obj.playlist.trackIds) { if (! record_arr.includes(ele.id.toString())) { await get_Music_Info(ele.id).then((data) => { if (data) { if (data.code == 200) { position ++; let music_info = data.songs[0]; let song_obj = new Song_Obj(music_info.id ,music_info.name, music_info.duration, music_info.mvid, music_info.noCopyrightRcmd, music_info.alias, music_info.transName); let aritst_arr = []; for (let a_ele of music_info.artists) { let artist_obj = new Aritst_Obj(a_ele.id, a_ele.name); aritst_arr.push(artist_obj); } let album_obj = new Album_Obj(music_info.album.id, music_info.album.name, music_info.album.picUrl); let music_obj = new Music_Obj(playlist_id, song_obj, aritst_arr, album_obj); tbody.appendChild(music_obj.createTableItem(position, (position % 2 === 1))); if (show_num) { show_num.textContent = '(已经加载' + position + '首歌)'; } } else { console.warn('Song cheating. code:', data.code); } } }); } } if (show_num) { show_num.textContent = '(加载完成)'; } } if (typeof(callback) === 'function') { callback(); } } function init_Cloud_Music() { if (location.href.indexOf('/playlist?id=') !== -1) { if (document.getElementById('m-playlist')) { document.querySelectorAll('.soil').forEach((item) => { item.parentNode.removeChild(item); }); let playlist_id = ''; if (document.getElementById('content-operation')) { playlist_id = document.getElementById('content-operation').getAttribute('data-rid'); } if (playlist_id) { let show_text = null; if (document.querySelector('.m-playlist-see-more .text')) { show_text = document.querySelector('.m-playlist-see-more .text'); show_text.textContent = '正在获取歌单信息,请稍等...'; } let details = { 'method': 'GET', 'url': 'https://api.imjad.cn/cloudmusic/?type=playlist&id=' + playlist_id, 'headers': { 'Content-Type': 'application/x-www-form-urlencoded' }, 'responseType': 'json', 'onload': function(res) { if (res.status == 200 && res.readyState == 4) { let playlist_obj = res.response; if (playlist_obj.code == 200) { if (show_text) { show_text.textContent = '已经获取歌单信息,正在创建歌曲条目,请稍等...'; } if (document.querySelector('.u-btni.u-btni-add')) { document.querySelector('.u-btni.u-btni-add').addEventListener('click', (e) => { e.stopPropagation(); document.querySelectorAll('#song-list-pre-cache tbody tr').forEach((item) => { if (! item.classList.contains('js-dis')) { item.querySelector('.icn-add').click(); } }); }); } if (document.querySelector('.u-btn2.u-btn2-2.u-btni-addply')) { document.querySelector('.u-btn2.u-btn2-2.u-btni-addply').addEventListener('click', () => { if (document.querySelector('.u-btni.u-btni-add')) { document.querySelector('.u-btni.u-btni-add').click(); } }); } main_Cloud_Music(playlist_id, playlist_obj, () => { if (document.querySelector('.m-playlist-see-more')) { let show_module = document.querySelector('.m-playlist-see-more'); show_module.parentNode.removeChild(show_module); } }); } else { console.warn('Playlist cheating. code:', playlist_obj.code); } } else { if (show_text) { show_text.textContent = '返回的歌单信息状态码异常。code: ' + res.status + ' readyState: ' + res.readyState; } console.warn('返回的歌单信息状态码异常。code: ' + res.status + ' readyState: ' + res.readyState); } }, 'onerror': function() { if (show_text) { show_text.textContent = '获取歌单信息失败了!可能是网络不佳或者 API 失效了。'; } console.error('获取歌单信息失败了!\n可能是网络不佳或者 API 失效了。'); } }; GM_xmlhttpRequest(details); } } } } init_Cloud_Music(); })();