Files
bitvid/js/channelViewCounts.js
thePR0M3TH3ANandClaude Opus 4.8 9e5cb9f57b [channel] Show view counts on channel-profile cards (were blank)
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]>
2026-07-02 10:44:09 -04:00

78 lines
2.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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
}
}
}