- Move from root publishing to clean `dist/` directory - Create `scripts/build-dist.mjs` to orchestrate build and copy assets - Update `package.json` build script - Update `netlify.toml` to publish `dist/` - Ignore `dist/` in `.gitignore` Co-authored-by: PR0M3TH3AN <[email protected]>
5.4 KiB
URL-first playback fallback orchestration
This document explains how bitvidApp.playVideoWithFallback in js/app.js coordinates hosted URL playback first and falls back to WebTorrent when needed. It also covers the supporting helpers in js/services/playbackService.js, js/playbackUtils.js, and js/magnetUtils.js, including how tracker lists and ws=/xs= hints are applied.
High-level flow
bitvidApp.playVideoWithFallback({ url, magnet })trims inputs, ensures the video modal is ready, and constructs a playback session viaplaybackService.createSession(...).- The session (from
js/services/playbackService.js) derives a canonical magnet payload usingderiveTorrentPlaybackConfig(fromjs/playbackUtils.js). - Playback starts with the hosted URL when
URL_FIRST_ENABLEDis true and a URL is available; otherwise, it goes directly to torrent playback. - If URL playback stalls or errors, the session triggers
playViaWebTorrentwith the normalized magnet and optional web seed hints.
Call flow into playbackService
bitvidApp.playVideoWithFallback performs UI preparation and delegates the decision-making to a PlaybackSession:
- Session setup
playbackService.createSession({ url, magnet, videoElement, probeUrl, playViaWebTorrent, ... })- The session captures
url,magnet, and a request signature to de-duplicate duplicate calls.
- Hosted URL probe
PlaybackSession.execute()callsprobeUrl(url)to check availability and decides whether to attempt direct playback.
- Hosted URL playback
- On a successful probe, the session assigns
video.src = urland callsvideo.play(). - It registers watchdogs (
registerUrlPlaybackWatchdogs) to detect stalls, errors, or aborts.
- On a successful probe, the session assigns
- Fallback to WebTorrent
- If watchdogs trigger or direct playback fails,
PlaybackSessioncallsplayViaWebTorrent(magnet, { fallbackMagnet, urlList }). urlListincludes the hosted URL (if present) so it becomes a WebTorrent web seed.
- If watchdogs trigger or direct playback fails,
Magnet helpers and normalization
playbackService doesn’t manipulate magnets directly. It relies on deriveTorrentPlaybackConfig in js/playbackUtils.js, which does the following:
- Calls
safeDecodeMagnet()fromjs/magnetUtils.jsso URL-encoded magnets become rawmagnet:?xt=urn:btih:...strings. - Accepts bare info hashes and promotes them to full magnet URIs when needed.
- Runs
normalizeAndAugmentMagnet()(fromjs/magnetUtils.js) to:- Append
ws=web seed hints when a hosted URL is present. - Append
xs=torrent hints when supplied. - Ensure WSS-only tracker URLs are present.
- Append
The result is a canonical magnet used by WebTorrent, plus an optional fallbackMagnet that preserves the original raw input if normalization changed it.
Tracker lists, ws/xs hints, and constants
Tracker and hint behavior is centralized in js/constants.js and js/magnetUtils.js:
WSS_TRACKERSinjs/constants.jsis the canonical browser-safe tracker list.normalizeAndAugmentMagnet()merges this list into the magnet if trackers are missing.normalizeAndAugmentMagnet()also appliesws=web seed hints (from the hosted URL) andxs=torrent hints (from user input), enforcing HTTPS when appropriate.URL_FIRST_ENABLED(also injs/constants.js) controls whether the hosted URL probe is attempted before torrent fallback.
Failure detection and hand-off points
The fallback hand-off happens in these places inside PlaybackSession.execute():
- URL probe fails:
probeUrl(url)reports a bad outcome → session skips direct playback and goes straight to WebTorrent. - Playback errors:
video.play()throws or fireserror→ session triggers the fallback. - Playback stalls: the watchdog timer (
registerUrlPlaybackWatchdogs) detectsstalled,abort, or no progress → session triggers the fallback. - Autoplay blocked: the browser blocks autoplay → session waits for a user gesture, re-enables watchdogs, and only falls back if playback still fails.
Sequence diagram
sequenceDiagram
participant App as bitvidApp (js/app.js)
participant Service as PlaybackService (js/services/playbackService.js)
participant Session as PlaybackSession
participant Video as HTMLVideoElement
participant Magnet as magnetUtils/playbackUtils
App->>Service: createSession({ url, magnet, videoElement, ... })
Service->>Session: new PlaybackSession(...)
Session->>Magnet: deriveTorrentPlaybackConfig()
Magnet-->>Session: normalized magnet + fallbackMagnet
Session->>App: showModalWithPoster()
Session->>App: probeUrl(url)
alt URL probe ok + URL_FIRST_ENABLED
Session->>Video: src=url; play()
Session->>Session: registerUrlPlaybackWatchdogs()
alt hosted playback succeeds
Session-->>App: sourcechange("url")
else watchdog/error triggers
Session->>App: playViaWebTorrent(magnet, { urlList })
Session-->>App: sourcechange("torrent")
end
else URL probe fails or URL-first disabled
Session->>App: playViaWebTorrent(magnet, { urlList })
Session-->>App: sourcechange("torrent")
end
Implementation notes
- The playback session is responsible for cleanup and emits events (
status,sourcechange,error,finished) thatbitvidApplistens to for UI updates. bitvidApp.playVideoWithFallbackkeeps the current video card and modal state in sync with the normalized magnet values so copy actions and stats reflect the actual playback payload.