Files
openmaic/OpenMAIC/lib/video-export-app/use-download-subtitles.ts
T

73 lines
2.8 KiB
TypeScript

'use client';
/**
* `useDownloadSubtitles` — download the classroom narration as a subtitle file
* (`.srt` by default) without rendering a video.
*
* The "clean video + sidecar subtitles" path (#867 item 2): with burn-in off,
* the exported MP4 has no captions, so the user downloads the subtitle file here
* and adds it in their own editor. Reuses {@link compileSubtitles}, which runs
* only the compiler (no asset collection, no ZIP, no render service), so it's
* fast and works whether or not the render service is configured.
*
* App-side / impure: store read, sonner toast, `saveAs` download.
*/
import { useCallback, useState } from 'react';
import { saveAs } from 'file-saver';
import { toast } from 'sonner';
import { useI18n } from '@/lib/hooks/use-i18n';
import { createLogger } from '@/lib/logger';
import { useVideoRenderStore } from '@/lib/store/video-render';
import { acquireExport, releaseExport } from './export-in-flight';
import { NoScenesError, sanitizeFilename } from './export-options';
const log = createLogger('DownloadSubtitles');
export type SubtitleFormat = 'srt' | 'vtt';
export function useDownloadSubtitles() {
const [downloading, setDownloading] = useState(false);
const { t, locale } = useI18n();
const resolution = useVideoRenderStore((state) => state.options.resolution);
const downloadSubtitles = useCallback(
async (format: SubtitleFormat = 'srt') => {
if (downloading) return;
// Shared with the ZIP export: both funnel through the same stage-store /
// Dexie compile, so only one export operation runs at a time.
if (!acquireExport()) return;
setDownloading(true);
const toastId = toast.loading(t('export.subtitlesCompiling'));
try {
const { compileSubtitles } = await import('./build-export-zip');
const { srt, vtt, stageName, cueCount } = await compileSubtitles({
resolution,
locale,
});
if (cueCount === 0) {
toast.error(t('export.subtitlesEmpty'), { id: toastId });
return;
}
const content = format === 'vtt' ? vtt : srt;
const mime = format === 'vtt' ? 'text/vtt' : 'application/x-subrip';
const blob = new Blob([content], { type: `${mime};charset=utf-8` });
saveAs(blob, `${sanitizeFilename(stageName)}.${format}`);
toast.success(t('export.subtitlesSuccess'), { id: toastId });
} catch (error) {
if (error instanceof NoScenesError) {
toast.error(t('export.videoNoScenes'), { id: toastId });
} else {
log.error('Subtitle download failed:', error);
toast.error(t('export.subtitlesFailed'), { id: toastId });
}
} finally {
releaseExport();
setDownloading(false);
}
},
[downloading, t, locale, resolution],
);
return { downloading, downloadSubtitles };
}