导出当前页网易云音乐列表为文本
// ==UserScript== // @name 网易云音乐列表导出 // @namespace undefined // @version 0.0.4 // @description 导出当前页网易云音乐列表为文本 // @author allen smith // @match *://music.163.com/* // @require https://cdn.bootcss.com/clipboard.js/1.7.1/clipboard.js // @require https://cdn.bootcdn.net/ajax/libs/Sortable/1.15.0/Sortable.min.js // @run-at document-end // @grant none // ==/UserScript== (function () { 'use strict'; // 检测页面 let htm = document.getElementsByClassName('f-oh'); if(htm.length === 0){ return; } // 创建dom节点 function createDocument(txt) { const template = `<div class='childdom'>${txt}</div>`; let doc = new DOMParser().parseFromString(template, 'text/html'); let div = doc.querySelector('.childdom'); return div; } // 检测文档变动 let doc = document.getElementById('g_mymusic'); let _body = document.body; let clipboard, btn, spli, interId, waitTimeoutId, wait ; let ckdiv; let check1, check2, check3, check4, check5; let sortdiv; doc.addEventListener('DOMSubtreeModified', function () { //查找列表动画 wait = document.getElementById('wait-animation'); if(wait) _body.removeChild(wait); wait = document.createElement("span"); wait.id = 'wait-animation'; wait.setAttribute('style', 'display:inline-block;position:absolute;right:50px;top:100px;padding:3px 5px;border:1px solid lightgray;background-color:white;color:black;border-radius:5px;font-size:14px;'); _body.appendChild(wait); wait.innerHTML = '导出:没有合适的列表'; //检测列表 let list = document.getElementsByClassName('m-table')[0]; if (!list) { btn = document.getElementById('export-btn'); spli = document.getElementById('export-spli'); if(btn) _body.removeChild(btn); if(spli) _body.removeChild(spli); return; } _body.removeChild(wait); //创建按钮 btn = null; spli = null; btn = document.getElementById('export-btn'); spli = document.getElementById('export-spli'); if (!spli) { spli = document.createElement("input"); spli.id = 'export-spli'; spli.className = 'export-spli'; spli.setAttribute('placeholder','自定义分隔符(默认 -- )'); spli.setAttribute('style', 'display:inline-block;position:absolute;right:50px;top:100px;padding:3px 5px;border:1px solid lightgray;background-color:white;color:black;border-radius:5px;font-size:14px;'); _body.appendChild(spli); } if (!btn) { btn = document.createElement("button"); btn.id = 'export-btn'; btn.className = 'export-btn'; btn.innerText = '导出列表'; btn.setAttribute('style', 'display:inline-block;position:absolute;right:50px;top:229px;padding:3px 5px;border:1px solid lightgray;background-color:white;color:black;border-radius:5px;font-size:14px;'); _body.appendChild(btn); } // 选择列 if(!ckdiv){ ckdiv = document.createElement("div"); ckdiv.id = 'ckdiv'; ckdiv.className = 'export-ck'; ckdiv.setAttribute('style', 'display:inline-block;position:absolute;right:50px;top:128px;padding:3px 5px;border:1px solid lightgray;background-color:white;color:black;border-radius:5px;font-size:14px;'); _body.appendChild(ckdiv); } // 排序 if(!sortdiv){ // sortdiv = document.createElement("div"); // sortdiv.id = 'sortdiv'; // sortdiv.className = 'sortdiv'; // sortdiv.setAttribute('style', 'display:inline-block;position:absolute;right:50px;top:156px;padding:3px 5px;border:1px solid lightgray;background-color:white;color:black;border-radius:5px;font-size:14px;'); let divstr = `<div id="sortdivbox" style="display:inline-block;position:absolute;right:50px;top:159px;padding:3px 5px;border:1px solid lightgray;background-color:white;color:black;border-radius:5px;font-size:14px;"><div>拖动以排序</div><div id="sortdiv" style="margin:10px 0px;cursor:pointer;"><span style="margin:0 4px;padding:4px 8px;border-radius:3px;border:1px solid lightgray">歌名</span><span style="margin:0 4px;padding:4px 8px;border-radius:3px;border:1px solid lightgray">歌手</span><span style="margin:0 4px;padding:4px 8px;border-radius:3px;border:1px solid lightgray">专辑</span><span style="margin:0 4px;padding:4px 8px;border-radius:3px;border:1px solid lightgray">时长</span><span style="margin:0 4px;padding:4px 8px;border-radius:3px;border:1px solid lightgray">链接</span></div></div>` _body.appendChild(createDocument(divstr)); sortdiv = new Sortable(document.querySelector('#sortdiv')) } let ckbuilder = function(id, label, uncheck, readonly){ let tmpid = 'ck_' + id; let ckbox = document.createElement("input"); ckbox.id = tmpid ckbox.setAttribute('type', 'checkbox'); ckbox.setAttribute('style', 'vertical-align: middle;margin-top: -2px;'); if(!uncheck) ckbox.checked = true; if(!!readonly) ckbox.setAttribute("disabled", "disabled"); ckdiv.appendChild(ckbox); let ckspn = document.createElement("label"); ckspn.setAttribute('for', tmpid); ckspn.innerHTML = ' ' + label; ckdiv.appendChild(ckspn); return ckbox; } if(!check1){ check1 = ckbuilder("ck01","歌名 ", false, true); } if(!check2){ check2 = ckbuilder("ck02","歌手 "); } if(!check3){ check3 = ckbuilder("ck03","专辑 ", true); } if(!check4){ check4 = ckbuilder("ck04","时长 ", true); } if(!check5){ check5 = ckbuilder("ck05","链接", true); } //创建剪贴板 if (clipboard) clipboard.destroy(); clipboard = new Clipboard('.export-btn', { text: function (trigger) { //导出列表 btn.innerText = '正在导出 ...'; let r###lt = ''; let listBody = list.getElementsByTagName('tbody')[0]; let rows = listBody.getElementsByTagName('tr'); for (let i = 0; i < rows.length; i++) { let ele = rows[i]; let cells = ele.getElementsByTagName('td'); let name = cells[1].getElementsByTagName('b')[0].getAttribute('title').replace(/<div class="soil">[\s\S\n]*?<\/div>/g, "").replace(/ /g, " ").replace(/&/g, "&"); let link = `https://music.163.com/#${cells[1].getElementsByTagName('a')[0].getAttribute('href')}` let time = cells[2].querySelector('.u-dur').innerText; let artist = cells[3].getElementsByTagName('span')[0].getAttribute('title').replace(/<div class="soil">[\s\S\n]*?<\/div>/g, "").replace(/ /g, " ").replace(/&/g, "&"); let album = cells[4].getElementsByTagName('a')[0].getAttribute('title').replace(/<div class="soil">[\s\S\n]*?<\/div>/g, "").replace(/ /g, " ").replace(/&/g, "&"); let spliChar = spli.value; if(!spliChar) spliChar = ' -- '; let isFirst = true; document.querySelectorAll('#sortdiv span').forEach(item=>{ let type = item.innerText; let tempSplit; if(isFirst){ tempSplit = ()=> {isFirst = false; return "";} }else { tempSplit = ()=> spliChar; } switch(type){ case "歌名": r###lt += tempSplit() + name; break; case "歌手": if(check2.checked){ r###lt += tempSplit() + artist; } break; case "专辑": if(check3.checked){ r###lt += tempSplit() + album; } break; case "时长": if(check4.checked){ r###lt += tempSplit() + time; } break; case "链接": if(check5.checked){ r###lt += tempSplit() + link; } break; } }) r###lt += '\r\n'; } //提示动画 btn.innerText = '已复制到剪贴板 ='; let count = 6; clearInterval(interId); interId = setInterval(function () { count--; if (count > 0){ btn.innerText = '已复制到剪贴板 ' + waitAnimationChar(count); } else{ btn.innerText = '导出列表'; clearInterval(interId); } }, 300); //输出到控制台 console.log(r###lt); //输出到剪贴板 trigger.setAttribute('aria-label', r###lt); return trigger.getAttribute('aria-label'); } }); }); //字符动画 let waitAnimationChar = function(n){ let temp = n % 3; if(temp === 0) return '#'; else if(temp == 1) return '$'; else if(temp == 2) return '+'; }; })();