您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
导出当前页网易云音乐列表为CSV文件
当前为
// ==UserScript== // @name 网易云音乐列表导出为CSV文件 // @name:en Export NetEase Cloud Music List to CSV File // @namespace undefined // @version 0.0.5.1 // @description 导出当前页网易云音乐列表为CSV文件 // @description:en Export the current page of NetEase cloud music list as a CSV file // @author allen smith, aspen138 // @match *://music.163.com/* // @license MIT // @icon https://s1.music.126.net/style/favicon.ico // @require https://update.greasyfork.org/scripts/27254/174357/clipboardjs.js // @require https://update.greasyfork.org/scripts/482500/1297545/Sortable%20JS.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; console.log("doc=", doc); function DOMSubtreeModifiedEventHandler() { console.log("DOMSubtreeModified event trigged."); //查找列表动画 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 = '导出:没有合适的列表'; //检测列表 console.log("find m-table elements", document.getElementsByClassName('m-table')); let list = document.getElementsByClassName('m-table')[0]; console.log("if clause before, list=", list); if (!list) { btn = document.getElementById('export-btn'); spli = document.getElementById('export-spli'); if (btn) _body.removeChild(btn); if (spli) _body.removeChild(spli); return; } console.log("if clause after, list=", list); _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(); // Example JavaScript with Clipboard.js and CSV download functionality clipboard = new Clipboard('.export-btn', { text: function (trigger) { // 导出列表 btn.innerText = '正在导出 ...'; let result = ''; let csvContent = ''; // Initialize CSV content let listBody = list.getElementsByTagName('tbody')[0]; let rows = listBody.getElementsByTagName('tr'); // Initialize CSV headers based on selected fields let headers = []; document.querySelectorAll('#sortdiv span').forEach(item => { let type = item.innerText; switch (type) { case "歌名": headers.push('歌名'); break; case "歌手": if (check2.checked) headers.push('歌手'); break; case "专辑": if (check3.checked) headers.push('专辑'); break; case "时长": if (check4.checked) headers.push('时长'); break; case "链接": if (check5.checked) headers.push('链接'); break; } }); csvContent += headers.join(',') + '\r\n'; // Add headers to CSV 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; let row = []; document.querySelectorAll('#sortdiv span').forEach(item => { let type = item.innerText; let tempSplit; if (isFirst) { tempSplit = () => { isFirst = false; return ""; } } else { tempSplit = () => spliChar; } switch (type) { case "歌名": row.push(`"${name}"`); // Enclose in quotes to handle commas break; case "歌手": if (check2.checked) { row.push(`"${artist}"`); } break; case "专辑": if (check3.checked) { row.push(`"${album}"`); } break; case "时长": if (check4.checked) { row.push(`"${time}"`); } break; case "链接": if (check5.checked) { row.push(`"${link}"`); } break; } }); result += row.join(spliChar) + '\r\n'; // For clipboard csvContent += row.join(',') + '\r\n'; // For CSV } // 提示动画 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(result); // 输出到剪贴板 trigger.setAttribute('aria-label', result); // Store CSV content in a data attribute for later use trigger.dataset.csv = csvContent; return trigger.getAttribute('aria-label'); } }); // Listen for the successful copy event to trigger CSV download clipboard.on('success', function (e) { // Retrieve CSV content from data attribute let csvContent = e.trigger.dataset.csv; // Encode CSV content //前面加的那个uFEFF是utf-8 BOM的头,目的是把utf-8的文件变成utf-8 BOM,让微软的excel打开csv文件后不会乱码. let encodedUri = 'data:text/csv;charset=utf-8,' + '\uFEFF' +encodeURIComponent(csvContent); // Create a link to download the encoded URI let link = document.createElement("a"); link.setAttribute("href", encodedUri); let timestamp = new Date().toISOString().slice(0, 19).replace(/[:T]/g, "-"); link.setAttribute("download", `网易云音乐-export-${timestamp}.csv`); document.body.appendChild(link); // Required for Firefox link.click(); document.body.removeChild(link); console.log("CSV file has been downloaded."); }); } doc.addEventListener('DOMSubtreeModified', DOMSubtreeModifiedEventHandler); setTimeout(() => { DOMSubtreeModifiedEventHandler(); }, 3 * 1000); //字符动画 let waitAnimationChar = function (n) { let temp = n % 3; if (temp === 0) return '#'; else if (temp == 1) return '$'; else if (temp == 2) return '+'; }; })();