{versionQuery.version.appVersion ?? 'version unknown'};
}
if (versionQuery.status === 'error') {
return version unavailable;
}
return loading version;
}
function EndpointRow({ icon, label, url }: { icon: ReactNode; label: string; url: string }) {
const [copied, setCopied] = useState(false);
const copyUrl = () => {
void navigator.clipboard?.writeText(url);
setCopied(true);
window.setTimeout(() => setCopied(false), 1200);
};
return (
{url}
{kicker}
{number}
{name}
{nowPlaying?.title ?? 'Now-playing data unavailable'}
{selectedChannels.length} selected
} variant="secondary">Renumber
} variant="secondary">Move to group
} variant="danger">Delete selected
>
) : (
<>
{onAirCount} on air
} onClick={() => navigateToPath('/app/new-channel')}>Add Channel
>
)}
| No. | Channel | Now playing | Streaming | FFmpeg |
|---|
{groups.length} groups
{channels.length}
{channel.number}
{schedules.length} schedule{schedules.length === 1 ? '' : 's'} · {orderedItems.length} item{orderedItems.length === 1 ? '' : 's'} · programs {totalDurationEstimate ?? 'unknown'}
{channel.number}
Monitor connected media sources and trigger per-library scans.
Adding sources is deferred to the existing server setup screens.
{totalItems.toLocaleString()} items · {source.libraries.length} librar{source.libraries.length === 1 ? 'y' : 'ies'}
{library.itemCount.toLocaleString()} items
{library.lastScan ? `Last scan ${formatDateTime(library.lastScan)}` : 'Never scanned'}
{selectedSummary.channelNumber} {selectedState?.onAir && {formatDateTime(nowPlaying?.startUtc ?? nowItem?.start)}
{formatDateTime(nowPlaying?.finishUtc ?? nowItem?.finish)}
{formatDateTime(item.start)}
{isFillerItem(item) ? : }
{item.title ?? 'Untitled item'}
{isFillerItem(item) &&
{formatDateTime(items[0].start)}
now
{formatDateTime(items[items.length - 1].finish)}
{route.description}
{pathname}