Fix muxing
This commit is contained in:
61
dist/server/services/jobManager.js
vendored
61
dist/server/services/jobManager.js
vendored
@@ -13,6 +13,20 @@ const muxer_1 = require("./muxer");
|
||||
const config_1 = require("../../config/config");
|
||||
const mediaUtils_1 = require("../../utils/mediaUtils");
|
||||
const events_1 = require("events");
|
||||
function jobTempDir(baseTempDir, jobId) {
|
||||
return path_1.default.join(baseTempDir, jobId);
|
||||
}
|
||||
function safeCleanupJobTmp(dir) {
|
||||
try {
|
||||
if (!fs_1.default.existsSync(dir))
|
||||
return;
|
||||
(0, mediaUtils_1.cleanupTempFiles)(dir);
|
||||
fs_1.default.rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
catch (err) {
|
||||
console.warn(`Failed to clean up tmp dir ${dir}:`, err.message);
|
||||
}
|
||||
}
|
||||
class JobManager {
|
||||
constructor() {
|
||||
this.queue = [];
|
||||
@@ -33,12 +47,22 @@ class JobManager {
|
||||
}
|
||||
createJob(videoPath, configOverride = {}, outputOptions = {}) {
|
||||
const baseConfig = (0, config_1.getDefaultConfig)();
|
||||
const mergedConfig = { ...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 = {};
|
||||
for (const [k, v] of Object.entries(configOverride)) {
|
||||
if (v === '' || v === null || v === undefined)
|
||||
continue;
|
||||
cleanedOverride[k] = v;
|
||||
}
|
||||
const mergedConfig = { ...baseConfig, ...cleanedOverride };
|
||||
const filename = path_1.default.basename(videoPath);
|
||||
const opts = {
|
||||
audio: outputOptions.audio !== false,
|
||||
subtitles: outputOptions.subtitles !== false,
|
||||
muxed: outputOptions.muxed || false
|
||||
muxed: outputOptions.muxed || false,
|
||||
muxMode: outputOptions.muxMode === 'mixed' ? 'mixed' : 'separate'
|
||||
};
|
||||
return (0, jobStore_1.createJob)(videoPath, filename, mergedConfig, opts);
|
||||
}
|
||||
@@ -92,6 +116,18 @@ class JobManager {
|
||||
throw new Error('Job not found');
|
||||
if (job.status === 'processing')
|
||||
throw new Error('Cannot delete a running job');
|
||||
try {
|
||||
const 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_1.default.basename(stored) === jobId ? stored : jobTempDir(stored, jobId);
|
||||
safeCleanupJobTmp(candidate);
|
||||
}
|
||||
catch {
|
||||
// ignore: cleanup is best-effort and must not block deletion
|
||||
}
|
||||
(0, jobStore_1.deleteJob)(jobId);
|
||||
}
|
||||
listJobs() {
|
||||
@@ -156,6 +192,14 @@ class JobManager {
|
||||
this.emitProgress(job.id);
|
||||
const config = JSON.parse(job.config);
|
||||
const 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_1.default.basename(baseTempDir) !== job.id) {
|
||||
config.tempDir = jobTempDir(baseTempDir, job.id);
|
||||
}
|
||||
fs_1.default.mkdirSync(config.tempDir, { recursive: true });
|
||||
const existingSegments = JSON.parse(job.segments || '[]');
|
||||
const lastContext = JSON.parse(job.last_context || '{}');
|
||||
const startIndex = existingSegments.length > 0 ? job.current_index : 0;
|
||||
@@ -209,8 +253,14 @@ class JobManager {
|
||||
outputSubtitlesVtt = vttPath;
|
||||
}
|
||||
if (outputOptions.muxed && fs_1.default.existsSync(outputAudio)) {
|
||||
const muxedPath = path_1.default.join(outputDir, `${baseName}_described.mkv`);
|
||||
(0, muxer_1.muxAudioDescription)(job.video_path, outputAudio, muxedPath);
|
||||
const isMixed = outputOptions.muxMode === 'mixed';
|
||||
const muxedPath = path_1.default.join(outputDir, `${baseName}${isMixed ? '_described_mixed' : '_described'}.mkv`);
|
||||
if (isMixed) {
|
||||
(0, muxer_1.muxMixedAudioDescription)(job.video_path, outputAudio, muxedPath);
|
||||
}
|
||||
else {
|
||||
(0, muxer_1.muxAudioDescription)(job.video_path, outputAudio, muxedPath);
|
||||
}
|
||||
outputMuxed = muxedPath;
|
||||
}
|
||||
(0, jobStore_1.saveJobOutputs)(job.id, {
|
||||
@@ -222,9 +272,11 @@ class JobManager {
|
||||
(0, jobStore_1.saveCheckpoint)(job.id, JSON.stringify(segments), totalUnits, totalUnits, 0, '{}', 100);
|
||||
(0, jobStore_1.updateJobStatus)(job.id, 'completed');
|
||||
this.emitProgress(job.id);
|
||||
safeCleanupJobTmp(config.tempDir);
|
||||
}
|
||||
catch (err) {
|
||||
if (err.message === 'JOB_PAUSED') {
|
||||
// Keep config.tempDir intact — restart will resume into the same dir.
|
||||
(0, jobStore_1.updateJobStatus)(job.id, 'paused');
|
||||
this.emitProgress(job.id);
|
||||
return;
|
||||
@@ -232,6 +284,7 @@ class JobManager {
|
||||
const errorMsg = err.message || 'Unknown error';
|
||||
(0, jobStore_1.updateJobStatus)(job.id, 'failed', errorMsg);
|
||||
this.emitProgress(job.id);
|
||||
safeCleanupJobTmp(config.tempDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user