mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
playback: fix false "No playable source found." on URL-only videos
A bitvid (kind-30078) video with a perfectly playable hosted URL (verified: archive.org 200 video/mp4 with byte ranges) failed with "No playable source found." — the video element's src was never even set. Root cause: the hosted-URL probe (fetch HEAD, mode:no-cors) runs BEFORE src is assigned, inside the playback-start window — but URL_PROBE_TIMEOUT_MS (4s) is LONGER than PLAYBACK_START_TIMEOUT (3s). A slow no-cors HEAD (archive.org, and any host that doesn't answer HEAD fast) consumed the whole start budget, the withTimeout wrapper aborted the attempt, and the URL was never loaded. A `<video>` element plays cross-origin URLs WITHOUT CORS anyway, so the fetch probe was both unnecessary and actively harmful here. Fix: - Skip the probe entirely when there's no magnet (URL-only) — nothing to fail over to, so the video element loads the URL directly. This is the reported case; verified live: the video now plays (readyState 4, currentTime advancing). - An ambiguous/error probe no longer VETOES the URL (only a definitively-read "bad" status deprioritizes it, and even then only when a magnet fallback exists) — the video element + watchdogs are the real arbiter. Tests: spec-corrected the always-probe assertion to a dual-source case + added a URL-only skip-probe test (tests/services/playbackService.test.mjs). 17 pass. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
1 parent
5a7481e30e
commit
68bdee8da5
2 files changed
+88
-7
No files matched your search
@@ -988,15 +988,35 @@ class PlaybackSession extends SimpleEventEmitter {
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
const probeResult = await this.service.probeHostedUrl({
|
||||
url: candidateUrl,
|
||||
magnet: this.trimmedMagnet,
|
||||
probeUrl,
|
||||
});
|
||||
// The probe (fetch HEAD) only helps DECIDE whether to fail over to P2P
|
||||
// fast. When the URL is the only source there's nothing to fail over
|
||||
// to — and the probe's timeout (URL_PROBE_TIMEOUT_MS, 4s) is LONGER than
|
||||
// the playback-start window (PLAYBACK_START_TIMEOUT, 3s), so a slow
|
||||
// no-cors HEAD (e.g. archive.org) would consume the whole budget and the
|
||||
// attempt would time out before `src` is ever set → a false "No playable
|
||||
// source found." So skip the probe when there's no magnet and let the
|
||||
// video element (the real arbiter) load the URL directly.
|
||||
const probeResult =
|
||||
this.magnetForPlayback
|
||||
? await this.service.probeHostedUrl({
|
||||
url: candidateUrl,
|
||||
magnet: this.trimmedMagnet,
|
||||
probeUrl,
|
||||
})
|
||||
: { outcome: "skipped-url-only" };
|
||||
const probeOutcome = probeResult?.outcome || "error";
|
||||
const probeStatus = probeResult?.status || "unknown";
|
||||
// A `<video>` element plays cross-origin URLs WITHOUT CORS, but this
|
||||
// probe uses fetch (CORS-limited): a benign no-cors HEAD failure or a
|
||||
// slow HEAD returns "error"/"opaque" for perfectly playable hosts (e.g.
|
||||
// archive.org — 200 video/mp4 with byte ranges). An ambiguous probe must
|
||||
// NEVER veto the URL into "No playable source found." Only a
|
||||
// definitively-READ failure status ("bad") deprioritizes it — and even
|
||||
// then, if there's no P2P fallback, we still try (a real media error is
|
||||
// clearer than a false "no source"). The video element + watchdogs are
|
||||
// the actual arbiter of playability.
|
||||
const shouldAttemptHosted =
|
||||
probeOutcome !== "bad" && probeOutcome !== "error";
|
||||
probeOutcome !== "bad" || !this.magnetForPlayback;
|
||||
|
||||
this.service.log(
|
||||
`[playVideoWithFallback] Hosted URL probe outcome=${probeOutcome} status=${probeStatus} shouldAttemptHosted=${shouldAttemptHosted}`
|
||||
|
||||
Reference in new issue
Block a user