From e022f0f633d8c0084372f92976fccc9957d670bd Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Sun, 1 Feb 2026 11:03:19 -0500 Subject: [PATCH 1/5] Handle web seed peers in torrent probe --- js/webtorrent.js | 67 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/js/webtorrent.js b/js/webtorrent.js index 447582f7..47f8eec6 100644 --- a/js/webtorrent.js +++ b/js/webtorrent.js @@ -345,16 +345,53 @@ export class TorrentClient { return; } - const settleHealthy = () => { - const peers = Math.max(1, Math.floor(normalizeNumber(torrent?.numPeers, 1))); - finalize({ healthy: true, peers, reason: "peer" }); + let webSeedCount = 0; + + const getWebSeedCount = () => { + if (torrent?.wires?.length) { + const wireCount = torrent.wires.filter( + (wire) => wire?.type === "webSeed" + ).length; + return Math.max(webSeedCount, wireCount); + } + return webSeedCount; }; - torrent.once("wire", settleHealthy); + const getPeerCounts = () => { + const regularPeers = Math.max( + 0, + Math.floor(normalizeNumber(torrent?.numPeers, 0)) + ); + const webSeeds = getWebSeedCount(); + return { + regularPeers, + webSeeds, + totalPeers: regularPeers + webSeeds, + }; + }; + + const settleHealthy = (counts = getPeerCounts()) => { + const peers = Math.max(1, counts.totalPeers); + const webseedOnly = counts.regularPeers === 0 && counts.webSeeds > 0; + finalize({ + healthy: true, + peers, + reason: webseedOnly ? "webseed" : "peer", + webseedOnly, + }); + }; + + torrent.on("wire", (wire) => { + if (wire?.type === "webSeed") { + webSeedCount += 1; + } + settleHealthy(); + }); torrent.once("error", (err) => { - const peers = Math.max(0, Math.floor(normalizeNumber(torrent?.numPeers, 0))); - const webseedOnly = peers === 0 && hasWebSeed; + const counts = getPeerCounts(); + const webseedOnly = counts.regularPeers === 0 && counts.webSeeds > 0; + const peers = Math.max(0, counts.totalPeers); finalize({ healthy: webseedOnly, reason: webseedOnly ? "webseed" : "error", @@ -366,8 +403,9 @@ export class TorrentClient { if (safeTimeout > 0) { timeoutId = setTimeout(() => { - const peers = Math.max(0, Math.floor(normalizeNumber(torrent?.numPeers, 0))); - const webseedOnly = peers === 0 && hasWebSeed; + const counts = getPeerCounts(); + const webseedOnly = counts.regularPeers === 0 && counts.webSeeds > 0; + const peers = Math.max(0, counts.totalPeers); finalize({ healthy: webseedOnly, peers, @@ -386,9 +424,16 @@ export class TorrentClient { if (!torrent || settled) { return; } - const peers = Math.max(0, Math.floor(normalizeNumber(torrent.numPeers, 0))); - if (peers > 0) { - finalize({ healthy: true, peers, reason: "peer" }); + const counts = getPeerCounts(); + if (counts.totalPeers > 0) { + const webseedOnly = + counts.regularPeers === 0 && counts.webSeeds > 0; + finalize({ + healthy: true, + peers: counts.totalPeers, + reason: webseedOnly ? "webseed" : "peer", + webseedOnly, + }); } }, pollInterval); }, pollInterval); From 31187736211dd3fe0137928d5efb3c88f8fc76f9 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Sun, 1 Feb 2026 11:05:30 -0500 Subject: [PATCH 2/5] Add explicit web seeds to torrent streams --- js/webtorrent.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/js/webtorrent.js b/js/webtorrent.js index 47f8eec6..e3b07b04 100644 --- a/js/webtorrent.js +++ b/js/webtorrent.js @@ -1035,6 +1035,15 @@ export class TorrentClient { chromeOptions.urlList = candidateUrls; } + const addExplicitWebSeeds = (torrent) => { + if (!candidateUrls.length || typeof torrent?.addWebSeed !== "function") { + return; + } + candidateUrls.forEach((url) => { + torrent.addWebSeed(url); + }); + }; + return new Promise((resolve, reject) => { // 3) Add the torrent to the client and handle accordingly. if (isFirefoxBrowser) { @@ -1044,6 +1053,7 @@ export class TorrentClient { { ...chromeOptions, maxWebConns: 4 }, (torrent) => { this.log("Torrent added (Firefox path):", torrent.name); + addExplicitWebSeeds(torrent); this.handleFirefoxTorrent(torrent, videoElement, resolve, reject); } ); @@ -1051,6 +1061,7 @@ export class TorrentClient { this.log("Starting torrent download (Chrome path)"); this.client.add(effectiveMagnetURI, chromeOptions, (torrent) => { this.log("Torrent added (Chrome path):", torrent.name); + addExplicitWebSeeds(torrent); this.handleChromeTorrent(torrent, videoElement, resolve, reject); }); } From 060e87dada51175ceffed6e79277733c898ec680 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 1 Feb 2026 16:12:13 +0000 Subject: [PATCH 3/5] docs: align development setup guide with build reality - Update `CONTRIBUTING.md` to detail the behavior of `npm run build`, specifically that it executes `scripts/build-dist.mjs` and copies an allowlist of files/directories to `dist/`. - Validate project health via `npm run lint`, `scripts/agent/validate-events.mjs`, and unit tests. - Confirm `README.md` correctly links to `CONTRIBUTING.md` for detailed developer setup. Co-authored-by: PR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 265b42d9..1cd631b4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -114,6 +114,7 @@ To set up the project locally: ``` (This runs `npm run build:css` to generate Tailwind styles.) + This command executes `scripts/build-dist.mjs` to prepare the `dist/` directory for deployment. It copies an explicit allowlist of files (including `index.html`, `_headers`, `_redirects`) and directories (including `assets`, `js`, `css`, `config`) to `dist/`, excluding development artifacts like `scripts/` and `issues/`. 3. **Run Tests**: From 80dd5dcade14baf5e157b3703fa6dee668be3455 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 1 Feb 2026 16:19:16 +0000 Subject: [PATCH 4/5] fix(test): add debug logging and increase timeout in webtorrent regression test - Increase `timeoutMs` in `tests/webtorrent-regression.test.mjs` from 50ms to 200ms to reduce flakiness in CI environments. - Add debug logging to `js/webtorrent.js` (guarded by `NODE_ENV === 'test'`) to inspect `probePeers` inputs and `client.add` errors, helping diagnose why `webseedOnly` detection might fail in CI. - Log failure details in `tests/webtorrent-regression.test.mjs` if assertion fails. Co-authored-by: PR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> --- js/webtorrent.js | 12 ++++++++++++ tests/webtorrent-regression.test.mjs | 6 +++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/js/webtorrent.js b/js/webtorrent.js index 447582f7..c8a35f00 100644 --- a/js/webtorrent.js +++ b/js/webtorrent.js @@ -207,6 +207,11 @@ export class TorrentClient { magnetURI, { timeoutMs = 8000, maxWebConns = 2, polls = 2, urlList = [] } = {} ) { + // Debug log for CI investigation + if (typeof process !== "undefined" && process.env.NODE_ENV === "test") { + console.log(`[probePeers] magnetURI=${magnetURI?.substring(0, 20)}... urlList=${JSON.stringify(urlList)}`); + } + const magnet = stripXsParameter(magnetURI); if (!magnet) { @@ -228,6 +233,10 @@ export class TorrentClient { const hasMagnetWebSeed = magnet.includes("ws=") || magnet.includes("webSeed="); const hasExplicitWebSeed = Array.isArray(urlList) && urlList.length > 0; + if (typeof process !== "undefined" && process.env.NODE_ENV === "test") { + console.log(`[probePeers] hasMagnetWebSeed=${hasMagnetWebSeed} hasExplicitWebSeed=${hasExplicitWebSeed}`); + } + if (hasExplicitWebSeed) { const wsParams = urlList .map((url) => `ws=${encodeURIComponent(url)}`) @@ -336,6 +345,9 @@ export class TorrentClient { } torrent = client.add(augmentedMagnet, addOptions); } catch (err) { + if (typeof process !== "undefined" && process.env.NODE_ENV === "test") { + console.log(`[probePeers] client.add threw:`, err); + } finalize({ reason: "error", error: toError(err), diff --git a/tests/webtorrent-regression.test.mjs b/tests/webtorrent-regression.test.mjs index 737d896b..39743de6 100644 --- a/tests/webtorrent-regression.test.mjs +++ b/tests/webtorrent-regression.test.mjs @@ -62,10 +62,14 @@ describe("WebTorrent Regression Tests", () => { const webSeedUrl = "http://localhost:8080/video.mp4"; const result = await client.probePeers(magnet, { - timeoutMs: 50, // Short timeout + timeoutMs: 200, // Short timeout (but safe for CI) urlList: [webSeedUrl] }); + if (!result.webseedOnly) { + console.log("Failed result:", result); + } + assert.strictEqual(result.webseedOnly, true, "Should detect webseed only scenario"); assert.strictEqual(result.healthy, true, "Should be healthy due to webseed"); assert.strictEqual(result.reason, "webseed", "Reason should be 'webseed'"); From ac23475b4a3d43a82e34d6176a85f215a6e11992 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 1 Feb 2026 16:25:04 +0000 Subject: [PATCH 5/5] fix(ci): instrument webtorrent logic to debug flaky regression test - Add detailed logging inside `js/webtorrent.js` (guarded by `NODE_ENV=test`) to inspect the state of `peers`, `hasWebSeed`, and `webseedOnly` when a probe times out. - This is intended to diagnose why `webseedOnly` evaluates to false in CI despite logs indicating `hasExplicitWebSeed` is true. Co-authored-by: PR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> --- js/webtorrent.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/js/webtorrent.js b/js/webtorrent.js index c8a35f00..4dee682a 100644 --- a/js/webtorrent.js +++ b/js/webtorrent.js @@ -380,6 +380,9 @@ export class TorrentClient { timeoutId = setTimeout(() => { const peers = Math.max(0, Math.floor(normalizeNumber(torrent?.numPeers, 0))); const webseedOnly = peers === 0 && hasWebSeed; + if (typeof process !== "undefined" && process.env.NODE_ENV === "test" && !webseedOnly && hasWebSeed) { + console.log(`[probePeers:timeout] logic check: peers=${peers} hasWebSeed=${hasWebSeed} webseedOnly=${webseedOnly}`); + } finalize({ healthy: webseedOnly, peers,