// ==UserScript==
// @name 网易云音乐直接下载
// @namespace https://www.ocrosoft.com/
// @description 在单曲页面显示歌词、翻译、封面、歌曲下载链接并以高音质试听,同时支持歌单、专辑、等页面直接下载单曲。该脚本受 GPL V2.0 许可证保护。
// @match *://music.163.com/*
// @grant GM_xmlhttpRequest
// @version 1.8
// ==/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).attr('data-res-action') == 'downloadDirect') {
if (res.lengthComputable) {
$(this.anchor).children('i')[0].text(`下载:${(res.loaded*100 / res.total).toFixed(2)}%`);
} else {
$(this.anchor).children('i').text("下载:" + anthorEvents.calcLength(res.loaded));
}
} else {
if (res.lengthComputable) {
this.anchor.innerHTML = `下载:${(res.loaded*100 / res.total).toFixed(2)}%`;
} else {
this.anchor.innerHTML = "下载:" + 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).prev().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();
try {
var jqs = document.createElement('script');
jqs.src = 'http://code.jquery.com/jquery-2.1.4.min.js';
document.body.insertBefore(jqs, document.body.firstChild);
} catch(e) {
//
}
var api = {
detailUrl: function(songIds) {
var tpl = (location.href.indexOf('https') == -1 ? 'http://music.ocrosoft.com/GetMusicLink.php?id=${songIds}': 'https://www.ocrosoft.com/outchain/GetMusicLink.php?id=${songIds}');
return tpl.replace('${songIds}', songIds.join(','));
},
detail: function(songIds, callback) {
$.ajax({
type: "get",
url: this.detailUrl(songIds),
dataType: "jsonp",
success: function(json) {
callback(json);
}
});
},
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'; //503207093
},
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).find('.tit');
cov = $(innerFrameDoc).find('.u-cover').children('img');
dl = $(innerFrameDoc).find('.u-btni-dl');
fileName = $(tit).children('.f-ff2')[0].innerText + ' - ' + tit.parent().next().find('.s-fc7')[0].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).attr({
'href': 'javascript:;'
}).click(function() {
alert("点击下方的下载按钮之后等待即可。");
});
$(showPlayer).attr({
'href': 'javascript:;'
}).click(function() {
$(innerFrame.contentWindow.document).find('#wyyyydda').attr('controls', 'true')[0].play();
});
$(lyricLink).attr('download', fileName + 'lrc');
$(tlyricLink).attr('download', fileName + 'lrc');
$(coverLink).attr('download', fileName + 'jpg').attr('href', cov.attr('data-src'));
downloader.BindAnthor(coverLink);
downloader.BindAnthor(dl[0]);
$(dl).attr({
'href': 'javascript:;',
'data-res-action': 'downloadDirect'
}).children('i').text('下载(稍候)');
api.detail([songId],
function(result) {
mp3Link.src = result.mp3Url;
});
api.media(songId,
function(result) {
if (result.lrc.lyric) {
lyricLink.href = 'data:text/plain;charset=utf-8,' + encodeURIComponent(result.lrc.lyric);
} else {
disableStyle(lyricLink);
}
if (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).attr('id', 'wyyyydda').css('margin-top', '10px');
$(link).bind('canplay',
function() {
$(dl).attr('href', this.src).attr('download', fileName + 'mp3').children('i').text('下载');
}).bind('error',
function() {
$(dl).attr('href', 'javascript:alert("无法加载歌曲,请前往反馈。");').children('i').text('下载(错误)');
});
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).find('span.icn-dl');
this.replaceAction(innerFrameDoc, downloadButtons);
},
replaceAction: function(innerFrameDoc, downloadButtons) {
for (var i = 0; i < downloadButtons.length; i++) {
if ($(downloadButtons[i]).attr('data-res-action') == 'download') {
$(downloadButtons[i]).attr('data-res-action', 'downloadDirect');
$(downloadButtons[i]).click(function() {
var id = $(this).attr('data-res-id');
var ele = this;
var nameAndAuthor = $(this).prev().attr('data-res-name') + ' - ' + $(this).prev().attr('data-res-author');
api.detail([id],
function(res) {
var audio = document.createElement('audio');
$(audio).attr({
'src': res.mp3Url,
'id': 'wyyyydda'
});
$(audio).bind('canplay',
function() {
var a = document.createElement('a');
$(a).attr({
'href': this.src,
'download': nameAndAuthor + '.mp3',
'id': 'tmp'
});
downloader.BindAnthor(a);
ele.parentNode.appendChild(document.createElement('br'));
ele.parentNode.appendChild(a);
a.click();
});
$(audio).bind('error',
function() {
alert('无法加载歌曲,请前往反馈。');
});
});
});
}
}
}
},
];
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();
/*setTimeout(function() {
var covp = $(innerFrame.contentWindow.document).find('.covdl').parent();
var covs = covp.children('.des');
if (covs.length != 2) return;
$(covs[1]).css('margin-right', '10px');
$(covs[1]).addClass('covdl');
covp[0].replaceChild(covs[1], covs[0]);
},
55);
setTimeout(function() {
var covp = $(innerFrame.contentWindow.document).find('.covdl').parent();
var covs = covp.children('.des');
$(covs[1]).remove();
},
2222);*/
}
}
});
}
})(window);