mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 16:02:26 +00:00
Channel-profile video cards rendered blank view counts. The main feed subscribes each card's [data-view-count] element to the shared view counter (VideoListView.ensureViewCountSubscription / registerVideoViewCountElement), but the channel-profile grid renders its own VideoCards and never did — so nothing ever populated the element. Add js/channelViewCounts.js (subscribeChannelCardViewCount / clearChannelCardViewCounts) and call it from channelProfile.js after each card's getRoot(); teardown runs in clearChannelVideoCardRegistry (already invoked on grid re-render / channel close). Logic lives in a new module so channelProfile.js stays under its size cap. On "are they counted correctly?": yes — this subscribes to the SAME batched kind-30079 view-count transport the feed uses (one shared subscription + the deduped cache), so the channel now shows the exact same counts the feed does. The counting itself was never the issue; the channel grid just wasn't displaying it. Tests: tests/channel-view-counts.test.mjs (3 — non-blank label, safe no-ops, idempotent teardown). Lint + build green. Co-Authored-By: Claude Opus 4.8 <[email protected]>
78 lines
2.4 KiB
JavaScript
78 lines
2.4 KiB
JavaScript
// Wire channel-profile video cards to the shared view counter. The main feed does
|
||
// this in VideoListView (ensureViewCountSubscription / registerVideoViewCountElement);
|
||
// the channel-profile grid renders its own VideoCards and never subscribed them, so
|
||
// every card's view count rendered blank. This mirrors the feed's behavior against
|
||
// the SAME batched view-count transport (one shared kind-30079 subscription), so the
|
||
// counts are identical to what the feed shows — the channel just wasn't displaying
|
||
// them (the counting itself is unchanged and shared).
|
||
|
||
import {
|
||
subscribeToVideoViewCount,
|
||
unsubscribeFromVideoViewCount,
|
||
formatViewCount,
|
||
} from "./viewCounter.js";
|
||
import { devLogger } from "./utils/logger.js";
|
||
|
||
const activeSubscriptions = [];
|
||
|
||
function formatViewCountLabel(total) {
|
||
const value = Number.isFinite(total) ? Number(total) : 0;
|
||
return `${formatViewCount(value)} ${value === 1 ? "view" : "views"}`;
|
||
}
|
||
|
||
// Subscribe one channel card's [data-view-count] element to its pointer.
|
||
export function subscribeChannelCardViewCount(cardEl, pointerInfo) {
|
||
const pointer = pointerInfo?.pointer;
|
||
if (!cardEl || !pointer) {
|
||
return;
|
||
}
|
||
const el = cardEl.querySelector("[data-view-count]");
|
||
if (!el) {
|
||
return;
|
||
}
|
||
if (!el.textContent || !el.textContent.trim()) {
|
||
el.textContent = "– views";
|
||
}
|
||
|
||
try {
|
||
const token = subscribeToVideoViewCount(
|
||
pointer,
|
||
({ total, status, partial }) => {
|
||
let text;
|
||
if (Number.isFinite(total)) {
|
||
text = formatViewCountLabel(total);
|
||
if (partial) {
|
||
text = `${text} (partial)`;
|
||
}
|
||
} else if (status === "hydrating") {
|
||
text = "Loading views…";
|
||
} else {
|
||
text = "– views";
|
||
}
|
||
if (el.isConnected) {
|
||
el.textContent = text;
|
||
el.dataset.viewCountState = partial ? "partial" : status;
|
||
}
|
||
},
|
||
);
|
||
activeSubscriptions.push({ pointer, token });
|
||
} catch (error) {
|
||
devLogger.warn(
|
||
"[ChannelProfile] Failed to subscribe card view count:",
|
||
error,
|
||
);
|
||
}
|
||
}
|
||
|
||
// Tear down every channel-card view-count subscription (on grid re-render / close).
|
||
export function clearChannelCardViewCounts() {
|
||
while (activeSubscriptions.length) {
|
||
const { pointer, token } = activeSubscriptions.pop();
|
||
try {
|
||
unsubscribeFromVideoViewCount(pointer, token);
|
||
} catch (error) {
|
||
// best-effort teardown
|
||
}
|
||
}
|
||
}
|