Compare commits
10
Commits
64d792632d
..
v0.1.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fbc836d9c4 | ||
|
|
de9d537a75 | ||
|
|
23a3f00df9 | ||
|
|
0a3225035c | ||
|
|
0848cd51be | ||
|
|
41723227c0 | ||
|
|
5da2003cd0 | ||
|
|
97abaf42d9 | ||
|
|
c366f0b8c4 | ||
|
|
c826669c7d |
No files matched your search
@@ -0,0 +1,81 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
- name: Package dist.zip
|
||||
shell: bash
|
||||
run: |
|
||||
cd dist
|
||||
zip -r "../vidplex-${{ github.ref_name }}.zip" .
|
||||
|
||||
- name: Create Gitea release
|
||||
shell: bash
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
GITEA_API: ${{ secrets.GITEA_API || 'http://192.168.1.74:30008/api/v1' }}
|
||||
REPO: ${{ github.repository }}
|
||||
TAG: ${{ github.ref_name }}
|
||||
run: |
|
||||
if [ -z "$GITEA_TOKEN" ]; then
|
||||
echo "::warning::GITEA_TOKEN secret is not set; skipping release creation. Add it in Gitea repo Settings > Secrets (repo scope)."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
json_id() { node -e 'let d="";process.stdin.on("data",c=>d+=c).on("end",()=>{const j=JSON.parse(d||"{}");if(j.id==null){console.error("no release id:",JSON.stringify(j));process.exit(1)}console.log(j.id)})'; }
|
||||
|
||||
release_id=$(
|
||||
curl -s -o /tmp/rel.json -w "%{http_code}" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
"$GITEA_API/repos/$REPO/releases/tags/$TAG"
|
||||
)
|
||||
|
||||
if [ "$release_id" = "200" ]; then
|
||||
echo "Release for $TAG already exists; reusing it."
|
||||
release_id=$(json_id < /tmp/rel.json)
|
||||
else
|
||||
echo "Creating release for $TAG."
|
||||
release_id=$(
|
||||
curl -s -o /tmp/rel.json -w "%{http_code}" -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"tag_name\": \"$TAG\", \"name\": \"$TAG\", \"body\": \"Automated release build for $TAG\"}" \
|
||||
"$GITEA_API/repos/$REPO/releases"
|
||||
)
|
||||
case "$release_id" in
|
||||
201|200) release_id=$(json_id < /tmp/rel.json) ;;
|
||||
*) echo "::error::release create returned HTTP $release_id: $(cat /tmp/rel.json)"; exit 1 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
echo "Uploading asset to release $release_id."
|
||||
resp=$(curl -s -o /tmp/att.json -w "%{http_code}" -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-F "attachment=@vidplex-${TAG}.zip" \
|
||||
"$GITEA_API/repos/$REPO/releases/$release_id/assets")
|
||||
if [ "$resp" != "200" ] && [ "$resp" != "201" ]; then
|
||||
echo "::error::asset upload returned HTTP $resp: $(cat /tmp/att.json)"
|
||||
exit 1
|
||||
fi
|
||||
cat /tmp/att.json
|
||||
echo
|
||||
@@ -0,0 +1,204 @@
|
||||
import { describe, it } from './runner.mjs';
|
||||
import { JSDOM } from 'jsdom';
|
||||
|
||||
const POPUP_HTML = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>VidPlex</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<h1>VidPlex</h1>
|
||||
<section class="instructions-panel" role="region" aria-labelledby="instructions-title">
|
||||
<div class="instructions-header">
|
||||
<div>
|
||||
<p class="instructions-kicker">Quick start</p>
|
||||
<h2 id="instructions-title">How to use VidPlex</h2>
|
||||
</div>
|
||||
<button
|
||||
id="instructions-toggle"
|
||||
type="button"
|
||||
class="instructions-toggle"
|
||||
aria-expanded="true"
|
||||
aria-controls="instructions-body"
|
||||
>
|
||||
Hide instructions
|
||||
</button>
|
||||
</div>
|
||||
<div id="instructions-body" class="instructions-body">
|
||||
<ol class="instructions-list">
|
||||
<li>
|
||||
<strong>Scan videos</strong>
|
||||
<span>Click <strong>Find Videos</strong> to search the current browser window for videos.</span>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Review the list</strong>
|
||||
<span>Check the popup list; each found video URL is clickable.</span>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Open the viewer</strong>
|
||||
<span>Click <strong>Open Viewer</strong> to open the 2x2 grid player in a new window.</span>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Reset and rescan</strong>
|
||||
<span>Click <strong>Clear</strong> to erase results and scan again.</span>
|
||||
</li>
|
||||
</ol>
|
||||
<p class="instructions-note">Warning: Browser pages, extension pages, and restricted frames can hide videos, so results may be incomplete.</p>
|
||||
<p class="instructions-learn-more">Learn more tooltip: Read the VidPlex README and audit notes.</p>
|
||||
</div>
|
||||
</section>
|
||||
<button id="find-btn">Find Videos (all tabs)</button>
|
||||
<div id="video-list" class="video-list" style="display:none;"></div>
|
||||
<div id="status" class="status" style="min-height:16px;"></div>
|
||||
<div id="btn-row" class="btn-row" style="display:none;">
|
||||
<button id="clear-btn" class="btn-secondary">Clear</button>
|
||||
<button id="open-btn">Open Viewer</button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
function installPopupDom() {
|
||||
const dom = new JSDOM(POPUP_HTML, { url: 'chrome-extension://test/src/viewer/index.html' });
|
||||
const previous = {
|
||||
window: globalThis.window,
|
||||
document: globalThis.document,
|
||||
navigator: globalThis.navigator,
|
||||
chrome: globalThis.chrome,
|
||||
HTMLElement: globalThis.HTMLElement,
|
||||
Node: globalThis.Node,
|
||||
};
|
||||
|
||||
globalThis.window = dom.window;
|
||||
globalThis.document = dom.window.document;
|
||||
Object.defineProperty(globalThis, 'navigator', {
|
||||
value: dom.window.navigator,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
});
|
||||
Object.defineProperty(globalThis, 'HTMLElement', {
|
||||
value: dom.window.HTMLElement,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
});
|
||||
Object.defineProperty(globalThis, 'Node', {
|
||||
value: dom.window.Node,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
});
|
||||
globalThis.chrome = {
|
||||
storage: {
|
||||
local: {
|
||||
get: async () => ({}),
|
||||
set: async () => undefined,
|
||||
remove: async () => undefined,
|
||||
},
|
||||
},
|
||||
tabs: { query: async () => [] },
|
||||
scripting: { executeScript: async () => [] },
|
||||
runtime: { getURL: (path) => `chrome-extension://test/${path}` },
|
||||
windows: { create: async () => ({ id: 1 }) },
|
||||
};
|
||||
|
||||
return {
|
||||
dom,
|
||||
cleanup() {
|
||||
dom.window.close();
|
||||
globalThis.window = previous.window;
|
||||
globalThis.document = previous.document;
|
||||
Object.defineProperty(globalThis, 'navigator', {
|
||||
value: previous.navigator,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
});
|
||||
globalThis.chrome = previous.chrome;
|
||||
Object.defineProperty(globalThis, 'HTMLElement', {
|
||||
value: previous.HTMLElement,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
});
|
||||
Object.defineProperty(globalThis, 'Node', {
|
||||
value: previous.Node,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async function mountPopup() {
|
||||
const { dom, cleanup } = installPopupDom();
|
||||
const moduleUrl = new URL('../src/viewer/index.js?test=' + Date.now(), import.meta.url);
|
||||
await import(moduleUrl.href);
|
||||
return { dom, cleanup };
|
||||
}
|
||||
|
||||
describe('Viewer popup instructions', () => {
|
||||
it('renders the drafted instructions copy on mount with accessible labeling', async () => {
|
||||
const { dom, cleanup } = await mountPopup();
|
||||
try {
|
||||
const doc = dom.window.document;
|
||||
const region = doc.querySelector('.instructions-panel');
|
||||
const title = doc.getElementById('instructions-title');
|
||||
const toggle = doc.getElementById('instructions-toggle');
|
||||
const body = doc.getElementById('instructions-body');
|
||||
|
||||
if (!region) throw new Error('Instructions region missing');
|
||||
if (region.getAttribute('role') !== 'region') throw new Error('Instructions region missing role="region"');
|
||||
if (region.getAttribute('aria-labelledby') !== 'instructions-title') throw new Error('Instructions region missing aria-labelledby');
|
||||
if (!title || title.textContent !== 'How to use VidPlex') throw new Error('Instructions title not rendered');
|
||||
if (!toggle) throw new Error('Instructions toggle missing');
|
||||
if (toggle.getAttribute('aria-controls') !== 'instructions-body') throw new Error('Toggle missing aria-controls');
|
||||
if (toggle.getAttribute('aria-expanded') !== 'true') throw new Error('Toggle should start expanded');
|
||||
if (!body || body.hidden) throw new Error('Instructions body should be visible on mount');
|
||||
|
||||
const expectedTexts = [
|
||||
'Scan videos',
|
||||
'Click Find Videos to search the current browser window for videos.',
|
||||
'Review the list',
|
||||
'Check the popup list; each found video URL is clickable.',
|
||||
'Open the viewer',
|
||||
'Click Open Viewer to open the 2x2 grid player in a new window.',
|
||||
'Reset and rescan',
|
||||
'Click Clear to erase results and scan again.',
|
||||
'Warning: Browser pages, extension pages, and restricted frames can hide videos, so results may be incomplete.',
|
||||
'Learn more tooltip: Read the VidPlex README and audit notes.',
|
||||
];
|
||||
|
||||
for (const text of expectedTexts) {
|
||||
if (!doc.body.textContent.includes(text)) {
|
||||
throw new Error(`Missing instructions copy: ${text}`);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
cleanup();
|
||||
}
|
||||
});
|
||||
|
||||
it('toggles the instructions panel open and closed', async () => {
|
||||
const { dom, cleanup } = await mountPopup();
|
||||
try {
|
||||
const doc = dom.window.document;
|
||||
const toggle = doc.getElementById('instructions-toggle');
|
||||
const body = doc.getElementById('instructions-body');
|
||||
|
||||
if (!toggle || !body) throw new Error('Instructions controls missing');
|
||||
|
||||
toggle.click();
|
||||
if (toggle.getAttribute('aria-expanded') !== 'false') throw new Error('Toggle should collapse the instructions');
|
||||
if (!body.hidden) throw new Error('Instructions body should be hidden after collapse');
|
||||
if (toggle.textContent !== 'Show instructions') throw new Error('Collapsed label should switch to Show instructions');
|
||||
|
||||
toggle.click();
|
||||
if (toggle.getAttribute('aria-expanded') !== 'true') throw new Error('Toggle should expand the instructions');
|
||||
if (body.hidden) throw new Error('Instructions body should be visible after expanding');
|
||||
if (toggle.textContent !== 'Hide instructions') throw new Error('Expanded label should switch back to Hide instructions');
|
||||
} finally {
|
||||
cleanup();
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
import './schema.test.mjs';
|
||||
import './viewer_units.test.mjs';
|
||||
import './instructions_ui.test.mjs';
|
||||
import './data_flow.test.mjs';
|
||||
import './viewer_integration.test.mjs';
|
||||
import './config_validation.test.mjs';
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# Instructions UI audit
|
||||
|
||||
## Scope
|
||||
This audit covers the VidPlex popup instructions banner added in `src/viewer/index.html`, `src/viewer/index.css`, and `src/viewer/index.js`.
|
||||
|
||||
## What the UI now explains
|
||||
- How to scan the current page for videos
|
||||
- How to review clickable results
|
||||
- How to open the 2x2 viewer
|
||||
- How to clear and rescan
|
||||
- A caveat that browser pages, extension pages, and restricted frames may hide videos
|
||||
|
||||
## Accessibility checks
|
||||
- The instructions section uses `role="region"` and an accessible label
|
||||
- The collapse toggle is wired with `aria-expanded` and `aria-controls`
|
||||
- The body is hidden with the `hidden` attribute when collapsed
|
||||
|
||||
## UX notes
|
||||
- The panel is visible on mount so first-time users see the steps immediately
|
||||
- The toggle label changes between “Hide instructions” and “Show instructions”
|
||||
- The copy intentionally stays short so the popup remains readable in a narrow extension window
|
||||
|
||||
## Validation
|
||||
- Covered by `__tests__/instructions_ui.test.mjs`
|
||||
- Verified alongside the existing build/test flow in the parent implementation task
|
||||
@@ -0,0 +1,17 @@
|
||||
# Instructions UI copy
|
||||
|
||||
## Banner copy
|
||||
Quick start
|
||||
How to use VidPlex
|
||||
|
||||
## Steps
|
||||
1. Scan videos — Click Find Videos to search the current browser window for videos.
|
||||
2. Review the list — Check the popup list; each found video URL is clickable.
|
||||
3. Open the viewer — Click Open Viewer to open the 2x2 grid player in a new window.
|
||||
4. Reset and rescan — Click Clear to erase results and scan again.
|
||||
|
||||
## Warning copy
|
||||
Warning: Browser pages, extension pages, and restricted frames can hide videos, so results may be incomplete.
|
||||
|
||||
## Learn-more copy
|
||||
Learn more tooltip: Read the VidPlex README and audit notes.
|
||||
@@ -0,0 +1,50 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720" role="img" aria-label="VidPlex popup instructions preview">
|
||||
<defs>
|
||||
<style>
|
||||
.bg { fill: #ffffff; }
|
||||
.panel { fill: #f8fafc; stroke: #e2e8f0; stroke-width: 1; }
|
||||
.text { fill: #1a1a2e; font-family: -apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif; }
|
||||
.muted { fill: #64748b; }
|
||||
.accent { fill: #4361ee; }
|
||||
.warn { fill: #7c3aed; }
|
||||
.small { font-size: 12px; }
|
||||
.tiny { font-size: 11px; letter-spacing: .08em; font-weight: 700; }
|
||||
.title { font-size: 18px; font-weight: 600; }
|
||||
.h2 { font-size: 14px; font-weight: 600; }
|
||||
.step-title { font-size: 12px; font-weight: 600; }
|
||||
.body { font-size: 12px; fill: #475569; }
|
||||
.button-text { font-size: 12px; fill: #4361ee; }
|
||||
.primary-text { fill: #ffffff; font-size: 14px; }
|
||||
</style>
|
||||
</defs>
|
||||
|
||||
<rect class="bg" x="0" y="0" width="1280" height="720"/>
|
||||
<text class="text title" x="18" y="30">VidPlex</text>
|
||||
|
||||
<rect class="panel" x="17" y="50" width="1264" height="276" rx="10"/>
|
||||
<text class="text muted tiny" x="30" y="72">QUICK START</text>
|
||||
<text class="text h2" x="30" y="90">How to use VidPlex</text>
|
||||
|
||||
<rect x="1150" y="62" width="104" height="28" rx="8" fill="#ffffff" stroke="#e2e8f0"/>
|
||||
<text class="button-text" x="1165" y="80">Hide instructions</text>
|
||||
|
||||
<g class="text">
|
||||
<text class="step-title" x="48" y="126">Scan videos</text>
|
||||
<text class="body" x="48" y="144">Click Find Videos to search the current browser window for videos.</text>
|
||||
|
||||
<text class="step-title" x="48" y="176">Review the list</text>
|
||||
<text class="body" x="48" y="194">Check the popup list; each found video URL is clickable.</text>
|
||||
|
||||
<text class="step-title" x="48" y="226">Open the viewer</text>
|
||||
<text class="body" x="48" y="244">Click Open Viewer to open the 2x2 grid player in a new window.</text>
|
||||
|
||||
<text class="step-title" x="48" y="276">Reset and rescan</text>
|
||||
<text class="body" x="48" y="294">Click Clear to erase results and scan again.</text>
|
||||
|
||||
<text class="warn small" x="30" y="319">Warning: Browser pages, extension pages, and restricted frames can hide videos, so results may be incomplete.</text>
|
||||
<text class="body" x="30" y="348">Learn more tooltip: Read the VidPlex README and audit notes.</text>
|
||||
</g>
|
||||
|
||||
<rect x="17" y="339" width="1264" height="31" rx="8" fill="#4361ee"/>
|
||||
<text class="primary-text" x="561" y="359">Find Videos (all tabs)</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1,26 @@
|
||||
# Instructions UI design
|
||||
|
||||
## Placement
|
||||
The instructions banner sits above the primary action button so new users can read the steps before interacting with the popup.
|
||||
|
||||
## Structure
|
||||
- Short kicker: “Quick start”
|
||||
- Heading: “How to use VidPlex”
|
||||
- Expand/collapse toggle for users who want a smaller popup
|
||||
- Ordered list of the core tasks
|
||||
- One warning line for edge cases
|
||||
- One short learn-more line that points to the README and audit notes
|
||||
|
||||
## Copy strategy
|
||||
The microcopy avoids jargon and keeps each step tied to a visible control:
|
||||
- Find Videos
|
||||
- Open Viewer
|
||||
- Clear
|
||||
|
||||
## Accessibility strategy
|
||||
- A labelled region exposes the whole panel to assistive tech
|
||||
- The toggle reflects the current visibility state
|
||||
- The collapsed state removes the body from the layout entirely
|
||||
|
||||
## Notes
|
||||
This design intentionally favors clarity over density because extension popups are small and users typically need the instructions only once.
|
||||
@@ -0,0 +1,42 @@
|
||||
# Add user instructions to goon plugin UI
|
||||
|
||||
Branch: `feature/goon-instructions`
|
||||
|
||||
## Summary
|
||||
Adds an always-visible, collapsible quick-start panel to the VidPlex popup so users can understand the scan / review / open / clear flow without reading the README first.
|
||||
|
||||
## Links
|
||||
- Audit notes: [docs/instructions-audit.md](docs/instructions-audit.md)
|
||||
- Design notes: [docs/instructions-design.md](docs/instructions-design.md)
|
||||
- Copy deck: [docs/instructions-copy.md](docs/instructions-copy.md)
|
||||
- Preview render: [docs/instructions-demo.svg](docs/instructions-demo.svg)
|
||||
|
||||
## Testing
|
||||
- `npm run build`
|
||||
- `npm test`
|
||||
|
||||
Manual verification:
|
||||
1. Open the extension popup.
|
||||
2. Confirm the instructions banner renders expanded on mount.
|
||||
3. Click the toggle and confirm the panel collapses / expands and the label changes.
|
||||
4. Confirm the main Scan Videos button still works normally.
|
||||
|
||||
## Changed files
|
||||
- `src/viewer/index.html`
|
||||
- `src/viewer/index.css`
|
||||
- `src/viewer/index.js`
|
||||
- `__tests__/instructions_ui.test.mjs`
|
||||
- `__tests__/run.mjs`
|
||||
- `docs/instructions-audit.md`
|
||||
- `docs/instructions-design.md`
|
||||
- `docs/instructions-copy.md`
|
||||
- `docs/instructions-demo.svg`
|
||||
|
||||
## Acceptance criteria
|
||||
- A PR exists against `master`.
|
||||
- The PR description includes summary, links to the design/copy docs, a visual preview, testing steps, changed files, and acceptance criteria.
|
||||
- Reviewers are requested before handoff.
|
||||
|
||||
## Open questions / risks
|
||||
- The repo still has some pre-existing lint warnings outside this change.
|
||||
- The preview asset is an SVG render of the UI rather than a raster screenshot.
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "VidPlex",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.1",
|
||||
"description": "Find videos on any page and view them in a grid.",
|
||||
"permissions": [
|
||||
"storage",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vidplex",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.1",
|
||||
"private": true,
|
||||
"description": "Chrome extension: find videos on a page and view them in a grid.",
|
||||
"type": "module",
|
||||
|
||||
@@ -54,7 +54,7 @@ async function persistVideoRequest(tabId, url) {
|
||||
await chrome.storage.local.set({ [key]: arr });
|
||||
}
|
||||
} catch(e) {
|
||||
console.warn('[goon-bg] Failed to persist video request:', e && e.message ? e.message : e);
|
||||
console.warn('[vidplex-bg] Failed to persist video request:', e && e.message ? e.message : e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ async function collectAllVideoUrls() {
|
||||
try {
|
||||
all = await collectAllVideoUrls();
|
||||
} catch (e) {
|
||||
console.warn('[goon-bg] collectAllVideoUrls failed:', e && e.message ? e.message : e);
|
||||
console.warn('[vidplex-bg] collectAllVideoUrls failed:', e && e.message ? e.message : e);
|
||||
all = [];
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ async function injectFreshToken(url) {
|
||||
const fresh = await freshLiveForGroup(groupKey, false);
|
||||
const token = fresh ? extractRawQuery(fresh) : '';
|
||||
tokenCache.set(groupKey, token);
|
||||
console.log('[goon-bg] injectFreshToken for', groupKey, (token ? token.substring(0, 40) + '…' : '(none captured)'));
|
||||
console.log('[vidplex-bg] injectFreshToken for', groupKey, (token ? token.substring(0, 40) + '…' : '(none captured)'));
|
||||
return token ? url + '?' + token : url;
|
||||
} catch {
|
||||
return url;
|
||||
@@ -238,7 +238,7 @@ chrome.webRequest.onBeforeRequest.addListener(
|
||||
|
||||
// Log video-like requests from any host (CDN-agnostic).
|
||||
if (isVideoRequest(details.url)) {
|
||||
console.log('[goon-bg] webRequest: video request in tab', details.tabId, ':', details.url.substring(0, 180));
|
||||
console.log('[vidplex-bg] webRequest: video request in tab', details.tabId, ':', details.url.substring(0, 180));
|
||||
await persistVideoRequest(details.tabId, details.url);
|
||||
// Capture the provider referer for this CDN host from the source tab's
|
||||
// URL: the browser sends the referring page's URL as the Referer for a
|
||||
@@ -255,7 +255,7 @@ chrome.webRequest.onBeforeRequest.addListener(
|
||||
if (ref) {
|
||||
await persistReferer(host, ref);
|
||||
refererCapturedDomains.add(domain);
|
||||
console.log('[goon-bg] captured referer for', domain, '->', ref);
|
||||
console.log('[vidplex-bg] captured referer for', domain, '->', ref);
|
||||
}
|
||||
} catch {
|
||||
// Tab may have closed mid-stream; a later request from a live tab
|
||||
@@ -267,7 +267,7 @@ chrome.webRequest.onBeforeRequest.addListener(
|
||||
// Also capture HLS manifest URLs (original logic)
|
||||
if (!isHlsManifest(details.url)) return;
|
||||
|
||||
console.log('[goon-bg] webRequest: HLS manifest in tab', details.tabId, ':', details.url.substring(0, 120));
|
||||
console.log('[vidplex-bg] webRequest: HLS manifest in tab', details.tabId, ':', details.url.substring(0, 120));
|
||||
|
||||
const key = 'wr_manifests_' + details.tabId;
|
||||
try {
|
||||
@@ -278,7 +278,7 @@ chrome.webRequest.onBeforeRequest.addListener(
|
||||
await chrome.storage.local.set({ [key]: arr });
|
||||
}
|
||||
} catch(e) {
|
||||
console.warn('[goon-bg] Failed to persist webRequest manifest:', e && e.message ? e.message : e);
|
||||
console.warn('[vidplex-bg] Failed to persist webRequest manifest:', e && e.message ? e.message : e);
|
||||
}
|
||||
},
|
||||
{ urls: ['<all_urls>'] }
|
||||
@@ -393,7 +393,7 @@ async function persistReferer(host, referer) {
|
||||
map[domain] = { referer, at: now };
|
||||
await chrome.storage.local.set({ goon_referers: map });
|
||||
} catch (e) {
|
||||
console.warn('[goon-bg] persistReferer failed:', e && e.message ? e.message : e);
|
||||
console.warn('[vidplex-bg] persistReferer failed:', e && e.message ? e.message : e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,7 +429,7 @@ async function ensureRefererRule(host, referer) {
|
||||
if (!domain || !referer) return;
|
||||
const api = chrome.declarativeNetRequest;
|
||||
if (!api || typeof api.updateSessionRules !== 'function') {
|
||||
console.warn('[goon-bg] declarativeNetRequest unavailable; skipping referer rule');
|
||||
console.warn('[vidplex-bg] declarativeNetRequest unavailable; skipping referer rule');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -462,9 +462,9 @@ async function ensureRefererRule(host, referer) {
|
||||
}],
|
||||
});
|
||||
refererRuleInstalled.set(domain, referer);
|
||||
console.log('[goon-bg] DNR referer rule installed for', domain, '(' + ruleId + ')');
|
||||
console.log('[vidplex-bg] DNR referer rule installed for', domain, '(' + ruleId + ')');
|
||||
} catch (e) {
|
||||
console.warn('[goon-bg] ensureRefererRule failed:', e && e.message ? e.message : e);
|
||||
console.warn('[vidplex-bg] ensureRefererRule failed:', e && e.message ? e.message : e);
|
||||
}
|
||||
})().finally(() => { refererRuleLocks.set(domain, null); });
|
||||
refererRuleLocks.set(domain, run);
|
||||
@@ -532,7 +532,7 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
||||
const fresh = await freshLiveForGroup(groupKey, true);
|
||||
sendResponse({ ok: true, fresh, groupKey, changed: !!(fresh && fresh !== url) });
|
||||
} catch (e) {
|
||||
console.warn('[goon-bg] resolveFreshManifest failed:', e && e.message ? e.message : e);
|
||||
console.warn('[vidplex-bg] resolveFreshManifest failed:', e && e.message ? e.message : e);
|
||||
sendResponse({ ok: false, error: e && e.message ? e.message : String(e), groupKey });
|
||||
}
|
||||
}
|
||||
@@ -573,7 +573,7 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
||||
const proxyUrl = resolved.replace(/\+/g, '%2B');
|
||||
const resp = await fetch(proxyUrl);
|
||||
if (!resp.ok) {
|
||||
console.warn('[goon-bg] proxyFetch', resp.status, message.url.substring(0, 120));
|
||||
console.warn('[vidplex-bg] proxyFetch', resp.status, message.url.substring(0, 120));
|
||||
sendResponse({ ok: false, status: resp.status, error: 'HTTP ' + resp.status });
|
||||
return;
|
||||
}
|
||||
@@ -589,7 +589,7 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
||||
const base64 = btoa(binary);
|
||||
sendResponse({ ok: true, data: base64, mimeType: resp.headers.get('content-type') || '' });
|
||||
} catch(e) {
|
||||
console.warn('[goon-bg] proxyFetch failed:', e && e.message ? e.message : e);
|
||||
console.warn('[vidplex-bg] proxyFetch failed:', e && e.message ? e.message : e);
|
||||
sendResponse({ ok: false, error: e && e.message ? e.message : String(e) });
|
||||
}
|
||||
})();
|
||||
@@ -615,6 +615,6 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
||||
}
|
||||
|
||||
default:
|
||||
console.warn('[goon-plugin] Unknown message type:', message.type);
|
||||
console.warn('[vidplex-plugin] Unknown message type:', message.type);
|
||||
}
|
||||
});
|
||||
+10
-10
@@ -67,8 +67,8 @@
|
||||
source: source,
|
||||
timestamp: event.data.timestamp
|
||||
});
|
||||
console.log('[goon-plugin] Intercepted HLS manifest via', source, ':', url);
|
||||
console.log('[goon-plugin] Total intercepted manifests so far:', interceptedManifests.length);
|
||||
console.log('[vidplex-plugin] Intercepted HLS manifest via', source, ':', url);
|
||||
console.log('[vidplex-plugin] Total intercepted manifests so far:', interceptedManifests.length);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -106,21 +106,21 @@
|
||||
*/
|
||||
function getVideoData() {
|
||||
const poster = extractPoster();
|
||||
console.log('[goon-content] getVideoData called. Poster:', poster);
|
||||
console.log('[goon-content] Intercepted manifests count:', interceptedManifests.length);
|
||||
console.log('[vidplex-content] getVideoData called. Poster:', poster);
|
||||
console.log('[vidplex-content] Intercepted manifests count:', interceptedManifests.length);
|
||||
if (interceptedManifests.length > 0) {
|
||||
console.log('[goon-content] Manifest details:', JSON.stringify(interceptedManifests.map(m => ({ url: m.url, source: m.source }))));
|
||||
console.log('[vidplex-content] Manifest details:', JSON.stringify(interceptedManifests.map(m => ({ url: m.url, source: m.source }))));
|
||||
}
|
||||
|
||||
// DOM video scan (isolated world — can access DOM but not page JS)
|
||||
const videoElements = [];
|
||||
try {
|
||||
const videos = document.querySelectorAll('video');
|
||||
console.log('[goon-content] Found', videos.length, '<video> elements in DOM');
|
||||
console.log('[vidplex-content] Found', videos.length, '<video> elements in DOM');
|
||||
for (const video of videos) {
|
||||
const style = window.getComputedStyle(video);
|
||||
const isVisible = style.display !== 'none' && video.clientWidth > 0 && video.clientHeight > 0;
|
||||
console.log('[goon-content] Video:', {
|
||||
console.log('[vidplex-content] Video:', {
|
||||
src: (video.currentSrc || video.src || '').substring(0, 120),
|
||||
visible: isVisible,
|
||||
dimensions: video.clientWidth + 'x' + video.clientHeight,
|
||||
@@ -147,10 +147,10 @@
|
||||
}
|
||||
}
|
||||
} catch(e) { /* ignore DOM access errors */
|
||||
console.warn('[goon-content] DOM scan error:', e && e.message ? e.message : e);
|
||||
console.warn('[vidplex-content] DOM scan error:', e && e.message ? e.message : e);
|
||||
}
|
||||
|
||||
console.log('[goon-content] Visible video elements:', videoElements.length);
|
||||
console.log('[vidplex-content] Visible video elements:', videoElements.length);
|
||||
// Expose interceptor data globally so the popup's deep probe can read it.
|
||||
window.__goon_plugin_data = window.__goon_plugin_data || {
|
||||
manifests: [],
|
||||
@@ -183,5 +183,5 @@
|
||||
return false;
|
||||
});
|
||||
|
||||
console.log('[goon-plugin] Content script loaded. Interceptors injected at document_start.');
|
||||
console.log('[vidplex-plugin] Content script loaded. Interceptors injected at document_start.');
|
||||
})();
|
||||
@@ -32,6 +32,90 @@ h1 {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.instructions-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding: 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.instructions-header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.instructions-kicker {
|
||||
margin-bottom: 2px;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.instructions-panel h2 {
|
||||
font-size: 14px;
|
||||
line-height: 1.3;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.instructions-toggle {
|
||||
flex: 0 0 auto;
|
||||
padding: 6px 10px;
|
||||
font-size: 12px;
|
||||
background: transparent;
|
||||
color: var(--accent);
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.instructions-toggle:hover {
|
||||
background: #eef2ff;
|
||||
}
|
||||
|
||||
.instructions-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.instructions-body[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.instructions-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
padding-left: 18px;
|
||||
}
|
||||
|
||||
.instructions-list li {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.instructions-list strong {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.instructions-list span,
|
||||
.instructions-note,
|
||||
.instructions-learn-more {
|
||||
font-size: 12px;
|
||||
line-height: 1.45;
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.instructions-note {
|
||||
color: #7c3aed;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 8px 16px;
|
||||
background: var(--accent);
|
||||
|
||||
@@ -9,6 +9,48 @@
|
||||
<body>
|
||||
<div id="app">
|
||||
<h1>VidPlex</h1>
|
||||
<section class="instructions-panel" role="region" aria-labelledby="instructions-title">
|
||||
<div class="instructions-header">
|
||||
<div>
|
||||
<p class="instructions-kicker">Quick start</p>
|
||||
<h2 id="instructions-title">How to use VidPlex</h2>
|
||||
</div>
|
||||
<button
|
||||
id="instructions-toggle"
|
||||
type="button"
|
||||
class="instructions-toggle"
|
||||
aria-expanded="true"
|
||||
aria-controls="instructions-body"
|
||||
>
|
||||
Hide instructions
|
||||
</button>
|
||||
</div>
|
||||
<div id="instructions-body" class="instructions-body">
|
||||
<ol class="instructions-list">
|
||||
<li>
|
||||
<strong>Start your videos</strong>
|
||||
<span>Open the videos you want to play, one per tab, and begin their playback.</span>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Scan videos</strong>
|
||||
<span>Click <strong>Find Videos</strong> to search the current browser window's tabs for playing videos.</span>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Review the list</strong>
|
||||
<span>Check to make sure the right number of videos was found.</span>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Open the viewer</strong>
|
||||
<span>Click <strong>Open Viewer</strong> to open the grid player in a new window.</span>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Reset and rescan</strong>
|
||||
<span>Click <strong>Clear</strong> to erase results and scan again.</span>
|
||||
</li>
|
||||
</ol>
|
||||
<p class="instructions-note">Warning: Browser pages, extension pages, and restricted frames can hide videos, so results may be incomplete.</p>
|
||||
</div>
|
||||
</section>
|
||||
<button id="find-btn">Find Videos (all tabs)</button>
|
||||
<div id="video-list" class="video-list" style="display:none;"></div>
|
||||
<div id="status" class="status" style="min-height:16px;"></div>
|
||||
|
||||
+24
-8
@@ -10,8 +10,8 @@ const TAGGED_KEY = 'goon_tagged';
|
||||
// Set to true to enable verbose console output in the popup.
|
||||
const DEBUG = true; // TEMP: enabled for debugging — revert to false when done
|
||||
|
||||
function log(...args) { if (DEBUG) console.log('[goon]', ...args); }
|
||||
function warn(...args) { if (DEBUG) console.warn('[goon]', ...args); }
|
||||
function log(...args) { if (DEBUG) console.log('[vidplex]', ...args); }
|
||||
function warn(...args) { if (DEBUG) console.warn('[vidplex]', ...args); }
|
||||
|
||||
/** Log a message to the active tab's page console (visible to the user in DevTools). */
|
||||
async function logToPage(msg) {
|
||||
@@ -21,7 +21,7 @@ async function logToPage(msg) {
|
||||
if (!tab) return;
|
||||
await chrome.scripting.executeScript({
|
||||
target: { tabId: tab.id },
|
||||
func: (m) => { console.log('[goon-page]', m); },
|
||||
func: (m) => { console.log('[vidplex-page]', m); },
|
||||
args: [msg],
|
||||
});
|
||||
} catch { /* ignore — tab may have navigated away */ }
|
||||
@@ -34,10 +34,26 @@ const openBtn = document.getElementById('open-btn');
|
||||
const statusEl = document.getElementById('status');
|
||||
const listEl = document.getElementById('video-list');
|
||||
const btnRow = document.getElementById('btn-row');
|
||||
const instructionsToggle = document.getElementById('instructions-toggle');
|
||||
const instructionsBody = document.getElementById('instructions-body');
|
||||
|
||||
listEl.style.wordBreak = 'break-word';
|
||||
listEl.style.whiteSpace = 'pre-wrap';
|
||||
|
||||
function setInstructionsExpanded(expanded) {
|
||||
if (!instructionsToggle || !instructionsBody) return;
|
||||
instructionsBody.hidden = !expanded;
|
||||
instructionsToggle.setAttribute('aria-expanded', String(expanded));
|
||||
instructionsToggle.textContent = expanded ? 'Hide instructions' : 'Show instructions';
|
||||
}
|
||||
|
||||
if (instructionsToggle && instructionsBody) {
|
||||
setInstructionsExpanded(true);
|
||||
instructionsToggle.addEventListener('click', () => {
|
||||
setInstructionsExpanded(instructionsBody.hidden);
|
||||
});
|
||||
}
|
||||
|
||||
/* ======================================================================== */
|
||||
/* UI helpers */
|
||||
/* ======================================================================== */
|
||||
@@ -120,7 +136,7 @@ function m3u8DeepProbeFn() {
|
||||
|
||||
// DEBUG: Log probe activity to console
|
||||
function probeLog(...args) {
|
||||
try { console.log('[goon-probe]', ...args); } catch(e) {}
|
||||
try { console.log('[vidplex-probe]', ...args); } catch(e) {}
|
||||
}
|
||||
// NOTE: the probe is injected with chrome.scripting's `world: 'MAIN'`, so it
|
||||
// runs in the page's main world and can see page globals. `typeof chrome` is
|
||||
@@ -973,14 +989,14 @@ function makeVideoEntry(video, tabTitle, posterFromContent) {
|
||||
if (video.hlsManifest) {
|
||||
// Reject fake/invalid manifest paths before storing
|
||||
if (!isValidManifestUrl(video.hlsManifest)) {
|
||||
console.warn('[goon] Rejecting fake manifest URL:', video.hlsManifest.substring(0, 120));
|
||||
console.warn('[vidplex] Rejecting fake manifest URL:', video.hlsManifest.substring(0, 120));
|
||||
} else {
|
||||
entry.hlsManifest = video.hlsManifest;
|
||||
}
|
||||
}
|
||||
// Also validate src when it looks like a manifest URL (no hlsManifest set but src has .m3u8)
|
||||
if (!entry.hlsManifest && entry.src?.includes('.m3u8') && !isValidManifestUrl(entry.src)) {
|
||||
console.warn('[goon] Rejecting fake manifest URL from src:', entry.src.substring(0, 120));
|
||||
console.warn('[vidplex] Rejecting fake manifest URL from src:', entry.src.substring(0, 120));
|
||||
// Don't treat it as HLS — leave mediaType as-is (likely 'video' or unset)
|
||||
}
|
||||
return entry;
|
||||
@@ -1297,7 +1313,7 @@ findBtn.addEventListener('click', async () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
console.group('[goon-diag] HLS diagnostics');
|
||||
console.group('[vidplex-diag] HLS diagnostics');
|
||||
for (const line of diag) {
|
||||
console.log(line);
|
||||
}
|
||||
@@ -1305,7 +1321,7 @@ findBtn.addEventListener('click', async () => {
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn('[goon-diag] Diagnostic failed:', e.message);
|
||||
console.warn('[vidplex-diag] Diagnostic failed:', e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+23
-23
@@ -149,7 +149,7 @@ const panelsEl = document.getElementById('panels');
|
||||
// caused "Cannot create property 'levelDetails' on number".
|
||||
const fireSuccess = (data) => {
|
||||
if (!onSuccess) {
|
||||
console.warn('[goon-viewer] no onSuccess callback for', (url || '').substring(0, 100));
|
||||
console.warn('[vidplex-viewer] no onSuccess callback for', (url || '').substring(0, 100));
|
||||
return;
|
||||
}
|
||||
const tLoad = Date.now();
|
||||
@@ -161,11 +161,11 @@ const panelsEl = document.getElementById('panels');
|
||||
|
||||
const fireError = (code, text) => {
|
||||
if (!onError) {
|
||||
console.error('[goon-viewer] no onError callback; error:', text || code, (url || '').substring(0, 100));
|
||||
console.error('[vidplex-viewer] no onError callback; error:', text || code, (url || '').substring(0, 100));
|
||||
return;
|
||||
}
|
||||
stats.loading.end = Date.now();
|
||||
console.warn('[goon-viewer] HlsLoader error:', code, text, (url || '').substring(0, 100));
|
||||
console.warn('[vidplex-viewer] HlsLoader error:', code, text, (url || '').substring(0, 100));
|
||||
onError({ code: code || 0, text: text || '', url, headers: {}, data: null }, stats, context, null);
|
||||
};
|
||||
|
||||
@@ -177,7 +177,7 @@ const panelsEl = document.getElementById('panels');
|
||||
if (needProxy) {
|
||||
// Route through the service worker to bypass the CDN's CORS/Referer
|
||||
// restrictions. The SW adds the required Referer and returns base64.
|
||||
console.log('[goon-viewer] Proxying via SW:', (url || '').substring(0, 120));
|
||||
console.log('[vidplex-viewer] Proxying via SW:', (url || '').substring(0, 120));
|
||||
chrome.runtime.sendMessage({ type: 'GOON_PROXY_FETCH', url, referer: refererForUrl(url) }, (resp) => {
|
||||
if (self._aborted) return;
|
||||
const lastErr = chrome.runtime.lastError;
|
||||
@@ -253,7 +253,7 @@ HlsLoader.canSupportLoader = function () { return true; };
|
||||
}
|
||||
return null;
|
||||
} catch(e) {
|
||||
console.warn('[goon-viewer] proxyFetch failed for:', url.substring(0, 120), e && e.message ? e.message : e);
|
||||
console.warn('[vidplex-viewer] proxyFetch failed for:', url.substring(0, 120), e && e.message ? e.message : e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -744,14 +744,14 @@ function wireHlsEvents(hls, video, panel) {
|
||||
state.fpsDropCount++;
|
||||
state.lastEvent = 'FPS_DROP';
|
||||
state.lastActivity = Date.now();
|
||||
console.warn(`[goon-viewer] FPS drop: current=${data.currentFPS}, threshold=${data.thresholdFPS}`);
|
||||
console.warn(`[vidplex-viewer] FPS drop: current=${data.currentFPS}, threshold=${data.thresholdFPS}`);
|
||||
renderPanelState(video, panel);
|
||||
});
|
||||
|
||||
hls.on(HlsEvents.FPS_MAX_LEVEL_DROP, (_ev, data) => {
|
||||
state.lastEvent = 'FPS_MAX_LEVEL_DROP';
|
||||
state.lastActivity = Date.now();
|
||||
console.warn(`[goon-viewer] Max level dropped due to FPS: ${data.currentLevel}`);
|
||||
console.warn(`[vidplex-viewer] Max level dropped due to FPS: ${data.currentLevel}`);
|
||||
renderPanelState(video, panel);
|
||||
});
|
||||
|
||||
@@ -798,7 +798,7 @@ function wireHlsEvents(hls, video, panel) {
|
||||
// tab with no live source doesn't loop forever.
|
||||
if ((video.dataset.hlsRescans || '0') | 0 < 3) {
|
||||
video.dataset.hlsRescans = ((video.dataset.hlsRescans || '0') | 0) + 1;
|
||||
console.log('[goon-viewer] fatal NETWORK_ERROR → auto-rescan attempt #' + video.dataset.hlsRescans);
|
||||
console.log('[vidplex-viewer] fatal NETWORK_ERROR → auto-rescan attempt #' + video.dataset.hlsRescans);
|
||||
showError(panel, 'Refreshing stream…');
|
||||
rescanAndRetry(video, panel, video.dataset.hlsManifest || '');
|
||||
} else {
|
||||
@@ -976,7 +976,7 @@ function playHls(video, manifestUrl, panel) {
|
||||
// without CORS headers blocks extension-origin requests from the viewer page).
|
||||
const needProxy = needsProxy(manifestUrl);
|
||||
if (needProxy) {
|
||||
console.log('[goon-viewer] Manifest needs proxying via service worker');
|
||||
console.log('[vidplex-viewer] Manifest needs proxying via service worker');
|
||||
}
|
||||
|
||||
destroyHls(video);
|
||||
@@ -1017,7 +1017,7 @@ function playHls(video, manifestUrl, panel) {
|
||||
};
|
||||
|
||||
// Log the manifest URL being loaded for debugging (helps diagnose playback failures).
|
||||
console.log(`[goon-viewer] Loading HLS manifest:`, manifestUrl.substring(0, 200));
|
||||
console.log(`[vidplex-viewer] Loading HLS manifest:`, manifestUrl.substring(0, 200));
|
||||
|
||||
// Remember the manifest actually loaded so a later auto-rescan can retry from
|
||||
// the freshest token on the same video (the service worker keys off the path).
|
||||
@@ -1039,14 +1039,14 @@ function loadHlsJs() {
|
||||
}
|
||||
|
||||
const hldsSrc = chrome.runtime.getURL('hlds.js');
|
||||
console.log('[goon-viewer] Trying script src:', hldsSrc);
|
||||
console.log('[vidplex-viewer] Trying script src:', hldsSrc);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const script = document.createElement('script');
|
||||
script.src = hldsSrc;
|
||||
script.onload = () => {
|
||||
if (window.Hls && typeof window.Hls.isSupported === 'function') {
|
||||
console.log('[goon-viewer] hlds.js via script src OK, Hls.isSupported:', window.Hls.isSupported());
|
||||
console.log('[vidplex-viewer] hlds.js via script src OK, Hls.isSupported:', window.Hls.isSupported());
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error('hlds.js loaded but did not register global Hls'));
|
||||
@@ -1076,12 +1076,12 @@ function loadHlsJs() {
|
||||
try {
|
||||
const resp = await chrome.runtime.sendMessage({ type: 'GOON_RESOLVE_MANIFEST', url: storedUrl });
|
||||
if (resp && resp.ok && resp.changed && resp.fresh) {
|
||||
console.log('[goon-viewer] resolved fresh manifest for', (resp.groupKey || '?'),
|
||||
console.log('[vidplex-viewer] resolved fresh manifest for', (resp.groupKey || '?'),
|
||||
'→', (resp.fresh || '').substring(0, 100));
|
||||
return resp.fresh;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[goon-viewer] resolveFreshManifest failed:', e && e.message ? e.message : e);
|
||||
console.warn('[vidplex-viewer] resolveFreshManifest failed:', e && e.message ? e.message : e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -1097,11 +1097,11 @@ function loadHlsJs() {
|
||||
const fresh = await resolveFreshManifest(originalUrl);
|
||||
if (!fresh) {
|
||||
showError(panel, 'Stream expired & no live source — reload the source tab, then re-open viewer.');
|
||||
console.warn('[goon-viewer] rescan gave up: no fresh manifest for', (originalUrl || '').substring(0, 100));
|
||||
console.warn('[vidplex-viewer] rescan gave up: no fresh manifest for', (originalUrl || '').substring(0, 100));
|
||||
return false;
|
||||
}
|
||||
if (panel) removeErrorOverlay(panel);
|
||||
console.log('[goon-viewer] retrying with fresh manifest:', fresh.substring(0, 120));
|
||||
console.log('[vidplex-viewer] retrying with fresh manifest:', fresh.substring(0, 120));
|
||||
playHls(video, fresh, panel);
|
||||
return true;
|
||||
}
|
||||
@@ -1147,7 +1147,7 @@ function createPanel(entry, tag) {
|
||||
}
|
||||
// mediaType says HLS but we have no manifest URL — fall through to native playback.
|
||||
// On Safari this may still work for .m3u8; on Chrome it will fail.
|
||||
console.warn('[goon-viewer] HLS entry missing manifest URL, src:', src);
|
||||
console.warn('[vidplex-viewer] HLS entry missing manifest URL, src:', src);
|
||||
}
|
||||
|
||||
video.src = src;
|
||||
@@ -1182,13 +1182,13 @@ async function init() {
|
||||
document.body.insertBefore(overlay, document.body.firstChild);
|
||||
|
||||
// === DIAGNOSTIC: Check storage + CORS ===
|
||||
console.log('[goon-viewer] Viewer ID:', id, 'Grid:', gridN + 'x' + gridN);
|
||||
console.log('[goon-viewer] Raw stored data:', JSON.stringify(videoUrls));
|
||||
console.log('[vidplex-viewer] Viewer ID:', id, 'Grid:', gridN + 'x' + gridN);
|
||||
console.log('[vidplex-viewer] Raw stored data:', JSON.stringify(videoUrls));
|
||||
|
||||
if (videoUrls.length > 0) {
|
||||
for (const entry of videoUrls) {
|
||||
const src = (entry.src || '').substring(0, 120);
|
||||
console.log('[goon-viewer] Entry:', {
|
||||
console.log('[vidplex-viewer] Entry:', {
|
||||
src: src,
|
||||
mediaType: entry.mediaType,
|
||||
hlsManifest: (entry.hlsManifest || '').substring(0, 120),
|
||||
@@ -1213,7 +1213,7 @@ async function init() {
|
||||
for (const url of [...new Set(urlsToTest)]) {
|
||||
const corsOk = await corsCheck(url);
|
||||
if (!corsOk) blockedHosts.add(registrableDomainOf(hostOfUrl(url)));
|
||||
console.log('[goon-viewer] CORS', corsOk ? 'OK' : 'BLOCKED:', url.substring(0, 120));
|
||||
console.log('[vidplex-viewer] CORS', corsOk ? 'OK' : 'BLOCKED:', url.substring(0, 120));
|
||||
}
|
||||
if (blockedHosts.size > 0) {
|
||||
for (const h of blockedHosts) if (h) proxyHosts.add(h);
|
||||
@@ -1222,9 +1222,9 @@ async function init() {
|
||||
|
||||
// Report whether any URL needs proxying (referer-protected host).
|
||||
const anyNeedsProxy = urlsNeedProxy(urlsToTest);
|
||||
console.log('[goon-viewer] Proxy required:', anyNeedsProxy);
|
||||
console.log('[vidplex-viewer] Proxy required:', anyNeedsProxy);
|
||||
} else {
|
||||
console.warn('[goon-viewer] No video entries in storage for ID:', id, '— data may have been cleared or never saved');
|
||||
console.warn('[vidplex-viewer] No video entries in storage for ID:', id, '— data may have been cleared or never saved');
|
||||
}
|
||||
|
||||
overlay.textContent = `Found ${videoUrls.length} video URL(s) in ${gridN}x${gridN} grid`;
|
||||
|
||||
Reference in new issue
Block a user