0.16.1-7 Release-Bugfixes
Deploy Docs to GitHub Pages / Deploy to GitHub Pages (push) Has been cancelled
Deploy Docs to GitHub Pages / Build Documentation (push) Has been cancelled

This commit is contained in:
2026-05-08 08:10:34 +02:00
parent 024a6305e2
commit 9b437fe5e5
52 changed files with 5815 additions and 2600 deletions
+124 -17
View File
@@ -528,6 +528,7 @@ async function openAndPrepareDatabase() {
await migrateLegacyProfiledToolSettings(dbInstance);
await migrateOutputTemplates(dbInstance);
await removeDeprecatedSettings(dbInstance);
await migrateTmdbMigrationFlags(dbInstance);
await migrateSettingsSchemaMetadata(dbInstance);
await ensurePipelineStateRow(dbInstance);
await backfillJobOutputFolders(dbInstance);
@@ -811,7 +812,9 @@ async function removeDeprecatedSettings(db) {
'use_plugin_architecture_audiobook_analyze',
'use_plugin_architecture_audiobook_encode',
'dvd_series_plugin_enabled',
'dvd_series_prescan_enabled'
'dvd_series_prescan_enabled',
'dvd_series_reuse_disc_profiles',
'musicbrainz_enabled'
];
for (const key of deprecatedKeys) {
const schemaResult = await db.run('DELETE FROM settings_schema WHERE key = ?', [key]);
@@ -828,6 +831,64 @@ async function removeDeprecatedSettings(db) {
);
}
async function migrateTmdbMigrationFlags(db) {
// Keep this migration idempotent. It helps initialize the new migrate_tmdb flag
// for existing rows after OMDb -> TMDb transition.
const nullableReset = await db.run(
`
UPDATE jobs
SET migrate_tmdb = 0
WHERE migrate_tmdb IS NULL
`
);
// Audio-only domains are outside TMDb migration scope.
const nonVideoMarked = await db.run(
`
UPDATE jobs
SET migrate_tmdb = 1
WHERE COALESCE(migrate_tmdb, 0) = 0
AND LOWER(TRIM(COALESCE(media_type, ''))) IN ('cd', 'audiobook')
`
);
// Rows with obvious TMDb assignment can be marked as migrated.
const obviousTmdbMarked = await db.run(
`
UPDATE jobs
SET migrate_tmdb = 1
WHERE COALESCE(migrate_tmdb, 0) = 0
AND (
makemkv_info_json LIKE '%"metadataProvider":"tmdb"%'
OR makemkv_info_json LIKE '%"tmdbId":%'
OR encode_plan_json LIKE '%"metadataProvider":"tmdb"%'
OR encode_plan_json LIKE '%"tmdbId":%'
)
`
);
// Explicit OMDb footprints must stay pending for manual migration.
const explicitOmdbPending = await db.run(
`
UPDATE jobs
SET migrate_tmdb = 0
WHERE (
COALESCE(selected_from_omdb, 0) = 1
OR (omdb_json IS NOT NULL AND TRIM(omdb_json) <> '')
OR makemkv_info_json LIKE '%"metadataProvider":"omdb"%'
OR encode_plan_json LIKE '%"metadataProvider":"omdb"%'
)
`
);
logger.info('migrate:tmdb-flag:done', {
nullableReset: Number(nullableReset?.changes || 0),
nonVideoMarked: Number(nonVideoMarked?.changes || 0),
obviousTmdbMarked: Number(obviousTmdbMarked?.changes || 0),
explicitOmdbPending: Number(explicitOmdbPending?.changes || 0)
});
}
// Aktualisiert settings_schema-Metadaten (required, description, validation_json)
// für bestehende Einträge, ohne user-konfigurierte Werte in settings_values anzutasten.
const SETTINGS_SCHEMA_METADATA_UPDATES = [
@@ -849,6 +910,18 @@ const SETTINGS_SCHEMA_METADATA_UPDATES = [
description: 'Preset Name für -Z (DVD). Leer = kein Preset, nur CLI-Parameter werden verwendet.',
validation_json: '{}'
},
{
key: 'dvd_series_language',
required: 1,
description: 'Bevorzugte TMDb-Sprache für Film- und Serienmetadaten (DVD/Blu-ray), z.B. de-DE oder en-US.',
validation_json: '{"minLength":2}'
},
{
key: 'dvd_series_fallback_languages',
required: 1,
description: 'Kommagetrennte TMDb-Fallback-Sprachen für Film- und Serienmetadaten (DVD/Blu-ray), z.B. de-DE,en-US,fr-FR.',
validation_json: '{"minLength":2}'
},
{
key: 'output_template_bluray_series_episode',
required: 1,
@@ -973,6 +1046,41 @@ async function migrateSettingsSchemaMetadata(db) {
});
}
const metadataLanguageLabel = 'Film-Sprache';
const metadataLanguageDescription = 'Bevorzugte TMDb-Sprache für Film- und Serienmetadaten (DVD/Blu-ray), z.B. de-DE oder en-US.';
const metadataLanguageResult = await db.run(
`UPDATE settings_schema
SET label = ?, description = ?, updated_at = CURRENT_TIMESTAMP
WHERE key = 'dvd_series_language' AND (label != ? OR description != ?)`,
[metadataLanguageLabel, metadataLanguageDescription, metadataLanguageLabel, metadataLanguageDescription]
);
if (metadataLanguageResult?.changes > 0) {
logger.info('migrate:settings-schema-language-updated', {
key: 'dvd_series_language',
label: metadataLanguageLabel
});
}
const metadataFallbackLanguageLabel = 'Fallback Sprache';
const metadataFallbackLanguageDescription = 'Kommagetrennte TMDb-Fallback-Sprachen für Film- und Serienmetadaten (DVD/Blu-ray), z.B. de-DE,en-US,fr-FR.';
const metadataFallbackLanguageResult = await db.run(
`UPDATE settings_schema
SET label = ?, description = ?, updated_at = CURRENT_TIMESTAMP
WHERE key = 'dvd_series_fallback_languages' AND (label != ? OR description != ?)`,
[
metadataFallbackLanguageLabel,
metadataFallbackLanguageDescription,
metadataFallbackLanguageLabel,
metadataFallbackLanguageDescription
]
);
if (metadataFallbackLanguageResult?.changes > 0) {
logger.info('migrate:settings-schema-fallback-language-updated', {
key: 'dvd_series_fallback_languages',
label: metadataFallbackLanguageLabel
});
}
const dvdSeriesMultiEpisodeTemplateDefault = '{seriesTitle}/Staffel {seasonNr}/S{0:seasonNr}E{episodeRange} - {episodeTitle} (Teil {parts})';
const legacyDvdSeriesMultiEpisodeTemplateDefaults = [
'{seriesTitle}/Staffel {seasonNr}/S{seasonNr}E{episodeRange}'
@@ -1063,9 +1171,18 @@ async function migrateSettingsSchemaMetadata(db) {
await db.run(
`INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index)
VALUES ('handbrake_pre_metadata_scan_enabled', 'Tools', 'Vorab-HandBrake-Scan vor Metadaten', 'boolean', 1, 'Wenn deaktiviert, wird der erste HandBrake-Scan vor der Metadatenauswahl übersprungen.', 'true', '[]', '{}', 221)`
VALUES ('series_playall_tolerance_lower_pct', 'Tools', 'Serie: PlayAll Untergrenze (%)', 'number', 1, 'Untere Toleranz in Prozent für die Plausibilitätsprüfung von PlayAll gegen Episodensumme (DVD/Blu-ray).', '10', '[]', '{"min":0,"max":100}', 234)`
);
await db.run(`INSERT OR IGNORE INTO settings_values (key, value) VALUES ('handbrake_pre_metadata_scan_enabled', 'true')`);
await db.run(`INSERT OR IGNORE INTO settings_values (key, value) VALUES ('series_playall_tolerance_lower_pct', '10')`);
await db.run(
`INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index)
VALUES ('series_playall_tolerance_upper_pct', 'Tools', 'Serie: PlayAll Obergrenze (%)', 'number', 1, 'Obere Toleranz in Prozent für die Plausibilitätsprüfung von PlayAll gegen Episodensumme (DVD/Blu-ray).', '10', '[]', '{"min":0,"max":100}', 235)`
);
await db.run(`INSERT OR IGNORE INTO settings_values (key, value) VALUES ('series_playall_tolerance_upper_pct', '10')`);
await db.run(`DELETE FROM settings_values WHERE key = 'handbrake_pre_metadata_scan_enabled'`);
await db.run(`DELETE FROM settings_schema WHERE key = 'handbrake_pre_metadata_scan_enabled'`);
await db.run(
`INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index)
@@ -1226,30 +1343,20 @@ async function migrateSettingsSchemaMetadata(db) {
await db.run(
`INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index)
VALUES ('dvd_series_language', 'Metadaten', 'DVD Serien-Sprache', 'string', 1, 'Bevorzugte Sprache für Serien-Metadaten im TMDb-Format, z.B. de-DE oder en-US.', 'de-DE', '[]', '{"minLength":2}', 403)`
VALUES ('dvd_series_language', 'Metadaten', 'Film-Sprache', 'string', 1, 'Bevorzugte TMDb-Sprache für Film- und Serienmetadaten (DVD/Blu-ray), z.B. de-DE oder en-US.', 'de-DE', '[]', '{"minLength":2}', 403)`
);
await db.run(`INSERT OR IGNORE INTO settings_values (key, value) VALUES ('dvd_series_language', 'de-DE')`);
await db.run(
`INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index)
VALUES ('dvd_series_fallback_languages', 'Metadaten', 'DVD Serien-Fallback-Sprachen', 'string', 1, 'Kommagetrennte TMDb-Sprachen für Fallback-Titel, z.B. de-DE,en-US,fr-FR.', 'de-DE,en-US', '[]', '{"minLength":2}', 404)`
VALUES ('dvd_series_fallback_languages', 'Metadaten', 'Fallback Sprache', 'string', 1, 'Kommagetrennte TMDb-Fallback-Sprachen für Film- und Serienmetadaten (DVD/Blu-ray), z.B. de-DE,en-US,fr-FR.', 'de-DE,en-US', '[]', '{"minLength":2}', 404)`
);
await db.run(`INSERT OR IGNORE INTO settings_values (key, value) VALUES ('dvd_series_fallback_languages', 'de-DE,en-US')`);
await db.run(
`INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index)
VALUES ('dvd_series_order_preference', 'Metadaten', 'DVD Serien-Ordnung', 'select', 1, 'Bevorzugte Episodenordnung für DVD-Serien. Episode Groups nutzen TMDb Alternate Orders, falls vorhanden.', 'episode_group', '[{"label":"Episode Group","value":"episode_group"},{"label":"Aired / Season","value":"aired"}]', '{}', 405)`
);
await db.run(`INSERT OR IGNORE INTO settings_values (key, value) VALUES ('dvd_series_order_preference', 'episode_group')`);
await db.run(
`INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index)
VALUES ('dvd_series_reuse_disc_profiles', 'Metadaten', 'DVD Disc-Profile wiederverwenden', 'boolean', 1, 'Verwendet zuvor bestätigte Disc-Profile erneut, um Episoden automatischer zuzuordnen.', 'true', '[]', '{}', 406)`
);
await db.run(`INSERT OR IGNORE INTO settings_values (key, value) VALUES ('dvd_series_reuse_disc_profiles', 'true')`);
await db.run(`DELETE FROM settings_values WHERE key IN ('tvdb_api_key', 'tvdb_subscriber_pin')`);
await db.run(`DELETE FROM settings_schema WHERE key IN ('tvdb_api_key', 'tvdb_subscriber_pin')`);
await db.run(`DELETE FROM settings_values WHERE key = 'dvd_series_order_preference'`);
await db.run(`DELETE FROM settings_schema WHERE key = 'dvd_series_order_preference'`);
// Converter-Pfade und Eigentümer
await db.run(