Rewrite frontend as single self-contained HTML file — all CSS/JS inline, no external files to fail loading
This commit is contained in:
164
dist/server/routes/jobs.js
vendored
Normal file
164
dist/server/routes/jobs.js
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.createJobsRouter = createJobsRouter;
|
||||
const express_1 = require("express");
|
||||
const path_1 = __importDefault(require("path"));
|
||||
const fs_1 = __importDefault(require("fs"));
|
||||
const jobStore_1 = require("../db/jobStore");
|
||||
function getParam(req, name) {
|
||||
const val = req.params[name];
|
||||
return Array.isArray(val) ? val[0] : val;
|
||||
}
|
||||
function createJobsRouter(jobManager) {
|
||||
const router = (0, express_1.Router)();
|
||||
router.get('/', (_req, res) => {
|
||||
const jobs = jobManager.listJobs();
|
||||
res.json({ jobs });
|
||||
});
|
||||
router.post('/', (req, res) => {
|
||||
const { videoPath, config, outputOptions } = req.body;
|
||||
if (!videoPath) {
|
||||
res.status(400).json({ error: 'videoPath is required' });
|
||||
return;
|
||||
}
|
||||
if (!fs_1.default.existsSync(videoPath)) {
|
||||
res.status(400).json({ error: `Video file not found: ${videoPath}` });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const job = jobManager.createJob(videoPath, config || {}, outputOptions || {});
|
||||
res.status(201).json({ job });
|
||||
}
|
||||
catch (err) {
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
router.get('/:id', (req, res) => {
|
||||
const job = (0, jobStore_1.getJob)(getParam(req, 'id'));
|
||||
if (!job) {
|
||||
res.status(404).json({ error: 'Job not found' });
|
||||
return;
|
||||
}
|
||||
res.json({ job });
|
||||
});
|
||||
router.post('/:id/start', async (req, res) => {
|
||||
try {
|
||||
await jobManager.startJob(getParam(req, 'id'));
|
||||
res.json({ success: true });
|
||||
}
|
||||
catch (err) {
|
||||
res.status(400).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
router.post('/:id/pause', async (req, res) => {
|
||||
try {
|
||||
await jobManager.pauseJob(getParam(req, 'id'));
|
||||
res.json({ success: true });
|
||||
}
|
||||
catch (err) {
|
||||
res.status(400).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
router.post('/:id/restart', async (req, res) => {
|
||||
try {
|
||||
await jobManager.restartJob(getParam(req, 'id'));
|
||||
res.json({ success: true });
|
||||
}
|
||||
catch (err) {
|
||||
res.status(400).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
router.post('/:id/cancel', async (req, res) => {
|
||||
try {
|
||||
await jobManager.cancelJob(getParam(req, 'id'));
|
||||
res.json({ success: true });
|
||||
}
|
||||
catch (err) {
|
||||
res.status(400).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
router.delete('/:id', (req, res) => {
|
||||
try {
|
||||
jobManager.deleteJob(getParam(req, 'id'));
|
||||
res.json({ success: true });
|
||||
}
|
||||
catch (err) {
|
||||
res.status(400).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
router.get('/:id/progress', (req, res) => {
|
||||
res.setHeader('Content-Type', 'text/event-stream');
|
||||
res.setHeader('Cache-Control', 'no-cache');
|
||||
res.setHeader('Connection', 'keep-alive');
|
||||
res.setHeader('X-Accel-Buffering', 'no');
|
||||
const sendProgress = (data) => {
|
||||
res.write(`data: ${JSON.stringify(data)}\n\n`);
|
||||
};
|
||||
const initialJob = (0, jobStore_1.getJob)(getParam(req, 'id'));
|
||||
if (initialJob) {
|
||||
sendProgress({
|
||||
id: initialJob.id,
|
||||
status: initialJob.status,
|
||||
progress: initialJob.progress,
|
||||
currentIndex: initialJob.current_index,
|
||||
totalUnits: initialJob.total_units,
|
||||
segments: JSON.parse(initialJob.segments),
|
||||
error: initialJob.error,
|
||||
output_audio: initialJob.output_audio,
|
||||
output_subtitles_srt: initialJob.output_subtitles_srt,
|
||||
output_subtitles_vtt: initialJob.output_subtitles_vtt,
|
||||
output_muxed: initialJob.output_muxed
|
||||
});
|
||||
}
|
||||
const unsubscribe = jobManager.onJobProgress(getParam(req, 'id'), (data) => {
|
||||
if (data.status === 'completed' || data.status === 'failed' || data.status === 'cancelled') {
|
||||
sendProgress(data);
|
||||
res.end();
|
||||
unsubscribe();
|
||||
return;
|
||||
}
|
||||
sendProgress(data);
|
||||
});
|
||||
req.on('close', () => {
|
||||
unsubscribe();
|
||||
});
|
||||
});
|
||||
router.get('/:id/download/:type', (req, res) => {
|
||||
const job = (0, jobStore_1.getJob)(getParam(req, 'id'));
|
||||
if (!job) {
|
||||
res.status(404).json({ error: 'Job not found' });
|
||||
return;
|
||||
}
|
||||
const type = getParam(req, 'type');
|
||||
let filePath = null;
|
||||
let filename = '';
|
||||
switch (type) {
|
||||
case 'audio':
|
||||
filePath = job.output_audio;
|
||||
filename = `${path_1.default.basename(job.video_filename, path_1.default.extname(job.video_filename))}_description.mp3`;
|
||||
break;
|
||||
case 'subtitles':
|
||||
const format = req.query.format || 'srt';
|
||||
filePath = format === 'vtt' ? job.output_subtitles_vtt : job.output_subtitles_srt;
|
||||
filename = `${path_1.default.basename(job.video_filename, path_1.default.extname(job.video_filename))}_description.${format}`;
|
||||
break;
|
||||
case 'muxed':
|
||||
filePath = job.output_muxed;
|
||||
filename = `${path_1.default.basename(job.video_filename, path_1.default.extname(job.video_filename))}_described.mkv`;
|
||||
break;
|
||||
default:
|
||||
res.status(400).json({ error: 'Invalid download type' });
|
||||
return;
|
||||
}
|
||||
if (!filePath || !fs_1.default.existsSync(filePath)) {
|
||||
res.status(404).json({ error: 'Output file not found' });
|
||||
return;
|
||||
}
|
||||
res.download(filePath, filename);
|
||||
});
|
||||
return router;
|
||||
}
|
||||
//# sourceMappingURL=jobs.js.map
|
||||
Reference in New Issue
Block a user