Fix the frontend

This commit is contained in:
2026-05-15 03:53:43 +02:00
parent 49df6a0baf
commit 05faf1ce3b
11 changed files with 747 additions and 867 deletions

View File

@@ -1,17 +1,31 @@
import path from 'path';
import fs from 'fs';
import {
getAllJobs, getJob, createJob, updateJobStatus, saveCheckpoint,
saveJobOutputs, deleteJob as deleteJobFromDb, Job, OutputOptions
import {
getAllJobs, getJob, createJob, updateJobStatus, saveCheckpoint,
saveJobOutputs, deleteJob as deleteJobFromDb, Job, OutputOptions
} from '../db/jobStore';
import { generateAudioDescriptionFromOptions } from '../../utils/processor';
import { generateSRT, generateVTT } from './subtitleGenerator';
import { muxAudioDescription } from './muxer';
import { getDefaultConfig, Config } from '../../config/config';
import { AudioSegment, BatchContext } from '../../interfaces';
import { getVideoDuration } from '../../utils/mediaUtils';
import { getVideoDuration, cleanupTempFiles } from '../../utils/mediaUtils';
import { EventEmitter } from 'events';
function jobTempDir(baseTempDir: string, jobId: string): string {
return path.join(baseTempDir, jobId);
}
function safeCleanupJobTmp(dir: string): void {
try {
if (!fs.existsSync(dir)) return;
cleanupTempFiles(dir);
fs.rmSync(dir, { recursive: true, force: true });
} catch (err: any) {
console.warn(`Failed to clean up tmp dir ${dir}:`, err.message);
}
}
interface ProgressData {
id: string;
status: string;
@@ -49,7 +63,17 @@ export class JobManager {
createJob(videoPath: string, configOverride: Partial<Config> = {}, outputOptions: Partial<OutputOptions> = {}): Job {
const baseConfig = getDefaultConfig();
const mergedConfig: Config = { ...baseConfig, ...configOverride };
// Drop empty/undefined/null values so blank form fields don't clobber the
// baked-in defaults (a blank prompt textarea must NOT overwrite the real
// prompt with "").
const cleanedOverride: Record<string, unknown> = {};
for (const [k, v] of Object.entries(configOverride)) {
if (v === '' || v === null || v === undefined) continue;
cleanedOverride[k] = v;
}
const mergedConfig: Config = { ...baseConfig, ...(cleanedOverride as Partial<Config>) };
const filename = path.basename(videoPath);
const opts: OutputOptions = {
@@ -111,6 +135,18 @@ export class JobManager {
if (!job) throw new Error('Job not found');
if (job.status === 'processing') throw new Error('Cannot delete a running job');
try {
const config: Config = JSON.parse(job.config);
// job.config may contain either the base tempDir (older jobs) or the
// per-job tempDir (newer jobs). Trim a trailing job-id segment if present;
// otherwise compute the per-job dir from the stored base.
const stored = config.tempDir || './desc/tmp/';
const candidate = path.basename(stored) === jobId ? stored : jobTempDir(stored, jobId);
safeCleanupJobTmp(candidate);
} catch {
// ignore: cleanup is best-effort and must not block deletion
}
deleteJobFromDb(jobId);
}
@@ -183,7 +219,16 @@ export class JobManager {
const config: Config = JSON.parse(job.config);
const outputOptions: OutputOptions = JSON.parse(job.output_options);
// Isolate this job's intermediates so concurrent jobs (or future resumes)
// don't collide on filenames like frame_00001.jpg / segment_3_std.wav.
// The pipeline already reads config.tempDir, so just override it here.
const baseTempDir = config.tempDir || './desc/tmp/';
if (path.basename(baseTempDir) !== job.id) {
config.tempDir = jobTempDir(baseTempDir, job.id);
}
fs.mkdirSync(config.tempDir, { recursive: true });
const existingSegments: AudioSegment[] = JSON.parse(job.segments || '[]');
const lastContext: BatchContext = JSON.parse(job.last_context || '{}');
@@ -278,16 +323,21 @@ export class JobManager {
updateJobStatus(job.id, 'completed');
this.emitProgress(job.id);
safeCleanupJobTmp(config.tempDir);
} catch (err: any) {
if (err.message === 'JOB_PAUSED') {
// Keep config.tempDir intact — restart will resume into the same dir.
updateJobStatus(job.id, 'paused');
this.emitProgress(job.id);
return;
}
const errorMsg = err.message || 'Unknown error';
updateJobStatus(job.id, 'failed', errorMsg);
this.emitProgress(job.id);
safeCleanupJobTmp(config.tempDir);
}
}
}