Last active
May 27, 2020 03:33
-
-
Save ccloli/c2089aa9f674f9f70ecd to your computer and use it in GitHub Desktop.
Hook XHR to hack NE
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var originalXMLHttpRequest = XMLHttpRequest; | |
var fakeXMLHttpRequest = function(){ | |
var __this__ = this; | |
var _this = new originalXMLHttpRequest(); | |
var _this_proto = _this.constructor.prototype; | |
Object.keys(originalXMLHttpRequest).forEach(function(elem){ | |
if (typeof originalXMLHttpRequest[elem] === 'function') { | |
__this__[elem] = function(){ | |
_this[elem].apply(_this, arguments); | |
}; | |
} | |
else { | |
var property = {}; | |
var originalProperty = Object.getOwnPropertyDescriptor(originalXMLHttpRequest, elem); | |
property.get = function(){ return _this[elem]; }; | |
if (originalProperty.set) property.set = function(val){ return _this[elem] = val; }; | |
Object.defineProperty(__this__, elem, property); | |
} | |
}); | |
Object.keys(_this_proto).forEach(function(elem){ | |
if (elem in __this__) return; | |
if (elem === 'responseText') return; | |
if (typeof _this[elem] === "function") { | |
if (elem === 'open') { // add requestURL support | |
__this__[elem] = function(){ | |
_this[elem].apply(_this, arguments); | |
__this__.requestURL = arguments[1]; | |
}; | |
} | |
else { | |
__this__[elem] = function(){ | |
_this[elem].apply(_this, arguments); | |
}; | |
} | |
} | |
else { | |
var property = {}; | |
var originalProperty = Object.getOwnPropertyDescriptor(_this_proto, elem); | |
property.get = function(){ return _this[elem]; }; | |
if (originalProperty.set) property.set = function(val){ return _this[elem] = val; }; | |
Object.defineProperty(__this__, elem, property); | |
} | |
}); | |
// modified example | |
Object.defineProperty(__this__, 'responseText', {get: function(){ return _this.responseText.replace(/123/, 'xyz'); }}); | |
this.originalXMLHttpRequest = _this; | |
} | |
window.XMLHttpRequest = fakeXMLHttpRequest; | |
/* | |
example: | |
var xhr = new XMLHttpRequest(); | |
xhr.open('GET', '/example'); | |
xhr.send(); | |
xhr.originalXMLHttpRequest.responseText; // 1234567890 | |
xhr.responseText; // xyz4567890 | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name 网易云音乐高音质支持 | |
// @version 2.1 | |
// @description 去除网页版网易云音乐仅可播放低音质(96Kbps)的限制,强制播放高音质版本 | |
// @match *://music.163.com/* | |
// @include *://music.163.com/* | |
// @author 864907600cc | |
// @icon https://secure.gravatar.com/avatar/147834caf9ccb0a66b2505c753747867 | |
// @run-at document-start | |
// @grant none | |
// @namespace http://ext.ccloli.com | |
// ==/UserScript== | |
// getTrackURL 源码来自 Chrome 扩展程序 网易云音乐增强器(Netease Music Enhancement) by [email protected] | |
// 菊苣这个加密算法你是怎么知道的 _(:3 | |
var getTrackURL = function getTrackURL (dfsId) { | |
var byte1 = '3' + 'g' + 'o' + '8' + '&' + '$' + '8' + '*' + '3' | |
+ '*' + '3' + 'h' + '0' + 'k' + '(' + '2' + ')' + '2'; | |
var byte1Length = byte1.length; | |
var byte2 = dfsId + ''; | |
var byte2Length = byte2.length; | |
var byte3 = []; | |
for (var i = 0; i < byte2Length; i++) { | |
byte3[i] = byte2.charCodeAt(i) ^ byte1.charCodeAt(i % byte1Length); | |
}; | |
byte3 = byte3.map(function(i) { | |
return String.fromCharCode(i) | |
}).join(''); | |
results = CryptoJS.MD5(byte3).toString(CryptoJS.enc.Base64); | |
results = results.replace(/\//g, '_').replace(/\+/g, '-'); | |
// 使用 p1 cdn 解决境外用户无法播放的问题 | |
var url = 'http://p1.music.126.net/' + results + '/' + byte2 + '.mp3'; | |
return url; | |
} | |
var modifyURL = function modifyURL(data, parentKey) { | |
console.log('API 返回了 ' + data.length + ' 首曲目'); | |
console.log('施放魔法!变变变!'); | |
data.forEach(function(elem){ | |
// 部分音乐没有高音质 | |
if (!parentKey) elem.mp3Url = getTrackURL(elem.hMusic ? elem.hMusic.dfsId : elem.mMusic ? elem.mMusic.dfsId : elem.lMusic.dfsId); | |
else elem[parentKey].mp3Url = getTrackURL(elem[parentKey].hMusic ? elem.hMusic[parentKey].dfsId : elem[parentKey].mMusic ? elem.mMusic[parentKey].dfsId : elem.lMusic[parentKey].dfsId); | |
}); | |
return data; | |
} | |
// 重新编写脚本,改用 hook xhr 的形式替换 URL 链接 | |
var originalXMLHttpRequest = window.XMLHttpRequest; | |
var fakeXMLHttpRequest = function(){ | |
var __this__ = this; | |
var _this = new originalXMLHttpRequest(); | |
var _this_proto = _this.constructor.prototype; | |
Object.keys(originalXMLHttpRequest).forEach(function(elem){ | |
if (typeof originalXMLHttpRequest[elem] === 'function') { | |
__this__[elem] = function(){ | |
_this[elem].apply(_this, arguments); | |
}; | |
} | |
else { | |
var property = {}; | |
var originalProperty = Object.getOwnPropertyDescriptor(originalXMLHttpRequest, elem); | |
property.get = function(){ return _this[elem]; }; | |
if (originalProperty.set) property.set = function(val){ return _this[elem] = val; }; | |
Object.defineProperty(__this__, elem, property); | |
} | |
}); | |
Object.keys(_this_proto).forEach(function(elem){ | |
if (elem in __this__) return; | |
if (elem === 'responseText') return; | |
if (typeof _this[elem] === 'function') { | |
if (elem === 'open') { // add requestURL support | |
__this__[elem] = function(){ | |
//console.log(elem, arguments); | |
if (arguments[1].indexOf('/enhance/player/') >= 0) { | |
// 对新版 api 请求旧的 api 接口 | |
__this__.ping = new fakeXMLHttpRequest(); | |
__this__.ping.open(arguments[0], arguments[1].replace('/enhance/player/url', '/detail'), false); // 不使用异步 xhr 以阻断原 xhr 请求 | |
__this__.ping.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); | |
} | |
_this[elem].apply(_this, arguments); | |
__this__.requestURL = arguments[1]; | |
/* | |
if (arguments[1].indexOf('/enhance/player/')) { | |
arguments[1] = arguments[1].replace('/enhance/player/url', '/detail'); | |
}*/ | |
}; | |
} | |
else if (elem === 'send') { // add requestURL support | |
__this__[elem] = function(){ | |
//console.log(elem, arguments); | |
//console.log(__this__.ping) | |
if (__this__.requestURL.indexOf('/enhance/player/') >= 0 && __this__.ping) __this__.ping.send(arguments[0]); | |
_this[elem].apply(_this, arguments); | |
}; | |
} | |
else { | |
__this__[elem] = function(){ | |
//console.log(elem, arguments); | |
_this[elem].apply(_this, arguments); | |
}; | |
} | |
} | |
else { | |
var property = {}; | |
var originalProperty = Object.getOwnPropertyDescriptor(_this_proto, elem); | |
property.get = function(){ /*console.log(elem);*/ return _this[elem]; }; | |
if (originalProperty.set) property.set = function(val){ return _this[elem] = val; }; | |
Object.defineProperty(__this__, elem, property); | |
} | |
}); | |
Object.defineProperty(__this__, 'responseText', { | |
get: function(){ | |
//console.log(_this.responseText); | |
//console.log('Request URL: ' + __this__.requestURL); | |
try { | |
if (__this__.requestURL.indexOf('/weapi/') < 0) return _this.responseText; | |
var action = __this__.requestURL.split('/weapi/')[1].split('?')[0].split('/'); | |
switch (action[0]) { | |
case 'album': | |
var res = JSON.parse(_this.responseText); | |
modifyURL(res.album.songs); | |
return JSON.stringify(res); | |
break; | |
case 'song': | |
if (action[1] !== 'detail') { | |
if (action[1] !== 'enhance' && action[2] !== 'player' && action[3] !== 'url') return _this.responseText; | |
var res = JSON.parse(_this.responseText); | |
/*window.ping = __this__.ping; | |
console.log(__this__.ping);*/ | |
if (__this__.ping) res.data[0].url = JSON.parse(__this__.ping.responseText).songs[0].mp3Url; // 替换旧版 api 的 url | |
return JSON.stringify(res); | |
} | |
var res = JSON.parse(_this.responseText); | |
modifyURL(res.songs); | |
return JSON.stringify(res); | |
break; | |
case 'playlist': | |
if (action[1] !== 'detail') return _this.responseText; | |
var res = JSON.parse(_this.responseText); | |
modifyURL(res.result.tracks); | |
return JSON.stringify(res); | |
break; | |
case 'dj': | |
if (action[2] === 'byradio') { | |
var res = JSON.parse(_this.responseText); | |
modifyURL(res.programs, 'mainSong'); | |
return JSON.stringify(res); | |
} | |
else if (action[2] === 'detail') { | |
var res = JSON.parse(_this.responseText); | |
res.program = modifyURL([res.program], 'mainSong')[0]; | |
return JSON.stringify(res); | |
} | |
else return _this.responseText; | |
break; | |
case 'v3': | |
switch (action[1]){ | |
// http://music.163.com/weapi/v3/playlist/detail | |
case 'playlist': | |
if (action[2] !== 'detail') return _this.responseText; | |
var res = JSON.parse(_this.responseText); | |
res.privileges.forEach(function(elem){ | |
var q = elem.pl || elem.dl || elem.fl || Math.min(elem.maxbr, 320000) || 320000; | |
elem.st = 0; | |
elem.pl = q; | |
elem.dl = q; | |
elem.fl = q; | |
}); | |
if (res.privileges.length < res.playlist.trackIds.length && res.playlist.trackIds.length === res.playlist.tracks.length) { | |
// 对超过 1000 的播放列表补充播放信息(需魔改 core.js) | |
for (var i = res.privileges.length; i < res.playlist.trackIds.length; i++) { | |
var q = res.playlist.tracks.h ? res.playlist.tracks.h.br : res.playlist.tracks.m ? res.playlist.tracks.m.br : res.playlist.tracks.l ? res.playlist.tracks.l.br : res.playlist.tracks.a ? res.playlist.tracks.a.br : 320000; | |
res.privileges.push({ | |
cp: 1, | |
cs: false, | |
dl: q, | |
fee: 0, | |
fl: q, | |
id: res.playlist.trackIds[i].id, | |
maxbr: q, | |
payed: 0, | |
pl: q, | |
sp: 7, | |
st: 0, | |
subp: 1 | |
}); | |
} | |
} | |
console.log(res); | |
return JSON.stringify(res); | |
break; | |
} | |
break; | |
default: | |
return _this.responseText; | |
} | |
} | |
catch (error) { | |
// 以防 api 转换失败也能正常返回数据 | |
console.error('转换出错!', error); | |
return _this.responseText; | |
} | |
} | |
}); | |
this.originalXMLHttpRequest = _this; | |
} | |
window.XMLHttpRequest = fakeXMLHttpRequest; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
User Script 只用作实例展示,故不再更新。如需要后续更新请前往 https://github.com/FirefoxBar/userscript/tree/master/163_Music_High_Quality_Support