0.13.1-3 Fix

This commit is contained in:
2026-04-13 10:22:09 +00:00
parent b2d8dffbf4
commit 63a45e70e7
10 changed files with 84 additions and 123 deletions
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "ripster-backend", "name": "ripster-backend",
"version": "0.13.1-2", "version": "0.13.1-3",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "ripster-backend", "name": "ripster-backend",
"version": "0.13.1-2", "version": "0.13.1-3",
"dependencies": { "dependencies": {
"archiver": "^7.0.1", "archiver": "^7.0.1",
"cors": "^2.8.5", "cors": "^2.8.5",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "ripster-backend", "name": "ripster-backend",
"version": "0.13.1-2", "version": "0.13.1-3",
"private": true, "private": true,
"type": "commonjs", "type": "commonjs",
"scripts": { "scripts": {
+3 -13
View File
@@ -807,7 +807,9 @@ async function removeDeprecatedSettings(db) {
'use_plugin_architecture_cd_rip', 'use_plugin_architecture_cd_rip',
'use_plugin_architecture_audiobook', 'use_plugin_architecture_audiobook',
'use_plugin_architecture_audiobook_analyze', 'use_plugin_architecture_audiobook_analyze',
'use_plugin_architecture_audiobook_encode' 'use_plugin_architecture_audiobook_encode',
'dvd_series_plugin_enabled',
'dvd_series_prescan_enabled'
]; ];
for (const key of deprecatedKeys) { for (const key of deprecatedKeys) {
const schemaResult = await db.run('DELETE FROM settings_schema WHERE key = ?', [key]); const schemaResult = await db.run('DELETE FROM settings_schema WHERE key = ?', [key]);
@@ -1032,18 +1034,6 @@ async function migrateSettingsSchemaMetadata(db) {
); );
await db.run(`INSERT OR IGNORE INTO settings_values (key, value) VALUES ('series_dir_dvd_owner', NULL)`); await db.run(`INSERT OR IGNORE INTO settings_values (key, value) VALUES ('series_dir_dvd_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 ('dvd_series_plugin_enabled', 'Features', 'DVD Serien-Plugin aktiviert', 'boolean', 1, 'Aktiviert die additive Serienerkennung für DVDs. Wenn deaktiviert, bleibt der bestehende DVD-Film-Flow unverändert.', 'false', '[]', '{}', 145)`
);
await db.run(`INSERT OR IGNORE INTO settings_values (key, value) VALUES ('dvd_series_plugin_enabled', 'false')`);
await db.run(
`INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index, depends_on)
VALUES ('dvd_series_prescan_enabled', 'Features', 'DVD HandBrake-Prescan aktiviert', 'boolean', 1, 'Führt nach der DVD-Erkennung einen zusätzlichen HandBrake-Prescan für die Serienheuristik aus.', 'true', '[]', '{}', 146, 'dvd_series_plugin_enabled')`
);
await db.run(`INSERT OR IGNORE INTO settings_values (key, value) VALUES ('dvd_series_prescan_enabled', 'true')`);
await db.run( await db.run(
`INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index) `INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index)
VALUES ('output_template_dvd_series_episode', 'Pfade', 'Output Template (DVD Serie, Episode)', 'string', 1, 'Template für einzelne DVD-Serienepisoden ohne Dateiendung. Platzhalter: {seriesTitle}, {seasonNr}, {episodeNr}, {episodeTitle}, {discNr}, {year}, {language}. Optional mit führender Null: {0:seasonNr}, {0:episodeNr}. Alias: {seasonNo}/{episodeNo} entspricht {seasonNr}/{episodeNr}.', '{seriesTitle}/Staffel {seasonNr}/S{seasonNr}E{episodeNr} - {episodeTitle}', '[]', '{"minLength":1}', 536)` VALUES ('output_template_dvd_series_episode', 'Pfade', 'Output Template (DVD Serie, Episode)', 'string', 1, 'Template für einzelne DVD-Serienepisoden ohne Dateiendung. Platzhalter: {seriesTitle}, {seasonNr}, {episodeNr}, {episodeTitle}, {discNr}, {year}, {language}. Optional mit führender Null: {0:seasonNr}, {0:episodeNr}. Alias: {seasonNo}/{episodeNo} entspricht {seasonNr}/{episodeNr}.', '{seriesTitle}/Staffel {seasonNr}/S{seasonNr}E{episodeNr} - {episodeTitle}', '[]', '{"minLength":1}', 536)`
-12
View File
@@ -86,18 +86,6 @@ class DVDSeriesPlugin extends SourcePlugin {
getSettingsSchema() { getSettingsSchema() {
return [ return [
{
key: 'dvd_series_plugin_enabled',
category: 'Features',
label: 'DVD Serien-Plugin aktiviert',
type: 'boolean',
required: 1,
description: 'Aktiviert die additive Serienerkennung für DVDs.',
default_value: 'false',
options_json: '[]',
validation_json: '{}',
order_index: 145
},
{ {
key: 'tmdb_api_read_access_token', key: 'tmdb_api_read_access_token',
category: 'Metadaten', category: 'Metadaten',
+72 -81
View File
@@ -11740,97 +11740,88 @@ class PipelineService extends EventEmitter {
if (mediaProfile === 'dvd' && analyzePlugin?.id === 'dvd') { if (mediaProfile === 'dvd' && analyzePlugin?.id === 'dvd') {
try { try {
const dvdSettings = await settingsService.getEffectiveSettingsMap('dvd'); const dvdSettings = await settingsService.getEffectiveSettingsMap('dvd');
const dvdSeriesPluginEnabled = ['1', 'true', 'yes', 'on'].includes( const reviewResult = await this.runPluginReviewScan(analyzePlugin, job, {
String(dvdSettings?.dvd_series_plugin_enabled || '').trim().toLowerCase() jobId: job.id,
); deviceInfo: deviceWithProfile,
const dvdSeriesPrescanEnabled = ['1', 'true', 'yes', 'on'].includes( reviewMode: 'pre_rip',
String(dvdSettings?.dvd_series_prescan_enabled || '').trim().toLowerCase() source: 'HANDBRAKE_SCAN',
); silent: true
});
pluginExecution = this.mergePluginExecutionState(pluginExecution, reviewResult?.pluginExecution || null);
if (dvdSeriesPluginEnabled && dvdSeriesPrescanEnabled) { const scanText = Array.isArray(reviewResult?.scanLines)
const reviewResult = await this.runPluginReviewScan(analyzePlugin, job, { ? reviewResult.scanLines.join('\n')
: '';
if (scanText) {
const { DVDSeriesPlugin } = require('../plugins/DVDSeriesPlugin');
const dvdSeriesPlugin = new DVDSeriesPlugin();
const dvdSeriesContext = await this.buildPluginContext(dvdSeriesPlugin.id, {
discInfo: deviceWithProfile,
jobId: job.id, jobId: job.id,
deviceInfo: deviceWithProfile, scanText,
reviewMode: 'pre_rip', detectedTitle: effectiveDetectedTitle
source: 'HANDBRAKE_SCAN',
silent: true
}); });
pluginExecution = this.mergePluginExecutionState(pluginExecution, reviewResult?.pluginExecution || null); const seriesPluginResult = await dvdSeriesPlugin.analyze(device.path, job, dvdSeriesContext);
pluginExecution = this.mergePluginExecutionState(
pluginExecution,
this.sanitizePluginExecutionState(dvdSeriesContext.getPluginExecution())
);
const scanText = Array.isArray(reviewResult?.scanLines) seriesAnalysis = seriesPluginResult?.seriesAnalysis || null;
? reviewResult.scanLines.join('\n') seriesLookupHint = seriesPluginResult?.seriesLookupHint || null;
: ''; const rawSeriesSummary = seriesAnalysis?.summary && typeof seriesAnalysis.summary === 'object'
if (scanText) { ? seriesAnalysis.summary
const { DVDSeriesPlugin } = require('../plugins/DVDSeriesPlugin'); : null;
const dvdSeriesPlugin = new DVDSeriesPlugin(); const seriesLike = Boolean(rawSeriesSummary?.seriesLike);
const dvdSeriesContext = await this.buildPluginContext(dvdSeriesPlugin.id, { seriesAnalysis = rawSeriesSummary
discInfo: deviceWithProfile, ? {
jobId: job.id, source: String(seriesAnalysis?.source || 'handbrake_scan_text').trim() || 'handbrake_scan_text',
scanText, generatedAt: seriesAnalysis?.generatedAt || nowIso(),
detectedTitle: effectiveDetectedTitle summary: {
}); seriesLike,
const seriesPluginResult = await dvdSeriesPlugin.analyze(device.path, job, dvdSeriesContext); confidence: String(rawSeriesSummary?.confidence || 'low').trim().toLowerCase() || 'low',
pluginExecution = this.mergePluginExecutionState( reasons: Array.isArray(rawSeriesSummary?.reasons) ? rawSeriesSummary.reasons : [],
pluginExecution, titleCount: Number(rawSeriesSummary?.titleCount || 0) || 0
this.sanitizePluginExecutionState(dvdSeriesContext.getPluginExecution())
);
seriesAnalysis = seriesPluginResult?.seriesAnalysis || null;
seriesLookupHint = seriesPluginResult?.seriesLookupHint || null;
const rawSeriesSummary = seriesAnalysis?.summary && typeof seriesAnalysis.summary === 'object'
? seriesAnalysis.summary
: null;
const seriesLike = Boolean(rawSeriesSummary?.seriesLike);
seriesAnalysis = rawSeriesSummary
? {
source: String(seriesAnalysis?.source || 'handbrake_scan_text').trim() || 'handbrake_scan_text',
generatedAt: seriesAnalysis?.generatedAt || nowIso(),
summary: {
seriesLike,
confidence: String(rawSeriesSummary?.confidence || 'low').trim().toLowerCase() || 'low',
reasons: Array.isArray(rawSeriesSummary?.reasons) ? rawSeriesSummary.reasons : [],
titleCount: Number(rawSeriesSummary?.titleCount || 0) || 0
}
} }
: null;
if (seriesLike) {
metadataProvider = 'tmdb';
metadataCandidates = [];
const fallbackQuery = String(seriesLookupHint?.query || effectiveDetectedTitle || '').trim() || null;
if (fallbackQuery) {
seriesLookupHint = {
...(seriesLookupHint && typeof seriesLookupHint === 'object' ? seriesLookupHint : {}),
query: fallbackQuery,
seriesTitle: String(seriesLookupHint?.seriesTitle || fallbackQuery).trim() || fallbackQuery
};
} }
: null;
if (seriesPluginResult?.providerConfigured && seriesLookupHint?.query) { if (seriesLike) {
metadataCandidates = await tmdbService.searchSeriesWithSeasons( metadataProvider = 'tmdb';
seriesLookupHint.query, metadataCandidates = [];
{ language: dvdSettings?.dvd_series_language || null } const fallbackQuery = String(seriesLookupHint?.query || effectiveDetectedTitle || '').trim() || null;
).catch((error) => { if (fallbackQuery) {
logger.warn('dvd-series:tmdb-search-failed', { seriesLookupHint = {
jobId: job.id, ...(seriesLookupHint && typeof seriesLookupHint === 'object' ? seriesLookupHint : {}),
query: seriesLookupHint?.query || null, query: fallbackQuery,
seasonNumber: seriesLookupHint?.seasonNumber || null, seriesTitle: String(seriesLookupHint?.seriesTitle || fallbackQuery).trim() || fallbackQuery
error: errorToMeta(error) };
});
return [];
});
}
} }
logger.info('dvd-series:analyze:done', { if (seriesPluginResult?.providerConfigured && seriesLookupHint?.query) {
jobId: job.id, metadataCandidates = await tmdbService.searchSeriesWithSeasons(
seriesLike: Boolean(seriesAnalysis?.summary?.seriesLike), seriesLookupHint.query,
confidence: seriesAnalysis?.summary?.confidence || null, { language: dvdSettings?.dvd_series_language || null }
metadataProvider, ).catch((error) => {
metadataCandidateCount: Array.isArray(metadataCandidates) ? metadataCandidates.length : 0, logger.warn('dvd-series:tmdb-search-failed', {
seriesLookupHint jobId: job.id,
}); query: seriesLookupHint?.query || null,
seasonNumber: seriesLookupHint?.seasonNumber || null,
error: errorToMeta(error)
});
return [];
});
}
} }
logger.info('dvd-series:analyze:done', {
jobId: job.id,
seriesLike: Boolean(seriesAnalysis?.summary?.seriesLike),
confidence: seriesAnalysis?.summary?.confidence || null,
metadataProvider,
metadataCandidateCount: Array.isArray(metadataCandidates) ? metadataCandidates.length : 0,
seriesLookupHint
});
} }
} catch (error) { } catch (error) {
logger.warn('dvd-series:analyze:fallback-legacy', { logger.warn('dvd-series:analyze:fallback-legacy', {
-8
View File
@@ -345,14 +345,6 @@ INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, des
VALUES ('hardware_monitoring_interval_ms', 'Monitoring', 'Hardware Monitoring Intervall (ms)', 'number', 1, 'Polling-Intervall für CPU/RAM/GPU/Storage-Metriken.', '5000', '[]', '{"min":1000,"max":60000}', 140); VALUES ('hardware_monitoring_interval_ms', 'Monitoring', 'Hardware Monitoring Intervall (ms)', 'number', 1, 'Polling-Intervall für CPU/RAM/GPU/Storage-Metriken.', '5000', '[]', '{"min":1000,"max":60000}', 140);
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('hardware_monitoring_interval_ms', '5000'); INSERT OR IGNORE INTO settings_values (key, value) VALUES ('hardware_monitoring_interval_ms', '5000');
INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index)
VALUES ('dvd_series_plugin_enabled', 'Features', 'DVD Serien-Plugin aktiviert', 'boolean', 1, 'Aktiviert die additive Serienerkennung für DVDs. Wenn deaktiviert, bleibt der bestehende DVD-Film-Flow unverändert.', 'false', '[]', '{}', 145);
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('dvd_series_plugin_enabled', 'false');
INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index, depends_on)
VALUES ('dvd_series_prescan_enabled', 'Features', 'DVD HandBrake-Prescan aktiviert', 'boolean', 1, 'Führt nach der DVD-Erkennung einen zusätzlichen HandBrake-Prescan für die Serienheuristik aus.', 'true', '[]', '{}', 146, 'dvd_series_plugin_enabled');
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('dvd_series_prescan_enabled', 'true');
-- Tools -- Tools
INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index) INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index)
VALUES ('makemkv_command', 'Tools', 'MakeMKV Kommando', 'string', 1, 'Pfad oder Befehl für makemkvcon.', 'makemkvcon', '[]', '{"minLength":1}', 200); VALUES ('makemkv_command', 'Tools', 'MakeMKV Kommando', 'string', 1, 'Pfad oder Befehl für makemkvcon.', 'makemkvcon', '[]', '{"minLength":1}', 200);
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "ripster-frontend", "name": "ripster-frontend",
"version": "0.13.1-2", "version": "0.13.1-3",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "ripster-frontend", "name": "ripster-frontend",
"version": "0.13.1-2", "version": "0.13.1-3",
"dependencies": { "dependencies": {
"primeicons": "^7.0.0", "primeicons": "^7.0.0",
"primereact": "^10.9.2", "primereact": "^10.9.2",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "ripster-frontend", "name": "ripster-frontend",
"version": "0.13.1-2", "version": "0.13.1-3",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "ripster", "name": "ripster",
"version": "0.13.1-2", "version": "0.13.1-3",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "ripster", "name": "ripster",
"version": "0.13.1-2", "version": "0.13.1-3",
"devDependencies": { "devDependencies": {
"concurrently": "^9.1.2" "concurrently": "^9.1.2"
} }
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "ripster", "name": "ripster",
"private": true, "private": true,
"version": "0.13.1-2", "version": "0.13.1-3",
"scripts": { "scripts": {
"dev": "concurrently \"npm run dev --prefix backend\" \"npm run dev --prefix frontend\"", "dev": "concurrently \"npm run dev --prefix backend\" \"npm run dev --prefix frontend\"",
"dev:backend": "npm run dev --prefix backend", "dev:backend": "npm run dev --prefix backend",