import { readFile, writeFile } from "node:fs/promises"; import { test, expect } from "@playwright/test"; import { channelStage, generateReport, pathExists, resetData, resolvePath, writeSettings, } from "./helpers"; const CHANNEL = "test-transcribe"; const DATA = `test-transcripts/channels/${CHANNEL}/data`; // Minimal metadata so transcribeOne's normalize pass runs (it needs // metadata.info.json) and writes transcript.cues.json. const META = JSON.stringify({ id: "vidA", title: "Synthetic chough video", upload_date: "20240101", duration: 10, }); async function selectChough() { await writeSettings({ adminTitle: "Test Admin", maxTranscriptPageBytes: 8388608, sleepBetweenDownloadsSeconds: 0, transcriptionApp: "chough", transcriptionApps: { chough: {} }, }); } test("chough app transcribes audio and writes a transcript.json", async ({ page, }) => { await resetData("one-transcribe-channel-with-audio"); await selectChough(); await generateReport(page, CHANNEL); await page.goto(channelStage(CHANNEL, "transcribe")); await page.getByRole("button", { name: "Transcribe missing" }).click(); await expect(page.getByLabel("Transcribe missing output")).toContainText( "3 succeeded", { timeout: 30_000 }, ); for (const id of ["vidA", "vidB", "vidC"]) { expect(await pathExists(`${DATA}/${id}/transcript.json`)).toBe(true); } // The raw transcript is chough-native (chunk_data with seconds). Reaching this // shape proves the chough app's argv ran AND that transcribeOne correctly // renamed chough's exact `-o` output (no ".json" appended) to transcript.json. const raw = JSON.parse( await readFile(resolvePath(`${DATA}/vidA/transcript.json`), "utf8"), ); expect(Array.isArray(raw.chunk_data)).toBe(true); expect(raw.transcription).toBeUndefined(); }); test("chough output normalizes to chough-tagged cues", async ({ page }) => { await resetData("one-transcribe-channel-with-audio"); await selectChough(); // Give vidA metadata so the normalize pass produces transcript.cues.json. await writeFile(resolvePath(`${DATA}/vidA/metadata.info.json`), META); await generateReport(page, CHANNEL); await page.goto(channelStage(CHANNEL, "transcribe")); await page.getByRole("button", { name: "Transcribe missing" }).click(); await expect(page.getByLabel("Transcribe missing output")).toContainText( "3 succeeded", { timeout: 30_000 }, ); await expect .poll(() => pathExists(`${DATA}/vidA/transcript.cues.json`), { timeout: 15_000, }) .toBe(true); const cues = JSON.parse( await readFile(resolvePath(`${DATA}/vidA/transcript.cues.json`), "utf8"), ); // The durable per-video format tag is recorded… expect(cues.transcriptFormat).toBe("chough-json"); // …and the cues come from chough's seconds-based chunk_data (start 0, end 5), // not misread as whisper milliseconds. expect(cues.cues.length).toBeGreaterThan(0); expect(cues.cues[0].start).toBe(0); expect(cues.cues[0].end).toBe(5); });