Guest User

Untitled

a guest
Jun 28th, 2025
376
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.31 KB | Source Code | 0 0
  1. // ==UserScript==
  2. // @name 网易云音乐
  3. // @namespace http://tampermonkey.net/
  4. // @version 27.0
  5. // @description 解锁网页完全歌单,来自公开音源
  6. // @author YourName & Gemini
  7. // @match *://music.163.com/*
  8. // @grant GM_xmlhttpRequest
  9. // @grant unsafeWindow
  10. // @run-at document-start
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16. // --- 新增: 设置Cookie ---
  17. // 强制将 os cookie 设置为 'pc',以获取桌面端体验
  18. document.cookie = 'os=pc; domain=.music.163.com; path=/; max-age=31536000';
  19.  
  20. function log(message, ...args) {
  21. console.log(`[NCM Unlocker v27.0]`, message, ...args);
  22. }
  23.  
  24. // --- API注入 ---
  25. const APIHooker = {
  26. hooks: [],
  27. originalOpen: XMLHttpRequest.prototype.open,
  28. originalSend: XMLHttpRequest.prototype.send,
  29.  
  30. hook: function(urlMatcher, dealer) {
  31. this.hooks.push({ matcher: urlMatcher, dealer: dealer });
  32. },
  33.  
  34. init: function() {
  35. const self = this;
  36. XMLHttpRequest.prototype.open = function(method, url, ...args) {
  37. this._hook = self.hooks.find(h => h.matcher.test(url));
  38. return self.originalOpen.apply(this, [method, url, ...args]);
  39. };
  40.  
  41. XMLHttpRequest.prototype.send = function(...sendArgs) {
  42. if (this._hook) {
  43. const hook = this._hook;
  44. let originalOnReadyStateChange = this.onreadystatechange;
  45.  
  46. this.onreadystatechange = function(...progressArgs) {
  47. if (this.readyState === 4 && this.status === 200) {
  48. hook.dealer(this, originalOnReadyStateChange, progressArgs);
  49. } else if (originalOnReadyStateChange) {
  50. originalOnReadyStateChange.apply(this, progressArgs);
  51. }
  52. };
  53. }
  54. return self.originalSend.apply(this, sendArgs);
  55. };
  56. }
  57. };
  58.  
  59.  
  60. // --- 核心逻辑 ---
  61. function main() {
  62. APIHooker.init();
  63. log('Cookie "os=pc" 已设置,注入器已初始化。');
  64.  
  65. const requestState = {};
  66.  
  67. // --- 按钮绕过 ---
  68. APIHooker.hook(
  69. /\/weapi\/(v3\/song\/detail|v1\/play\/record|v6\/playlist\/detail)/,
  70. (xhr, originalCallback, callbackArgs) => {
  71. try {
  72. let data = JSON.parse(xhr.responseText);
  73. let privilegesModified = false;
  74. const fixPrivilege = (p) => {
  75. if (p && (p.st !== 0 || p.fee > 0 || p.pl === 0)) {
  76. p.st = 0; p.fee = 0; p.pl = 320000; p.dl = 320000;
  77. p.plLevel = 'exhigh'; p.dlLevel = 'exhigh';
  78. privilegesModified = true;
  79. }
  80. };
  81. if (data.privileges) data.privileges.forEach(fixPrivilege);
  82. if (data.songs) data.songs.forEach(s => s.privilege && fixPrivilege(s.privilege));
  83. if (data.allData) data.allData.forEach(d => d.song && d.song.privilege && fixPrivilege(d.song.privilege));
  84. if (data.weekData) data.weekData.forEach(d => d.song && d.song.privilege && fixPrivilege(d.song.privilege));
  85.  
  86. if (privilegesModified) {
  87. const modifiedText = JSON.stringify(data);
  88. Object.defineProperty(xhr, 'responseText', { value: modifiedText, writable: true });
  89. }
  90. } catch(e) { /* Silent fail */ }
  91.  
  92. if (originalCallback) originalCallback.apply(xhr, callbackArgs);
  93. }
  94. );
  95.  
  96. // --- 注入 ---
  97. APIHooker.hook(/\/weapi\/song\/enhance\/player\/url\/v1/, (xhr, originalCallback, callbackArgs) => {
  98. let originalResponse;
  99. try { originalResponse = JSON.parse(xhr.responseText); } catch (e) {
  100. if (originalCallback) originalCallback.apply(xhr, callbackArgs); return;
  101. }
  102.  
  103. const songData = originalResponse.data[0];
  104. if (!songData || !songData.id || (songData.url && songData.code === 200)) {
  105. if (originalCallback) originalCallback.apply(xhr, callbackArgs); return;
  106. }
  107.  
  108. if (requestState[songData.id] === 'processing') return;
  109. requestState[songData.id] = 'processing';
  110.  
  111. GM_xmlhttpRequest({
  112. method: 'GET',
  113. url: `https://wyy-api-three.vercel.app/song/url?id=${songData.id}&quality=320k`,
  114. onload: function(response) {
  115. try {
  116. if (response.status === 200) {
  117. const customData = JSON.parse(response.responseText);
  118. const customUrl = customData.url;
  119. if (customUrl) {
  120. const fakeResponse = {
  121. data: [{ ...songData, url: customUrl, br: 320000, code: 200, type: 'mp3', fee: 0, md5: '0', level: 'exhigh', flag: 0 }],
  122. code: 200
  123. };
  124. const fakeResponseText = JSON.stringify(fakeResponse);
  125. Object.defineProperty(xhr, 'responseText', { value: fakeResponseText, writable: true });
  126. log(`✅ 音源注入成功 (ID: ${songData.id})`);
  127. }
  128. }
  129. } catch (e) { /* Silent fail */ }
  130. if (originalCallback) originalCallback.apply(xhr, callbackArgs);
  131. setTimeout(() => delete requestState[songData.id], 500);
  132. },
  133. onerror: function(e) {
  134. if (originalCallback) originalCallback.apply(xhr, callbackArgs);
  135. setTimeout(() => delete requestState[songData.id], 500);
  136. }
  137. });
  138. });
  139. }
  140.  
  141. if (document.body) { main(); } else { new MutationObserver((_, obs) => { if (document.body) { obs.disconnect(); main(); } }).observe(document.documentElement, { childList: true }); }
  142. })();
  143.  
Advertisement
Add Comment
Please, Sign In to add comment