- 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)
- Deep-probe HLS manifests via known player globals, inline scripts, config objects
- Scan main frame only (no nested iframes); pick largest visible video per tab
- Store mediaType/hlsManifest metadata through the pipeline
- CSP-safe interceptor injection via script.src (not inline textContent)
- Remove probeFn/scrapeFn from Vite build entries (non-existent files)
- Refactor: extract m3u8DeepProbeFn, scrapeFn, scanVideos, storeVideos,
makeVideoEntry, filterValidTabs, probeHlsManifests, dedupManifests, scrapeTab
to module-level functions (no inline closures recreated on every click)
- Clean up viewer.js: extract createVideoElement(), createPanel(),
consolidate HLS_CONFIG, remove console.log noise
- Add DEBUG flag to gate console output in popup
- Unify url/src fields — prefer 'src' everywhere
- Remove dead code in renderList and setTimeout(100) hack
- Query HLS data structures directly from page JS state per tab
- Strategies: video element HLS instances, window-level player vars,
intercepted data, inline scripts, global config objects, content script
- Fixed merge logic: index.js now correctly processes interceptedManifests
and hlsQueryResults instead of non-existent playerData
- Skip blob: URLs in DOM scan (HLS-internal, can't be played directly)
- Only attach HLS manifest when actually detected for that tab
Previous approach (DOM snapshot via executeScript) failed on Pornhub because:
- Video player loads asynchronously via JavaScript
- HLS manifest arrives via XHR/fetch AFTER page render
- <video> element only shows blob: URL, not the actual manifest
New approach:
- Content script injects interceptor into MAIN world at document_start
- Interceptor patches XMLHttpRequest and fetch() to capture .m3u8 URLs
- Periodic DOM scans detect HLS player instances on <video> elements
- Global config object scanning for embedded stream URLs
- Popup queries content script via chrome.tabs.sendMessage for real-time data
- If no DOM videos found but content script has data, create entries from intercepted sources
Changes:
- content.js: Full rewrite with main-world injection + XHR/fetch interception
- index.js: Query content scripts via messages, merge with DOM snapshot
- manifest.json: all_frames + document_start for early injection
- Strategy 1: scan inline <script> blocks for .m3u8 URLs (skip subtitles/captions)
- Strategy 2: check video element HLS player instances (hlsInstance, _hls)
- Strategy 3: probe common global config objects (hlsConfig, playerConfig, etc.)
- Storage items now include hlsManifest and mediaType fields
- When HLS detected and src is blob:/empty, promote manifest URL to primary
- Backward compatible: direct MP4 entries unaffected
- Remove the hardcoded 4-tab limit in the find-videos flow
- Add per-tab try/catch so inaccessible tabs are skipped gracefully
- Filter out tabs that produced no frames from the dedup pipeline
- Update button label and status messages accordingly