import type { Metadata } from "next";
import Link from "next/link";
import { getPaths } from "yt-dlp-transcript-common/lib/paths";
import {
mediaScanKey,
mediaScanTotals,
unreviewedFindings,
type MediaScanOverrides,
type MediaScanReport,
} from "yt-dlp-transcript-common/lib/mediaScan";
import type {
DuplicateCluster,
DuplicateOverrides,
DuplicateReport,
} from "yt-dlp-transcript-common/lib/duplicates";
import type { AutoPausedRow } from "yt-dlp-transcript-common/views/review";
import { loadReviewSummary } from "./lib/loadReview";
import { ResumeAutoPausedButton } from "./components/ResumeAutoPausedButton";
import { RunDuplicateDetectionButton } from "./components/RunDuplicateDetectionButton";
import { RunMediaScanButton } from "./components/RunMediaScanButton";
import { MediaScanFindingRow } from "./components/MediaScanFindingRow";
import { DuplicateClusterReview } from "./components/DuplicateClusterReview";
export const dynamic = "force-dynamic";
export const metadata: Metadata = { title: "Review" };
// CORPUS REVIEW: the two findings a PERSON decides about. Duplicate clusters
// and media-integrity findings are both flag-only, both carry a reviewed state,
// and neither is an operation or a pile of reclaimable bytes — which is why
// they are here rather than on an operation page or on /cleanup.
export default async function ReviewPage() {
const review = await loadReviewSummary(getPaths());
return (
Review
);
}
// CHANNELS THE MACHINE PAUSED WHILE NOBODY WAS LOOKING.
//
// The storage watch forces a channel to `paused` when the drive its media is on
// stops being there, and restores it when the drive comes back. Both halves are
// right; what was missing was anywhere that said it had happened. Until this,
// the record surfaced as one chip beside one channel's tier on /channels — so
// the way you found out a platter had gone away was by noticing that a channel
// had quietly stopped doing anything.
//
// IT IS A REVIEW FINDING, not a storage row: the decision is about a CHANNEL,
// and what to do about it is a judgement — resume it and accept that a lane
// will keep skipping it, or go plug the drive in. /storage is where the second
// one happens, so the section links there rather than duplicating its controls.
//
// RENDERED ONLY WHEN THERE IS SOMETHING TO SAY. Unlike the two sections below
// it, an empty state here would be a permanent all-clear about a condition that
// is normally absent — noise on every render of a page whose whole job is to be
// worth reading.
function AutoPausedSection({ rows }: { rows: AutoPausedRow[] }) {
if (rows.length === 0) return null;
return (
Auto-paused channels ({rows.length})
Storage
The storage watch paused these because the drive holding their media
stopped answering. Each returns to its previous tier on its own when the
drive is back — resume one only to override that, which is a decision
the watch will then respect until the next time the drive goes away.
);
}
// Corrupt media already on disk. Flag-only, exactly like the duplicates section
// above it — the probes have existed since the audio-checked download landed;
// what was missing was ever running them against files that are already here.
function MediaScanSection({
report,
overrides,
}: {
report: MediaScanReport | null;
overrides: MediaScanOverrides;
}) {
const findings = report?.findings ?? [];
const outstanding = unreviewedFindings(report, overrides);
const totals = report ? mediaScanTotals(report) : null;
return (
Media integrity{outstanding.length > 0 ? ` (${outstanding.length})` : ""}
Checks the audio and video files still on disk for corruption or
truncation. Flag-only — nothing here deletes anything.
{totals && totals.scannedAt ? (
<>
{" "}
Last scan{" "}
{" "}
· {totals.filesScanned.toLocaleString()} file(s) across{" "}
{totals.videosScanned.toLocaleString()} video dir(s)
{totals.deepProbed > 0
? `, ${totals.deepProbed.toLocaleString()} fully decoded`
: ""}
.
>
) : (
" Never run."
)}
{findings.length === 0 ? (
{/* "Never run" is NOT "all clear", and saying so would be the one way
this section could actively mislead. */}
{report
? "Every file the scan read was intact."
: "Run a scan to check the media on disk."}
{matchLabel[cluster.matchKind]}
{/* Nothing compared these videos' content — one side has no transcript.
The cluster is a suspect for a human, stays out of the built site,
and shares no derived work until someone confirms it. */}
{cluster.needsReview && !override?.confirmed && !override?.notDuplicate && (
needs review
)}
{override?.confirmed && confirmed}
{override?.notDuplicate && not a duplicate}
{cluster.score !== null && (
score {cluster.score.toFixed(2)}
)}
{cluster.contained && clip-of-longer}
{cluster.crossPlatform && cross-platform}
{cluster.crossChannel && cross-channel}
{cluster.videoRefs.length} videos · ~{cluster.durationBucket}s
{/* The confirm path exists precisely for `needsReview` clusters:
clusterMaySharePartial fails closed, so until a human says
"confirmed" these share no digest and never reach a built site.
Content-confirmed clusters need no confirmation — but they can still
be rejected, which is the only way to un-assert a wrong one. */}