小鹅通 通用m3u8获取

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

目前为 2023-11-15 提交的版本。查看 最新版本

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

QingJ © 2025

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