Files
SubMiner/src/config/resolve/subtitle-generation.test.ts
T
sudacode 2d623838d5 feat(subtitles): add local Japanese subtitle generation
- Generate Japanese SRTs through the overlay modal or launcher
- Support managed whisper.cpp models and optional dialogue detection
2026-09-07 21:43:53 -07:00

91 lines
4.0 KiB
TypeScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { resolveConfig } from '../resolve';
import { buildConfigSettingsRegistry } from '../settings/registry';
import { SUBTITLE_GENERATION_MODELS } from '../../shared/subtitle-generation-model-catalog';
import { resolveSubtitleGenerationConfig } from '../../shared/subtitle-generation';
test('every downloadable multilingual model is accepted by config and offered in settings', () => {
const settings = buildConfigSettingsRegistry(resolveConfig({}).resolved).find(
(entry) => entry.configPath === 'subtitleGeneration.managedModel',
);
assert.deepEqual(
settings?.enumValues,
SUBTITLE_GENERATION_MODELS.map((model) => model.id),
);
for (const { id } of SUBTITLE_GENERATION_MODELS) {
const { resolved, warnings } = resolveConfig({ subtitleGeneration: { managedModel: id } });
assert.equal(resolved.subtitleGeneration.managedModel, id);
assert.equal(warnings.length, 0);
}
});
test('generation config rejects English-only, unknown, and prototype model names', () => {
for (const managedModel of ['tiny.en', 'small.en-q5_1', 'unknown', 'toString', '__proto__']) {
const warnings: string[] = [];
const resolved = resolveSubtitleGenerationConfig({ managedModel }, (key) => warnings.push(key));
assert.equal(resolved.managedModel, 'small');
assert.equal(warnings.length, 1);
}
});
test('generation config is resolved and its external model path is editable without restart', () => {
const { resolved, warnings } = resolveConfig({
subtitleGeneration: { modelPath: '/models/japanese.bin', managedModel: 'medium', threads: 8 },
});
assert.equal(resolved.subtitleGeneration.modelPath, '/models/japanese.bin');
assert.equal(resolved.subtitleGeneration.managedModel, 'medium');
assert.equal(warnings.length, 0);
const field = buildConfigSettingsRegistry(resolved).find(
(entry) => entry.configPath === 'subtitleGeneration.modelPath',
);
assert.equal(field?.category, 'integrations');
assert.equal(field?.restartBehavior, 'hot-reload');
});
test('generation executable overrides default to empty and accept blank values without warnings', () => {
for (const subtitleGeneration of [
{},
{ whisperPath: '', ffmpegPath: '', ffprobePath: '' },
{ whisperPath: ' ', ffmpegPath: ' ', ffprobePath: ' ' },
]) {
const { resolved, warnings } = resolveConfig({ subtitleGeneration });
assert.equal(resolved.subtitleGeneration.whisperPath, '');
assert.equal(resolved.subtitleGeneration.ffmpegPath, '');
assert.equal(resolved.subtitleGeneration.ffprobePath, '');
assert.equal(warnings.length, 0);
}
});
test('subtitle generation shortcut can be customized or disabled', () => {
assert.equal(resolveConfig({}).resolved.shortcuts.openSubtitleGeneration, 'Ctrl+Shift+G');
assert.equal(
resolveConfig({ shortcuts: { openSubtitleGeneration: 'Ctrl+Alt+G' } }).resolved.shortcuts
.openSubtitleGeneration,
'Ctrl+Alt+G',
);
assert.equal(
resolveConfig({ shortcuts: { openSubtitleGeneration: null } }).resolved.shortcuts
.openSubtitleGeneration,
null,
);
});
test('dialogue detection paths are optional, validated, and editable in Settings', () => {
const { resolved, warnings } = resolveConfig({
subtitleGeneration: { vadModelPath: ' /models/silero.bin ', vadPath: ' /bin/vad ' },
});
assert.equal(resolved.subtitleGeneration.vadModelPath, '/models/silero.bin');
assert.equal(resolved.subtitleGeneration.vadPath, '/bin/vad');
assert.equal(warnings.length, 0);
for (const key of ['vadModelPath', 'vadPath'] as const) {
const field = buildConfigSettingsRegistry(resolved).find(
(entry) => entry.configPath === `subtitleGeneration.${key}`,
);
assert.equal(field?.category, 'integrations');
assert.equal(field?.restartBehavior, 'hot-reload');
assert.equal(resolveConfig({}).resolved.subtitleGeneration[key], '');
assert.equal(resolveConfig({ subtitleGeneration: { [key]: false } }).warnings.length, 1);
}
});