225 lines
6.2 KiB
JavaScript
225 lines
6.2 KiB
JavaScript
const express = require('express');
|
|
const asyncHandler = require('../middleware/asyncHandler');
|
|
const historyService = require('../services/historyService');
|
|
const pipelineService = require('../services/pipelineService');
|
|
const logger = require('../services/logger').child('HISTORY_ROUTE');
|
|
|
|
const router = express.Router();
|
|
|
|
router.get(
|
|
'/',
|
|
asyncHandler(async (req, res) => {
|
|
const parsedLimit = Number(req.query.limit);
|
|
const limit = Number.isFinite(parsedLimit) && parsedLimit > 0
|
|
? Math.trunc(parsedLimit)
|
|
: null;
|
|
const statuses = String(req.query.statuses || '')
|
|
.split(',')
|
|
.map((value) => String(value || '').trim())
|
|
.filter(Boolean);
|
|
const lite = ['1', 'true', 'yes'].includes(String(req.query.lite || '').toLowerCase());
|
|
logger.info('get:jobs', {
|
|
reqId: req.reqId,
|
|
status: req.query.status,
|
|
statuses: statuses.length > 0 ? statuses : null,
|
|
search: req.query.search,
|
|
limit,
|
|
lite
|
|
});
|
|
|
|
const jobs = await historyService.getJobs({
|
|
status: req.query.status,
|
|
statuses,
|
|
search: req.query.search,
|
|
limit,
|
|
includeFsChecks: !lite
|
|
});
|
|
|
|
res.json({ jobs });
|
|
})
|
|
);
|
|
|
|
router.get(
|
|
'/database',
|
|
asyncHandler(async (req, res) => {
|
|
logger.info('get:database', {
|
|
reqId: req.reqId,
|
|
status: req.query.status,
|
|
search: req.query.search
|
|
});
|
|
|
|
const rows = await historyService.getDatabaseRows({
|
|
status: req.query.status,
|
|
search: req.query.search
|
|
});
|
|
|
|
res.json({ rows });
|
|
})
|
|
);
|
|
|
|
router.get(
|
|
'/orphan-raw',
|
|
asyncHandler(async (req, res) => {
|
|
logger.info('get:orphan-raw', { reqId: req.reqId });
|
|
const result = await historyService.getOrphanRawFolders();
|
|
res.json(result);
|
|
})
|
|
);
|
|
|
|
router.post(
|
|
'/orphan-raw/import',
|
|
asyncHandler(async (req, res) => {
|
|
const rawPath = String(req.body?.rawPath || '').trim();
|
|
logger.info('post:orphan-raw:import', { reqId: req.reqId, rawPath });
|
|
const job = await historyService.importOrphanRawFolder(rawPath);
|
|
const uiReset = await pipelineService.resetFrontendState('history_orphan_import');
|
|
res.json({ job, uiReset });
|
|
})
|
|
);
|
|
|
|
router.post(
|
|
'/:id/omdb/assign',
|
|
asyncHandler(async (req, res) => {
|
|
const id = Number(req.params.id);
|
|
const payload = req.body || {};
|
|
logger.info('post:job:omdb:assign', {
|
|
reqId: req.reqId,
|
|
id,
|
|
imdbId: payload?.imdbId || null,
|
|
hasTitle: Boolean(payload?.title),
|
|
hasYear: Boolean(payload?.year)
|
|
});
|
|
|
|
const job = await historyService.assignOmdbMetadata(id, payload);
|
|
|
|
// Rename raw/output folders to reflect new metadata (best-effort, non-blocking)
|
|
pipelineService.renameJobFolders(id).catch((err) => {
|
|
logger.warn('post:job:omdb:assign:rename-failed', { id, error: err.message });
|
|
});
|
|
|
|
res.json({ job });
|
|
})
|
|
);
|
|
|
|
router.post(
|
|
'/:id/cd/assign',
|
|
asyncHandler(async (req, res) => {
|
|
const id = Number(req.params.id);
|
|
const payload = req.body || {};
|
|
logger.info('post:job:cd:assign', {
|
|
reqId: req.reqId,
|
|
id,
|
|
mbId: payload?.mbId || null,
|
|
hasTitle: Boolean(payload?.title),
|
|
hasArtist: Boolean(payload?.artist),
|
|
trackCount: Array.isArray(payload?.tracks) ? payload.tracks.length : 0
|
|
});
|
|
|
|
const job = await historyService.assignCdMetadata(id, payload);
|
|
|
|
// Rename raw/output folders to reflect new metadata (best-effort, non-blocking)
|
|
pipelineService.renameJobFolders(id).catch((err) => {
|
|
logger.warn('post:job:cd:assign:rename-failed', { id, error: err.message });
|
|
});
|
|
|
|
res.json({ job });
|
|
})
|
|
);
|
|
|
|
router.post(
|
|
'/:id/delete-files',
|
|
asyncHandler(async (req, res) => {
|
|
const id = Number(req.params.id);
|
|
const target = String(req.body?.target || 'both');
|
|
|
|
logger.warn('post:delete-files', {
|
|
reqId: req.reqId,
|
|
id,
|
|
target
|
|
});
|
|
|
|
const result = await historyService.deleteJobFiles(id, target);
|
|
res.json(result);
|
|
})
|
|
);
|
|
|
|
router.get(
|
|
'/:id/delete-preview',
|
|
asyncHandler(async (req, res) => {
|
|
const id = Number(req.params.id);
|
|
const includeRelated = ['1', 'true', 'yes'].includes(String(req.query.includeRelated || '1').toLowerCase());
|
|
|
|
logger.info('get:delete-preview', {
|
|
reqId: req.reqId,
|
|
id,
|
|
includeRelated
|
|
});
|
|
|
|
const preview = await historyService.getJobDeletePreview(id, { includeRelated });
|
|
res.json({ preview });
|
|
})
|
|
);
|
|
|
|
router.post(
|
|
'/:id/delete',
|
|
asyncHandler(async (req, res) => {
|
|
const id = Number(req.params.id);
|
|
const target = String(req.body?.target || 'none');
|
|
const includeRelated = ['1', 'true', 'yes'].includes(String(req.body?.includeRelated || 'false').toLowerCase());
|
|
|
|
logger.warn('post:delete-job', {
|
|
reqId: req.reqId,
|
|
id,
|
|
target,
|
|
includeRelated
|
|
});
|
|
|
|
const result = await historyService.deleteJob(id, target, { includeRelated });
|
|
const uiReset = await pipelineService.resetFrontendState('history_delete');
|
|
res.json({ ...result, uiReset });
|
|
})
|
|
);
|
|
|
|
router.get(
|
|
'/:id',
|
|
asyncHandler(async (req, res) => {
|
|
const id = Number(req.params.id);
|
|
const includeLiveLog = ['1', 'true', 'yes'].includes(String(req.query.includeLiveLog || '').toLowerCase());
|
|
const includeLogs = ['1', 'true', 'yes'].includes(String(req.query.includeLogs || '').toLowerCase());
|
|
const includeAllLogs = ['1', 'true', 'yes'].includes(String(req.query.includeAllLogs || '').toLowerCase());
|
|
const lite = ['1', 'true', 'yes'].includes(String(req.query.lite || '').toLowerCase());
|
|
const parsedTail = Number(req.query.logTailLines);
|
|
const logTailLines = Number.isFinite(parsedTail) && parsedTail > 0
|
|
? Math.trunc(parsedTail)
|
|
: null;
|
|
const includeFsChecks = !(lite || includeLiveLog);
|
|
|
|
logger.info('get:job-detail', {
|
|
reqId: req.reqId,
|
|
id,
|
|
includeLiveLog,
|
|
includeLogs,
|
|
includeAllLogs,
|
|
logTailLines,
|
|
lite,
|
|
includeFsChecks
|
|
});
|
|
const job = await historyService.getJobWithLogs(id, {
|
|
includeLiveLog,
|
|
includeLogs,
|
|
includeAllLogs,
|
|
logTailLines,
|
|
includeFsChecks
|
|
});
|
|
if (!job) {
|
|
const error = new Error('Job nicht gefunden.');
|
|
error.statusCode = 404;
|
|
throw error;
|
|
}
|
|
|
|
res.json({ job });
|
|
})
|
|
);
|
|
|
|
module.exports = router;
|