mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
fix(liveness): don't bury WebTorrent-only content under hide-until-verified
A WebTorrent-only card's sole liveness signal is the swarm probe (20s timeout, 5min cache), and P2P liveness is slow + intermittent — a live-but-slow video is indistinguishable from a dead one until that probe finishes. Hiding such a card until the swarm verifies could bury perfectly good P2P content for minutes. hide-until-verified now only suppresses a card while the FAST, reliable CDN probe is still running. Once the CDN resolves dead (or is absent, i.e. P2P-only), it falls back to show-pending for the WebTorrent part: shown while the swarm is checked, hidden only once it too is confirmed dead. Burying live content is worse than a brief flash of a dead one, and only the slow P2P probe is at issue. cardNeedsEagerLivenessProbe likewise skips P2P-only cards (they start visible). Tests: hide-foreign does-not-bury-WebTorrent-only coverage in tests/video-card-source-visibility.test.mjs. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
129d877d38
commit
2e510b2330
2 files changed
+78
-12
No files matched your search
@@ -13,13 +13,16 @@ export function cardNeedsEagerLivenessProbe(cardLike) {
|
||||
return false;
|
||||
}
|
||||
const policy = getCardLivenessPolicy();
|
||||
if (policy === "hide-all") {
|
||||
return true;
|
||||
}
|
||||
if (policy === "hide-foreign") {
|
||||
return card.dataset.foreign === "true";
|
||||
}
|
||||
const gated =
|
||||
policy === "hide-all" ||
|
||||
(policy === "hide-foreign" && card.dataset.foreign === "true");
|
||||
if (!gated) {
|
||||
return false;
|
||||
}
|
||||
// Only cards backed by a fast CDN probe are hidden-until-verified (so they need
|
||||
// eager probing while hidden). P2P-only cards fall back to show-pending — they
|
||||
// start visible and are probed normally on scroll, so no eager kick is needed.
|
||||
return Boolean(card.dataset.urlHealthUrl);
|
||||
}
|
||||
|
||||
function resolveCardElement(cardLike) {
|
||||
@@ -99,13 +102,29 @@ export function updateVideoCardSourceVisibility(cardLike) {
|
||||
const hideUntilVerified =
|
||||
policy === "hide-all" || (policy === "hide-foreign" && isForeign);
|
||||
|
||||
const shouldHide = hideUntilVerified
|
||||
? // Hidden until at least one source proves playable (covers the pending
|
||||
// window too, so a dead foreign stranger never flashes in).
|
||||
!cdnHealthy && !streamHealthy
|
||||
: // Default: only hide once every source has come back dead.
|
||||
// Default policy: hide only once every source has come back dead.
|
||||
const confirmedDead =
|
||||
!cdnHealthy && !streamHealthy && !cdnPending && !streamPending;
|
||||
|
||||
let shouldHide;
|
||||
if (!hideUntilVerified) {
|
||||
shouldHide = confirmedDead;
|
||||
} else if (cdnHealthy || streamHealthy) {
|
||||
shouldHide = false; // proven playable → show
|
||||
} else if (cdnPending) {
|
||||
// Still waiting on the FAST, reliable CDN probe (~4s) — keep it hidden so a
|
||||
// dead foreign card never flashes in.
|
||||
shouldHide = true;
|
||||
} else {
|
||||
// CDN is resolved dead (or absent) and the only remaining signal is the slow,
|
||||
// unreliable WebTorrent swarm probe (20s + 5min cache). Do NOT bury the card
|
||||
// behind it — a live-but-slow P2P video is indistinguishable from a dead one
|
||||
// until that probe finishes, and burying live content is worse than a brief
|
||||
// flash. Fall back to show-pending for the stream: show while it's checked,
|
||||
// hide only once it too is confirmed dead.
|
||||
shouldHide = !streamHealthy && !streamPending;
|
||||
}
|
||||
|
||||
if (shouldHide) {
|
||||
if (!card.hidden) {
|
||||
card.hidden = true;
|
||||
|
||||
@@ -160,13 +160,25 @@ test("VideoCard hides cards without playable sources until a healthy CDN update
|
||||
assert.equal(root.dataset.sourceVisibility, "visible", "visibility dataset should reflect the restored state");
|
||||
});
|
||||
|
||||
function makeCard(document, { foreign = "false", owner = "false", url = "checking", stream = "checking" } = {}) {
|
||||
function makeCard(
|
||||
document,
|
||||
{
|
||||
foreign = "false",
|
||||
owner = "false",
|
||||
url = "checking",
|
||||
stream = "checking",
|
||||
cdnUrl = "https://cdn.example/v.mp4", // pass "" for a WebTorrent-only card
|
||||
} = {}
|
||||
) {
|
||||
const card = document.createElement("article");
|
||||
card.classList.add("card");
|
||||
card.dataset.ownerIsViewer = owner;
|
||||
card.dataset.foreign = foreign;
|
||||
card.dataset.urlHealthState = url;
|
||||
card.dataset.streamHealthState = stream;
|
||||
if (cdnUrl) {
|
||||
card.dataset.urlHealthUrl = encodeURIComponent(cdnUrl);
|
||||
}
|
||||
document.body.appendChild(card);
|
||||
return card;
|
||||
}
|
||||
@@ -225,6 +237,41 @@ test("CARD_LIVENESS_POLICY=hide-all hides every pending non-owner card but never
|
||||
assert.equal(nativeCard.hidden, false, "card appears once a source verifies");
|
||||
});
|
||||
|
||||
// WebTorrent-only foreign content must NOT get buried under hide-foreign: its
|
||||
// only signal is the slow/unreliable swarm probe (20s + 5min cache), so a
|
||||
// live-but-slow P2P video would otherwise stay hidden. It falls back to
|
||||
// show-pending instead (shown while checked, hidden only once confirmed dead).
|
||||
test("hide-foreign does not bury WebTorrent-only foreign cards (no CDN to verify fast)", (t) => {
|
||||
const { document } = setupDom(t);
|
||||
setCardLivenessPolicy("hide-foreign");
|
||||
t.after(() => setCardLivenessPolicy("show-pending"));
|
||||
|
||||
// No CDN url → urlHealthState resolves to "offline"; stream probe still running.
|
||||
const p2pCard = makeCard(document, {
|
||||
foreign: "true",
|
||||
cdnUrl: "",
|
||||
url: "offline",
|
||||
stream: "checking",
|
||||
});
|
||||
updateVideoCardSourceVisibility(p2pCard);
|
||||
assert.equal(p2pCard.hidden, false, "P2P-only foreign card is shown while its swarm is checked, not buried");
|
||||
assert.equal(
|
||||
cardNeedsEagerLivenessProbe(p2pCard),
|
||||
false,
|
||||
"P2P-only card is show-pending, so it is not eager-probed",
|
||||
);
|
||||
|
||||
// Only once the swarm probe also confirms it dead does it hide.
|
||||
p2pCard.dataset.streamHealthState = "unhealthy";
|
||||
updateVideoCardSourceVisibility(p2pCard);
|
||||
assert.equal(p2pCard.hidden, true, "confirmed-dead P2P card finally hides");
|
||||
|
||||
// A CDN-backed foreign card, by contrast, IS hidden while its fast probe runs.
|
||||
const cdnCard = makeCard(document, { foreign: "true", url: "checking", stream: "checking" });
|
||||
updateVideoCardSourceVisibility(cdnCard);
|
||||
assert.equal(cdnCard.hidden, true, "CDN-backed foreign card stays hidden during its fast probe");
|
||||
});
|
||||
|
||||
// Hide-until-verified cards start display:none, so the viewport observer can't
|
||||
// fire for them — they must be eager-probed. This predicate gates that, and it
|
||||
// must mirror the visibility policy exactly so the right cards get probed.
|
||||
|
||||
Reference in new issue
Block a user