Archilyzer · Source

archilyzer

Archilyzer
git clone https://archilyzer.pages.dev/source/archilyzer.git
Log | Files | Refs | README | LICENSE

commit da1ba11d3c19c24a459062f8a23a8da7f6aaa4e9
parent bdb750fc3e9c37e0805c2b2b87a706c2bd3fa0f8
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Sat, 16 May 2026 15:10:43 -0400

untranscribable tweaks

Diffstat:
Meditor/app/channels/[slug]/components/stages/DiagnosticsStage.tsx | 32+++++++++++++++++++++++++-------
Meditor/app/channels/[slug]/components/stages/TranscodeStage.tsx | 12++++++++++++
Meditor/app/channels/[slug]/lib/stageStatus.ts | 4+++-
Meditor/app/channels/[slug]/whisperActions.ts | 25+++++++++++++++++++++++++
4 files changed, 65 insertions(+), 8 deletions(-)

diff --git a/editor/app/channels/[slug]/components/stages/DiagnosticsStage.tsx b/editor/app/channels/[slug]/components/stages/DiagnosticsStage.tsx @@ -57,13 +57,6 @@ export function DiagnosticsStage({ }: Props) { const buckets: DiagnosticBucket[] = [ { - ids: untranscribableIds, - label: "Marked untranscribable", - description: - "transcript.json present but contains an empty transcription array.", - ariaLabel: "marked untranscribable", - }, - { ids: noMetadataIds, label: "Missing metadata.info.json", description: @@ -178,6 +171,31 @@ export function DiagnosticsStage({ </div> )} </div> + {untranscribableIds.length > 0 && ( + <div + aria-label="marked untranscribable" + className="flex flex-col gap-2 rounded border border-zinc-200 dark:border-zinc-800 p-3" + > + <div> + <h4 className="text-sm font-semibold"> + Marked untranscribable ({untranscribableIds.length}) + </h4> + <p className="text-xs text-zinc-500"> + Videos explicitly marked as untranscribable (transcript.json with + an empty transcription array). Informational only — no action + needed. + </p> + </div> + <VideoIdList + slug={slug} + ids={untranscribableIds} + ariaLabel="marked untranscribable list" + emptyAriaLabel="marked untranscribable empty" + emptyMessage="None" + itemAriaLabel={(id) => `marked untranscribable ${id}`} + /> + </div> + )} </div> ); } diff --git a/editor/app/channels/[slug]/components/stages/TranscodeStage.tsx b/editor/app/channels/[slug]/components/stages/TranscodeStage.tsx @@ -9,6 +9,7 @@ import { import { QueueControl } from "../../../../components/QueueControl"; import { cancelJobAction } from "../../../../jobs/actions"; import { + clearFailedTranscodingsAction, removeFailedTranscodingsAction, transcodeFailuresAction, } from "../../whisperActions"; @@ -153,6 +154,17 @@ function FailedTranscodingsSection({ /> {ids.length > 0 ? ( <div className="flex flex-col gap-2"> + <StreamActionLog + trigger={() => clearFailedTranscodingsAction(slug, removeQueue)} + cancelAction={cancelJobAction} + buttonLabel={`Clear failed-transcodings list (${ids.length})`} + runningLabel="Clearing…" + label="Clear failed-transcodings list" + /> + <p className="text-xs text-zinc-500"> + Clears the list only — video directories stay on disk. Use this when + ffmpeg has been fixed or the listing is stale. + </p> <label className="flex items-center gap-2 text-xs text-zinc-600 dark:text-zinc-400"> Type <span className="font-mono">remove</span> diff --git a/editor/app/channels/[slug]/lib/stageStatus.ts b/editor/app/channels/[slug]/lib/stageStatus.ts @@ -52,6 +52,7 @@ const JOB_KIND_TO_STAGE: Record<string, StageId> = { "download-missing": "download", "transcode-failures": "transcode", "remove-failed-transcodings": "transcode", + "clear-failed-transcodings": "transcode", "transcode-audio": "transcode", "whisper-all": "transcribe", "whisper-retry": "transcribe", @@ -111,8 +112,9 @@ export function computeStageStatuses( const transcribePending = buckets.downloadedNoTranscript.length; const transcribeFailed = failedVideoIds.length; const cleanupPending = buckets.multipleAudioFormats.length; + // `untranscribable` is deliberately excluded: those videos are an intentional + // user decision ("mark untranscribable"), not an anomaly with an action. const diagnosticsPending = - buckets.untranscribable.length + buckets.noMetadata.length + buckets.missingFromArchive.length + buckets.duplicateDirs.length; diff --git a/editor/app/channels/[slug]/whisperActions.ts b/editor/app/channels/[slug]/whisperActions.ts @@ -10,6 +10,10 @@ import { TRANSCRIPTION_QUEUE } from "yt-dlp-transcript-common/lib/platform"; import { runWhisperBatch } from "yt-dlp-transcript-common/controller/whisperBatch"; import { runTranscodeFailures } from "yt-dlp-transcript-common/controller/transcodeFailures"; import { removeFailedTranscodings } from "yt-dlp-transcript-common/controller/removeFailedTranscodings"; +import { + clearFailedTranscodings, + loadFailedTranscodings, +} from "yt-dlp-transcript-common/controller/failedTranscodings"; import { clearFailedTranscriptions } from "yt-dlp-transcript-common/controller/failedTranscriptions"; import { cleanAudioFromTranscribed } from "yt-dlp-transcript-common/controller/cleanAudioFromTranscribed"; import { cleanExtraAudioFormats } from "yt-dlp-transcript-common/controller/cleanExtraAudioFormats"; @@ -148,6 +152,27 @@ export async function removeFailedTranscodingsAction( }); } +export async function clearFailedTranscodingsAction( + slug: string, + queueKey?: string, +): Promise<StreamActionResult> { + const paths = getPaths(); + return runManagedFunction({ + kind: "clear-failed-transcodings", + queueKey: queueKey === undefined ? defaultQueueKey(slug) : queueKey.trim(), + paths, + channelSlug: slug, + fn: async (onLog) => { + const ids = await loadFailedTranscodings(paths, slug); + await clearFailedTranscodings(paths, slug); + onLog( + `Cleared ${ids.length} entr${ids.length === 1 ? "y" : "ies"} from failed-transcodings; video dirs left intact.`, + ); + revalidatePath(`/channels/${slug}`); + }, + }); +} + export async function cleanExtraAudioFormatsAction( slug: string, queueKey?: string,