0.12.0-7 remove legacy
This commit is contained in:
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "ripster-backend",
|
"name": "ripster-backend",
|
||||||
"version": "0.12.0-6",
|
"version": "0.12.0-7",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "ripster-backend",
|
"name": "ripster-backend",
|
||||||
"version": "0.12.0-6",
|
"version": "0.12.0-7",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"archiver": "^7.0.1",
|
"archiver": "^7.0.1",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ripster-backend",
|
"name": "ripster-backend",
|
||||||
"version": "0.12.0-6",
|
"version": "0.12.0-7",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
+18
-197
@@ -790,7 +790,24 @@ async function removeDeprecatedSettings(db) {
|
|||||||
'filename_template_dvd',
|
'filename_template_dvd',
|
||||||
'output_folder_template_bluray',
|
'output_folder_template_bluray',
|
||||||
'output_folder_template_dvd',
|
'output_folder_template_dvd',
|
||||||
'output_extension_audiobook'
|
'output_extension_audiobook',
|
||||||
|
'use_plugin_architecture',
|
||||||
|
'use_plugin_architecture_bluray',
|
||||||
|
'use_plugin_architecture_bluray_analyze',
|
||||||
|
'use_plugin_architecture_bluray_rip',
|
||||||
|
'use_plugin_architecture_bluray_review',
|
||||||
|
'use_plugin_architecture_bluray_encode',
|
||||||
|
'use_plugin_architecture_dvd',
|
||||||
|
'use_plugin_architecture_dvd_analyze',
|
||||||
|
'use_plugin_architecture_dvd_rip',
|
||||||
|
'use_plugin_architecture_dvd_review',
|
||||||
|
'use_plugin_architecture_dvd_encode',
|
||||||
|
'use_plugin_architecture_cd',
|
||||||
|
'use_plugin_architecture_cd_analyze',
|
||||||
|
'use_plugin_architecture_cd_rip',
|
||||||
|
'use_plugin_architecture_audiobook',
|
||||||
|
'use_plugin_architecture_audiobook_analyze',
|
||||||
|
'use_plugin_architecture_audiobook_encode'
|
||||||
];
|
];
|
||||||
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]);
|
||||||
@@ -996,202 +1013,6 @@ async function migrateSettingsSchemaMetadata(db) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Plugin-Architektur Toggle (Phase 2) — hierarchisch mit depends_on
|
|
||||||
// Struktur: global → medium (depends_on: global) → phase (depends_on: medium)
|
|
||||||
//
|
|
||||||
// Implementierungsstand:
|
|
||||||
// ✅ = plugin-pfad aktiv ⏳ = noch nicht implementiert (readonly, immer aus)
|
|
||||||
//
|
|
||||||
// BluRay / DVD: Analyse ✅ Rip ✅ Review ⏳ Encode ⏳
|
|
||||||
// CD: Analyse ✅ Rip ✅
|
|
||||||
// Audiobook: Analyse ✅ Encode ⏳
|
|
||||||
|
|
||||||
const pluginArchitectureSettings = [
|
|
||||||
// ── Global ──────────────────────────────────────────────────────────────
|
|
||||||
{
|
|
||||||
key: 'use_plugin_architecture',
|
|
||||||
label: 'Neue Plugin-Architektur (Beta)',
|
|
||||||
description: 'Masterschalter: Aktiviert die neue modulare Plugin-Architektur (Phase 2). Alle Medium-Schalter darunter sind nur wirksam wenn dieser aktiv ist.',
|
|
||||||
defaultValue: 'false',
|
|
||||||
orderIndex: 9999,
|
|
||||||
dependsOn: null,
|
|
||||||
validationJson: '{}'
|
|
||||||
},
|
|
||||||
// ── Blu-ray ──────────────────────────────────────────────────────────────
|
|
||||||
{
|
|
||||||
key: 'use_plugin_architecture_bluray',
|
|
||||||
label: 'Blu-ray Plugin',
|
|
||||||
description: 'Aktiviert das Blu-ray Plugin. Deaktiviert = Legacy-Pfad für alle Blu-ray-Phasen.',
|
|
||||||
defaultValue: 'true',
|
|
||||||
orderIndex: 10000,
|
|
||||||
dependsOn: 'use_plugin_architecture',
|
|
||||||
validationJson: '{}'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'use_plugin_architecture_bluray_analyze',
|
|
||||||
label: 'Analyse (Blu-ray)',
|
|
||||||
description: 'Disc-Erkennung und OMDB-Suche laufen über das Plugin.',
|
|
||||||
defaultValue: 'true',
|
|
||||||
orderIndex: 10001,
|
|
||||||
dependsOn: 'use_plugin_architecture_bluray',
|
|
||||||
validationJson: '{}'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'use_plugin_architecture_bluray_rip',
|
|
||||||
label: 'Rip (Blu-ray)',
|
|
||||||
description: 'MakeMKV-Rip läuft über das Plugin.',
|
|
||||||
defaultValue: 'true',
|
|
||||||
orderIndex: 10002,
|
|
||||||
dependsOn: 'use_plugin_architecture_bluray',
|
|
||||||
validationJson: '{}'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'use_plugin_architecture_bluray_review',
|
|
||||||
label: 'Review / Mediainfo-Prüfung (Blu-ray)',
|
|
||||||
description: 'HandBrake-Scan läuft über das Blu-ray-Plugin.',
|
|
||||||
defaultValue: 'true',
|
|
||||||
orderIndex: 10003,
|
|
||||||
dependsOn: 'use_plugin_architecture_bluray',
|
|
||||||
validationJson: '{}'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'use_plugin_architecture_bluray_encode',
|
|
||||||
label: 'Encoding (Blu-ray)',
|
|
||||||
description: 'Encoding läuft über das Blu-ray-Plugin.',
|
|
||||||
defaultValue: 'true',
|
|
||||||
orderIndex: 10004,
|
|
||||||
dependsOn: 'use_plugin_architecture_bluray',
|
|
||||||
validationJson: '{}'
|
|
||||||
},
|
|
||||||
// ── DVD ──────────────────────────────────────────────────────────────────
|
|
||||||
{
|
|
||||||
key: 'use_plugin_architecture_dvd',
|
|
||||||
label: 'DVD Plugin',
|
|
||||||
description: 'Aktiviert das DVD Plugin. Deaktiviert = Legacy-Pfad für alle DVD-Phasen.',
|
|
||||||
defaultValue: 'true',
|
|
||||||
orderIndex: 10010,
|
|
||||||
dependsOn: 'use_plugin_architecture',
|
|
||||||
validationJson: '{}'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'use_plugin_architecture_dvd_analyze',
|
|
||||||
label: 'Analyse (DVD)',
|
|
||||||
description: 'Disc-Erkennung und OMDB-Suche laufen über das Plugin.',
|
|
||||||
defaultValue: 'true',
|
|
||||||
orderIndex: 10011,
|
|
||||||
dependsOn: 'use_plugin_architecture_dvd',
|
|
||||||
validationJson: '{}'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'use_plugin_architecture_dvd_rip',
|
|
||||||
label: 'Rip (DVD)',
|
|
||||||
description: 'MakeMKV-Rip läuft über das Plugin.',
|
|
||||||
defaultValue: 'true',
|
|
||||||
orderIndex: 10012,
|
|
||||||
dependsOn: 'use_plugin_architecture_dvd',
|
|
||||||
validationJson: '{}'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'use_plugin_architecture_dvd_review',
|
|
||||||
label: 'Review / Mediainfo-Prüfung (DVD)',
|
|
||||||
description: 'Review-/Track-Analyse läuft über das DVD-Plugin.',
|
|
||||||
defaultValue: 'true',
|
|
||||||
orderIndex: 10013,
|
|
||||||
dependsOn: 'use_plugin_architecture_dvd',
|
|
||||||
validationJson: '{}'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'use_plugin_architecture_dvd_encode',
|
|
||||||
label: 'Encoding (DVD)',
|
|
||||||
description: 'Encoding läuft über das DVD-Plugin.',
|
|
||||||
defaultValue: 'true',
|
|
||||||
orderIndex: 10014,
|
|
||||||
dependsOn: 'use_plugin_architecture_dvd',
|
|
||||||
validationJson: '{}'
|
|
||||||
},
|
|
||||||
// ── Audio-CD ─────────────────────────────────────────────────────────────
|
|
||||||
{
|
|
||||||
key: 'use_plugin_architecture_cd',
|
|
||||||
label: 'Audio-CD Plugin',
|
|
||||||
description: 'Aktiviert das Audio-CD Plugin. Deaktiviert = Legacy-Pfad für alle CD-Phasen.',
|
|
||||||
defaultValue: 'true',
|
|
||||||
orderIndex: 10020,
|
|
||||||
dependsOn: 'use_plugin_architecture',
|
|
||||||
validationJson: '{}'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'use_plugin_architecture_cd_analyze',
|
|
||||||
label: 'Analyse (Audio-CD)',
|
|
||||||
description: 'TOC-Auslesung läuft über das Plugin.',
|
|
||||||
defaultValue: 'true',
|
|
||||||
orderIndex: 10021,
|
|
||||||
dependsOn: 'use_plugin_architecture_cd',
|
|
||||||
validationJson: '{}'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'use_plugin_architecture_cd_rip',
|
|
||||||
label: 'Rip (Audio-CD)',
|
|
||||||
description: 'CD-Rip/RAW-Rip/Encode-aus-RAW läuft über das Plugin.',
|
|
||||||
defaultValue: 'true',
|
|
||||||
orderIndex: 10022,
|
|
||||||
dependsOn: 'use_plugin_architecture_cd',
|
|
||||||
validationJson: '{}'
|
|
||||||
},
|
|
||||||
// ── Audiobook ────────────────────────────────────────────────────────────
|
|
||||||
{
|
|
||||||
key: 'use_plugin_architecture_audiobook',
|
|
||||||
label: 'Audiobook Plugin',
|
|
||||||
description: 'Aktiviert das Audiobook Plugin. Deaktiviert = Legacy-Pfad für alle Audiobook-Phasen.',
|
|
||||||
defaultValue: 'true',
|
|
||||||
orderIndex: 10030,
|
|
||||||
dependsOn: 'use_plugin_architecture',
|
|
||||||
validationJson: '{}'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'use_plugin_architecture_audiobook_analyze',
|
|
||||||
label: 'Analyse (Audiobook)',
|
|
||||||
description: 'ffprobe-Metadatenanalyse läuft über das Plugin.',
|
|
||||||
defaultValue: 'true',
|
|
||||||
orderIndex: 10031,
|
|
||||||
dependsOn: 'use_plugin_architecture_audiobook',
|
|
||||||
validationJson: '{}'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'use_plugin_architecture_audiobook_encode',
|
|
||||||
label: 'Encoding (Audiobook)',
|
|
||||||
description: 'Encoding läuft über das Audiobook-Plugin.',
|
|
||||||
defaultValue: 'true',
|
|
||||||
orderIndex: 10032,
|
|
||||||
dependsOn: 'use_plugin_architecture_audiobook',
|
|
||||||
validationJson: '{}'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
for (const setting of pluginArchitectureSettings) {
|
|
||||||
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 (?, 'Erweitert', ?, 'boolean', 1, ?, ?, '[]', ?, ?, ?)`,
|
|
||||||
[setting.key, setting.label, setting.description, setting.defaultValue, setting.validationJson, setting.orderIndex, setting.dependsOn ?? null]
|
|
||||||
);
|
|
||||||
// depends_on und order_index für bereits existierende Zeilen aktualisieren
|
|
||||||
await db.run(
|
|
||||||
`UPDATE settings_schema SET depends_on = ?, order_index = ?, validation_json = ?, updated_at = CURRENT_TIMESTAMP
|
|
||||||
WHERE key = ? AND (depends_on IS NOT ? OR order_index != ? OR validation_json != ?)`,
|
|
||||||
[setting.dependsOn ?? null, setting.orderIndex, setting.validationJson, setting.key, setting.dependsOn ?? null, setting.orderIndex, setting.validationJson]
|
|
||||||
);
|
|
||||||
await db.run(
|
|
||||||
`UPDATE settings_schema
|
|
||||||
SET label = ?, description = ?, default_value = ?, updated_at = CURRENT_TIMESTAMP
|
|
||||||
WHERE key = ?
|
|
||||||
AND (label != ? OR description != ? OR COALESCE(default_value, '') != COALESCE(?, ''))`,
|
|
||||||
[setting.label, setting.description, setting.defaultValue, setting.key, setting.label, setting.description, setting.defaultValue]
|
|
||||||
);
|
|
||||||
await db.run(`INSERT OR IGNORE INTO settings_values (key, value) VALUES (?, ?)`, [setting.key, setting.defaultValue]);
|
|
||||||
// Readonly-Toggles immer auf 'false' zurücksetzen (nie aktivierbar)
|
|
||||||
if (setting.validationJson === '{"readonly":true}') {
|
|
||||||
await db.run(`UPDATE settings_values SET value = 'false' WHERE key = ?`, [setting.key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await db.run(`
|
await db.run(`
|
||||||
CREATE TABLE IF NOT EXISTS user_prefs (
|
CREATE TABLE IF NOT EXISTS user_prefs (
|
||||||
key TEXT PRIMARY KEY,
|
key TEXT PRIMARY KEY,
|
||||||
|
|||||||
@@ -4007,93 +4007,12 @@ class PipelineService extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async isPluginArchitectureEnabled() {
|
async resolveAnalyzePlugin(discInfo = null) {
|
||||||
return this.isPluginArchitectureEnabledForPlugin(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
getPluginArchitectureSettingKey(pluginId = null) {
|
|
||||||
const normalizedPluginId = String(pluginId || '').trim().toLowerCase();
|
|
||||||
if (!normalizedPluginId) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const byPluginId = {
|
|
||||||
bluray: 'use_plugin_architecture_bluray',
|
|
||||||
dvd: 'use_plugin_architecture_dvd',
|
|
||||||
cd: 'use_plugin_architecture_cd',
|
|
||||||
audiobook: 'use_plugin_architecture_audiobook'
|
|
||||||
};
|
|
||||||
return byPluginId[normalizedPluginId] || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
isPluginArchitectureEnabledForSettings(settingsMap = null, pluginId = null, phase = null) {
|
|
||||||
const settings = settingsMap && typeof settingsMap === 'object' ? settingsMap : {};
|
|
||||||
const globalEnabled = this.normalizeBooleanSetting(settings.use_plugin_architecture);
|
|
||||||
if (!globalEnabled) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pluginSettingKey = this.getPluginArchitectureSettingKey(pluginId);
|
|
||||||
if (!pluginSettingKey) {
|
|
||||||
return globalEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(pluginSettingKey in settings)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.normalizeBooleanSetting(settings[pluginSettingKey])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Phasen-spezifischer Toggle: use_plugin_architecture_{id}_{phase}
|
|
||||||
if (phase) {
|
|
||||||
const normalizedId = String(pluginId || '').trim().toLowerCase();
|
|
||||||
const phaseKey = `use_plugin_architecture_${normalizedId}_${phase}`;
|
|
||||||
if (phaseKey in settings && !this.normalizeBooleanSetting(settings[phaseKey])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
async isPluginArchitectureEnabledForPlugin(pluginId = null, phase = null) {
|
|
||||||
try {
|
|
||||||
const settingsMap = await settingsService.getSettingsMap();
|
|
||||||
return this.isPluginArchitectureEnabledForSettings(settingsMap, pluginId, phase);
|
|
||||||
} catch (error) {
|
|
||||||
logger.warn('plugin-architecture:settings-read-failed', {
|
|
||||||
error: errorToMeta(error),
|
|
||||||
pluginId: pluginId || null,
|
|
||||||
phase: phase || null
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async resolveAnalyzePlugin(discInfo = null, phase = 'analyze') {
|
|
||||||
const enabled = await this.isPluginArchitectureEnabledForPlugin(null);
|
|
||||||
if (!enabled) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const registry = this.ensureSourcePluginRegistry();
|
const registry = this.ensureSourcePluginRegistry();
|
||||||
if (!registry) {
|
if (!registry) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const plugin = registry.findPlugin(discInfo);
|
return registry.findPlugin(discInfo) || null;
|
||||||
if (!plugin?.id) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const pluginEnabled = await this.isPluginArchitectureEnabledForPlugin(plugin.id, phase);
|
|
||||||
if (!pluginEnabled) {
|
|
||||||
logger.info('plugin-architecture:plugin-phase-disabled', {
|
|
||||||
pluginId: plugin.id,
|
|
||||||
phase,
|
|
||||||
mediaProfile: discInfo?.mediaProfile || null
|
|
||||||
});
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return plugin;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sanitizePluginExecutionState(rawState = null) {
|
sanitizePluginExecutionState(rawState = null) {
|
||||||
@@ -7284,11 +7203,6 @@ class PipelineService extends EventEmitter {
|
|||||||
});
|
});
|
||||||
const settings = await settingsService.getEffectiveSettingsMap(mediaProfile);
|
const settings = await settingsService.getEffectiveSettingsMap(mediaProfile);
|
||||||
const reviewPlugin = await this.resolveAnalyzePlugin({ mediaProfile }, 'review').catch(() => null);
|
const reviewPlugin = await this.resolveAnalyzePlugin({ mediaProfile }, 'review').catch(() => null);
|
||||||
const reviewPluginEnabled = Boolean(
|
|
||||||
reviewPlugin
|
|
||||||
&& reviewPlugin.id === mediaProfile
|
|
||||||
&& typeof reviewPlugin.review === 'function'
|
|
||||||
);
|
|
||||||
let reviewPluginExecution = null;
|
let reviewPluginExecution = null;
|
||||||
const analyzeContext = mkInfo?.analyzeContext || {};
|
const analyzeContext = mkInfo?.analyzeContext || {};
|
||||||
const playlistAnalysis = analyzeContext.playlistAnalysis || this.snapshot.context?.playlistAnalysis || null;
|
const playlistAnalysis = analyzeContext.playlistAnalysis || this.snapshot.context?.playlistAnalysis || null;
|
||||||
@@ -7340,42 +7254,20 @@ class PipelineService extends EventEmitter {
|
|||||||
const lines = [];
|
const lines = [];
|
||||||
let runInfo = null;
|
let runInfo = null;
|
||||||
let sourceArg = null;
|
let sourceArg = null;
|
||||||
if (reviewPluginEnabled) {
|
const pluginScan = await this.runPluginReviewScan(reviewPlugin, job, {
|
||||||
const pluginScan = await this.runPluginReviewScan(reviewPlugin, job, {
|
jobId,
|
||||||
jobId,
|
deviceInfo,
|
||||||
deviceInfo,
|
reviewMode: 'pre_rip',
|
||||||
reviewMode: 'pre_rip',
|
source: 'HANDBRAKE_SCAN',
|
||||||
source: 'HANDBRAKE_SCAN',
|
silent: !this.isPrimaryJob(jobId)
|
||||||
silent: !this.isPrimaryJob(jobId)
|
});
|
||||||
});
|
lines.push(...pluginScan.scanLines);
|
||||||
lines.push(...pluginScan.scanLines);
|
runInfo = pluginScan.runInfo || null;
|
||||||
runInfo = pluginScan.runInfo || null;
|
sourceArg = pluginScan.sourceArg || null;
|
||||||
sourceArg = pluginScan.sourceArg || null;
|
reviewPluginExecution = this.mergePluginExecutionState(
|
||||||
reviewPluginExecution = this.mergePluginExecutionState(
|
reviewPluginExecution,
|
||||||
reviewPluginExecution,
|
pluginScan.pluginExecution
|
||||||
pluginScan.pluginExecution
|
);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const scanConfig = await settingsService.buildHandBrakeScanConfig(deviceInfo, { mediaProfile });
|
|
||||||
logger.info('disc-track-review:command', {
|
|
||||||
jobId,
|
|
||||||
cmd: scanConfig.cmd,
|
|
||||||
args: scanConfig.args,
|
|
||||||
sourceArg: scanConfig.sourceArg,
|
|
||||||
selectedTitleId: selectedMakemkvTitleId
|
|
||||||
});
|
|
||||||
|
|
||||||
runInfo = await this.runCommand({
|
|
||||||
jobId,
|
|
||||||
stage: 'MEDIAINFO_CHECK',
|
|
||||||
source: 'HANDBRAKE_SCAN',
|
|
||||||
cmd: scanConfig.cmd,
|
|
||||||
args: scanConfig.args,
|
|
||||||
collectLines: lines,
|
|
||||||
collectStderrLines: false
|
|
||||||
});
|
|
||||||
sourceArg = scanConfig.sourceArg;
|
|
||||||
}
|
|
||||||
|
|
||||||
const parsed = parseMediainfoJsonOutput(lines.join('\n'));
|
const parsed = parseMediainfoJsonOutput(lines.join('\n'));
|
||||||
if (!parsed) {
|
if (!parsed) {
|
||||||
@@ -7533,11 +7425,6 @@ class PipelineService extends EventEmitter {
|
|||||||
});
|
});
|
||||||
const settings = await settingsService.getEffectiveSettingsMap(mediaProfile);
|
const settings = await settingsService.getEffectiveSettingsMap(mediaProfile);
|
||||||
const reviewPlugin = await this.resolveAnalyzePlugin({ mediaProfile }, 'review').catch(() => null);
|
const reviewPlugin = await this.resolveAnalyzePlugin({ mediaProfile }, 'review').catch(() => null);
|
||||||
const reviewPluginEnabled = Boolean(
|
|
||||||
reviewPlugin
|
|
||||||
&& reviewPlugin.id === mediaProfile
|
|
||||||
&& typeof reviewPlugin.review === 'function'
|
|
||||||
);
|
|
||||||
let reviewPluginExecution = null;
|
let reviewPluginExecution = null;
|
||||||
const analyzeContext = mkInfo?.analyzeContext || {};
|
const analyzeContext = mkInfo?.analyzeContext || {};
|
||||||
let playlistAnalysis = forceFreshAnalyze
|
let playlistAnalysis = forceFreshAnalyze
|
||||||
@@ -7699,39 +7586,18 @@ class PipelineService extends EventEmitter {
|
|||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
const resolveScanLines = [];
|
const resolveScanLines = [];
|
||||||
if (reviewPluginEnabled) {
|
const pluginScan = await this.runPluginReviewScan(reviewPlugin, job, {
|
||||||
const pluginScan = await this.runPluginReviewScan(reviewPlugin, job, {
|
jobId,
|
||||||
jobId,
|
rawPath,
|
||||||
rawPath,
|
reviewMode: 'rip',
|
||||||
reviewMode: 'rip',
|
source: 'HANDBRAKE_SCAN_PLAYLIST_MAP',
|
||||||
source: 'HANDBRAKE_SCAN_PLAYLIST_MAP',
|
silent: !this.isPrimaryJob(jobId)
|
||||||
silent: !this.isPrimaryJob(jobId)
|
});
|
||||||
});
|
resolveScanLines.push(...pluginScan.scanLines);
|
||||||
resolveScanLines.push(...pluginScan.scanLines);
|
reviewPluginExecution = this.mergePluginExecutionState(
|
||||||
reviewPluginExecution = this.mergePluginExecutionState(
|
reviewPluginExecution,
|
||||||
reviewPluginExecution,
|
pluginScan.pluginExecution
|
||||||
pluginScan.pluginExecution
|
);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const resolveScanConfig = await settingsService.buildHandBrakeScanConfigForInput(rawPath, { mediaProfile });
|
|
||||||
logger.info('backup-track-review:handbrake-predecision-command', {
|
|
||||||
jobId,
|
|
||||||
cmd: resolveScanConfig.cmd,
|
|
||||||
args: resolveScanConfig.args,
|
|
||||||
sourceArg: resolveScanConfig.sourceArg,
|
|
||||||
candidatePlaylists: playlistCandidates.map((item) => item.playlistFile || item.playlistId)
|
|
||||||
});
|
|
||||||
|
|
||||||
await this.runCommand({
|
|
||||||
jobId,
|
|
||||||
stage: 'MEDIAINFO_CHECK',
|
|
||||||
source: 'HANDBRAKE_SCAN_PLAYLIST_MAP',
|
|
||||||
cmd: resolveScanConfig.cmd,
|
|
||||||
args: resolveScanConfig.args,
|
|
||||||
collectLines: resolveScanLines,
|
|
||||||
collectStderrLines: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const resolveScanJson = parseMediainfoJsonOutput(resolveScanLines.join('\n'));
|
const resolveScanJson = parseMediainfoJsonOutput(resolveScanLines.join('\n'));
|
||||||
if (resolveScanJson) {
|
if (resolveScanJson) {
|
||||||
@@ -7753,16 +7619,9 @@ class PipelineService extends EventEmitter {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (reviewPluginEnabled) {
|
const error = new Error('HandBrake Playlist-Trackdaten konnten nicht geparst werden.');
|
||||||
const error = new Error('HandBrake Playlist-Trackdaten konnten nicht geparst werden (Plugin-Review aktiv, kein Fallback).');
|
error.runInfo = null;
|
||||||
error.runInfo = null;
|
throw error;
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
await historyService.appendLog(
|
|
||||||
jobId,
|
|
||||||
'SYSTEM',
|
|
||||||
'HandBrake Playlist-Trackdaten konnten nicht geparst werden (Warteansicht ohne Audiodetails).'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.warn('backup-track-review:handbrake-predecision-failed', {
|
logger.warn('backup-track-review:handbrake-predecision-failed', {
|
||||||
@@ -7774,9 +7633,7 @@ class PipelineService extends EventEmitter {
|
|||||||
'SYSTEM',
|
'SYSTEM',
|
||||||
`HandBrake Voranalyse für Playlist-Auswahl fehlgeschlagen: ${error.message}`
|
`HandBrake Voranalyse für Playlist-Auswahl fehlgeschlagen: ${error.message}`
|
||||||
);
|
);
|
||||||
if (reviewPluginEnabled) {
|
throw error;
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
playlistAnalysis = enrichPlaylistAnalysisWithHandBrakeCache(playlistAnalysis, handBrakePlaylistScan);
|
playlistAnalysis = enrichPlaylistAnalysisWithHandBrakeCache(playlistAnalysis, handBrakePlaylistScan);
|
||||||
@@ -8024,42 +7881,19 @@ class PipelineService extends EventEmitter {
|
|||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
const resolveScanLines = [];
|
const resolveScanLines = [];
|
||||||
if (reviewPluginEnabled) {
|
const pluginScan = await this.runPluginReviewScan(reviewPlugin, job, {
|
||||||
const pluginScan = await this.runPluginReviewScan(reviewPlugin, job, {
|
jobId,
|
||||||
jobId,
|
rawPath,
|
||||||
rawPath,
|
reviewMode: 'rip',
|
||||||
reviewMode: 'rip',
|
source: 'HANDBRAKE_SCAN_PLAYLIST_MAP',
|
||||||
source: 'HANDBRAKE_SCAN_PLAYLIST_MAP',
|
silent: !this.isPrimaryJob(jobId)
|
||||||
silent: !this.isPrimaryJob(jobId)
|
});
|
||||||
});
|
resolveScanLines.push(...pluginScan.scanLines);
|
||||||
resolveScanLines.push(...pluginScan.scanLines);
|
handBrakeResolveRunInfo = pluginScan.runInfo || null;
|
||||||
handBrakeResolveRunInfo = pluginScan.runInfo || null;
|
reviewPluginExecution = this.mergePluginExecutionState(
|
||||||
reviewPluginExecution = this.mergePluginExecutionState(
|
reviewPluginExecution,
|
||||||
reviewPluginExecution,
|
pluginScan.pluginExecution
|
||||||
pluginScan.pluginExecution
|
);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const resolveScanConfig = await settingsService.buildHandBrakeScanConfigForInput(rawPath, { mediaProfile });
|
|
||||||
logger.info('backup-track-review:handbrake-resolve-command', {
|
|
||||||
jobId,
|
|
||||||
cmd: resolveScanConfig.cmd,
|
|
||||||
args: resolveScanConfig.args,
|
|
||||||
sourceArg: resolveScanConfig.sourceArg,
|
|
||||||
selectedPlaylistId: resolvedPlaylistId,
|
|
||||||
selectedMakemkvTitleId: selectedTitleForReview
|
|
||||||
});
|
|
||||||
|
|
||||||
handBrakeResolveRunInfo = await this.runCommand({
|
|
||||||
jobId,
|
|
||||||
stage: 'MEDIAINFO_CHECK',
|
|
||||||
source: 'HANDBRAKE_SCAN_PLAYLIST_MAP',
|
|
||||||
cmd: resolveScanConfig.cmd,
|
|
||||||
args: resolveScanConfig.args,
|
|
||||||
collectLines: resolveScanLines,
|
|
||||||
collectStderrLines: false,
|
|
||||||
silent: !this.isPrimaryJob(jobId)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const resolveScanJson = parseMediainfoJsonOutput(resolveScanLines.join('\n'));
|
const resolveScanJson = parseMediainfoJsonOutput(resolveScanLines.join('\n'));
|
||||||
if (!resolveScanJson) {
|
if (!resolveScanJson) {
|
||||||
@@ -9887,11 +9721,6 @@ class PipelineService extends EventEmitter {
|
|||||||
});
|
});
|
||||||
const settings = await settingsService.getEffectiveSettingsMap(mediaProfile);
|
const settings = await settingsService.getEffectiveSettingsMap(mediaProfile);
|
||||||
const reviewPlugin = await this.resolveAnalyzePlugin({ mediaProfile }, 'review').catch(() => null);
|
const reviewPlugin = await this.resolveAnalyzePlugin({ mediaProfile }, 'review').catch(() => null);
|
||||||
const reviewPluginEnabled = Boolean(
|
|
||||||
reviewPlugin
|
|
||||||
&& reviewPlugin.id === mediaProfile
|
|
||||||
&& typeof reviewPlugin.review === 'function'
|
|
||||||
);
|
|
||||||
let reviewPluginExecution = null;
|
let reviewPluginExecution = null;
|
||||||
const analyzeContext = mkInfo?.analyzeContext || {};
|
const analyzeContext = mkInfo?.analyzeContext || {};
|
||||||
const selectedPlaylistId = normalizePlaylistId(
|
const selectedPlaylistId = normalizePlaylistId(
|
||||||
@@ -10025,42 +9854,19 @@ class PipelineService extends EventEmitter {
|
|||||||
|
|
||||||
const dvdScanLines = [];
|
const dvdScanLines = [];
|
||||||
let dvdScanRunInfo = null;
|
let dvdScanRunInfo = null;
|
||||||
if (reviewPluginEnabled) {
|
const pluginScan = await this.runPluginReviewScan(reviewPlugin, job, {
|
||||||
const pluginScan = await this.runPluginReviewScan(reviewPlugin, job, {
|
jobId,
|
||||||
jobId,
|
rawPath: dvdHandBrakeScanInputPath,
|
||||||
rawPath: dvdHandBrakeScanInputPath,
|
reviewMode: 'rip',
|
||||||
reviewMode: 'rip',
|
source: 'HANDBRAKE_SCAN_DVD',
|
||||||
source: 'HANDBRAKE_SCAN_DVD',
|
silent: !this.isPrimaryJob(jobId)
|
||||||
silent: !this.isPrimaryJob(jobId)
|
});
|
||||||
});
|
dvdScanLines.push(...pluginScan.scanLines);
|
||||||
dvdScanLines.push(...pluginScan.scanLines);
|
dvdScanRunInfo = pluginScan.runInfo || null;
|
||||||
dvdScanRunInfo = pluginScan.runInfo || null;
|
reviewPluginExecution = this.mergePluginExecutionState(
|
||||||
reviewPluginExecution = this.mergePluginExecutionState(
|
reviewPluginExecution,
|
||||||
reviewPluginExecution,
|
pluginScan.pluginExecution
|
||||||
pluginScan.pluginExecution
|
);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const dvdScanConfig = await settingsService.buildHandBrakeScanConfigForInput(dvdHandBrakeScanInputPath, {
|
|
||||||
mediaProfile,
|
|
||||||
settingsMap: settings
|
|
||||||
});
|
|
||||||
logger.info('mediainfo:review:dvd-handbrake-scan:command', {
|
|
||||||
jobId,
|
|
||||||
dvdHandBrakeScanInputPath,
|
|
||||||
cmd: dvdScanConfig.cmd,
|
|
||||||
args: dvdScanConfig.args
|
|
||||||
});
|
|
||||||
|
|
||||||
dvdScanRunInfo = await this.runCommand({
|
|
||||||
jobId,
|
|
||||||
stage: 'MEDIAINFO_CHECK',
|
|
||||||
source: 'HANDBRAKE_SCAN_DVD',
|
|
||||||
cmd: dvdScanConfig.cmd,
|
|
||||||
args: dvdScanConfig.args,
|
|
||||||
collectLines: dvdScanLines,
|
|
||||||
collectStderrLines: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
dvdHandBrakeScanJson = parseMediainfoJsonOutput(dvdScanLines.join('\n'));
|
dvdHandBrakeScanJson = parseMediainfoJsonOutput(dvdScanLines.join('\n'));
|
||||||
if (dvdHandBrakeScanJson) {
|
if (dvdHandBrakeScanJson) {
|
||||||
@@ -10077,28 +9883,15 @@ class PipelineService extends EventEmitter {
|
|||||||
'SYSTEM',
|
'SYSTEM',
|
||||||
`HandBrake DVD-Scan: Audio=${audioCount}, Subtitle=${subtitleCount}, Dauer=${formatDurationClock(titleInfo.durationSeconds)}`
|
`HandBrake DVD-Scan: Audio=${audioCount}, Subtitle=${subtitleCount}, Dauer=${formatDurationClock(titleInfo.durationSeconds)}`
|
||||||
);
|
);
|
||||||
} else if (reviewPluginEnabled) {
|
} else {
|
||||||
const error = new Error('HandBrake DVD-Scan: Kein Titel erkannt (Plugin-Review aktiv, kein Fallback).');
|
const error = new Error('HandBrake DVD-Scan: Kein Titel erkannt.');
|
||||||
error.runInfo = dvdScanRunInfo;
|
error.runInfo = dvdScanRunInfo;
|
||||||
throw error;
|
throw error;
|
||||||
} else {
|
|
||||||
await historyService.appendLog(
|
|
||||||
jobId,
|
|
||||||
'SYSTEM',
|
|
||||||
'HandBrake DVD-Scan: Kein Titel erkannt, falle auf MediaInfo zurück.'
|
|
||||||
);
|
|
||||||
dvdHandBrakeScanJson = null;
|
|
||||||
}
|
}
|
||||||
} else if (reviewPluginEnabled) {
|
} else {
|
||||||
const error = new Error('HandBrake DVD-Scan: Ausgabe nicht lesbar (Plugin-Review aktiv, kein Fallback).');
|
const error = new Error('HandBrake DVD-Scan: Ausgabe nicht lesbar.');
|
||||||
error.runInfo = dvdScanRunInfo;
|
error.runInfo = dvdScanRunInfo;
|
||||||
throw error;
|
throw error;
|
||||||
} else {
|
|
||||||
await historyService.appendLog(
|
|
||||||
jobId,
|
|
||||||
'SYSTEM',
|
|
||||||
'HandBrake DVD-Scan: Ausgabe nicht lesbar, falle auf MediaInfo zurück.'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mediaInfoRuns.push({ filePath: dvdHandBrakeScanInputPath, runInfo: dvdScanRunInfo, fallbackRunInfo: null });
|
mediaInfoRuns.push({ filePath: dvdHandBrakeScanInputPath, runInfo: dvdScanRunInfo, fallbackRunInfo: null });
|
||||||
@@ -10282,41 +10075,19 @@ class PipelineService extends EventEmitter {
|
|||||||
await this.updateProgress('MEDIAINFO_CHECK', 100, null, 'HandBrake DVD Titel-Scan läuft', jobId);
|
await this.updateProgress('MEDIAINFO_CHECK', 100, null, 'HandBrake DVD Titel-Scan läuft', jobId);
|
||||||
const dvdTitleScanLines = [];
|
const dvdTitleScanLines = [];
|
||||||
let dvdTitleScanRunInfo = null;
|
let dvdTitleScanRunInfo = null;
|
||||||
if (reviewPluginEnabled) {
|
const pluginScan = await this.runPluginReviewScan(reviewPlugin, job, {
|
||||||
const pluginScan = await this.runPluginReviewScan(reviewPlugin, job, {
|
jobId,
|
||||||
jobId,
|
rawPath: dvdScanInputPath,
|
||||||
rawPath: dvdScanInputPath,
|
reviewMode: 'rip',
|
||||||
reviewMode: 'rip',
|
source: 'HANDBRAKE_SCAN_DVD_TITLES',
|
||||||
source: 'HANDBRAKE_SCAN_DVD_TITLES',
|
silent: !this.isPrimaryJob(jobId)
|
||||||
silent: !this.isPrimaryJob(jobId)
|
});
|
||||||
});
|
dvdTitleScanLines.push(...pluginScan.scanLines);
|
||||||
dvdTitleScanLines.push(...pluginScan.scanLines);
|
dvdTitleScanRunInfo = pluginScan.runInfo || null;
|
||||||
dvdTitleScanRunInfo = pluginScan.runInfo || null;
|
reviewPluginExecution = this.mergePluginExecutionState(
|
||||||
reviewPluginExecution = this.mergePluginExecutionState(
|
reviewPluginExecution,
|
||||||
reviewPluginExecution,
|
pluginScan.pluginExecution
|
||||||
pluginScan.pluginExecution
|
);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const dvdTitleScanConfig = await settingsService.buildHandBrakeScanConfigForInput(dvdScanInputPath, {
|
|
||||||
mediaProfile,
|
|
||||||
settingsMap: settings
|
|
||||||
});
|
|
||||||
logger.info('mediainfo:review:dvd-title-scan:command', {
|
|
||||||
jobId,
|
|
||||||
cmd: dvdTitleScanConfig.cmd,
|
|
||||||
args: dvdTitleScanConfig.args,
|
|
||||||
dvdScanInputPath
|
|
||||||
});
|
|
||||||
dvdTitleScanRunInfo = await this.runCommand({
|
|
||||||
jobId,
|
|
||||||
stage: 'MEDIAINFO_CHECK',
|
|
||||||
source: 'HANDBRAKE_SCAN_DVD_TITLES',
|
|
||||||
cmd: dvdTitleScanConfig.cmd,
|
|
||||||
args: dvdTitleScanConfig.args,
|
|
||||||
collectLines: dvdTitleScanLines,
|
|
||||||
collectStderrLines: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
dvdTitleScanJson = parseMediainfoJsonOutput(dvdTitleScanLines.join('\n'));
|
dvdTitleScanJson = parseMediainfoJsonOutput(dvdTitleScanLines.join('\n'));
|
||||||
if (dvdTitleScanJson) {
|
if (dvdTitleScanJson) {
|
||||||
const allTitles = parseHandBrakeTitleList(dvdTitleScanJson);
|
const allTitles = parseHandBrakeTitleList(dvdTitleScanJson);
|
||||||
@@ -10408,18 +10179,10 @@ class PipelineService extends EventEmitter {
|
|||||||
);
|
);
|
||||||
enrichedReview = { ...enrichedReview, encodeInputPath: dvdScanInputPath };
|
enrichedReview = { ...enrichedReview, encodeInputPath: dvdScanInputPath };
|
||||||
}
|
}
|
||||||
} else if (reviewPluginEnabled) {
|
} else {
|
||||||
const error = new Error('HandBrake DVD Titel-Scan: Ausgabe nicht lesbar (Plugin-Review aktiv, kein Fallback).');
|
const error = new Error('HandBrake DVD Titel-Scan: Ausgabe nicht lesbar.');
|
||||||
error.runInfo = dvdTitleScanRunInfo;
|
error.runInfo = dvdTitleScanRunInfo;
|
||||||
throw error;
|
throw error;
|
||||||
} else {
|
|
||||||
logger.warn('mediainfo:review:dvd-title-scan:parse-failed', { jobId });
|
|
||||||
await historyService.appendLog(
|
|
||||||
jobId,
|
|
||||||
'SYSTEM',
|
|
||||||
'HandBrake DVD Titel-Scan: Ausgabe nicht lesbar. Ohne Titel-ID fortgefahren.'
|
|
||||||
);
|
|
||||||
enrichedReview = { ...enrichedReview, encodeInputPath: dvdScanInputPath };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10947,11 +10710,6 @@ class PipelineService extends EventEmitter {
|
|||||||
});
|
});
|
||||||
const settings = await settingsService.getEffectiveSettingsMap(mediaProfile);
|
const settings = await settingsService.getEffectiveSettingsMap(mediaProfile);
|
||||||
const encodePlugin = await this.resolveAnalyzePlugin({ mediaProfile }, 'encode').catch(() => null);
|
const encodePlugin = await this.resolveAnalyzePlugin({ mediaProfile }, 'encode').catch(() => null);
|
||||||
const encodePluginEnabled = Boolean(
|
|
||||||
encodePlugin
|
|
||||||
&& encodePlugin.id === mediaProfile
|
|
||||||
&& typeof encodePlugin.encode === 'function'
|
|
||||||
);
|
|
||||||
let encodePluginExecution = null;
|
let encodePluginExecution = null;
|
||||||
const resolvedRawPath = this.resolveCurrentRawPathForSettings(settings, mediaProfile, job.raw_path);
|
const resolvedRawPath = this.resolveCurrentRawPathForSettings(settings, mediaProfile, job.raw_path);
|
||||||
const activeRawPath = resolvedRawPath || String(job.raw_path || '').trim() || null;
|
const activeRawPath = resolvedRawPath || String(job.raw_path || '').trim() || null;
|
||||||
@@ -11292,45 +11050,26 @@ class PipelineService extends EventEmitter {
|
|||||||
}
|
}
|
||||||
: parseHandBrakeProgress;
|
: parseHandBrakeProgress;
|
||||||
let handbrakeInfo = null;
|
let handbrakeInfo = null;
|
||||||
if (encodePluginEnabled) {
|
const encodeCtx = await this.buildPluginContext(encodePlugin.id, {
|
||||||
const encodeCtx = await this.buildPluginContext(encodePlugin.id, {
|
jobId,
|
||||||
jobId,
|
inputPath,
|
||||||
inputPath,
|
outputPath: incompleteOutputPath,
|
||||||
outputPath: incompleteOutputPath,
|
encodePlan: effectiveEncodePlan,
|
||||||
encodePlan: effectiveEncodePlan,
|
runCommand: this.runCommand.bind(this),
|
||||||
runCommand: this.runCommand.bind(this),
|
progressParser: handBrakeProgressParser,
|
||||||
progressParser: handBrakeProgressParser,
|
encodeSource: 'HANDBRAKE',
|
||||||
encodeSource: 'HANDBRAKE',
|
encodeStage: 'ENCODING'
|
||||||
encodeStage: 'ENCODING'
|
});
|
||||||
});
|
handbrakeInfo = await encodePlugin.encode(job, encodeCtx);
|
||||||
handbrakeInfo = await encodePlugin.encode(job, encodeCtx);
|
encodePluginExecution = this.mergePluginExecutionState(
|
||||||
encodePluginExecution = this.mergePluginExecutionState(
|
encodePluginExecution,
|
||||||
encodePluginExecution,
|
this.sanitizePluginExecutionState(encodeCtx.getPluginExecution())
|
||||||
this.sanitizePluginExecutionState(encodeCtx.getPluginExecution())
|
);
|
||||||
);
|
logger.info('plugin:encode:used', {
|
||||||
logger.info('plugin:encode:used', {
|
jobId,
|
||||||
jobId,
|
pluginId: encodePlugin.id,
|
||||||
pluginId: encodePlugin.id,
|
mediaProfile
|
||||||
mediaProfile
|
});
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const handBrakeConfig = await settingsService.buildHandBrakeConfig(inputPath, incompleteOutputPath, {
|
|
||||||
trackSelection,
|
|
||||||
titleId: handBrakeTitleId,
|
|
||||||
mediaProfile,
|
|
||||||
settingsMap: settings,
|
|
||||||
userPreset: encodePlan?.userPreset || null
|
|
||||||
});
|
|
||||||
logger.info('encoding:command', { jobId, cmd: handBrakeConfig.cmd, args: handBrakeConfig.args });
|
|
||||||
handbrakeInfo = await this.runCommand({
|
|
||||||
jobId,
|
|
||||||
stage: 'ENCODING',
|
|
||||||
source: 'HANDBRAKE',
|
|
||||||
cmd: handBrakeConfig.cmd,
|
|
||||||
args: handBrakeConfig.args,
|
|
||||||
parser: handBrakeProgressParser
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const outputFinalization = finalizeOutputPathForCompletedEncode(
|
const outputFinalization = finalizeOutputPathForCompletedEncode(
|
||||||
incompleteOutputPath,
|
incompleteOutputPath,
|
||||||
preferredFinalOutputPath
|
preferredFinalOutputPath
|
||||||
@@ -11650,20 +11389,6 @@ class PipelineService extends EventEmitter {
|
|||||||
try {
|
try {
|
||||||
await this.ensureMakeMKVRegistration(jobId, 'RIPPING');
|
await this.ensureMakeMKVRegistration(jobId, 'RIPPING');
|
||||||
|
|
||||||
const ripConfig = await settingsService.buildMakeMKVRipConfig(rawJobDir, device, {
|
|
||||||
selectedTitleId: effectiveSelectedTitleId,
|
|
||||||
mediaProfile,
|
|
||||||
settingsMap: settings,
|
|
||||||
backupOutputBase
|
|
||||||
});
|
|
||||||
logger.info('rip:command', {
|
|
||||||
jobId,
|
|
||||||
cmd: ripConfig.cmd,
|
|
||||||
args: ripConfig.args,
|
|
||||||
ripMode,
|
|
||||||
selectedPlaylist: effectiveSelectedPlaylistFile,
|
|
||||||
selectedTitleId: effectiveSelectedTitleId
|
|
||||||
});
|
|
||||||
if (ripMode === 'backup') {
|
if (ripMode === 'backup') {
|
||||||
await historyService.appendLog(
|
await historyService.appendLog(
|
||||||
jobId,
|
jobId,
|
||||||
@@ -11702,28 +11427,16 @@ class PipelineService extends EventEmitter {
|
|||||||
}
|
}
|
||||||
let ripCommandSucceeded = false;
|
let ripCommandSucceeded = false;
|
||||||
try {
|
try {
|
||||||
if (ripPlugin) {
|
// Plugin-Pfad: VideoDiscPlugin.rip() baut eigene ripConfig + ruft ctx.extra.runCommand()
|
||||||
// Plugin-Pfad: VideoDiscPlugin.rip() baut eigene ripConfig + ruft ctx.extra.runCommand()
|
const ripCtx = await this.buildPluginContext(ripPlugin.id, {
|
||||||
const ripCtx = await this.buildPluginContext(ripPlugin.id, {
|
jobId,
|
||||||
jobId,
|
rawJobDir,
|
||||||
rawJobDir,
|
deviceInfo: device,
|
||||||
deviceInfo: device,
|
selectedTitleId: effectiveSelectedTitleId,
|
||||||
selectedTitleId: effectiveSelectedTitleId,
|
backupOutputBase,
|
||||||
backupOutputBase,
|
runCommand: this.runCommand.bind(this)
|
||||||
runCommand: this.runCommand.bind(this)
|
});
|
||||||
});
|
makemkvInfo = await ripPlugin.rip(job, ripCtx);
|
||||||
makemkvInfo = await ripPlugin.rip(job, ripCtx);
|
|
||||||
} else {
|
|
||||||
// Legacy-Pfad
|
|
||||||
makemkvInfo = await this.runCommand({
|
|
||||||
jobId,
|
|
||||||
stage: 'RIPPING',
|
|
||||||
source: 'MAKEMKV_RIP',
|
|
||||||
cmd: ripConfig.cmd,
|
|
||||||
args: ripConfig.args,
|
|
||||||
parser: parseMakeMkvProgress
|
|
||||||
});
|
|
||||||
}
|
|
||||||
ripCommandSucceeded = true;
|
ripCommandSucceeded = true;
|
||||||
} finally {
|
} finally {
|
||||||
if (devicePath && !ripCommandSucceeded) {
|
if (devicePath && !ripCommandSucceeded) {
|
||||||
@@ -15292,11 +15005,11 @@ class PipelineService extends EventEmitter {
|
|||||||
activeJobId,
|
activeJobId,
|
||||||
'SYSTEM',
|
'SYSTEM',
|
||||||
skipRip
|
skipRip
|
||||||
? `CD-Encode aus RAW gestartet (${cdRipPlugin ? 'Plugin' : 'Legacy'}): Format=${format}, Tracks=${effectiveSelectedTrackPositions.join(',') || 'alle'}`
|
? `CD-Encode aus RAW gestartet: Format=${format}, Tracks=${effectiveSelectedTrackPositions.join(',') || 'alle'}`
|
||||||
: (
|
: (
|
||||||
skipEncode
|
skipEncode
|
||||||
? `CD-RAW-Rip gestartet (${cdRipPlugin ? 'Plugin' : 'Legacy'}): Tracks=${effectiveSelectedTrackPositions.join(',') || 'alle'}`
|
? `CD-RAW-Rip gestartet: Tracks=${effectiveSelectedTrackPositions.join(',') || 'alle'}`
|
||||||
: `CD-Rip gestartet (${cdRipPlugin ? 'Plugin' : 'Legacy'}): Format=${format}, Tracks=${effectiveSelectedTrackPositions.join(',') || 'alle'}`
|
: `CD-Rip gestartet: Format=${format}, Tracks=${effectiveSelectedTrackPositions.join(',') || 'alle'}`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
if (
|
if (
|
||||||
|
|||||||
@@ -478,74 +478,6 @@ INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, des
|
|||||||
VALUES ('ui_expert_mode', 'Benachrichtigungen', 'Expertenmodus', 'boolean', 1, 'Schaltet erweiterte Einstellungen in der UI ein.', 'false', '[]', '{}', 495);
|
VALUES ('ui_expert_mode', 'Benachrichtigungen', 'Expertenmodus', 'boolean', 1, 'Schaltet erweiterte Einstellungen in der UI ein.', 'false', '[]', '{}', 495);
|
||||||
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('ui_expert_mode', 'false');
|
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('ui_expert_mode', 'false');
|
||||||
|
|
||||||
INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index, depends_on)
|
|
||||||
VALUES ('use_plugin_architecture', 'Erweitert', 'Neue Plugin-Architektur (Beta)', 'boolean', 1, 'Masterschalter: Aktiviert die neue modulare Plugin-Architektur (Phase 2). Alle Medium-Schalter darunter sind nur wirksam wenn dieser aktiv ist.', 'false', '[]', '{}', 9999, NULL);
|
|
||||||
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('use_plugin_architecture', 'false');
|
|
||||||
|
|
||||||
INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index, depends_on)
|
|
||||||
VALUES ('use_plugin_architecture_bluray', 'Erweitert', 'Blu-ray Plugin', 'boolean', 1, 'Aktiviert das Blu-ray Plugin. Deaktiviert = Legacy-Pfad für alle Blu-ray-Phasen.', 'true', '[]', '{}', 10000, 'use_plugin_architecture');
|
|
||||||
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('use_plugin_architecture_bluray', 'true');
|
|
||||||
|
|
||||||
INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index, depends_on)
|
|
||||||
VALUES ('use_plugin_architecture_bluray_analyze', 'Erweitert', 'Analyse (Blu-ray)', 'boolean', 1, 'Disc-Erkennung und OMDB-Suche laufen über das Plugin.', 'true', '[]', '{}', 10001, 'use_plugin_architecture_bluray');
|
|
||||||
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('use_plugin_architecture_bluray_analyze', 'true');
|
|
||||||
|
|
||||||
INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index, depends_on)
|
|
||||||
VALUES ('use_plugin_architecture_bluray_rip', 'Erweitert', 'Rip (Blu-ray)', 'boolean', 1, 'MakeMKV-Rip läuft über das Plugin.', 'true', '[]', '{}', 10002, 'use_plugin_architecture_bluray');
|
|
||||||
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('use_plugin_architecture_bluray_rip', 'true');
|
|
||||||
|
|
||||||
INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index, depends_on)
|
|
||||||
VALUES ('use_plugin_architecture_bluray_review', 'Erweitert', 'Review / Mediainfo-Prüfung (Blu-ray)', 'boolean', 1, 'Noch nicht implementiert — kommt in einem späteren Sprint.', 'false', '[]', '{"readonly":true}', 10003, 'use_plugin_architecture_bluray');
|
|
||||||
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('use_plugin_architecture_bluray_review', 'false');
|
|
||||||
|
|
||||||
INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index, depends_on)
|
|
||||||
VALUES ('use_plugin_architecture_bluray_encode', 'Erweitert', 'Encoding (Blu-ray)', 'boolean', 1, 'Noch nicht implementiert — kommt in einem späteren Sprint.', 'false', '[]', '{"readonly":true}', 10004, 'use_plugin_architecture_bluray');
|
|
||||||
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('use_plugin_architecture_bluray_encode', 'false');
|
|
||||||
|
|
||||||
INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index, depends_on)
|
|
||||||
VALUES ('use_plugin_architecture_dvd', 'Erweitert', 'DVD Plugin', 'boolean', 1, 'Aktiviert das DVD Plugin. Deaktiviert = Legacy-Pfad für alle DVD-Phasen.', 'true', '[]', '{}', 10010, 'use_plugin_architecture');
|
|
||||||
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('use_plugin_architecture_dvd', 'true');
|
|
||||||
|
|
||||||
INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index, depends_on)
|
|
||||||
VALUES ('use_plugin_architecture_dvd_analyze', 'Erweitert', 'Analyse (DVD)', 'boolean', 1, 'Disc-Erkennung und OMDB-Suche laufen über das Plugin.', 'true', '[]', '{}', 10011, 'use_plugin_architecture_dvd');
|
|
||||||
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('use_plugin_architecture_dvd_analyze', 'true');
|
|
||||||
|
|
||||||
INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index, depends_on)
|
|
||||||
VALUES ('use_plugin_architecture_dvd_rip', 'Erweitert', 'Rip (DVD)', 'boolean', 1, 'MakeMKV-Rip läuft über das Plugin.', 'true', '[]', '{}', 10012, 'use_plugin_architecture_dvd');
|
|
||||||
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('use_plugin_architecture_dvd_rip', 'true');
|
|
||||||
|
|
||||||
INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index, depends_on)
|
|
||||||
VALUES ('use_plugin_architecture_dvd_review', 'Erweitert', 'Review / Mediainfo-Prüfung (DVD)', 'boolean', 1, 'Review-/Track-Analyse läuft über das DVD-Plugin.', 'true', '[]', '{}', 10013, 'use_plugin_architecture_dvd');
|
|
||||||
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('use_plugin_architecture_dvd_review', 'true');
|
|
||||||
|
|
||||||
INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index, depends_on)
|
|
||||||
VALUES ('use_plugin_architecture_dvd_encode', 'Erweitert', 'Encoding (DVD)', 'boolean', 1, 'Encoding läuft über das DVD-Plugin.', 'true', '[]', '{}', 10014, 'use_plugin_architecture_dvd');
|
|
||||||
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('use_plugin_architecture_dvd_encode', 'true');
|
|
||||||
|
|
||||||
INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index, depends_on)
|
|
||||||
VALUES ('use_plugin_architecture_cd', 'Erweitert', 'Audio-CD Plugin', 'boolean', 1, 'Aktiviert das Audio-CD Plugin. Deaktiviert = Legacy-Pfad für alle CD-Phasen.', 'true', '[]', '{}', 10020, 'use_plugin_architecture');
|
|
||||||
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('use_plugin_architecture_cd', 'true');
|
|
||||||
|
|
||||||
INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index, depends_on)
|
|
||||||
VALUES ('use_plugin_architecture_cd_analyze', 'Erweitert', 'Analyse (Audio-CD)', 'boolean', 1, 'TOC-Auslesung läuft über das Plugin.', 'true', '[]', '{}', 10021, 'use_plugin_architecture_cd');
|
|
||||||
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('use_plugin_architecture_cd_analyze', 'true');
|
|
||||||
|
|
||||||
INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index, depends_on)
|
|
||||||
VALUES ('use_plugin_architecture_cd_rip', 'Erweitert', 'Rip (Audio-CD)', 'boolean', 1, 'CD-Rip/RAW-Rip/Encode-aus-RAW läuft über das Plugin.', 'true', '[]', '{}', 10022, 'use_plugin_architecture_cd');
|
|
||||||
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('use_plugin_architecture_cd_rip', 'true');
|
|
||||||
|
|
||||||
INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index, depends_on)
|
|
||||||
VALUES ('use_plugin_architecture_audiobook', 'Erweitert', 'Audiobook Plugin', 'boolean', 1, 'Aktiviert das Audiobook Plugin. Deaktiviert = Legacy-Pfad für alle Audiobook-Phasen.', 'true', '[]', '{}', 10030, 'use_plugin_architecture');
|
|
||||||
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('use_plugin_architecture_audiobook', 'true');
|
|
||||||
|
|
||||||
INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index, depends_on)
|
|
||||||
VALUES ('use_plugin_architecture_audiobook_analyze', 'Erweitert', 'Analyse (Audiobook)', 'boolean', 1, 'ffprobe-Metadatenanalyse läuft über das Plugin.', 'true', '[]', '{}', 10031, 'use_plugin_architecture_audiobook');
|
|
||||||
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('use_plugin_architecture_audiobook_analyze', 'true');
|
|
||||||
|
|
||||||
INSERT OR IGNORE INTO settings_schema (key, category, label, type, required, description, default_value, options_json, validation_json, order_index, depends_on)
|
|
||||||
VALUES ('use_plugin_architecture_audiobook_encode', 'Erweitert', 'Encoding (Audiobook)', 'boolean', 1, 'Noch nicht implementiert — Encoding läuft noch über Legacy.', 'false', '[]', '{"readonly":true}', 10032, 'use_plugin_architecture_audiobook');
|
|
||||||
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('use_plugin_architecture_audiobook_encode', 'false');
|
|
||||||
|
|
||||||
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 ('pushover_enabled', 'Benachrichtigungen', 'PushOver aktiviert', 'boolean', 1, 'Master-Schalter für PushOver Versand.', 'false', '[]', '{}', 500);
|
VALUES ('pushover_enabled', 'Benachrichtigungen', 'PushOver aktiviert', 'boolean', 1, 'Master-Schalter für PushOver Versand.', 'false', '[]', '{}', 500);
|
||||||
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('pushover_enabled', 'false');
|
INSERT OR IGNORE INTO settings_values (key, value) VALUES ('pushover_enabled', 'false');
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "ripster-frontend",
|
"name": "ripster-frontend",
|
||||||
"version": "0.12.0-6",
|
"version": "0.12.0-7",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "ripster-frontend",
|
"name": "ripster-frontend",
|
||||||
"version": "0.12.0-6",
|
"version": "0.12.0-7",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"primeicons": "^7.0.0",
|
"primeicons": "^7.0.0",
|
||||||
"primereact": "^10.9.2",
|
"primereact": "^10.9.2",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ripster-frontend",
|
"name": "ripster-frontend",
|
||||||
"version": "0.12.0-6",
|
"version": "0.12.0-7",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { Tag } from 'primereact/tag';
|
|||||||
import blurayIndicatorIcon from '../assets/media-bluray.svg';
|
import blurayIndicatorIcon from '../assets/media-bluray.svg';
|
||||||
import discIndicatorIcon from '../assets/media-disc.svg';
|
import discIndicatorIcon from '../assets/media-disc.svg';
|
||||||
import otherIndicatorIcon from '../assets/media-other.svg';
|
import otherIndicatorIcon from '../assets/media-other.svg';
|
||||||
import { resolveJobPluginExecution } from '../utils/pluginExecution';
|
|
||||||
import { getProcessStatusLabel, getStatusLabel } from '../utils/statusPresentation';
|
import { getProcessStatusLabel, getStatusLabel } from '../utils/statusPresentation';
|
||||||
|
|
||||||
const CD_FORMAT_LABELS = {
|
const CD_FORMAT_LABELS = {
|
||||||
@@ -725,9 +724,6 @@ export default function JobDetailDialog({
|
|||||||
const mediaTypeAlt = mediaTypeLabel;
|
const mediaTypeAlt = mediaTypeLabel;
|
||||||
const statusMeta = statusBadgeMeta(job?.status, queueLocked);
|
const statusMeta = statusBadgeMeta(job?.status, queueLocked);
|
||||||
const omdbInfo = job?.omdbInfo && typeof job.omdbInfo === 'object' ? job.omdbInfo : {};
|
const omdbInfo = job?.omdbInfo && typeof job.omdbInfo === 'object' ? job.omdbInfo : {};
|
||||||
const pluginExecution = resolveJobPluginExecution(job, null, {
|
|
||||||
currentStatus: job?.status
|
|
||||||
});
|
|
||||||
const configuredSelection = buildConfiguredScriptAndChainSelection(job);
|
const configuredSelection = buildConfiguredScriptAndChainSelection(job);
|
||||||
const hasConfiguredSelection = configuredSelection.preScriptIds.length > 0
|
const hasConfiguredSelection = configuredSelection.preScriptIds.length > 0
|
||||||
|| configuredSelection.postScriptIds.length > 0
|
|| configuredSelection.postScriptIds.length > 0
|
||||||
@@ -928,12 +924,6 @@ export default function JobDetailDialog({
|
|||||||
<i className={`pi ${statusMeta.icon}`} aria-hidden="true" />
|
<i className={`pi ${statusMeta.icon}`} aria-hidden="true" />
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
{pluginExecution ? (
|
|
||||||
<>
|
|
||||||
<span className="job-infos-sep">|</span>
|
|
||||||
<Tag value={pluginExecution.label} severity="warning" title={pluginExecution.title} />
|
|
||||||
</>
|
|
||||||
) : null}
|
|
||||||
<span className="job-infos-sep">|</span>
|
<span className="job-infos-sep">|</span>
|
||||||
{isCd ? (
|
{isCd ? (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import blurayIndicatorIcon from '../assets/media-bluray.svg';
|
|||||||
import discIndicatorIcon from '../assets/media-disc.svg';
|
import discIndicatorIcon from '../assets/media-disc.svg';
|
||||||
import otherIndicatorIcon from '../assets/media-other.svg';
|
import otherIndicatorIcon from '../assets/media-other.svg';
|
||||||
import audiobookIndicatorIcon from '../assets/media-audiobook.svg';
|
import audiobookIndicatorIcon from '../assets/media-audiobook.svg';
|
||||||
import { resolveJobPluginExecution } from '../utils/pluginExecution';
|
|
||||||
import { getStatusLabel, getStatusSeverity, normalizeStatus } from '../utils/statusPresentation';
|
import { getStatusLabel, getStatusSeverity, normalizeStatus } from '../utils/statusPresentation';
|
||||||
|
|
||||||
const processingStates = ['ANALYZING', 'RIPPING', 'MEDIAINFO_CHECK', 'ENCODING', 'CD_ANALYZING', 'CD_RIPPING', 'CD_ENCODING'];
|
const processingStates = ['ANALYZING', 'RIPPING', 'MEDIAINFO_CHECK', 'ENCODING', 'CD_ANALYZING', 'CD_RIPPING', 'CD_ENCODING'];
|
||||||
@@ -2834,10 +2833,6 @@ export default function DashboardPage({
|
|||||||
? pipelineForJob.context.selectedMetadata
|
? pipelineForJob.context.selectedMetadata
|
||||||
: {};
|
: {};
|
||||||
const audiobookChapterCount = Array.isArray(audiobookMeta?.chapters) ? audiobookMeta.chapters.length : 0;
|
const audiobookChapterCount = Array.isArray(audiobookMeta?.chapters) ? audiobookMeta.chapters.length : 0;
|
||||||
const pluginExecution = resolveJobPluginExecution(job, pipelineForJob?.context, {
|
|
||||||
currentStatus: jobState
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isExpanded) {
|
if (isExpanded) {
|
||||||
return (
|
return (
|
||||||
<div key={jobId} className="dashboard-job-expanded">
|
<div key={jobId} className="dashboard-job-expanded">
|
||||||
@@ -2859,7 +2854,6 @@ export default function DashboardPage({
|
|||||||
</strong>
|
</strong>
|
||||||
<div className="dashboard-job-badges">
|
<div className="dashboard-job-badges">
|
||||||
<Tag value={statusBadgeValue} severity={statusBadgeSeverity} />
|
<Tag value={statusBadgeValue} severity={statusBadgeSeverity} />
|
||||||
{pluginExecution ? <Tag value={pluginExecution.label} severity="warning" title={pluginExecution.title} /> : null}
|
|
||||||
{isCurrentSession ? <Tag value="Aktive Session" severity="info" /> : null}
|
{isCurrentSession ? <Tag value="Aktive Session" severity="info" /> : null}
|
||||||
{isResumable ? <Tag value="Fortsetzbar" severity="success" /> : null}
|
{isResumable ? <Tag value="Fortsetzbar" severity="success" /> : null}
|
||||||
{normalizedStatus === 'READY_TO_ENCODE'
|
{normalizedStatus === 'READY_TO_ENCODE'
|
||||||
@@ -2993,7 +2987,6 @@ export default function DashboardPage({
|
|||||||
</div>
|
</div>
|
||||||
<div className="dashboard-job-badges">
|
<div className="dashboard-job-badges">
|
||||||
<Tag value={statusBadgeValue} severity={statusBadgeSeverity} />
|
<Tag value={statusBadgeValue} severity={statusBadgeSeverity} />
|
||||||
{pluginExecution ? <Tag value={pluginExecution.label} severity="warning" title={pluginExecution.title} /> : null}
|
|
||||||
{isCurrentSession ? <Tag value="Aktive Session" severity="info" /> : null}
|
{isCurrentSession ? <Tag value="Aktive Session" severity="info" /> : null}
|
||||||
{isResumable ? <Tag value="Fortsetzbar" severity="success" /> : null}
|
{isResumable ? <Tag value="Fortsetzbar" severity="success" /> : null}
|
||||||
{normalizedStatus === 'READY_TO_ENCODE'
|
{normalizedStatus === 'READY_TO_ENCODE'
|
||||||
|
|||||||
@@ -1,138 +0,0 @@
|
|||||||
function normalizeStage(value) {
|
|
||||||
const stage = String(value || '').trim().toLowerCase();
|
|
||||||
return stage || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizeStatus(value) {
|
|
||||||
return String(value || '').trim().toUpperCase() || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function inferExpectedPluginStage({ currentStatus = null, currentStage = null } = {}) {
|
|
||||||
const explicitStage = normalizeStage(currentStage);
|
|
||||||
if (explicitStage) {
|
|
||||||
return explicitStage;
|
|
||||||
}
|
|
||||||
|
|
||||||
const status = normalizeStatus(currentStatus);
|
|
||||||
if (!status) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
status === 'ANALYZING'
|
|
||||||
|| status === 'CD_ANALYZING'
|
|
||||||
|| status === 'METADATA_SELECTION'
|
|
||||||
|| status === 'CD_METADATA_SELECTION'
|
|
||||||
|| status === 'CD_READY_TO_RIP'
|
|
||||||
) {
|
|
||||||
return 'analyze';
|
|
||||||
}
|
|
||||||
if (status === 'RIPPING' || status === 'CD_RIPPING') {
|
|
||||||
return 'rip';
|
|
||||||
}
|
|
||||||
if (status === 'MEDIAINFO_CHECK' || status === 'WAITING_FOR_USER_DECISION' || status === 'READY_TO_ENCODE') {
|
|
||||||
return 'review';
|
|
||||||
}
|
|
||||||
if (status === 'ENCODING' || status === 'CD_ENCODING') {
|
|
||||||
return 'encode';
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function matchesExpectedStage(executionState, expectedStage) {
|
|
||||||
if (!executionState) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!expectedStage) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const stages = Array.isArray(executionState.stages) ? executionState.stages : [];
|
|
||||||
if (stages.length === 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return stages.includes(expectedStage);
|
|
||||||
}
|
|
||||||
|
|
||||||
const STAGE_LABELS = {
|
|
||||||
analyze: 'Analyse',
|
|
||||||
rip: 'Rip',
|
|
||||||
review: 'Review',
|
|
||||||
encode: 'Encode',
|
|
||||||
finalize: 'Finalize',
|
|
||||||
oncancel: 'Cancel',
|
|
||||||
onretry: 'Retry'
|
|
||||||
};
|
|
||||||
|
|
||||||
export function normalizePluginExecutionState(rawState) {
|
|
||||||
if (!rawState || typeof rawState !== 'object' || Array.isArray(rawState)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const markerSource = String(rawState.markerSource || '').trim().toLowerCase();
|
|
||||||
const pluginFile = String(rawState.pluginFile || '').trim();
|
|
||||||
if (markerSource !== 'plugin-file' || !pluginFile) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pluginId = String(rawState.pluginId || '').trim().toLowerCase() || null;
|
|
||||||
const pluginName = String(rawState.pluginName || '').trim() || pluginId || 'Plugin';
|
|
||||||
const explicitStages = Array.isArray(rawState.stages)
|
|
||||||
? rawState.stages.map((stage) => normalizeStage(stage)).filter(Boolean)
|
|
||||||
: [];
|
|
||||||
const byStage = rawState.byStage && typeof rawState.byStage === 'object' && !Array.isArray(rawState.byStage)
|
|
||||||
? rawState.byStage
|
|
||||||
: {};
|
|
||||||
const stages = Array.from(new Set([
|
|
||||||
...explicitStages,
|
|
||||||
...Object.keys(byStage).map((stage) => normalizeStage(stage)).filter(Boolean),
|
|
||||||
...[normalizeStage(rawState.lastStage)].filter(Boolean)
|
|
||||||
]));
|
|
||||||
const stageLabels = stages.map((stage) => STAGE_LABELS[stage] || stage);
|
|
||||||
const titleParts = [
|
|
||||||
`Plugin-Code aktiv: ${pluginName}`,
|
|
||||||
pluginId ? `ID: ${pluginId}` : null,
|
|
||||||
`Datei: ${pluginFile}`,
|
|
||||||
stageLabels.length > 0 ? `Phasen: ${stageLabels.join(', ')}` : null
|
|
||||||
].filter(Boolean);
|
|
||||||
|
|
||||||
return {
|
|
||||||
markerSource,
|
|
||||||
pluginId,
|
|
||||||
pluginName,
|
|
||||||
pluginFile,
|
|
||||||
stages,
|
|
||||||
stageLabels,
|
|
||||||
label: `Beta: ${pluginName}`,
|
|
||||||
title: titleParts.join(' | ')
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resolveJobPluginExecution(job = null, liveContext = null, options = {}) {
|
|
||||||
const liveExecution = normalizePluginExecutionState(liveContext?.pluginExecution);
|
|
||||||
const makemkvExecution = normalizePluginExecutionState(job?.makemkvInfo?.pluginExecution);
|
|
||||||
const mediainfoExecution = normalizePluginExecutionState(job?.mediainfoInfo?.pluginExecution);
|
|
||||||
const handbrakeExecution = normalizePluginExecutionState(job?.handbrakeInfo?.pluginExecution);
|
|
||||||
const jobExecution = normalizePluginExecutionState(job?.pluginExecution);
|
|
||||||
|
|
||||||
const expectedStage = inferExpectedPluginStage(options);
|
|
||||||
const candidates = [liveExecution, handbrakeExecution, mediainfoExecution, makemkvExecution, jobExecution].filter(Boolean);
|
|
||||||
if (candidates.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!expectedStage) {
|
|
||||||
return candidates[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
const stageMatch = candidates.find((state) => matchesExpectedStage(state, expectedStage));
|
|
||||||
if (stageMatch) {
|
|
||||||
return stageMatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function inferPluginStageFromStatus(status) {
|
|
||||||
return inferExpectedPluginStage({ currentStatus: status });
|
|
||||||
}
|
|
||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "ripster",
|
"name": "ripster",
|
||||||
"version": "0.12.0-6",
|
"version": "0.12.0-7",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "ripster",
|
"name": "ripster",
|
||||||
"version": "0.12.0-6",
|
"version": "0.12.0-7",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"concurrently": "^9.1.2"
|
"concurrently": "^9.1.2"
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "ripster",
|
"name": "ripster",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.12.0-6",
|
"version": "0.12.0-7",
|
||||||
"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",
|
||||||
|
|||||||
Reference in New Issue
Block a user