// ==UserScript== // @name 网易云音乐直接下载 // @namespace https://www.ocrosoft.com/ // @description 在单曲页面显示歌词、翻译、封面、歌曲下载链接并以高音质试听,同时支持歌单、专辑、等页面直接下载单曲。该脚本受 GPL V2.0 许可证保护。脚本仍在测试,如遇到错误,请反馈网址。 // @match *://music.163.com/* // @grant GM_xmlhttpRequest // @version 2.0 // @downloadURL none // ==/UserScript== /** * 修改自 https://greasyfork.org/zh-CN/scripts/10548-%E7%BD%91%E6%98%93%E4%BA%91%E9%9F%B3%E4%B9%90%E4%B8%8B%E8%BD%BD * API 源码: https://github.com/Ocrosoft/NetEase_OutChain * 此脚本开源,API开源,但请不要在未经允许的情况下在其他程序中调用此脚本中的API,在非程序调用且小流量的个人使用场景下可以使用。 **/ /** * */ (function(root) { 'use strict'; /* * @opentdoor 的跨域下载接口 */ function Downloader() { // request function FileRequest(url, progress, callback) { var req = GM_xmlhttpRequest({ method: 'GET', url: url, onprogress: function(res) { if (progress) progress(res); }, overrideMimeType: "text/plain;charset=x-user-defined", onreadystatechange: function(res) { if (res.readyState == 4) { if (res.status == 200) { var str = res.response; var ta1 = []; for (var i = 0; i < str.length; i++) { ta1[i] = str.charCodeAt(i) & 0x00ff; } var ua8 = new Uint8Array(ta1); var blob = new Blob([ua8]); callback(blob, res.status); } else { callback(null, res.status); } } } }); } //save file function SaveFile(blob, filename) { if (root.navigator.msSaveBlob) { root.navigator.msSaveBlob(blob, filename); } else { var anchor = root.document.createElement('a'); var url = root.URL.createObjectURL(blob); anchor.download = filename; anchor.href = url; var evt = root.document.createEvent("MouseEvents"); evt.initEvent("click", true, true); anchor.dispatchEvent(evt); root.URL.revokeObjectURL(url); } } //interface function FileDownload(url, filename, downloading, success, error) { FileRequest(url, downloading, function(blob, status) { if (status == 200) { SaveFile(blob, filename); if (typeof success == 'function') success(); } else { if (typeof error == 'function') error(status); } }); } this.FileDownload = FileDownload; var anthorEvents = { onprogress: function(res) { if (this.anchor.getAttribute('data-res-action') == 'downloadDirect') { if (res.lengthComputable) { this.anchor.querySelector('i').innerText = '下载:' + (res.loaded * 100 / res.total).toFixed(2) + '%'; } else { this.anchor.querySelector('i').innerText = '下载:' + anthorEvents.calcLength(res.loaded); } } else { if (res.lengthComputable) { this.anchor.innerText = '下载:' + (res.loaded * 100 / res.total).toFixed(2) + '%'; } else { this.anchor.innerText = "下载:" + anthorEvents.calcLength(res.loaded); } } }, calcLength: function(b) { b = Number(b) / 1024; if (b < 1024) { return b.toFixed(1) + "KB"; } b = b / 1024; if (b < 1024) { return b.toFixed(2) + "MB"; } b = b / 1024; return b.toFixed(3) + "GB"; }, onsuccess: function() { this.anchor.innerHTML = this.Html; this.doing = false; if (this.anchor.id == 'tmp') { this.anchor.previousElementSibling.remove(); this.anchor.remove(); } }, onerror: function() { this.anchor.innerHTML = "下载失败"; this.handler = setTimeout(function(t) { t.anchor.innerHTML = t.Html; t.doing = false; }, 2000, this); }, onAnthorClick: function(e) { e = e || event; var a = this.anchor; var ex = /([\w\s]+)(\.\w)(\?.*)?$/i.exec(a.href || ""); var name = a.download || a.title; if (ex) { if (!name && ex.length > 1) name = ex[1]; if (name && name.indexOf('.') == -1 && ex.length > 2) name += ex[2]; } if (!name || !a.href) return; e.preventDefault(); if (this.doing) return; this.doing = true; FileDownload(a.href, name, anthorEvents.onprogress.bind(this), anthorEvents.onsuccess.bind(this), anthorEvents.onerror.bind(this)); } }; //interface function BindAnthor(a) { var env = { Html: a.innerHTML, anchor: a }; a.addEventListener('click', anthorEvents.onAnthorClick.bind(env), true); } this.BindAnthor = BindAnthor; } var downloader = new Downloader(); var api = { detailUrl: function(songIds) { var tpl = (location.href.indexOf('https') == -1 ? 'http://music.ocrosoft.com/GetMusicLinkt.php?id=${songIds}': 'https://www.ocrosoft.com/outchain/GetMusicLinkt.php?id=${songIds}'); return tpl.replace('${songIds}', songIds.join(',')); }, detail: function(songIds, callback, username=null, password=null) { var script = document.createElement('script'); script.innerHTML = 'var returnMusicData;'; document.body.appendChild(script); returnMusicData = function(data) { callback(data); }; script = document.createElement('script'); var url = this.detailUrl(songIds) + '&callback=returnMusicData'; if(username) url += '&username=' + username + '&password=' + password; script.setAttribute('src', url); document.body.appendChild(script); }, mediaUrl: function(songId) { return (location.href.indexOf('https') == -1 ? 'http': 'https') + '://music.163.com/api/song/lyric?os=pc&id=' + songId + '&lv=-1&kv=-1&tv=-1'; }, media: function(songId, callback) { var req = new XMLHttpRequest(); req.open('GET', this.mediaUrl(songId), true); req.onload = function() { callback(JSON.parse(this.responseText)); }; req.send(); }, }; var innerFrame = document.querySelector('iframe'); var tit, cov, dl; var fileName; var pages = [{ url: 'http://music.163.com/#/song?id=', handler: function() { var innerFrameDoc = innerFrame.contentWindow.document; var albumNode = innerFrameDoc.querySelectorAll('p.des.s-fc4')[1]; tit = innerFrameDoc.querySelector('.tit'); cov = innerFrameDoc.querySelector('.u-cover').querySelector('img'); dl = innerFrameDoc.querySelector('.u-btni-dl'); fileName = tit.querySelector('.f-ff2').innerText + ' - ' + tit.parentNode.nextElementSibling.querySelector('.s-fc7').innerText + '.'; var parentNode = albumNode.parentNode; var songId = location.href.match(/id=([0-9]+)/)[1]; var downloadLine = this.createDownloadLine(songId); parentNode.insertBefore(downloadLine, albumNode.nextElementSibling); }, createDownloadLine: function(songId) { var disableStyle = function(link) { link.text += '(无)'; link.style.color = 'gray'; link.style.textDecoration = 'none'; link.style.cursor = 'auto'; }; var mp3Link = this.createMP3Link(); var lyricLink = this.createLink('歌词'); var tlyricLink = this.createLink('翻译'); var coverLink = this.createLink('封面'); var mp3Help = this.createLink('如何下载歌曲?'); var showPlayer = this.createLink('高音质试听'); mp3Help.addEventListener('click', function() { alert("点击下方的下载按钮之后等待即可。"); }); showPlayer.addEventListener('click', function() { var player = innerFrame.contentWindow.document.querySelector('#wyyyydda'); player.setAttribute('controls', 'true'); player.play(); }); lyricLink.setAttribute('download', fileName + 'lrc'); tlyricLink.setAttribute('download', fileName.substring(0, fileName.length - 1) + '(翻译).lrc'); coverLink.setAttribute('download', fileName + 'jpg'); coverLink.href = cov.getAttribute('data-src'); downloader.BindAnthor(coverLink); downloader.BindAnthor(dl); dl.href = 'javascript:;'; dl.setAttribute('data-res-action', 'downloadDirect'); dl.querySelector('i').innerText = '下载(稍候)'; api.detail([songId], function(result) { mp3Link.src = result.mp3Url; }); api.media(songId, function(result) { if (result.lrc && result.lrc.lyric) { lyricLink.href = 'data:text/plain;charset=utf-8,' + encodeURIComponent(result.lrc.lyric); } else { disableStyle(lyricLink); } if (result.tlyric && result.tlyric.lyric) { tlyricLink.href = 'data:text/plain;charset=utf-8,' + encodeURIComponent(result.tlyric.lyric); } else { disableStyle(tlyricLink); } }); var container = this.createLineContainer('下载'); container.appendChild(lyricLink); // 原文lrc container.appendChild(tlyricLink); // 翻译lrc container.appendChild(coverLink); // 封面 container.appendChild(mp3Help); // 帮助 container.appendChild(showPlayer); // 试听 container.appendChild(document.createElement('br')); container.appendChild(mp3Link); // audio标签 return container; }, createLink: function(label) { var link = document.createElement('a'); link.innerHTML = label; link.className = 's-fc7'; link.style.marginRight = '10px'; link.href = 'javascript:;'; return link; }, createMP3Link: function() { var link = document.createElement('audio'); link.setAttribute('id', 'wyyyydda'); link.style.marginTop = '10px'; link.addEventListener('canplay', function() { dl.href = this.src; dl.setAttribute('download', fileName + 'mp3'); dl.querySelector('i').innerText = '下载'; }); link.addEventListener('error', function() { var username = prompt('无法加载歌曲。付费歌曲请输入会员手机号'); if(username !== null){ var password = prompt('请输入密码。(不会记录,仅用于模拟登陆)'); var _self = this; if(password !== null){ api.detail([location.href.match(/id=([0-9]+)/)[1]], function(result) { _self.src = result.mp3Url; }, username, password); } } dl.querySelector('i').innerText = '下载'; }); return link; }, createLineContainer: function(label) { var container = document.createElement('p'); container.className = 'desc s-fc4'; container.innerHTML = label + ':'; container.style.margin = '10px 0'; return container; }, }, { url: ['http://music.163.com/#/playlist?id=', // 歌单 'http://music.163.com/#/artist?id=', // 歌手 'http://music.163.com/#/discover/toplist', // 榜单 'http://music.163.com/#/album?id=', // 专辑 'http://music.163.com/#/discover/recommend/taste' // 每日推荐 ], handler: function() { var innerFrameDoc = innerFrame.contentWindow.document; var downloadButtons = (innerFrameDoc).querySelectorAll('span.icn-dl'); this.replaceAction(innerFrameDoc, downloadButtons); }, replaceAction: function(innerFrameDoc, downloadButtons) { for (var i = 0; i < downloadButtons.length; i++) { if (downloadButtons[i].getAttribute('data-res-action') == 'download') { downloadButtons[i].setAttribute('data-res-action', 'downloadDirect'); downloadButtons[i].addEventListener('click', function() { var id = this.getAttribute('data-res-id'); var ele = this; var nameAndAuthor = this.previousElementSibling.getAttribute('data-res-name') + ' - ' + this.previousElementSibling.getAttribute('data-res-author'); api.detail([id], function(res) { var audio = document.createElement('audio'); audio.setAttribute('src', res.mp3Url); audio.setAttribute('id', 'wyyyydda'); audio.addEventListener('canplay', function() { var a = document.createElement('a'); a.setAttribute('href', this.src); a.setAttribute('download', nameAndAuthor + '.mp3'); a.setAttribute('id', 'tmp'); downloader.BindAnthor(a); ele.parentNode.appendChild(document.createElement('br')); ele.parentNode.appendChild(a); a.click(); }); audio.addEventListener('error', function() { var _id = id; var username = prompt('无法加载歌曲。付费歌曲请输入会员手机号。'); if(username !== null){ var password = prompt('请输入密码。(不会记录,仅用于模拟登陆)'); var _self = this; if(password !== null){ api.detail([_id], function(result) { _self.src = result.mp3Url; }, username, password); } } }); }); }); } } } }, ]; function matchPagesURL(href, urls) { var ret = false; var t = location.href.split('://')[1]; if (Array.isArray(urls)) { urls.forEach(function(ele) { if (t.indexOf(ele.split('://')[1]) === 0) { ret = true; return; } }); } else { if (t.indexOf(urls.split('://')[1]) === 0) { ret = true; } } return ret; } if (innerFrame) { innerFrame.addEventListener('load', function() { var i, page; for (i = 0; i < pages.length; i += 1) { page = pages[i]; if (matchPagesURL(location.href, page.url)) { page.handler(); } } }); } })(window);