Greasy Fork

来自缓存

Greasy Fork is available in English.

Picking Songs in iirose

Support music.163.com and Xiami.com now!

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Picking Songs in iirose
// @namespace    http://tampermonkey.net/
// @version      3.0
// @description  Support music.163.com and Xiami.com now!
// @author       Keane
// @match        https://iirose.com/messages.html
// @match        https://emumo.xiami.com/radio/play/*
// @match        https://www.xiami.com/*
// @match        https://music.163.com/
// @grant       GM.setValue
// @grant       GM.getValue
// ==/UserScript==


(function() {
    'use strict';

    //get url of current page
    var url = window.location.href;
    GM.setValue("song", -5);//default to be -5 means null
    var autoPicking = true;
    var XMPicking = true;
    var WYPicking = true;
    //save a shuffled song list and current pointer
    var shuffledSongList = [];
    var shufflePointer = 0;

    var WYMutationNode;
    var WYConfig = {attributes: true, childList: true, subtree: true};
    var WYCurrentURL = "";
    //mutation observer callback function
    const WYcallback = function(mutationsList, observer) {
        // Use traditional 'for loops' for IE 11
        for(let mutation of mutationsList) {
            //console.log("網易音乐切换了");
            if (mutation.type === 'childList') {
                //console.log('The child attribute was modified.');
                if(WYCurrentURL != document.getElementsByClassName("f-thide name fc1 f-fl")[0].getAttribute("href")){
                    WYCurrentURL = document.getElementsByClassName("f-thide name fc1 f-fl")[0].getAttribute("href");
                    console.log('The new song URL is '+WYCurrentURL);
                    SendMessage(WYMusicParser(WYCurrentURL));
                }
            }
        }
    };
    const WYobserver = new MutationObserver(WYcallback);


    //for xiami radio page
    if (url.search("xiami.com/radio")>=0){
        var timerXiami = setInterval(function(){

            if(document.getElementsByClassName("artist_info fl")[0]!=undefined){
                clearInterval(timerXiami);

                xiami_old();
            }
        }, 1000);
    }
    //for iirose
    else if (url.search("iirose.com")>=0){
        iirose();
    }
    //for xiami new view
    else if (url.search("xiami.com")>=0){
        xiami_new();
    }
    //for 163 music
    else if (url.search("music.163.com/")>=0){
        console.log(document.getElementsByClassName("f-thide name fc1 f-fl")[0].innerHTML);
        WYMusic();

    }
    else {
        console.log("Failed to match the website!");
    }

    //a quick shuffle algorithm
    function shuffleArray(array) {
        for (let i = array.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [array[i], array[j]] = [array[j], array[i]];
        }
    }
    //a simple sleep function
    function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    //xiami Collection starts
    function xiamiCollection(){
        //generate a button

        console.log("51");

        var parentDiv = document.getElementById("element_r");
        var newNode = document.createElement ('div');
        newNode.innerHTML='<form style="font-size:16px">'
            +'<br><br>给蔷薇花园点歌!<br><br>'
            +'从:<input type="number" name="startNum" max="50" style="border: 2px solid red;font-size: 16px;"> <br><br>到:<input type="number" name="endNum" style="border: 2px solid red;font-size: 16px;"><br><br>'
            +'点:<input type="number" name="pickNum" min="1" max="10" style="border: 2px solid red;font-size: 16px;"> 首<br><br>'
            +'<input type="checkbox" name="random" value="random" style="border: 2px solid red;font-size: 16px;">   随机播放<br><br>'
            +'<input id="pick!" type="button" style="background-color: #4CAF50;font-size: 16px;text-align:center;" value="  点歌! "> <br><br>'
            +'<input id="pickFive!" type="button" style="background-color: #4CAF50;font-size: 16px;text-align:center;" value="  点五首歌! "> </form>';
        parentDiv.appendChild (newNode);
        document.getElementById("pick!").addEventListener("click", pickCollection);
        document.getElementById("pickFive!").addEventListener("click", pickCollectionFive);
        /*
            <form>
            从:
            <input type="number" name="startNum" min="1" max="5">
            到:
            <input type="number" name="endNum" min="1" max="5">
            <br>
            点
            <input type="number" name="pickNum" min="1" max="5">
            首
            <br>
            <input type="checkbox" name="random" value="random"> 随机播放<br>
            <input type="submit">
            </form>
            */

    }
    async function pickCollection(){
        //for xiami collection        
        var songList = getSongList();
        console.log("song size is "+songList.length);
        var pickList = [];
        var startP = document.getElementsByName("startNum")[0].value;
        var endP = document.getElementsByName("endNum")[0].value;
        var range = document.getElementsByName("pickNum")[0].value;
        var random = document.getElementsByName("random")[0].checked;
        console.log("new89"+startP+endP+range+random);
        if (isNaN(startP)){ startP=0;
                          }
        if (isNaN(endP)){ endP=50;
                        }
        if (isNaN(range)){ range=5;
                         }
        startP = parseInt(startP);endP = parseInt(endP);range = parseInt(range);
        if (range>endP-startP){startP=1;endP=50;
                              }
        pickList = songList.slice(startP, endP);

        if (random){
            shuffleArray(pickList);
        }

        var song;
        var count = 1;
        await sleep(2000);
        for (song of pickList){
            if (count>range){break;}
            song.replace( /\s\s+/g, ' ' );
            GM.setValue("song", song);
            console.log("sended "+song);
            count += 1;
            await sleep(2000);
        }

    }
    async function pickCollectionFive(){
        //for xiami collection
        if (shuffledSongList.length==0){
            shuffledSongList = getSongList();
            shuffleArray(shuffledSongList);
        }

        console.log("song size is "+shuffledSongList.length);
        var pickList = [];
        var range = 5;
        console.log("ShufflePointer (before):"+shufflePointer);
        if (shufflePointer+range+1>shuffledSongList.length){
            pickList=shuffledSongList.slice(shufflePointer).concat(shuffledSongList.slice(0, shufflePointer+range-shuffledSongList.length));
            shufflePointer=shufflePointer+range-shuffledSongList.length;
        }
        else {
            pickList = shuffledSongList.slice(shufflePointer, shufflePointer+range);
            shufflePointer=shufflePointer+range;
        }
        console.log("ShufflePointer (after):"+shufflePointer);

        var song;
        var count = 1;
        await sleep(2000);
        for (song of pickList){
            song.replace( /\s\s+/g, ' ' );
            GM.setValue("song", song);
            console.log("sended "+song);

            await sleep(2000);
        }


    }
    function getSongList(){
        var list = document.getElementsByClassName("song_name");
        var listSize = list.length;
        var tempNode;
        var songList = [];
        for (tempNode of list){
            var songNameList=tempNode.innerText.split("-—")[0].split(" "); // like ["Return", "Of", "The", "Mack", "(...", ""]
            var tempSoneNameNode;
            var songName="";
            for (tempSoneNameNode of songNameList){
                if (tempSoneNameNode.search(/\.\.\./)>=0){
                    //console.log("99"+tempSoneNameNode);
                    break;
                }
                tempSoneNameNode=tempSoneNameNode.replace('(','').replace(')','');
                songName += tempSoneNameNode;
                songName += ' ';
            }
            var artisitList=tempNode.innerText.split("-—")[1].split(";");//like [" Dale Castell", "Tamia"]
            var lastWord = artisitList[artisitList.length-1].split(' ').slice(-1)[0];
            if (lastWord=='MV'){
                //console.log('before: '+artisitList);
                artisitList[artisitList.length-1]=artisitList[artisitList.length-1].split(' ').slice(0,-1).join(' ');
                //console.log('after: '+artisitList);
            }
            var artisitName=artisitList.join(' ');
            songList.push(songName+'|'+artisitName);
            //console.log(songName+'|'+artisitName);
        }
        return songList;
    }


    //163 music starts here
    function WYMusic(){
        WYMutationNode = document.getElementsByClassName("j-flag words")[0];
        WYCurrentURL = document.getElementsByClassName("f-thide name fc1 f-fl")[0].getAttribute("href");
        WYobserver.observe(WYMutationNode, WYConfig);
        console.log("observer starts");
    }

    function WYMusicParser(url){
        var songID = url.split("=")[1];
        var msgString = "WY|"+songID;
        return msgString;
    }

    //xiami music starts here
    function xiami_old(){
        //send first message to iirose

        xiamiInfoParser(false);

        //an api that can be used to monitor changes in the webpage
        var mutationObserver = new MutationObserver(function(mutations) {
            mutations.forEach(function(mutation) {
                //console.log(mutation);

                //send message whenever it observers a change
                xiamiInfoParser(false);

            });
        });

        //it focuses on the title of the page
        mutationObserver.observe(document.querySelector('title'), {
            attributes: true,
            characterData: true,
            childList: true,
            subtree: true,
            attributeOldValue: true,
            characterDataOldValue: true
        });


    }
    function xiami_new(){
        sleep(200);
        //send first message to iirose, or not
        //xiamiSendMessage(xiamiInfoParser(false));
        addXMLRequestCallback( function( xhr ) {
            //check if is getPlayInfo request
            if (xhr.__sufei_url.search("getPlayInfo")>-1){
                var songID = xhr.__sufei_url.split('[')[1].split(']')[0];
                console.log("the new song's ID is "+songID.toString());
                xiamiInfoParser(true, songID);
            }
        });

    }
    //add a hook to XML requests
    function addXMLRequestCallback(callback){
        var oldSend, i;
        if( XMLHttpRequest.callbacks ) {
            // we've already overridden send() so just add the callback
            XMLHttpRequest.callbacks.push( callback );
        } else {
            // create a callback queue
            XMLHttpRequest.callbacks = [callback];
            // store the native send()
            oldSend = XMLHttpRequest.prototype.send;
            // override the native send()
            XMLHttpRequest.prototype.send = function(){
                // process the callback queue
                // the xhr instance is passed into each callback but seems pretty useless
                // you can't tell what its destination is or call abort() without an error
                // so only really good for logging that a request has happened
                // I could be wrong, I hope so...
                // EDIT: I suppose you could override the onreadystatechange handler though
                for( i = 0; i < XMLHttpRequest.callbacks.length; i++ ) {
                    XMLHttpRequest.callbacks[i]( this );
                }
                // call the native send()
                oldSend.apply(this, arguments);
            }
        }
    }
    //get music info to send to iirose
    function xiamiInfoParser(isnew, songID=""){
        if(isnew){
            console.log("sending " + songID.toString());
            SendMessage("xm|"+songID);
        }
        else{
            var timerXiamiMessage = setInterval(function () {
                //this timer waits for the page to load every 0.1s
                //if the artist info is loaded we assume the page finished loading cuz that's what we need.
                if(document.getElementsByClassName("artist_info fl")[0]!=null){
                    clearInterval(timerXiamiMessage);

                    //get song name and artist name
                    var songName = document.title.split("——")[0];
                    var artistName = document.getElementsByClassName("artist_info fl")[0].getElementsByTagName("strong")[0].innerHTML;
                    var message = songName+"|"+artistName;

                    SendMessage( message);

                    //set the "song" value with the above info

                }
            }, 100);}
    }

    //send info to iirose
    function SendMessage(msg){
        GM.setValue("song", msg);
        console.log("sended "+msg);

    }

    //play with iirose
    async function iirose(){
        //this timer checks if the window has loaded. Do checking every 3 seconds.
        createBtns();
        if (autoPicking){
            var timer = setInterval(function () {
                if(document.getElementById("moveinput")!=null){
                    clearInterval(timer);

                    //current song info
                    var tempSong=-5;

                    //this timer checks if there is a new message from xiami
                    var pickTimer = setInterval(async function () {

                        //get value from xiami. If not changed, do nothing and wait
                        var realSong = await GM.getValue("song", -5);
                        if(realSong!=tempSong){

                            //changed! pick the real song here
                            console.log("successfully recieve message "+realSong);
                            await pickingSong(realSong);

                            //update tempSong
                            tempSong = realSong;
                        }


                        //console.log("one more loop in iirose");
                    }, 500);
                }

            }, 3000);
        }
        return;
    }

    //pick a song with the sring
    //pick with songID
    function XMDirectPicking(url) {
        var t = url.trim();
        if (t) {
            var o = t.match(Variable.regexp.assets.getLink);
            o ? ("[" == t[0] && (o[0] = t.replace(Variable.regexp.pregmedia.linkSpaceAround2, "$1")),
                 Utils.service.moveinputDo("<> " + o[0])) : "#" == t[0] ? Utils.service.moveinputDo(t) : (-1 < Constant.Shortcuts.all.indexOf("@" + t) && (t += " "),
                                                                                                          Utils.service.moveinputDo("@" + (" " == e[0] ? " " : "") + t))
        }
    }
    function WYDirectPicking(url){
        var t = url.trim();
        if (t) {
            var o = t.match(Variable.regexp.assets.getLink);
            o ? ("[" == t[0] && (o[0] = t.replace(Variable.regexp.pregmedia.linkSpaceAround2, "$1")),
                 Utils.service.moveinputDo("<> " + o[0])) : "#" == t[0] ? Utils.service.moveinputDo(t) : (-1 < Constant.Shortcuts.all.indexOf("@" + t) && (t += " "),
                                                                                                          Utils.service.moveinputDo("@" + (" " == e[0] ? " " : "") + t))
        }
    }
    //pick with song name & artisit name (old version)
    function pickingSong(songInfo){
        if (songInfo=='-5') return;
        var inputArray = songInfo.split("|");

        if(!isNaN(inputArray[1])){
            if (inputArray[0]=='xm'){
                if (!XMPicking){console.log("虾米点歌功能已关闭");return;}
                console.log('recieved Xiami songID '+inputArray[1]);
                var url = "https://www.xiami.com/song/"+inputArray[1].toString();
                XMDirectPicking(url);
            }
            else if (inputArray[0]=='WY'){
                if (!WYPicking){console.log("网易云点歌功能已关闭");return;}
                console.log('recieved 163 songID '+inputArray[1]);
                url = "https://music.163.com/#/song?id="+inputArray[1].toString();
                WYDirectPicking(url);
            }
        }
        else{
            var str = songInfo.replace("|"," ");
            inputString("@"+str);

            //this timer checks whether the search results have loaded
            var timer2 = setInterval(function () {

                //if find nothing OR have found some songs, end the timer
                if((document.getElementsByClassName("emptyShow")[0]!=null)||(document.getElementsByClassName("demandHolderPlayBtn")[0]!=null)){

                    //if find something
                    if(document.getElementsByClassName("emptyShow")[0]==null){
                        var songList = document.getElementsByClassName("demandHolderPlayBtn");
                        //console.log(songList[0]);


                        if(songList[0].getElementsByClassName("mainColor")[0].getElementsByClassName("buttonText")[0]!=null){
                            clearInterval(timer2);
                            //if successfully pick a song
                            var flag = 0;

                            //loop until one button can be clicked
                            for (var i = 0; i < songList.length; i++) {

                                var node = null;
                                for (var j = 0; j < songList[i].childNodes.length; j++) {
                                    if (songList[i].childNodes[j].className == "mainColor") {
                                        node = songList[i].childNodes[j];
                                        break;
                                    }
                                }

                                //check if clickable
                                if (node.hasAttribute("onclick")){
                                    node.click();
                                    console.log("pick "+i);
                                    flag=1;
                                    break;
                                }
                                console.log("cannot pick "+i);
                            }

                            //no button was clicked. Go back
                            if (flag==0){
                                //click return
                                console.log("failed");
                                //document.getElementsByClassName("footerItemBgShape_pointer")[0].onclick.apply();
                                Objs.demandHolder.function.event.call(this,0);
                                inputString("点歌失败,因为没有 "+str+" 的版权。");
                            }
                        }
                    }
                    //if find nothing
                    else {

                        //这里有bug!!
                        clearInterval(timer2);
                        Objs.demandHolder.function.event.call(this,0);
                        //document.getElementsByClassName("footerItemBgShape_pointer")[0].onclick.apply();
                        var strList=songInfo.split("|");
                        if (strList.length>1){
                            inputString("点歌失败,因为搜索不到 "+str+"。尝试模糊搜索 "+strList[0]);
                            setTimeout(function(){pickingSong(strList[0]);}, 1000)
                        }
                        else{
                            inputString("模糊搜索也失败了。");
                            //location.reload();
                        }

                    }





                }
                //
            }, 800);

            //var newSize = songlist.length;//for future use
        }

    }

    //some tools
    //create a set of buttons in menu
    function createBtns(){
        var headerDiv;
        if (!document.getElementById("customHeader")) {
            var heziDiv = document.getElementsByClassName("functionButton functionButtonGroup")[7];
            headerDiv = document.getElementsByClassName("functionButton functionButtonGroup")[7].cloneNode(true);
            headerDiv.children[0].className = "functionBtnIcon mdi-lightbulb-on";
            headerDiv.children[1].innerHTML = "自定义";
            headerDiv.id = "customHeader";
            heziDiv.parentNode.insertBefore(headerDiv, heziDiv);
        }
        headerDiv = document.getElementById("customHeader");
        var btnHolderDiv;
        if (!document.getElementById("customBox")) {
            btnHolderDiv = document.createElement("div");
            btnHolderDiv.id = "customBox";
            btnHolderDiv.className = "functionItemBox";
            headerDiv.parentNode.insertBefore(btnHolderDiv, headerDiv.nextSibling);
        }
        btnHolderDiv = document.getElementById("customBox");

        var XnewNodeSpan0 = document.createElement("span");
        var XnewNodeSpan1 = document.createElement("span");
        var XnewNodeDiv = document.createElement("div");
        var WnewNodeSpan0 = document.createElement("span");
        var WnewNodeSpan1 = document.createElement("span");
        var WnewNodeDiv = document.createElement("div");
        var style = document.createElement('style');

        XnewNodeSpan0.className = "functionBtnIcon mdi-music";
        XnewNodeSpan0.id = "xiami-music";
        XnewNodeSpan1.className = "functionBtnFont";
        XnewNodeSpan1.id = "XiamiText";
        XnewNodeSpan1.innerHTML = " 虾米自动点歌    : 开启";
        XnewNodeDiv.className = "functionButton";
        XnewNodeDiv.id = "XiamiBtn";
        XnewNodeDiv.onclick = function(){togglePicking("xiami")};
        XnewNodeDiv.append(XnewNodeSpan0);
        XnewNodeDiv.append(XnewNodeSpan1);
        btnHolderDiv.append(XnewNodeDiv);

        WnewNodeSpan0.className = "functionBtnIcon mdi-music";
        WnewNodeSpan0.id = "wangyi-music";
        WnewNodeSpan1.className = "functionBtnFont";
        WnewNodeSpan1.id = "WangyiText";
        WnewNodeSpan1.innerHTML = "网易云自动点歌: 开启";
        WnewNodeDiv.className = "functionButton";
        WnewNodeDiv.id = "WangyiBtn";
        WnewNodeDiv.onclick = function(){togglePicking("wangyi")};
        WnewNodeDiv.append(WnewNodeSpan0);
        WnewNodeDiv.append(WnewNodeSpan1);
        btnHolderDiv.append(WnewNodeDiv);

    }
    function togglePicking(website){
        if (website=='xiami'){
            var Xnode = document.getElementById("xiami-music");
            if (XMPicking) {
                Xnode.className = "functionBtnIcon mdi-music-off";
                document.getElementById("XiamiText").innerHTML = " 虾米自动点歌    : 关闭";
                _alert("虾米自动点歌已暂停");
            }
            else {
                Xnode.className = "functionBtnIcon mdi-music";
                document.getElementById("XiamiText").innerHTML = " 虾米自动点歌    : 开启";
                _alert("虾米自动点歌已开始");
            }
            XMPicking = !XMPicking;

        }
        else if (website=='wangyi'){
            var Wnode = document.getElementById("wangyi-music");
            if (WYPicking) {
                Wnode.className = "functionBtnIcon mdi-music-off";
                document.getElementById("WangyiText").innerHTML = "网易云自动点歌: 关闭";
                _alert("网易云自动点歌已暂停");
            }
            else {
                Wnode.className = "functionBtnIcon mdi-music";
                document.getElementById("WangyiText").innerHTML = "网易云自动点歌: 开启";
                _alert("网易云自动点歌已开始");
                 }
            WYPicking = !WYPicking;
        }
        else {
            _alert("Error: Invalid Input.");
        }

    }
    //this method types and submit a string in the typearea
    function inputString(str){
        /*
        var inputBox = document.getElementById("moveinput");
        var originText = inputBox.value;
        var submit = document.getElementsByClassName("moveinputSendBtn")[0];
        inputBox.value = str;
        submit.click();
        inputBox.value = originText;
        */
        Utils.service.moveinputDo(str);
    }

    //this method add a script to html so that u can use the script in console
    function addScript(scriptText){
        var scriptElem = document.createElement('script');
        scriptElem.innerHTML = scriptText;
        document.body.appendChild(scriptElem);
    }

    // Your code here...
})();