DVD Integration
This commit is contained in:
@@ -9,6 +9,44 @@ const { errorToMeta } = require('../utils/errorMeta');
|
||||
const { setLogRootDir, getJobLogDir } = require('../services/logPathService');
|
||||
|
||||
const schemaFilePath = path.resolve(__dirname, '../../../db/schema.sql');
|
||||
const LEGACY_PROFILE_SETTING_MIGRATIONS = [
|
||||
{
|
||||
legacyKey: 'mediainfo_extra_args',
|
||||
profileKeys: ['mediainfo_extra_args_bluray', 'mediainfo_extra_args_dvd']
|
||||
},
|
||||
{
|
||||
legacyKey: 'makemkv_rip_mode',
|
||||
profileKeys: ['makemkv_rip_mode_bluray', 'makemkv_rip_mode_dvd']
|
||||
},
|
||||
{
|
||||
legacyKey: 'makemkv_analyze_extra_args',
|
||||
profileKeys: ['makemkv_analyze_extra_args_bluray', 'makemkv_analyze_extra_args_dvd']
|
||||
},
|
||||
{
|
||||
legacyKey: 'makemkv_rip_extra_args',
|
||||
profileKeys: ['makemkv_rip_extra_args_bluray', 'makemkv_rip_extra_args_dvd']
|
||||
},
|
||||
{
|
||||
legacyKey: 'handbrake_preset',
|
||||
profileKeys: ['handbrake_preset_bluray', 'handbrake_preset_dvd']
|
||||
},
|
||||
{
|
||||
legacyKey: 'handbrake_extra_args',
|
||||
profileKeys: ['handbrake_extra_args_bluray', 'handbrake_extra_args_dvd']
|
||||
},
|
||||
{
|
||||
legacyKey: 'output_extension',
|
||||
profileKeys: ['output_extension_bluray', 'output_extension_dvd']
|
||||
},
|
||||
{
|
||||
legacyKey: 'filename_template',
|
||||
profileKeys: ['filename_template_bluray', 'filename_template_dvd']
|
||||
},
|
||||
{
|
||||
legacyKey: 'output_folder_template',
|
||||
profileKeys: ['output_folder_template_bluray', 'output_folder_template_dvd']
|
||||
}
|
||||
];
|
||||
|
||||
let dbInstance;
|
||||
|
||||
@@ -484,6 +522,7 @@ async function openAndPrepareDatabase() {
|
||||
await applySchemaModel(dbInstance, schemaModel);
|
||||
|
||||
await seedDefaultSettings(dbInstance);
|
||||
await migrateLegacyProfiledToolSettings(dbInstance);
|
||||
await removeDeprecatedSettings(dbInstance);
|
||||
await ensurePipelineStateRow(dbInstance);
|
||||
const syncedLogRoot = await configureRuntimeLogRootFromSettings(dbInstance, { ensure: true });
|
||||
@@ -573,6 +612,72 @@ async function seedDefaultSettings(db) {
|
||||
logger.info('seed:settings', { count: seeded });
|
||||
}
|
||||
|
||||
async function readCurrentOrDefaultSettingValue(db, key) {
|
||||
if (!key) {
|
||||
return null;
|
||||
}
|
||||
return db.get(
|
||||
`
|
||||
SELECT
|
||||
s.default_value AS defaultValue,
|
||||
v.value AS currentValue,
|
||||
COALESCE(v.value, s.default_value) AS effectiveValue
|
||||
FROM settings_schema s
|
||||
LEFT JOIN settings_values v ON v.key = s.key
|
||||
WHERE s.key = ?
|
||||
LIMIT 1
|
||||
`,
|
||||
[key]
|
||||
);
|
||||
}
|
||||
|
||||
async function migrateLegacyProfiledToolSettings(db) {
|
||||
let copiedCount = 0;
|
||||
for (const migration of LEGACY_PROFILE_SETTING_MIGRATIONS) {
|
||||
const legacyRow = await readCurrentOrDefaultSettingValue(db, migration.legacyKey);
|
||||
if (!legacyRow) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const targetKey of migration.profileKeys || []) {
|
||||
const targetRow = await readCurrentOrDefaultSettingValue(db, targetKey);
|
||||
if (!targetRow) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const currentValue = targetRow.currentValue;
|
||||
const defaultValue = targetRow.defaultValue;
|
||||
const shouldCopy = (
|
||||
currentValue === null
|
||||
|| currentValue === undefined
|
||||
|| String(currentValue) === String(defaultValue ?? '')
|
||||
);
|
||||
if (!shouldCopy) {
|
||||
continue;
|
||||
}
|
||||
|
||||
await db.run(
|
||||
`
|
||||
INSERT INTO settings_values (key, value, updated_at)
|
||||
VALUES (?, ?, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT(key) DO UPDATE SET
|
||||
value = excluded.value,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
`,
|
||||
[targetKey, legacyRow.effectiveValue ?? null]
|
||||
);
|
||||
copiedCount += 1;
|
||||
logger.info('migrate:legacy-tool-setting-copied', {
|
||||
from: migration.legacyKey,
|
||||
to: targetKey
|
||||
});
|
||||
}
|
||||
}
|
||||
if (copiedCount > 0) {
|
||||
logger.info('migrate:legacy-tool-settings:done', { copiedCount });
|
||||
}
|
||||
}
|
||||
|
||||
async function ensurePipelineStateRow(db) {
|
||||
await db.run(
|
||||
`
|
||||
@@ -584,7 +689,19 @@ async function ensurePipelineStateRow(db) {
|
||||
}
|
||||
|
||||
async function removeDeprecatedSettings(db) {
|
||||
const deprecatedKeys = ['pushover_notify_disc_detected'];
|
||||
const deprecatedKeys = [
|
||||
'pushover_notify_disc_detected',
|
||||
'mediainfo_extra_args',
|
||||
'makemkv_rip_mode',
|
||||
'makemkv_analyze_extra_args',
|
||||
'makemkv_rip_extra_args',
|
||||
'handbrake_preset',
|
||||
'handbrake_extra_args',
|
||||
'output_extension',
|
||||
'filename_template',
|
||||
'output_folder_template',
|
||||
'makemkv_backup_mode'
|
||||
];
|
||||
for (const key of deprecatedKeys) {
|
||||
const result = await db.run('DELETE FROM settings_schema WHERE key = ?', [key]);
|
||||
if (result?.changes > 0) {
|
||||
|
||||
@@ -146,18 +146,6 @@ const defaultSchema = [
|
||||
validation: { minLength: 1 },
|
||||
orderIndex: 205
|
||||
},
|
||||
{
|
||||
key: 'mediainfo_extra_args',
|
||||
category: 'Tools',
|
||||
label: 'Mediainfo Extra Args',
|
||||
type: 'string',
|
||||
required: 0,
|
||||
description: 'Zusätzliche CLI-Parameter für mediainfo.',
|
||||
defaultValue: '',
|
||||
options: [],
|
||||
validation: {},
|
||||
orderIndex: 206
|
||||
},
|
||||
{
|
||||
key: 'makemkv_min_length_minutes',
|
||||
category: 'Tools',
|
||||
@@ -170,57 +158,6 @@ const defaultSchema = [
|
||||
validation: { min: 1, max: 1000 },
|
||||
orderIndex: 210
|
||||
},
|
||||
{
|
||||
key: 'pipeline_max_parallel_jobs',
|
||||
category: 'Tools',
|
||||
label: 'Parallele Jobs',
|
||||
type: 'number',
|
||||
required: 1,
|
||||
description: 'Maximale Anzahl parallel laufender Jobs. Weitere Starts landen in der Queue.',
|
||||
defaultValue: '1',
|
||||
options: [],
|
||||
validation: { min: 1, max: 12 },
|
||||
orderIndex: 211
|
||||
},
|
||||
{
|
||||
key: 'makemkv_rip_mode',
|
||||
category: 'Tools',
|
||||
label: 'MakeMKV Rip Modus',
|
||||
type: 'select',
|
||||
required: 1,
|
||||
description: 'mkv: direkte MKV-Dateien; backup: vollständige Blu-ray Struktur im RAW-Ordner.',
|
||||
defaultValue: 'backup',
|
||||
options: [
|
||||
{ label: 'MKV', value: 'mkv' },
|
||||
{ label: 'Backup', value: 'backup' }
|
||||
],
|
||||
validation: {},
|
||||
orderIndex: 212
|
||||
},
|
||||
{
|
||||
key: 'makemkv_analyze_extra_args',
|
||||
category: 'Tools',
|
||||
label: 'MakeMKV Analyze Extra Args',
|
||||
type: 'string',
|
||||
required: 0,
|
||||
description: 'Zusätzliche CLI-Parameter für Analyze.',
|
||||
defaultValue: '',
|
||||
options: [],
|
||||
validation: {},
|
||||
orderIndex: 220
|
||||
},
|
||||
{
|
||||
key: 'makemkv_rip_extra_args',
|
||||
category: 'Tools',
|
||||
label: 'MakeMKV Rip Extra Args',
|
||||
type: 'string',
|
||||
required: 0,
|
||||
description: 'Zusätzliche CLI-Parameter für Rip.',
|
||||
defaultValue: '',
|
||||
options: [],
|
||||
validation: {},
|
||||
orderIndex: 230
|
||||
},
|
||||
{
|
||||
key: 'handbrake_command',
|
||||
category: 'Tools',
|
||||
@@ -231,31 +168,7 @@ const defaultSchema = [
|
||||
defaultValue: 'HandBrakeCLI',
|
||||
options: [],
|
||||
validation: { minLength: 1 },
|
||||
orderIndex: 300
|
||||
},
|
||||
{
|
||||
key: 'handbrake_preset',
|
||||
category: 'Tools',
|
||||
label: 'HandBrake Preset',
|
||||
type: 'string',
|
||||
required: 1,
|
||||
description: 'Preset Name für -Z.',
|
||||
defaultValue: 'H.264 MKV 1080p30',
|
||||
options: [],
|
||||
validation: { minLength: 1 },
|
||||
orderIndex: 310
|
||||
},
|
||||
{
|
||||
key: 'handbrake_extra_args',
|
||||
category: 'Tools',
|
||||
label: 'HandBrake Extra Args',
|
||||
type: 'string',
|
||||
required: 0,
|
||||
description: 'Zusätzliche CLI-Argumente.',
|
||||
defaultValue: '--audio-lang-list deu,eng --first-audio --subtitle-lang-list deu,eng --first-subtitle --aencoder copy --audio-copy-mask ac3,eac3,dts --audio-fallback ac3 --encoder-preset slow --quality 18 --encoder-tune film --encoder-profile high --encoder-level 4.1',
|
||||
options: [],
|
||||
validation: {},
|
||||
orderIndex: 320
|
||||
orderIndex: 215
|
||||
},
|
||||
{
|
||||
key: 'handbrake_restart_delete_incomplete_output',
|
||||
@@ -267,15 +180,102 @@ const defaultSchema = [
|
||||
defaultValue: 'true',
|
||||
options: [],
|
||||
validation: {},
|
||||
orderIndex: 220
|
||||
},
|
||||
{
|
||||
key: 'pipeline_max_parallel_jobs',
|
||||
category: 'Tools',
|
||||
label: 'Parallele Jobs',
|
||||
type: 'number',
|
||||
required: 1,
|
||||
description: 'Maximale Anzahl parallel laufender Jobs. Weitere Starts landen in der Queue.',
|
||||
defaultValue: '1',
|
||||
options: [],
|
||||
validation: { min: 1, max: 12 },
|
||||
orderIndex: 225
|
||||
},
|
||||
{
|
||||
key: 'mediainfo_extra_args_bluray',
|
||||
category: 'Tools',
|
||||
label: 'Mediainfo Extra Args',
|
||||
type: 'string',
|
||||
required: 0,
|
||||
description: 'Zusätzliche CLI-Parameter für mediainfo (Blu-ray).',
|
||||
defaultValue: '',
|
||||
options: [],
|
||||
validation: {},
|
||||
orderIndex: 300
|
||||
},
|
||||
{
|
||||
key: 'makemkv_rip_mode_bluray',
|
||||
category: 'Tools',
|
||||
label: 'MakeMKV Rip Modus',
|
||||
type: 'select',
|
||||
required: 1,
|
||||
description: 'mkv: direkte MKV-Dateien; backup: vollständige Blu-ray Struktur im RAW-Ordner.',
|
||||
defaultValue: 'backup',
|
||||
options: [
|
||||
{ label: 'MKV', value: 'mkv' },
|
||||
{ label: 'Backup', value: 'backup' }
|
||||
],
|
||||
validation: {},
|
||||
orderIndex: 305
|
||||
},
|
||||
{
|
||||
key: 'makemkv_analyze_extra_args_bluray',
|
||||
category: 'Tools',
|
||||
label: 'MakeMKV Analyze Extra Args',
|
||||
type: 'string',
|
||||
required: 0,
|
||||
description: 'Zusätzliche CLI-Parameter für Analyze (Blu-ray).',
|
||||
defaultValue: '',
|
||||
options: [],
|
||||
validation: {},
|
||||
orderIndex: 310
|
||||
},
|
||||
{
|
||||
key: 'makemkv_rip_extra_args_bluray',
|
||||
category: 'Tools',
|
||||
label: 'MakeMKV Rip Extra Args',
|
||||
type: 'string',
|
||||
required: 0,
|
||||
description: 'Zusätzliche CLI-Parameter für Rip (Blu-ray).',
|
||||
defaultValue: '',
|
||||
options: [],
|
||||
validation: {},
|
||||
orderIndex: 315
|
||||
},
|
||||
{
|
||||
key: 'handbrake_preset_bluray',
|
||||
category: 'Tools',
|
||||
label: 'HandBrake Preset',
|
||||
type: 'string',
|
||||
required: 1,
|
||||
description: 'Preset Name für -Z (Blu-ray).',
|
||||
defaultValue: 'H.264 MKV 1080p30',
|
||||
options: [],
|
||||
validation: { minLength: 1 },
|
||||
orderIndex: 320
|
||||
},
|
||||
{
|
||||
key: 'handbrake_extra_args_bluray',
|
||||
category: 'Tools',
|
||||
label: 'HandBrake Extra Args',
|
||||
type: 'string',
|
||||
required: 0,
|
||||
description: 'Zusätzliche CLI-Argumente (Blu-ray).',
|
||||
defaultValue: '--audio-lang-list deu,eng --first-audio --subtitle-lang-list deu,eng --first-subtitle --aencoder copy --audio-copy-mask ac3,eac3,dts --audio-fallback ac3 --encoder-preset slow --quality 18 --encoder-tune film --encoder-profile high --encoder-level 4.1',
|
||||
options: [],
|
||||
validation: {},
|
||||
orderIndex: 325
|
||||
},
|
||||
{
|
||||
key: 'output_extension',
|
||||
key: 'output_extension_bluray',
|
||||
category: 'Tools',
|
||||
label: 'Ausgabeformat',
|
||||
type: 'select',
|
||||
required: 1,
|
||||
description: 'Dateiendung für finale Datei.',
|
||||
description: 'Dateiendung für finale Datei (Blu-ray).',
|
||||
defaultValue: 'mkv',
|
||||
options: [
|
||||
{ label: 'MKV', value: 'mkv' },
|
||||
@@ -285,28 +285,142 @@ const defaultSchema = [
|
||||
orderIndex: 330
|
||||
},
|
||||
{
|
||||
key: 'filename_template',
|
||||
key: 'filename_template_bluray',
|
||||
category: 'Tools',
|
||||
label: 'Dateiname Template',
|
||||
type: 'string',
|
||||
required: 1,
|
||||
description: 'Verfügbare Tokens: ${title}, ${year}, ${imdbId}.',
|
||||
description: 'Verfügbare Tokens: ${title}, ${year}, ${imdbId} (Blu-ray).',
|
||||
defaultValue: '${title} (${year})',
|
||||
options: [],
|
||||
validation: { minLength: 1 },
|
||||
orderIndex: 340
|
||||
orderIndex: 335
|
||||
},
|
||||
{
|
||||
key: 'output_folder_template',
|
||||
key: 'output_folder_template_bluray',
|
||||
category: 'Tools',
|
||||
label: 'Ordnername Template',
|
||||
type: 'string',
|
||||
required: 0,
|
||||
description: 'Optional. Verfügbare Tokens: ${title}, ${year}, ${imdbId}. Leer = Dateiname-Template verwenden.',
|
||||
description: 'Optional. Verfügbare Tokens: ${title}, ${year}, ${imdbId}. Leer = Dateiname-Template (Blu-ray).',
|
||||
defaultValue: '',
|
||||
options: [],
|
||||
validation: {},
|
||||
orderIndex: 345
|
||||
orderIndex: 340
|
||||
},
|
||||
{
|
||||
key: 'mediainfo_extra_args_dvd',
|
||||
category: 'Tools',
|
||||
label: 'Mediainfo Extra Args',
|
||||
type: 'string',
|
||||
required: 0,
|
||||
description: 'Zusätzliche CLI-Parameter für mediainfo (DVD).',
|
||||
defaultValue: '',
|
||||
options: [],
|
||||
validation: {},
|
||||
orderIndex: 500
|
||||
},
|
||||
{
|
||||
key: 'makemkv_rip_mode_dvd',
|
||||
category: 'Tools',
|
||||
label: 'MakeMKV Rip Modus',
|
||||
type: 'select',
|
||||
required: 1,
|
||||
description: 'mkv: direkte MKV-Dateien; backup: vollständige Disc-Struktur im RAW-Ordner.',
|
||||
defaultValue: 'mkv',
|
||||
options: [
|
||||
{ label: 'MKV', value: 'mkv' },
|
||||
{ label: 'Backup', value: 'backup' }
|
||||
],
|
||||
validation: {},
|
||||
orderIndex: 505
|
||||
},
|
||||
{
|
||||
key: 'makemkv_analyze_extra_args_dvd',
|
||||
category: 'Tools',
|
||||
label: 'MakeMKV Analyze Extra Args',
|
||||
type: 'string',
|
||||
required: 0,
|
||||
description: 'Zusätzliche CLI-Parameter für Analyze (DVD).',
|
||||
defaultValue: '',
|
||||
options: [],
|
||||
validation: {},
|
||||
orderIndex: 510
|
||||
},
|
||||
{
|
||||
key: 'makemkv_rip_extra_args_dvd',
|
||||
category: 'Tools',
|
||||
label: 'MakeMKV Rip Extra Args',
|
||||
type: 'string',
|
||||
required: 0,
|
||||
description: 'Zusätzliche CLI-Parameter für Rip (DVD).',
|
||||
defaultValue: '',
|
||||
options: [],
|
||||
validation: {},
|
||||
orderIndex: 515
|
||||
},
|
||||
{
|
||||
key: 'handbrake_preset_dvd',
|
||||
category: 'Tools',
|
||||
label: 'HandBrake Preset',
|
||||
type: 'string',
|
||||
required: 1,
|
||||
description: 'Preset Name für -Z (DVD).',
|
||||
defaultValue: 'H.264 MKV 480p30',
|
||||
options: [],
|
||||
validation: { minLength: 1 },
|
||||
orderIndex: 520
|
||||
},
|
||||
{
|
||||
key: 'handbrake_extra_args_dvd',
|
||||
category: 'Tools',
|
||||
label: 'HandBrake Extra Args',
|
||||
type: 'string',
|
||||
required: 0,
|
||||
description: 'Zusätzliche CLI-Argumente (DVD).',
|
||||
defaultValue: '--audio-lang-list deu,eng --first-audio --subtitle-lang-list deu,eng --first-subtitle --aencoder copy --audio-copy-mask ac3,eac3,dts --audio-fallback ac3 --encoder-preset slow --quality 18 --encoder-tune film --encoder-profile high --encoder-level 4.1',
|
||||
options: [],
|
||||
validation: {},
|
||||
orderIndex: 525
|
||||
},
|
||||
{
|
||||
key: 'output_extension_dvd',
|
||||
category: 'Tools',
|
||||
label: 'Ausgabeformat',
|
||||
type: 'select',
|
||||
required: 1,
|
||||
description: 'Dateiendung für finale Datei (DVD).',
|
||||
defaultValue: 'mkv',
|
||||
options: [
|
||||
{ label: 'MKV', value: 'mkv' },
|
||||
{ label: 'MP4', value: 'mp4' }
|
||||
],
|
||||
validation: {},
|
||||
orderIndex: 530
|
||||
},
|
||||
{
|
||||
key: 'filename_template_dvd',
|
||||
category: 'Tools',
|
||||
label: 'Dateiname Template',
|
||||
type: 'string',
|
||||
required: 1,
|
||||
description: 'Verfügbare Tokens: ${title}, ${year}, ${imdbId} (DVD).',
|
||||
defaultValue: '${title} (${year})',
|
||||
options: [],
|
||||
validation: { minLength: 1 },
|
||||
orderIndex: 535
|
||||
},
|
||||
{
|
||||
key: 'output_folder_template_dvd',
|
||||
category: 'Tools',
|
||||
label: 'Ordnername Template',
|
||||
type: 'string',
|
||||
required: 0,
|
||||
description: 'Optional. Verfügbare Tokens: ${title}, ${year}, ${imdbId}. Leer = Dateiname-Template (DVD).',
|
||||
defaultValue: '',
|
||||
options: [],
|
||||
validation: {},
|
||||
orderIndex: 540
|
||||
},
|
||||
{
|
||||
key: 'omdb_api_key',
|
||||
|
||||
Reference in New Issue
Block a user