export const PLAYBACK_COMMENT_VISIBLE_MS = 4_000; export function getPlaybackCommentVisibleMs(playbackRate = 1): number { const safePlaybackRate = Number.isFinite(playbackRate) && playbackRate > 0 ? playbackRate : 1; return PLAYBACK_COMMENT_VISIBLE_MS * safePlaybackRate; } export interface PlaybackComment { id: string; content: string; videoTimestampMs: number; authorEmail?: string | null; authorName?: string | null; parentId?: string | null; resolved?: boolean; } export function getActivePlaybackComments( comments: PlaybackComment[] | undefined, currentMs: number, playbackRate = 1, ): PlaybackComment[] { if (!comments?.length || !Number.isFinite(currentMs) || currentMs < 0) { return []; } const visibleMs = getPlaybackCommentVisibleMs(playbackRate); return comments .filter((comment) => { const timestamp = comment.videoTimestampMs; return ( comment.parentId == null && comment.resolved !== true && comment.content.trim().length > 0 && Number.isFinite(timestamp) && timestamp >= 0 && currentMs >= timestamp && currentMs < timestamp + visibleMs ); }) .sort( (a, b) => a.videoTimestampMs - b.videoTimestampMs || a.id.localeCompare(b.id), ); } export function PlaybackCommentOverlay({ comments, currentMs, playbackRate = 1, }: { comments: PlaybackComment[] | undefined; currentMs: number; playbackRate?: number; }) { const activeComments = getActivePlaybackComments( comments, currentMs, playbackRate, ); if (activeComments.length === 0) return null; return (
{author}
{comment.content}