- Add Hls.cast(video) detection (Strategy B1) — uses the official hls.js API to retrieve bound instances from <video> elements - Add _goon_hls_manifest annotation check (Strategy B2) — reads interceptor-set manifest URLs directly on video elements - Refactor scrapeFn to a 5-priority HLS detection chain: 1. Direct .m3u8 in video.src 2. Interceptor-set _goon_hls_manifest 3. Hls.cast(video) official API 4. Direct HTTP source (non-blob) 5. Deep probe fallback (page globals/scripts) - Replace fragile Object.defineProperty Hls detection with polling interval in interceptors.js — avoids conflicts with page JS - Add buffered range tracking and duration to content.js video scan data - Add 8 new tests for HLS detection priority chain (55 total)
This commit is contained in:
1 parent
7276824758
commit
bc3f37ae4c
4 files changed
+212
-13
No files matched your search
+45
-2
@@ -138,6 +138,27 @@ function m3u8DeepProbeFn() {
|
||||
}
|
||||
|
||||
// Strategy B: Video element HLS instances
|
||||
// B1: Use Hls.cast(video) — the official hls.js API to get the bound instance
|
||||
if (typeof Hls !== 'undefined' && typeof Hls.cast === 'function') {
|
||||
for (const v of document.querySelectorAll('video')) {
|
||||
try {
|
||||
const hlsInst = Hls.cast(v);
|
||||
if (hlsInst && hlsInst.url) {
|
||||
if (!seen.has(hlsInst.url)) { seen.add(hlsInst.url); manifests.push({ url: hlsInst.url, player: 'Hls.cast' }); }
|
||||
}
|
||||
} catch { /* ignore */ }
|
||||
}
|
||||
}
|
||||
|
||||
// B2: Check interceptor-set manifest annotation on video elements
|
||||
for (const v of document.querySelectorAll('video')) {
|
||||
if (v._goon_hls_manifest && !seen.has(v._goon_hls_manifest)) {
|
||||
seen.add(v._goon_hls_manifest);
|
||||
manifests.push({ url: v._goon_hls_manifest, player: 'video._goon_hls_manifest' });
|
||||
}
|
||||
}
|
||||
|
||||
// B3: Fallback — walk video element keys looking for HLS-related objects
|
||||
for (const v of document.querySelectorAll('video')) {
|
||||
for (const key of Object.keys(v)) {
|
||||
if (key.toLowerCase().includes('hls') || key === 'player') {
|
||||
@@ -200,12 +221,34 @@ function scrapeFn(hlsManifests) {
|
||||
let mediaType = 'video';
|
||||
let src = rawSrc;
|
||||
|
||||
// Priority 1: Direct .m3u8 source (rare but possible)
|
||||
if (rawSrc.includes('.m3u8') && rawSrc.startsWith('http')) {
|
||||
hlsManifest = rawSrc;
|
||||
mediaType = 'hls';
|
||||
} else if (rawSrc.startsWith('http') && !rawSrc.startsWith('blob:')) {
|
||||
}
|
||||
// Priority 2: Interceptor annotation — Hls.attachMedia() patched by interceptors
|
||||
else if (v._goon_hls_manifest) {
|
||||
hlsManifest = v._goon_hls_manifest;
|
||||
mediaType = 'hls';
|
||||
src = hlsManifest;
|
||||
}
|
||||
// Priority 3: Hls.cast(video) — official hls.js API (works when Hls is loaded)
|
||||
else if (typeof Hls !== 'undefined' && typeof Hls.cast === 'function') {
|
||||
try {
|
||||
const hlsInst = Hls.cast(v);
|
||||
if (hlsInst && hlsInst.url) {
|
||||
hlsManifest = hlsInst.url;
|
||||
mediaType = 'hls';
|
||||
src = hlsManifest;
|
||||
}
|
||||
} catch { /* ignore */ }
|
||||
}
|
||||
// Priority 4: Direct HTTP source (non-blob)
|
||||
if (!hlsManifest && rawSrc.startsWith('http') && !rawSrc.startsWith('blob:')) {
|
||||
mediaType = 'video';
|
||||
} else if (hlsManifests && hlsManifests.length > 0) {
|
||||
}
|
||||
// Priority 5: Deep probe fallback — use manifests found by scanning page globals/scripts
|
||||
if (!hlsManifest && hlsManifests && hlsManifests.length > 0) {
|
||||
hlsManifest = hlsManifests[0].url || hlsManifests[0];
|
||||
mediaType = 'hls';
|
||||
src = hlsManifest;
|
||||
|
||||
Reference in new issue
Block a user