// ==UserScript== // @name Picking Songs With Xiami in iirose.com // @namespace http://tampermonkey.net/ // @version 2.0 // @description open xiami.com and iirose.com at the same time. Play any song with xiami and it will pushed automatically to iirose.com. Just mute one of them. 使用方法:同时打开虾米Xiami.com和iirose.com,使用虾米收听的任何歌曲都会同步推送至iirose。 // @author KeaneW // @match https://iirose.com/messages.html // @match https://emumo.xiami.com/radio/play/* // @match https://www.xiami.com/* // @grant GM.setValue // @grant GM.getValue // @downloadURL none // ==/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; //save a shuffled song list and current pointer var shuffledSongList = []; var shufflePointer = 0; //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(); } else if (url.search("xiami.com")>=0){ xiami_new(); } 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]]; } } //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='
' +'

给蔷薇花园点歌!

' +'从:

到:

' +'点:

' +' 随机播放

' +'

' +'
'; parentDiv.appendChild (newNode); document.getElementById("pick!").addEventListener("click", pickCollection); document.getElementById("pickFive!").addEventListener("click", pickCollectionFive); /*
从: 到:

随机播放
*/ } // async function pickCollection(){ //for xiami collection console.log("84"); 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; } //play with xiami 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); } }); } 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); } } } function xiamiInfoParser(isnew, songID=""){ if(isnew){ console.log("sending " + songID.toString()); xiamiSendMessage(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; xiamiSendMessage( message); //set the "song" value with the above info } }, 100);} } //collect and send info to iirose function xiamiSendMessage(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. 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); } //add entryIirose() to console /*var scriptText='function entryIirose(str){ if(str.length>14){console.log("智障吗,搞那么长?");str="艰苦奋斗严肃活泼";} var rainbow=["C30002", "C30040", "C3007D", "C300BB", "8D00C3", "4F00C3", "1200C3", "002AC3", "0068C3", "00A5C3", "00C3A2", "00C365", "00C327", "15C300", "52C300", "90C300", "C3B800", "C37A00", "C33D00", "C30000", "C30022", "C30060", "C3009D", "AA00C3", "6D00C3", "2F00C3", "000DC3", "004AC3", "0088C3", "00C3C0", "00C382", "00C345", "00C307", "35C300", "72C300", "B0C300", "C39800", "C35A00", "C31D00", "C3001F"];var offset=Math.floor(Math.random()*rainbow.length);var text=str.split("");for(var i=0;i " + o[0])) : "#" == t[0] ? Utils.service.moveinputDo(t) : (-1 < Constant.Shortcuts.all.indexOf("@" + t) && (t += " "), Utils.service.moveinputDo("@" + (" " == e[0] ? " " : "") + t)) } } function pickingSong(songInfo){ if (songInfo=='-5') return; if(!isNaN(songInfo)){ console.log('recieved songID '+songInfo); var url = "https://www.xiami.com/song/"+songInfo.toString(); DirectPicking(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 //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); } //show a rainbow when enter a room. Very annoying! //expired /* async function entryIirose(str){ if(str !=null){GM.setValue("entry",str);} str = await GM.getValue("entry", "我踩着七彩祥云来了~") if(str.length>13){ console.log("智障吗,搞那么长?"); str="本人专属跑马灯入场"; GM.setValue("entry",str); } var rainbow = ["C30002", "C30040", "C3007D", "C300BB", "8D00C3", "4F00C3", "1200C3", "002AC3", "0068C3", "00A5C3", "00C3A2", "00C365", "00C327", "15C300", "52C300", "90C300", "C3B800", "C37A00", "C33D00", "C30000", "C30022", "C30060", "C3009D", "AA00C3", "6D00C3", "2F00C3", "000DC3", "004AC3", "0088C3", "00C3C0", "00C382", "00C345", "00C307", "35C300", "72C300", "B0C300", "C39800", "C35A00", "C31D00", "C3001F"]; // var rainbow = ["00ABE5", "0063E5", "001CE6", "2C00E7", "7400E8", "BE00E9", "EA00CC", "EA0083", "EB003A", "EC0F00", "ED5900", "EEA400", "EEEF00", "A4EF00", "5AF000", "0EF100", "00F23C", "00F389", "00F4D5", "00C7F5","007DF5", "0033F5", "1600F5", "6000F5", "AA00F5", "F400F5", "F500AB", "F50060", "F50016", "F53300", "F57D00", "F5C700", "D8F500", "8DF500", "43F500", "00F506", "00F550", "00F59A", "00F5E4", "00BBF5"]; var offset = Math.floor(Math.random() * rainbow.length); var text = str.split(""); for (var i=0;i