Greasy Fork is available in English.

QQ音乐网页播放器歌词lrc获取器

QQ音乐网页播放器歌词获取器,直接在播放器内获取lrc

  1. // ==UserScript==
  2. // @name QQ音乐网页播放器歌词lrc获取器
  3. // @namespace AnnAngela
  4. // @match https://y.qq.com/n/ryqq/player*
  5. // @grant unsafeWindow
  6. // @grant GM_setClipboard
  7. // @version 1.0
  8. // @author AnnAngela
  9. // @description QQ音乐网页播放器歌词获取器,直接在播放器内获取lrc
  10. // @run-at document-start
  11. // ==/UserScript==
  12. "use strict";
  13. const base65Charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  14. const decodeQMStupidEncodedText = function (encodedText) {
  15. const filteredText = encodedText.replace(/[^A-Za-z0-9+/=]/g, "");
  16. let transferedText = "";
  17. for (let i = 0; i < encodedText.length; void 0) {
  18. const i1 = i++;
  19. const i2 = i++;
  20. const i3 = i++;
  21. const i4 = i++;
  22. const transferedCode1 = base65Charset.indexOf(filteredText.charAt(i2));
  23. const charCode = base65Charset.indexOf(filteredText.charAt(i1)) << 2 | transferedCode1 >> 4;
  24. const transferedCode2 = base65Charset.indexOf(filteredText.charAt(i3));
  25. const transferedCode3 = (15 & transferedCode1) << 4 | transferedCode2 >> 2;
  26. const transferedCode4 = base65Charset.indexOf(filteredText.charAt(i4));
  27. const transferedCode5 = (3 & transferedCode2) << 6 | transferedCode4;
  28. transferedText += String.fromCharCode(charCode);
  29. if (transferedCode2 !== 64) {
  30. transferedText += String.fromCharCode(transferedCode3);
  31. }
  32. if (transferedCode4 !== 64) {
  33. transferedText += String.fromCharCode(transferedCode5);
  34. }
  35. }
  36. let decodedText = "";
  37. for (let j = 0; j < transferedText.length; void 0) {
  38. const charCode = transferedText.charCodeAt(j);
  39. if (charCode < 128) {
  40. decodedText += String.fromCharCode(charCode);
  41. j++;
  42. } else if (charCode > 191 && charCode < 224) {
  43. const charCode2 = transferedText.charCodeAt(j + 1);
  44. decodedText += String.fromCharCode((31 & charCode) << 6 | 63 & charCode2);
  45. j += 2;
  46. } else {
  47. const charCode3 = transferedText.charCodeAt(j + 1);
  48. const charCode4 = transferedText.charCodeAt(j + 2);
  49. decodedText += String.fromCharCode((15 & charCode) << 12 | (63 & charCode3) << 6 | 63 & charCode4);
  50. j += 3;
  51. }
  52. }
  53. return decodedText;
  54. };
  55. const lyrics = {};
  56. class XHR extends unsafeWindow.XMLHttpRequest {
  57. constructor(...args) {
  58. super(...args);
  59. this.addEventListener("readystatechange", () => {
  60. if (this.readyState === 4 && this.responseURL.startsWith("https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg")) {
  61. try {
  62. const json = JSON.parse(this.responseText);
  63. const songmid = new URL(this.responseURL).searchParams.get("songmid");
  64. if (typeof songmid === "string" && songmid.length > 4 && json.code === 0 && json.type !== 3) {
  65. const originalLyric = decodeQMStupidEncodedText(json.lyric);
  66. const translatedLyric = decodeQMStupidEncodedText(json.trans);
  67. const playSongData = JSON.parse(localStorage.getItem("playSongData"));
  68. const title = playSongData.value.songList.filter(({ mid }) => mid === songmid)[0].title;
  69. lyrics[title] = { originalLyric, translatedLyric };
  70. }
  71. } catch (e) {
  72. console.error("[Lyric Fetcher From QQMusic Web Player] Error:", e);
  73. }
  74. }
  75. });
  76. }
  77. }
  78. unsafeWindow.XMLHttpRequest = XHR;
  79. window.addEventListener("load", () => {
  80. const container = document.createElement("div");
  81. document.body.appendChild(container);
  82. container.setAttribute("style", "position:fixed;top:20%;bottom:20%;left:30%;right:30%;z-index:999999999;background:white;opacity:0;pointer-event:none;");
  83. const button = document.createElement("div");
  84. document.body.appendChild(button);
  85. button.setAttribute("style", "position:fixed;bottom:1em;right:1em;z-index:999999999;background:white;padding: .25rem; border-radius: .25rem;cursor:pointer;");
  86. button.innerText = "获取歌词lrc";
  87. let opening = false;
  88. button.addEventListener("click", () => {
  89. if (opening) {
  90. opening = false;
  91. container.style.opacity = "0";
  92. container.style.pointerEvents = "none";
  93. button.innerText = "获取歌词lrc";
  94. return;
  95. }
  96. opening = true;
  97. container.style.opacity = "1";
  98. container.style.pointerEvents = "all";
  99. button.innerText = "关闭歌词lrc窗口";
  100. container.innerHTML = '<h2 style="text-align: center;">获取歌词lrc</h2>';
  101. const ul = document.createElement("ul");
  102. ul.style.margin = "revert";
  103. ul.style.padding = "revert";
  104. container.appendChild(ul);
  105. for (const [name, { originalLyric, translatedLyric }] of Object.entries(lyrics)) {
  106. const li = document.createElement("li");
  107. ul.appendChild(li);
  108. li.style.listStyle = "revert";
  109. li.style.margin = "revert";
  110. li.style.padding = "revert";
  111. const span = document.createElement("span");
  112. li.appendChild(span);
  113. span.innerText = name;
  114. if (originalLyric) {
  115. const br = document.createElement("br");
  116. li.appendChild(br);
  117. const span = document.createElement("span");
  118. li.appendChild(span);
  119. span.innerText = "原文歌词:";
  120. const button = document.createElement("button");
  121. button.innerText = "复制到剪切板";
  122. button.addEventListener("click", () => {
  123. GM_setClipboard(originalLyric);
  124. });
  125. li.appendChild(button);
  126. const br2 = document.createElement("br");
  127. li.appendChild(br2);
  128. const span2 = document.createElement("span");
  129. span2.innerText = `预览:${originalLyric.length > 100 ? `${originalLyric.slice(0, 100)}……` : originalLyric}`;
  130. li.appendChild(span2);
  131. }
  132. if (translatedLyric) {
  133. const br = document.createElement("br");
  134. li.appendChild(br);
  135. const span = document.createElement("span");
  136. li.appendChild(span);
  137. span.innerText = "翻译歌词:";
  138. const button = document.createElement("button");
  139. button.innerText = "复制到剪切板";
  140. button.addEventListener("click", () => {
  141. GM_setClipboard(translatedLyric);
  142. });
  143. li.appendChild(button);
  144. const br2 = document.createElement("br");
  145. li.appendChild(br2);
  146. const span2 = document.createElement("span");
  147. span2.innerText = `预览:${translatedLyric.length > 100 ? `${translatedLyric.slice(0, 100)}……` : translatedLyric}`;
  148. li.appendChild(span2);
  149. }
  150. }
  151. });
  152. });