This commit is contained in:
owenchen committed 2026-11-03 09:19:50 +08:00
1 parent ac0112b4a3
commit 90bb20e75f
24 files changed
+2722

No files matched your search

@@ -0,0 +1,144 @@
// 资源嗅探脚本:在安装页面播放器脚本之前接管 fetch / XMLHttpRequest / createObjectURL,
// 把真正被下载的媒体地址(mp4 / m3u8 等)回报给宿主程序,用于"下载视频"按钮。
(function () {
if (window.__mediaSniffInstalled) return;
window.__mediaSniffInstalled = true;
window.__mediaUrls = [];
window.__m3u8Blobs = [];
var MEDIA_EXT =
/\.(mp4|flv|m3u8|mpd|mkv|mov|m4v|webm|f4v|3gp|mpg|mpeg|ts)(\?|#|$)/i;
var PLAIN_EXT =
/\.(jpg|jpeg|png|gif|webp|ico|svg|bmp|css|js|json|woff2?|ttf|map|txt)(\?|#|$)/i;
function isMediaUrl(u) {
if (!u) return false;
u = String(u);
if (u.indexOf("blob:") === 0 || u.indexOf("data:") === 0) return false;
if (PLAIN_EXT.test(u)) return false;
return MEDIA_EXT.test(u) || /\/(video|vod|playback|media)[\/-]/i.test(u);
}
function absUrl(u) {
try {
return new URL(String(u), location.href).href;
} catch (e) {
return String(u);
}
}
function post(msg) {
try {
if (
window.chrome &&
window.chrome.webview &&
window.chrome.webview.postMessage
) {
window.chrome.webview.postMessage(JSON.stringify(msg));
}
} catch (e) {}
}
function remember(text) {
if (!text || typeof text !== "string") return;
if (text.indexOf("#EXTM3U") < 0) return;
if (window.__m3u8Blobs.indexOf(text) >= 0) return;
window.__m3u8Blobs.push(text);
post({ type: "hlsText", text: text });
}
function report(u) {
try {
var full = absUrl(u);
if (!isMediaUrl(full)) return;
if (window.__mediaUrls.indexOf(full) >= 0) return;
window.__mediaUrls.push(full);
// base 是发出这个请求的文档地址:播放器常在跨域 iframe 里,
// 宿主必须用它当 Referer,用顶层页面地址会被防盗链判为非法来源
post({ type: "media", url: full, base: location.href });
} catch (e) {}
}
window.__reportMedia = report;
window.__rememberHlsText = remember;
// 抖音等站点会用 atob(base64) 把播放地址还原出来,这里顺手抓一份解码结果
try {
var origAtob = window.atob;
if (origAtob) {
window.atob = function (s) {
var r = origAtob.apply(this, arguments);
try {
if (r && typeof r === "string") {
if (r.indexOf("#EXTM3U") >= 0) remember(r);
else if (isMediaUrl(r)) report(r);
}
} catch (e) {}
return r;
};
}
} catch (e) {}
try {
var origFetch = window.fetch;
if (origFetch) {
window.fetch = function (input, init) {
try {
var u =
typeof input === "string" || input instanceof URL
? input
: input && input.url;
if (u) report(u);
} catch (e) {}
return origFetch.apply(this, arguments);
};
}
} catch (e) {}
try {
var xhrOpen = XMLHttpRequest.prototype.open;
var xhrSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function (method, u) {
try {
if (u) report(u);
} catch (e) {}
return xhrOpen.apply(this, arguments);
};
XMLHttpRequest.prototype.send = function () {
var xhr = this;
try {
xhr.addEventListener("load", function () {
try {
if (xhr.responseType === "" || xhr.responseType === "text") {
remember(xhr.responseText);
} else if (
xhr.responseType === "blob" &&
xhr.response &&
xhr.response.text
) {
xhr.response.text().then(remember);
}
} catch (e) {}
});
} catch (e) {}
return xhrSend.apply(this, arguments);
};
} catch (e) {}
// MSE 播放时 video.src 只能是 blob:,抓不到 http 地址,所以靠上面的分片嗅探兜底;
// 这里额外记录 createObjectURL 的调用,方便识别"确实在用 MSE"。
try {
var ocu = window.URL && window.URL.createObjectURL;
if (ocu) {
window.URL.createObjectURL = function (obj) {
var u = ocu.apply(this, arguments);
try {
window.__usesMse = true;
if (obj && typeof obj.text === "function") obj.text().then(remember);
} catch (e) {}
return u;
};
}
} catch (e) {}
})();