From ef2e48912d25a1c08e2a376e0d688ab28b39e130 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Sat, 11 Jul 2026 19:04:14 -0400 Subject: [PATCH] fix(playback): P2P peer discovery for Blossom videos + forced-torrent URL fallback (#30) Two torrent-path robustness fixes surfaced while testing WebTorrent peering: - streamVideo now sets announce: [...WSS_TRACKERS]. A .torrent-buffer add (Blossom companion piece-map) has an EMPTY embedded announce list, so without this it reached no tracker, found no WebRTC peers, and streamed webseed-only (looked like a stuck '1 peer'). WebTorrent merges these with any trackers already on the source. - A forced-torrent playback now falls back to the hosted URL when the torrent DEFINITIVELY fails (e.g. a transient companion-lookup failure under relay congestion, or a dead swarm) instead of hard-erroring 'No playable source found'. Only triggers on real failure, not a slow swarm. Rollback noted inline. Co-Authored-By: Claude Opus 4.8 --- js/services/playbackService.js | 15 +++++++++++++-- js/webtorrent.js | 12 +++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/js/services/playbackService.js b/js/services/playbackService.js index c927ed82..e6b74bc6 100644 --- a/js/services/playbackService.js +++ b/js/services/playbackService.js @@ -1288,8 +1288,19 @@ class PlaybackSession extends SimpleEventEmitter { } } - // Fallback to URL - if (httpsUrl && forcedSource !== "torrent") { + // Fallback to URL. Even when P2P was explicitly forced, a hosted URL is a + // better outcome than a hard "No playable source found" if the torrent + // DEFINITIVELY failed (e.g. a transient companion-lookup failure or a dead + // swarm). The torrent-first attempt above already ran — and, when there was + // no URL plan B, waited indefinitely — so we only reach here on real + // failure, not on a slow-but-working swarm. + // Rollback: restore `&& forcedSource !== "torrent"` to make forced P2P hard-fail. + if (httpsUrl) { + if (forcedSource === "torrent") { + this.service.log( + "[playVideoWithFallback] Forced torrent failed; falling back to the hosted URL." + ); + } const urlResult = await attemptHostedPlayback(); if (urlResult && urlResult.source === "url") { return urlResult; diff --git a/js/webtorrent.js b/js/webtorrent.js index 87c04fe8..5264177c 100644 --- a/js/webtorrent.js +++ b/js/webtorrent.js @@ -941,7 +941,17 @@ export class TorrentClient { // Cap peer connections for the streaming torrent too. 30 is plenty to // saturate playback bandwidth while avoiding the WebRTC-handshake storm // that can peg the main thread (WebTorrent's default is 55). - const chromeOptions = { strategy: "sequential", maxConns: 30 }; + // Announce to the WSS trackers explicitly. The magnet path already carries + // trackers (playbackUtils augments it), but a .torrent-buffer add + // (torrentFileBytes, from a Blossom video's companion event) has an EMPTY + // embedded announce list — without this it would reach no tracker, discover + // no WebRTC peers, and stream from the webseed only (looks like "1 peer"). + // WebTorrent merges this with any trackers already on the source, deduped. + const chromeOptions = { + strategy: "sequential", + maxConns: 30, + announce: [...WSS_TRACKERS], + }; /** * CRITICAL: Passing `urlList` ensures the client can stream from the webseed. * Without this, videos with 0 P2P peers will fail to play even if a valid