fix: vendor hls.js locally (CSP) and handle null executeScript results
CI / test (pull_request) Failing after 24s
CI / test (pull_request) Failing after 24s
Two fixes addressing kfj001 review #37 on commit b19035a:
1. Vendor hls.js bundle locally — chrome.runtime.getURL('hls.min.js')
instead of CDN, bypassing site CSP (script-src 'self') blocks.
Added hls.min.js to vite.config.ts entry points, manifest web_accessible_resources.
2. Handle null entries in executeScript results — destroyed frames
return null when allFrames:true, causing 'Cannot read properties of
null (reading 'result')' in probeHlsManifests() and scrapeTab().
Added null guards before accessing .result.
83/83 tests pass. Build: 10 modules, 413KB hls bundle.
This commit is contained in:
1 parent
b19035ad29
commit
a1f4d2241b
7 files changed
+975
-16
No files matched your search
+10
-3
@@ -391,7 +391,9 @@ async function probeHlsManifests(tabId) {
|
||||
target: { tabId, allFrames: true, world: 'MAIN' },
|
||||
func: m3u8DeepProbeFn,
|
||||
});
|
||||
return results.flatMap(r => r.result || []);
|
||||
// When allFrames is true, destroyed frames may return null entries.
|
||||
// Filter them out before accessing .result to avoid TypeError.
|
||||
return results.filter(r => r && typeof r === 'object').flatMap(r => r.result || []);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
@@ -460,11 +462,16 @@ async function scrapeTab(tabId, manifests) {
|
||||
func: scrapeFn,
|
||||
args: [manifests],
|
||||
});
|
||||
// Prefer the result with the largest video (may come from an iframe)
|
||||
// When allFrames is true, destroyed frames may return null entries.
|
||||
// Filter them out before accessing .result to avoid TypeError.
|
||||
const valid = results
|
||||
.filter(r => r && typeof r === 'object')
|
||||
.map(r => r.result)
|
||||
.filter(r => r && r.videos && r.videos.length > 0);
|
||||
if (valid.length === 0) return results[0]?.result || null;
|
||||
if (valid.length === 0) {
|
||||
const firstValid = results.find(r => r && typeof r === 'object');
|
||||
return firstValid?.result || null;
|
||||
}
|
||||
valid.sort((a, b) => {
|
||||
const aArea = a.videos[0]?.area || 0;
|
||||
const bArea = b.videos[0]?.area || 0;
|
||||
|
||||
+10
-4
@@ -19,7 +19,10 @@
|
||||
* overlays and an aggregate status bar.
|
||||
*/
|
||||
|
||||
const HLS_CDN = 'https://cdn.jsdelivr.net/npm/hls.js@1.5.17';
|
||||
// HLS is vendored locally to avoid CSP blocks on sites like Pornhub that
|
||||
// restrict script-src to 'self'. The hls.min.js bundle is built by Vite
|
||||
// and exposed via chrome.runtime.getURL() so it loads from the extension
|
||||
// origin, bypassing page CSP entirely.
|
||||
|
||||
/**
|
||||
* Grid-optimized hls.js configuration.
|
||||
@@ -711,7 +714,10 @@ function playHls(video, manifestUrl, panel) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Load hls.js from CDN. Returns a Promise that resolves when ready.
|
||||
* Load hls.js from the extension bundle. Returns a Promise that resolves when ready.
|
||||
* We load from chrome.runtime.getURL() (extension origin) instead of a CDN to
|
||||
* avoid CSP blocks — sites like Pornhub restrict script-src to 'self', which
|
||||
* would block any cross-origin <script src> injection in the viewer window.
|
||||
*/
|
||||
function loadHlsJs() {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -720,9 +726,9 @@ function loadHlsJs() {
|
||||
return;
|
||||
}
|
||||
const script = document.createElement('script');
|
||||
script.src = HLS_CDN;
|
||||
script.src = chrome.runtime.getURL('hls.min.js');
|
||||
script.onload = () => resolve();
|
||||
script.onerror = () => reject(new Error('Hls.js CDN unavailable'));
|
||||
script.onerror = () => reject(new Error('Hls.js bundle unavailable - rebuild the extension.'));
|
||||
document.head.appendChild(script);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user