Merge pull request #1130 from PR0M3TH3AN/codex/create-documentation-for-playback-fallback

Add playback fallback documentation and README link
This commit is contained in:
thePR0M3TH3AN authored and GitHub committed 2026-01-07 20:02:27 -05:00
commit 16052cc0fa
2 files changed
+95

No files matched your search

+1
View File
@@ -53,6 +53,7 @@ Hosted URLs remain the preferred playback path, and you can still add a magnet o
2. **WebTorrent fallback**: If the URL probe fails or returns an error status, bitvid falls back to WebTorrent using the raw magnet. The helpers append HTTPS `ws=`/`xs=` hints so peers seed quickly.
3. **Safety checks**: Magnets are decoded with `safeDecodeMagnet()` and normalized via `normalizeAndAugmentMagnet()` before reaching WebTorrent. Trackers remain WSS-only to satisfy browser constraints.
4. **Operator playbook**: If a deployment causes playback regressions, flip the relevant feature flags back to their default values in `js/constants.js` and redeploy. Capture the rollback steps in AGENTS.md and the PR description so the Main channel stays stable.
5. **Deep dive**: See [`docs/playback-fallback.md`](docs/playback-fallback.md) for the call flow into `playbackService`, magnet normalization details, and fallback hand-off points.
### Watch history & view counts
+94
View File
@@ -0,0 +1,94 @@
# 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
1. `bitvidApp.playVideoWithFallback({ url, magnet })` trims inputs, ensures the video modal is ready, and constructs a playback session via `playbackService.createSession(...)`.
2. The session (from `js/services/playbackService.js`) derives a canonical magnet payload using `deriveTorrentPlaybackConfig` (from `js/playbackUtils.js`).
3. Playback starts with the hosted URL when `URL_FIRST_ENABLED` is true and a URL is available; otherwise, it goes directly to torrent playback.
4. If URL playback stalls or errors, the session triggers `playViaWebTorrent` with 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()` calls `probeUrl(url)` to check availability and decides whether to attempt direct playback.
- **Hosted URL playback**
- On a successful probe, the session assigns `video.src = url` and calls `video.play()`.
- It registers watchdogs (`registerUrlPlaybackWatchdogs`) to detect stalls, errors, or aborts.
- **Fallback to WebTorrent**
- If watchdogs trigger or direct playback fails, `PlaybackSession` calls `playViaWebTorrent(magnet, { fallbackMagnet, urlList })`.
- `urlList` includes the hosted URL (if present) so it becomes a WebTorrent web seed.
## Magnet helpers and normalization
`playbackService` doesn’t manipulate magnets directly. It relies on `deriveTorrentPlaybackConfig` in `js/playbackUtils.js`, which does the following:
- Calls `safeDecodeMagnet()` from `js/magnetUtils.js` so URL-encoded magnets become raw `magnet:?xt=urn:btih:...` strings.
- Accepts bare info hashes and promotes them to full magnet URIs when needed.
- Runs `normalizeAndAugmentMagnet()` (from `js/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.
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_TRACKERS` in `js/constants.js` is the canonical browser-safe tracker list. `normalizeAndAugmentMagnet()` merges this list into the magnet if trackers are missing.
- `normalizeAndAugmentMagnet()` also applies `ws=` web seed hints (from the hosted URL) and `xs=` torrent hints (from user input), enforcing HTTPS when appropriate.
- `URL_FIRST_ENABLED` (also in `js/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()`:
1. **URL probe fails**: `probeUrl(url)` reports a bad outcome → session skips direct playback and goes straight to WebTorrent.
2. **Playback errors**: `video.play()` throws or fires `error` → session triggers the fallback.
3. **Playback stalls**: the watchdog timer (`registerUrlPlaybackWatchdogs`) detects `stalled`, `abort`, or no progress → session triggers the fallback.
4. **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
```mermaid
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`) that `bitvidApp` listens to for UI updates.
- `bitvidApp.playVideoWithFallback` keeps the current video card and modal state in sync with the normalized magnet values so copy actions and stats reflect the actual playback payload.