// ==UserScript== // @name 小鹅通 通用m3u8获取 // @namespace https://94cat.com/ // @version 0.1 // @description 获取某鹅通m3u8内容 重新拼装真实ts地址和解密真实密钥 发送给扩展 // @author mz // @match https://*/* // @match http://*/* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @grant none // @run-at document-start // @license GPL v3 // @downloadURL none // ==/UserScript== (function () { 'use strict'; const _JSONparse = JSON.parse; JSON.parse = function () { let data = _JSONparse.apply(this, arguments); findMedia(data); return data; } JSON.parse.toString = function () { return _JSONparse.toString(); } async function findMedia(data, raw = undefined, depth = 0) { for (let key in data) { if (typeof data[key] == "object") { if (depth > 25) { continue; } if (!raw) { raw = data; } findMedia(data[key], raw, ++depth); continue; } if (typeof data[key] == "string" && key == "video_urls" && data[key].slice(-4) == "__ba") { let base64 = data[key].replace("__ba", ""); base64 = base64.replaceAll("@", "1").replaceAll("#", "2").replaceAll("$", "3").replaceAll("%", "4"); let json = _JSONparse(atob(base64)); if (!json) { return } for (let obj of json) { fetch(obj.url).then(response => response.text()) .then(m3u8 => { const lines = m3u8.split('\n'); let keyFlag = false; for (let i = 0; i < lines.length; i++) { if (!keyFlag && lines[i].includes("#EXT-X-KEY:METHOD=AES-128,URI=")) { const match = lines[i].match(/URI="([^"]*)"/); if (match && match[1]) { keyFlag = true; getKey(match[1] + "&uid=" + window.__user_id); } continue; } if (lines[i][0] != "#") { lines[i] = `${obj.ext.host}/${obj.ext.path}/${lines[i]}&${obj.ext.param}`; } } m3u8 = lines.join('\n'); let url = URL.createObjectURL(new Blob([new TextEncoder("utf-8").encode(m3u8)])); window.postMessage({ action: "catCatchAddMedia", url: url, href: location.href, ext: "m3u8" }); }); } } } } function uid2byte(uid) { const byteArray = new Array; for (let i = 0; i < uid.length; i++) { let temp = uid.charCodeAt(i); if (temp >= 65536 && temp <= 1114111) { byteArray.push(temp >> 18 & 7 | 240); byteArray.push(temp >> 12 & 63 | 128); byteArray.push(temp >> 6 & 63 | 128); byteArray.push(63 & temp | 128); } else if (temp >= 2048 && temp <= 65535) { byteArray.push(temp >> 12 & 15 | 224); byteArray.push(temp >> 6 & 63 | 128); byteArray.push(63 & temp | 128); } else if (temp >= 128 && temp <= 2047) { byteArray.push(temp >> 6 & 31 | 192); byteArray.push(63 & temp | 128); } else { byteArray.push(255 & temp); } } return byteArray; } function getKey(url) { fetch(url).then(response => response.arrayBuffer()) .then(buffer => { let newKey = []; buffer = new Uint8Array(buffer); const uidByte = uid2byte(window.__user_id); for (let i in buffer) { newKey.push(buffer[i] ^ uidByte[i]); } window.postMessage({ action: "catCatchAddKey", key: newKey, href: location.href }); }); } })();