0.12.0-16 misc fixes

This commit is contained in:
2026-03-30 14:37:23 +00:00
parent 76b020d5c0
commit 5284dd2a43
30 changed files with 6955 additions and 896 deletions
+132 -12
View File
@@ -2991,6 +2991,75 @@ class HistoryService {
}));
}
async findLatestReplacementJobId(sourceJobId) {
const normalizedSourceJobId = normalizeJobIdValue(sourceJobId);
if (!normalizedSourceJobId) {
return null;
}
const db = await getDb();
const rows = await db.all(
`
SELECT a.job_id
FROM job_lineage_artifacts a
JOIN jobs j ON j.id = a.job_id
WHERE a.source_job_id = ?
ORDER BY a.id DESC
`,
[normalizedSourceJobId]
);
for (const row of (Array.isArray(rows) ? rows : [])) {
const candidateJobId = normalizeJobIdValue(row?.job_id);
if (!candidateJobId || candidateJobId === normalizedSourceJobId) {
continue;
}
return candidateJobId;
}
return null;
}
async getJobByIdOrReplacement(jobId) {
const normalizedJobId = normalizeJobIdValue(jobId);
if (!normalizedJobId) {
return {
requestedJobId: null,
resolvedJobId: null,
replaced: false,
job: null
};
}
const directJob = await this.getJobById(normalizedJobId);
if (directJob) {
return {
requestedJobId: normalizedJobId,
resolvedJobId: normalizedJobId,
replaced: false,
job: directJob
};
}
const replacementJobId = await this.findLatestReplacementJobId(normalizedJobId);
if (!replacementJobId) {
return {
requestedJobId: normalizedJobId,
resolvedJobId: normalizedJobId,
replaced: false,
job: null
};
}
const replacementJob = await this.getJobById(replacementJobId);
return {
requestedJobId: normalizedJobId,
resolvedJobId: replacementJobId,
replaced: Boolean(replacementJob),
job: replacementJob || null
};
}
async getRunningJobs() {
const db = await getDb();
const [rows, settings] = await Promise.all([
@@ -4357,21 +4426,72 @@ class HistoryService {
const rawRoot = normalizeComparablePath(effectiveRawDir);
const stat = fs.lstatSync(rawPath);
const isFile = stat.isFile();
const plan = resolvedPaths.encodePlan || {};
// Für Converter-Jobs: Datei liegt in einem Unterordner → Ordner löschen
let deletePath = rawPath;
if (isFile && resolvedPaths.mediaType === 'converter') {
const parentDir = normalizeComparablePath(path.dirname(rawPath));
if (parentDir && parentDir !== rawRoot && isPathInside(rawRoot, parentDir)) {
deletePath = parentDir;
// Für Converter-Jobs: nur die zum Job gehörenden Dateien löschen.
// Der übergeordnete Ordner wird nur entfernt, wenn er danach leer ist.
// Ausnahme: Ordner-Jobs (isFolder=true) haben einen dedizierten Ordner → komplett löschen.
const isConverterFolder = resolvedPaths.mediaType === 'converter' && Boolean(plan.isFolder);
const isSharedAudio = resolvedPaths.mediaType === 'converter' && Boolean(plan.isSharedAudio);
const isConverterFileJob = resolvedPaths.mediaType === 'converter' && !isConverterFolder;
if (isConverterFileJob) {
// Bestimme die zu löschenden Dateien dieses Jobs
let filesToDelete = null;
if (isSharedAudio && Array.isArray(plan.inputPaths) && plan.inputPaths.length > 0) {
// Shared-Audio-Job: nur die explizit gelisteten Einzeldateien entfernen
filesToDelete = plan.inputPaths.map(normalizeComparablePath).filter(Boolean);
} else if (isFile) {
// Einzeldatei-Job: nur diese eine Datei entfernen
filesToDelete = [rawPath];
}
}
const keepRoot = deletePath === rawRoot;
const result = deleteFilesRecursively(deletePath, keepRoot);
summary.raw.deleted = true;
summary.raw.filesDeleted = result.filesDeleted;
summary.raw.dirsRemoved = result.dirsRemoved;
if (filesToDelete) {
let filesDeleted = 0;
const parentDirs = new Set();
for (const filePath of filesToDelete) {
if (!isPathInside(rawRoot, filePath)) continue;
if (!fs.existsSync(filePath)) continue;
const fStat = fs.lstatSync(filePath);
if (!fStat.isFile()) continue;
fs.unlinkSync(filePath);
filesDeleted++;
const parentDir = normalizeComparablePath(path.dirname(filePath));
if (parentDir && parentDir !== rawRoot && isPathInside(rawRoot, parentDir)) {
parentDirs.add(parentDir);
}
}
// Übergeordneten Ordner löschen, wenn er nach dem Löschen leer ist
let dirsRemoved = 0;
for (const parentDir of parentDirs) {
try {
if (!fs.existsSync(parentDir)) continue;
const remaining = fs.readdirSync(parentDir);
if (remaining.length === 0) {
fs.rmdirSync(parentDir);
dirsRemoved++;
}
} catch (_err) { /* ignore */ }
}
summary.raw.deleted = true;
summary.raw.filesDeleted = filesDeleted;
summary.raw.dirsRemoved = dirsRemoved;
} else {
// Fallback: rawPath ist ein Verzeichnis ohne explizite Dateiliste
const keepRoot = rawPath === rawRoot;
const result = deleteFilesRecursively(rawPath, keepRoot);
summary.raw.deleted = true;
summary.raw.filesDeleted = result.filesDeleted;
summary.raw.dirsRemoved = result.dirsRemoved;
}
} else {
// Regulärer Job oder dedizierter Converter-Ordner-Job (isFolder=true): gesamten Pfad löschen
const keepRoot = rawPath === rawRoot;
const result = deleteFilesRecursively(rawPath, keepRoot);
summary.raw.deleted = true;
summary.raw.filesDeleted = result.filesDeleted;
summary.raw.dirsRemoved = result.dirsRemoved;
}
}
}