commit 45b500ef39502d56fdeebe3c17748aa909af67db parent b48312187dba716598416f87d56557b92095dde3 Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st> Date: Tue, 6 Oct 2026 08:48:37 -0400 editor: Set as transcript pins the pick, so it beats en-orig The caption-track rule ranks en-orig above en, so a copy to transcript.en.vtt alone no longer made a track the transcript. The action now also writes transcript-pin.json, which ranks transcript.en.vtt first; the section's text says so and that deleting the pin returns the video to the automatic pick. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Diffstat:
3 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/editor/app/channels/[slug]/videos/[id]/components/cards/TranscriptSourceSection.tsx b/editor/app/channels/[slug]/videos/[id]/components/cards/TranscriptSourceSection.tsx @@ -5,7 +5,7 @@ import type { SubtitleProvenance } from "yt-dlp-transcript-common/lib/subtitlePr import { setPrimaryTranscriptAction, } from "../../videoActions"; -import { CANONICAL_VTT, WHISPER_FILENAME } from "./videoFiles"; +import { CANONICAL_VTT, TRANSCRIPT_PIN_FILENAME, WHISPER_FILENAME } from "./videoFiles"; const PROVENANCE_LABEL: Record<SubtitleProvenance, string> = { asr: "YouTube auto-captions", @@ -46,10 +46,11 @@ export function TranscriptSourceSection({ <div className="flex flex-col gap-3"> <p className="text-sm text-muted-foreground"> Pick which subtitle track is this video's primary transcript. The - chosen track is copied to <code>{CANONICAL_VTT}</code> — the canonical - name the index and viewer read. Reversible: delete{" "} - <code>{CANONICAL_VTT}</code> in Files to fall back to the automatic - English pick, or choose another track to switch. + chosen track is copied to <code>{CANONICAL_VTT}</code> and pinned there + with <code>{TRANSCRIPT_PIN_FILENAME}</code>. Unpinned, the transcript + is the first English track with text, <code>transcript.en-orig.vtt</code>{" "} + first. Reversible: delete <code>{TRANSCRIPT_PIN_FILENAME}</code> in + Files to fall back to that pick, or choose another track to switch. </p> {hasWhisper && ( <p diff --git a/editor/app/channels/[slug]/videos/[id]/components/cards/videoFiles.ts b/editor/app/channels/[slug]/videos/[id]/components/cards/videoFiles.ts @@ -14,6 +14,8 @@ export type VideoFile = { export const WHISPER_FILENAME = "transcript.json"; export const CANONICAL_VTT = "transcript.en.vtt"; +// lib/videoStatus.ts TRANSCRIPT_PIN_FILENAME (this module is client-side). +export const TRANSCRIPT_PIN_FILENAME = "transcript-pin.json"; export function isTranscriptVttName(name: string): boolean { return /^transcript\.[^.]+\.vtt$/.test(name); diff --git a/editor/app/channels/[slug]/videos/[id]/videoActions.ts b/editor/app/channels/[slug]/videos/[id]/videoActions.ts @@ -46,6 +46,7 @@ import { import { onDrive } from "yt-dlp-transcript-common/lib/storageHealth"; import { isTierable } from "yt-dlp-transcript-common/lib/mediaTier"; import { setExcludedFromTruncatedCheck } from "yt-dlp-transcript-common/lib/excludeTruncatedCheck-server"; +import { pinTranscript } from "yt-dlp-transcript-common/lib/transcriptPin-server"; import { pruneFailedTranscriptions } from "yt-dlp-transcript-common/controller/failedTranscriptions"; import { transcodeAudio } from "yt-dlp-transcript-common/controller/transcode"; import { @@ -583,9 +584,10 @@ export async function deleteVideoFileAction( // Promote a transcript.<lang>.vtt track to the canonical transcript.en.vtt so // the index, snapshot, and viewer all treat it as the primary transcript. The // chosen file is copied (not moved) so the original language-coded track is kept -// and the choice stays reversible/repeatable — delete transcript.en.vtt to fall -// back to the automatic regional-English pick, or pick a different track to -// switch again. +// and the choice stays reversible/repeatable — delete transcript-pin.json to +// fall back to the automatic pick, or pick a different track to switch again. +// The pin is what makes the copy win: the caption-track rule otherwise ranks +// transcript.en-orig.vtt above transcript.en.vtt (lib/videoStatus.ts). export async function setPrimaryTranscriptAction( slug: string, videoId: string, @@ -611,6 +613,7 @@ export async function setPrimaryTranscriptAction( if (filename !== VTT_FILENAME) { await writeFileAtomic(path.join(videoDir, VTT_FILENAME), raw); } + await pinTranscript(videoDir, filename); // The video page reads the dir directly, so it reflects the new primary right // away. The channel list + diagnostics bucket read the cached snapshot and // refresh on the next snapshot regeneration (same as the other video actions).