0.10.2-16 Frontend Features
This commit is contained in:
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "ripster-backend",
|
||||
"version": "0.10.2-15",
|
||||
"version": "0.10.2-16",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "ripster-backend",
|
||||
"version": "0.10.2-15",
|
||||
"version": "0.10.2-16",
|
||||
"dependencies": {
|
||||
"archiver": "^7.0.1",
|
||||
"cors": "^2.8.5",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ripster-backend",
|
||||
"version": "0.10.2-15",
|
||||
"version": "0.10.2-16",
|
||||
"private": true,
|
||||
"type": "commonjs",
|
||||
"scripts": {
|
||||
|
||||
@@ -961,6 +961,12 @@ async function migrateSettingsSchemaMetadata(db) {
|
||||
VALUES ('download_dir_owner', 'Pfade', 'Eigentümer Download ZIP-Ordner', 'string', 0, 'Eigentümer der vorbereiteten ZIP-Dateien im Format user:gruppe. Leer = Standardbenutzer des Dienstes.', NULL, '[]', '{}', 1185)`
|
||||
);
|
||||
await db.run(`INSERT OR IGNORE INTO settings_values (key, value) VALUES ('download_dir_owner', NULL)`);
|
||||
|
||||
await db.run(
|
||||
`INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index)
|
||||
VALUES ('auto_eject_after_rip', 'Laufwerk', 'Laufwerk nach Rip auswerfen', 'boolean', 1, 'Wenn aktiv, wird das Laufwerk nach erfolgreichem Abschluss eines Rip-Vorgangs automatisch ausgeworfen (eject).', 'false', '[]', '{}', 45)`
|
||||
);
|
||||
await db.run(`INSERT OR IGNORE INTO settings_values (key, value) VALUES ('auto_eject_after_rip', 'false')`);
|
||||
}
|
||||
|
||||
async function getDb() {
|
||||
|
||||
@@ -2110,9 +2110,14 @@ class HistoryService {
|
||||
toNormalizedPath(resolvedPaths?.rawDir),
|
||||
...explicitRawPaths.map((candidatePath) => toNormalizedPath(path.dirname(candidatePath)))
|
||||
]);
|
||||
// Only configured base dirs become protectedRoots (must never be deleted themselves)
|
||||
const movieRoots = sanitizeRoots([
|
||||
...getConfiguredMediaPathList(settings || {}, 'movie_dir'),
|
||||
toNormalizedPath(resolvedPaths?.movieDir),
|
||||
toNormalizedPath(resolvedPaths?.movieDir)
|
||||
]);
|
||||
// Includes parent dirs of output files for addCandidate safety checks
|
||||
const movieAllowedPaths = sanitizeRoots([
|
||||
...movieRoots,
|
||||
...explicitMoviePaths.map((candidatePath) => toNormalizedPath(path.dirname(candidatePath)))
|
||||
]);
|
||||
|
||||
@@ -2204,7 +2209,7 @@ class HistoryService {
|
||||
'movie',
|
||||
outputPath,
|
||||
artifactMoviePathSet.has(outputPath) ? 'lineage_output_path' : 'output_path',
|
||||
movieRoots
|
||||
movieAllowedPaths
|
||||
);
|
||||
const parentDir = toNormalizedPath(path.dirname(outputPath));
|
||||
if (parentDir && !movieRoots.includes(parentDir)) {
|
||||
@@ -2213,7 +2218,7 @@ class HistoryService {
|
||||
'movie',
|
||||
parentDir,
|
||||
artifactMoviePathSet.has(outputPath) ? 'lineage_output_parent' : 'output_parent',
|
||||
movieRoots
|
||||
movieAllowedPaths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5201,6 +5201,32 @@ class PipelineService extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
async ejectDriveIfEnabled(settingsMap, devicePath = null) {
|
||||
try {
|
||||
const enabled = String(settingsMap?.auto_eject_after_rip || '').trim().toLowerCase();
|
||||
if (enabled !== 'true' && enabled !== '1') {
|
||||
return;
|
||||
}
|
||||
const device = devicePath
|
||||
|| (settingsMap?.drive_mode === 'explicit' ? String(settingsMap?.drive_device || '').trim() : null)
|
||||
|| String(settingsMap?.drive_device || '').trim()
|
||||
|| '/dev/sr0';
|
||||
logger.info('eject:drive', { device });
|
||||
await new Promise((resolve) => {
|
||||
execFile('eject', [device], { timeout: 10000 }, (error) => {
|
||||
if (error) {
|
||||
logger.warn('eject:drive:failed', { device, error: errorToMeta(error) });
|
||||
} else {
|
||||
logger.info('eject:drive:ok', { device });
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
logger.warn('eject:drive:error', { error: errorToMeta(error) });
|
||||
}
|
||||
}
|
||||
|
||||
normalizeDiscValue(value) {
|
||||
return String(value || '').trim().toLowerCase();
|
||||
}
|
||||
@@ -9605,6 +9631,7 @@ class PipelineService extends EventEmitter {
|
||||
title: 'Ripster - Job abgeschlossen',
|
||||
message: `${job.title || job.detected_title || `Job #${jobId}`} -> ${finalizedOutputPath}`
|
||||
});
|
||||
void this.ejectDriveIfEnabled(settings);
|
||||
}
|
||||
|
||||
setTimeout(async () => {
|
||||
@@ -13267,6 +13294,7 @@ class PipelineService extends EventEmitter {
|
||||
title: 'Ripster - CD Rip erfolgreich',
|
||||
message: `Job #${jobId}: ${selectedMeta?.title || 'Audio CD'}`
|
||||
});
|
||||
void this.ejectDriveIfEnabled(settings);
|
||||
} catch (error) {
|
||||
settleLifecycle();
|
||||
const failedCdLive = buildLiveContext(currentTrackPosition || null);
|
||||
|
||||
Reference in New Issue
Block a user