网易云音乐列表导出

导出当前页网易云音乐列表为文本

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==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 result = '';
                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(/&nbsp;/g, " ").replace(/&amp;/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(/&nbsp;/g, " ").replace(/&amp;/g, "&");
                    let album = cells[4].getElementsByTagName('a')[0].getAttribute('title').replace(/<div class="soil">[\s\S\n]*?<\/div>/g, "").replace(/&nbsp;/g, " ").replace(/&amp;/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 "歌名":
                                result += tempSplit() + name;
                                break;
                            case "歌手":
                                if(check2.checked){
                                    result += tempSplit() + artist;
                                }
                                break;
                            case "专辑":
                                if(check3.checked){
                                    result += tempSplit() + album;
                                }
                                break;
                            case "时长":
                                if(check4.checked){
                                    result += tempSplit() + time;
                                }
                                break;
                            case "链接":
                                if(check5.checked){
                                    result += tempSplit() + link;
                                }
                                break;
                        }
                    })
                    result += '\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(result);
                //输出到剪贴板
                trigger.setAttribute('aria-label', result);
                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 '+';
    };
})();