import { useState, useEffect } from 'react'; import { CoverImage } from './CoverImage'; import { formatDuration, formatNumber, formatPercent } from '../../lib/formatters'; import { getStatsClient } from '../../hooks/useStatsApi'; import { buildLookupRateDisplay } from '../../lib/yomitan-lookup'; import type { MediaDetailData } from '../../types/stats'; interface MediaHeaderProps { detail: NonNullable; initialKnownWordsSummary?: { totalUniqueWords: number; knownWordCount: number; } | null; } export function MediaHeader({ detail, initialKnownWordsSummary = null }: MediaHeaderProps) { const knownTokenRate = detail.totalLookupCount > 0 ? detail.totalLookupHits / detail.totalLookupCount : null; const avgSessionMs = detail.totalSessions > 0 ? Math.round(detail.totalActiveMs / detail.totalSessions) : 0; const lookupRate = buildLookupRateDisplay(detail.totalYomitanLookupCount, detail.totalTokensSeen); const [knownWordsSummary, setKnownWordsSummary] = useState<{ totalUniqueWords: number; knownWordCount: number; } | null>(initialKnownWordsSummary); useEffect(() => { let cancelled = false; getStatsClient() .getMediaKnownWordsSummary(detail.videoId) .then((data) => { if (!cancelled) setKnownWordsSummary(data); }) .catch(() => { if (!cancelled) setKnownWordsSummary(null); }); return () => { cancelled = true; }; }, [detail.videoId]); return (

{detail.canonicalTitle}

{formatDuration(detail.totalActiveMs)}
total watch time
{formatNumber(detail.totalCards)}
cards mined
{formatNumber(detail.totalTokensSeen)}
token occurrences
{formatNumber(detail.totalYomitanLookupCount)}
Yomitan lookups
{lookupRate?.shortValue ?? '\u2014'}
{lookupRate?.longValue ?? 'lookup rate'}
{knownWordsSummary && knownWordsSummary.totalUniqueWords > 0 ? (
{formatNumber(knownWordsSummary.knownWordCount)} /{' '} {formatNumber(knownWordsSummary.totalUniqueWords)}
known unique words ( {Math.round( (knownWordsSummary.knownWordCount / knownWordsSummary.totalUniqueWords) * 100, )} %)
) : (
{formatPercent(knownTokenRate)}
known token match rate
)}
{detail.totalSessions}
sessions
{formatDuration(avgSessionMs)}
avg session
); }