小鹅通 通用m3u8获取

获取某鹅通m3u8内容 重新拼装真实ts地址和解密真实密钥 发送给扩展

目前為 2023-08-30 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name 小鹅通 通用m3u8获取
  3. // @namespace https://94cat.com/
  4. // @version 0.6
  5. // @description 获取某鹅通m3u8内容 重新拼装真实ts地址和解密真实密钥 发送给扩展
  6. // @author mz
  7. // @match https://*/*
  8. // @match http://*/*
  9. // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
  10. // @grant none
  11. // @run-at document-start
  12. // @license GPL v3
  13. // ==/UserScript==
  14. (function () {
  15. 'use strict';
  16.  
  17. let URLext = {};
  18. const _indexOf = String.prototype.indexOf;
  19. String.prototype.indexOf = function () {
  20. if (arguments[0] == "#EXTM3U") {
  21. if (Object.keys(URLext).length == 0) { return _indexOf.apply(this, arguments); }
  22. const lines = this.split('\n');
  23. let m3u8 = '';
  24. for (let i = 0; i < lines.length; i++) {
  25. if (lines[i].startsWith("#EXT-X-KEY") && lines[i].includes('URI=""')) {
  26. continue;
  27. }
  28. if (lines[i][0] != "#") {
  29. m3u8 += `${URLext.host}/${URLext.path}/${lines[i]}&${URLext.param}\n`;
  30. continue;
  31. }
  32. m3u8 += lines[i] + "\n";
  33. if (lines[i] == '#EXT-X-ENDLIST') { break; }
  34. }
  35. const url = URL.createObjectURL(new Blob([new TextEncoder("utf-8").encode(m3u8)]));
  36. window.postMessage({ action: "catCatchAddMedia", url: url, href: location.href, ext: "m3u8" });
  37. }
  38. return _indexOf.apply(this, arguments);
  39. }
  40. String.prototype.indexOf.toString = function () {
  41. return _indexOf.toString();
  42. }
  43.  
  44. const _JSONparse = JSON.parse;
  45. JSON.parse = function () {
  46. let data = _JSONparse.apply(this, arguments);
  47. findMedia(data);
  48. return data;
  49. }
  50. JSON.parse.toString = function () {
  51. return _JSONparse.toString();
  52. }
  53. async function findMedia(data, raw = undefined, depth = 0) {
  54. for (let key in data) {
  55. if (typeof data[key] == "object") {
  56. if (depth > 25) { continue; }
  57. if (!raw) { raw = data; }
  58. findMedia(data[key], raw, ++depth);
  59. continue;
  60. }
  61. if (typeof data[key] == "string" && key == "video_urls" && data[key].slice(-4) == "__ba") {
  62. let base64 = data[key].replace("__ba", "");
  63. base64 = base64.replaceAll("@", "1").replaceAll("#", "2").replaceAll("$", "3").replaceAll("%", "4");
  64. let json = _JSONparse(atob(base64));
  65. if (!json) { return }
  66. for (let obj of json) {
  67. fetch(obj.url).then(response => response.text())
  68. .then(m3u8 => {
  69. const lines = m3u8.split('\n');
  70. let keyFlag = false;
  71. for (let i = 0; i < lines.length; i++) {
  72. if (lines[i] == '#EXT-X-ENDLIST') { break; }
  73. if (!keyFlag && lines[i].includes("#EXT-X-KEY:METHOD=AES-128,URI=")) {
  74. const match = lines[i].match(/URI="([^"]*)"/);
  75. if (match && match[1]) {
  76. keyFlag = true;
  77. if (window.__user_id) {
  78. getKey(match[1] + "&uid=" + window.__user_id, window.__user_id);
  79. } else if (document.cookie) {
  80. for (let cookie of document.cookie.split(';')) {
  81. cookie = cookie.trim();
  82. if (cookie.substring(0, 10) == "userInfo={") {
  83. cookie = cookie.slice(9);
  84. cookie = isJSON(cookie);
  85. cookie && cookie.user_id && getKey(match[1] + "&uid=" + cookie.user_id, cookie.user_id);
  86. break;
  87. }
  88. }
  89. }
  90. }
  91. continue;
  92. }
  93. if (lines[i][0] != "#") {
  94. lines[i] = `${obj.ext.host}/${obj.ext.path}/${lines[i]}&${obj.ext.param}`;
  95. }
  96. }
  97. m3u8 = lines.join('\n');
  98. let url = URL.createObjectURL(new Blob([new TextEncoder("utf-8").encode(m3u8)]));
  99. window.postMessage({ action: "catCatchAddMedia", url: url, href: location.href, ext: "m3u8" });
  100. });
  101. }
  102. } else if (data.confusion_m3u8 && data.ext) {
  103. URLext = data.ext;
  104. }
  105. }
  106. }
  107. function uid2byte(uid) {
  108. const byteArray = new Array;
  109. for (let i = 0; i < uid.length; i++) {
  110. let temp = uid.charCodeAt(i);
  111. if (temp >= 65536 && temp <= 1114111) {
  112. byteArray.push(temp >> 18 & 7 | 240);
  113. byteArray.push(temp >> 12 & 63 | 128);
  114. byteArray.push(temp >> 6 & 63 | 128);
  115. byteArray.push(63 & temp | 128);
  116. } else if (temp >= 2048 && temp <= 65535) {
  117. byteArray.push(temp >> 12 & 15 | 224);
  118. byteArray.push(temp >> 6 & 63 | 128);
  119. byteArray.push(63 & temp | 128);
  120. } else if (temp >= 128 && temp <= 2047) {
  121. byteArray.push(temp >> 6 & 31 | 192);
  122. byteArray.push(63 & temp | 128);
  123. } else {
  124. byteArray.push(255 & temp);
  125. }
  126. }
  127. return byteArray;
  128. }
  129. function getKey(url, userId) {
  130. fetch(url).then(response => response.arrayBuffer())
  131. .then(buffer => {
  132. let newKey = [];
  133. buffer = new Uint8Array(buffer);
  134. const uidByte = uid2byte(userId);
  135. for (let i in buffer) {
  136. newKey.push(buffer[i] ^ uidByte[i]);
  137. }
  138. console.log(newKey);
  139. window.postMessage({ action: "catCatchAddKey", key: newKey, href: location.href });
  140. });
  141. }
  142.  
  143. const _xhrOpen = XMLHttpRequest.prototype.open;
  144. XMLHttpRequest.prototype.open = function () {
  145. this.addEventListener("readystatechange", function (event) {
  146. const response = this.currentTarget ? this.currentTarget.response : this.response;
  147. const isJson = isJSON(response);
  148. isJson && findMedia(isJson);
  149. });
  150. _xhrOpen.apply(this, arguments);
  151. }
  152. XMLHttpRequest.prototype.open.toString = function () {
  153. return _xhrOpen.toString();
  154. }
  155.  
  156. function isJSON(str) {
  157. if (typeof str == "object") {
  158. return str;
  159. }
  160. if (typeof str == "string") {
  161. try {
  162. return _JSONparse(str);
  163. } catch (e) { return false; }
  164. }
  165. return false;
  166. }
  167. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址