// ==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 // @downloadURL https://update.greasyfork.icu/scripts/403335/Picking%20Songs%20in%20iirose.user.js // @updateURL https://update.greasyfork.icu/scripts/403335/Picking%20Songs%20in%20iirose.meta.js // ==/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='
'; parentDiv.appendChild (newNode); document.getElementById("pick!").addEventListener("click", pickCollection); document.getElementById("pickFive!").addEventListener("click", pickCollectionFive); /* */ } 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... })();