0.13.0 DVD Series
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
'use strict';
|
||||
|
||||
const { SourcePlugin } = require('./PluginBase');
|
||||
const dvdSeriesScanService = require('../services/dvdSeriesScanService');
|
||||
const tmdbService = require('../services/tmdbService');
|
||||
|
||||
/**
|
||||
* Companion-Plugin für Serien-DVDs.
|
||||
*
|
||||
* Dieses Plugin ersetzt den bestehenden DVDPlugin-Flow nicht. Es wird in einem
|
||||
* späteren Schritt explizit aus dem DVD-Flow aufgerufen, sobald ein Prescan eine
|
||||
* serientypische Titelstruktur vermuten lässt.
|
||||
*/
|
||||
class DVDSeriesPlugin extends SourcePlugin {
|
||||
get id() {
|
||||
return 'dvd_series';
|
||||
}
|
||||
|
||||
get name() {
|
||||
return 'DVD Series';
|
||||
}
|
||||
|
||||
detect() {
|
||||
return false;
|
||||
}
|
||||
|
||||
async analyze(_devicePath, job, ctx) {
|
||||
ctx.markExecution('analyze', {
|
||||
pluginId: this.id,
|
||||
pluginName: this.name,
|
||||
pluginFile: 'DVDSeriesPlugin.js'
|
||||
});
|
||||
|
||||
const scanText = String(ctx.extra?.scanText || '').trim();
|
||||
if (!scanText) {
|
||||
return {
|
||||
parsedScan: null,
|
||||
seriesAnalysis: null,
|
||||
providerConfigured: await tmdbService.isConfigured()
|
||||
};
|
||||
}
|
||||
|
||||
const result = dvdSeriesScanService.analyzeHandBrakeScan(scanText, ctx.extra?.seriesOptions || {});
|
||||
const seriesLookupHint = dvdSeriesScanService.deriveSeriesLookupHint([
|
||||
{
|
||||
value: result?.parsed?.discTitle || '',
|
||||
source: 'handbrake_disc_title'
|
||||
},
|
||||
{
|
||||
value: ctx.extra?.detectedTitle || '',
|
||||
source: 'detected_title'
|
||||
}
|
||||
]);
|
||||
return {
|
||||
parsedScan: result.parsed,
|
||||
seriesAnalysis: result.analysis,
|
||||
seriesLookupHint,
|
||||
providerConfigured: await tmdbService.isConfigured()
|
||||
};
|
||||
}
|
||||
|
||||
async review(_job, ctx) {
|
||||
ctx.markExecution('review', {
|
||||
pluginId: this.id,
|
||||
pluginName: this.name,
|
||||
pluginFile: 'DVDSeriesPlugin.js'
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
async rip() {
|
||||
throw new Error('DVDSeriesPlugin.rip() ist ein Companion-Plugin und wird nicht direkt ausgeführt.');
|
||||
}
|
||||
|
||||
async encode() {
|
||||
throw new Error('DVDSeriesPlugin.encode() ist ein Companion-Plugin und wird nicht direkt ausgeführt.');
|
||||
}
|
||||
|
||||
async searchSeries(query, options = {}) {
|
||||
return tmdbService.searchSeries(query, options);
|
||||
}
|
||||
|
||||
async searchSeriesWithSeason(query, seasonNumber, options = {}) {
|
||||
return tmdbService.searchSeriesWithSeason(query, seasonNumber, options);
|
||||
}
|
||||
|
||||
getSettingsSchema() {
|
||||
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',
|
||||
category: 'Metadaten',
|
||||
label: 'TMDb Read Access Token',
|
||||
type: 'string',
|
||||
required: 0,
|
||||
description: 'Read Access Token für Serien-Metadaten über TheMovieDB (TMDb).',
|
||||
default_value: null,
|
||||
options_json: '[]',
|
||||
validation_json: '{}',
|
||||
order_index: 401
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { DVDSeriesPlugin };
|
||||
@@ -161,7 +161,9 @@ class VideoDiscPlugin extends SourcePlugin {
|
||||
cmd: scanConfig.cmd,
|
||||
args: scanConfig.args,
|
||||
collectLines: scanLines,
|
||||
collectStderrLines: false,
|
||||
// HandBrake scan details (duration/chapters/audio/subtitles) are often
|
||||
// emitted on stderr. Collect both streams for reliable disc heuristics.
|
||||
collectStderrLines: true,
|
||||
silent: reviewSilent
|
||||
});
|
||||
} catch (cmdError) {
|
||||
@@ -179,6 +181,7 @@ class VideoDiscPlugin extends SourcePlugin {
|
||||
cmd: scanConfig.cmd,
|
||||
args: scanConfig.args,
|
||||
onStdoutLine: (line) => scanLines.push(line),
|
||||
onStderrLine: (line) => scanLines.push(line),
|
||||
context: { jobId: job?.id, source: `${this.id}Plugin.review` }
|
||||
});
|
||||
}
|
||||
@@ -219,6 +222,7 @@ class VideoDiscPlugin extends SourcePlugin {
|
||||
deviceInfo,
|
||||
selectedTitleId = null,
|
||||
backupOutputBase = null,
|
||||
disableMinLengthFilter = false,
|
||||
isCancelled,
|
||||
onProcessHandle
|
||||
} = ctx.extra || {};
|
||||
@@ -237,7 +241,8 @@ class VideoDiscPlugin extends SourcePlugin {
|
||||
selectedTitleId,
|
||||
mediaProfile: this.mediaProfile,
|
||||
settingsMap: settings,
|
||||
backupOutputBase
|
||||
backupOutputBase,
|
||||
disableMinLengthFilter
|
||||
});
|
||||
|
||||
const ripMode = String(ripConfig.ripMode || settings.makemkv_rip_mode || 'mkv')
|
||||
@@ -249,7 +254,8 @@ class VideoDiscPlugin extends SourcePlugin {
|
||||
args: ripConfig.args,
|
||||
ripMode,
|
||||
rawJobDir,
|
||||
selectedTitleId
|
||||
selectedTitleId,
|
||||
disableMinLengthFilter
|
||||
});
|
||||
|
||||
ctx.emitProgress(0, ripMode === 'backup'
|
||||
@@ -443,7 +449,7 @@ function _assertNotCancelled(isCancelled) {
|
||||
}
|
||||
}
|
||||
|
||||
async function _runCommandCaptured({ cmd, args, onStdoutLine, context }) {
|
||||
async function _runCommandCaptured({ cmd, args, onStdoutLine, onStderrLine, context }) {
|
||||
const lines = [];
|
||||
const handle = spawnTrackedProcess({
|
||||
cmd,
|
||||
@@ -454,7 +460,12 @@ async function _runCommandCaptured({ cmd, args, onStdoutLine, context }) {
|
||||
onStdoutLine(line);
|
||||
}
|
||||
},
|
||||
onStderrLine: () => {},
|
||||
onStderrLine: (line) => {
|
||||
lines.push(line);
|
||||
if (typeof onStderrLine === 'function') {
|
||||
onStderrLine(line);
|
||||
}
|
||||
},
|
||||
context: context || {}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user