0.13.1 DVD Series rc1
This commit is contained in:
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "ripster-backend",
|
||||
"version": "0.13.0-1",
|
||||
"version": "0.13.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "ripster-backend",
|
||||
"version": "0.13.0-1",
|
||||
"version": "0.13.1",
|
||||
"dependencies": {
|
||||
"archiver": "^7.0.1",
|
||||
"cors": "^2.8.5",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ripster-backend",
|
||||
"version": "0.13.0-1",
|
||||
"version": "0.13.1",
|
||||
"private": true,
|
||||
"type": "commonjs",
|
||||
"scripts": {
|
||||
|
||||
@@ -1159,6 +1159,29 @@ function normalizePositiveIntegerOrNull(value) {
|
||||
return Math.trunc(parsed);
|
||||
}
|
||||
|
||||
function isSeriesBatchEpisodeSubJobPlan(encodePlan = null) {
|
||||
const plan = encodePlan && typeof encodePlan === 'object' ? encodePlan : {};
|
||||
if (Boolean(plan?.seriesBatchChild) || Boolean(plan?.seriesBatchVirtualEpisode)) {
|
||||
return true;
|
||||
}
|
||||
const parentJobId = normalizePositiveIntegerOrNull(plan?.seriesBatchParentJobId);
|
||||
const titleId = normalizePositiveIntegerOrNull(plan?.seriesBatchTitleId);
|
||||
const childIndex = normalizePositiveIntegerOrNull(plan?.seriesBatchChildIndex);
|
||||
const childCount = normalizePositiveIntegerOrNull(plan?.seriesBatchChildCount);
|
||||
if (parentJobId && (titleId || childIndex || childCount)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isSeriesBatchEpisodeSubJobRow(row = null) {
|
||||
const source = row && typeof row === 'object' ? row : {};
|
||||
const plan = source?.encodePlan && typeof source.encodePlan === 'object'
|
||||
? source.encodePlan
|
||||
: parseJsonSafe(source?.encode_plan_json, null);
|
||||
return isSeriesBatchEpisodeSubJobPlan(plan);
|
||||
}
|
||||
|
||||
function extractSeasonNumberFromText(value) {
|
||||
const text = String(value || '').trim();
|
||||
if (!text) {
|
||||
@@ -3675,8 +3698,24 @@ class HistoryService {
|
||||
}
|
||||
|
||||
const allContainerChildRows = [...childRows, ...nestedChildRows];
|
||||
const directDiskRowsByContainerId = new Map();
|
||||
const directEpisodeRowsByContainerId = new Map();
|
||||
const directChildRowById = new Map();
|
||||
for (const row of childRows) {
|
||||
const containerId = normalizeJobIdValue(row?.parent_job_id);
|
||||
const isEpisodeSubJob = isSeriesBatchEpisodeSubJobRow(row);
|
||||
if (containerId) {
|
||||
const map = isEpisodeSubJob
|
||||
? directEpisodeRowsByContainerId
|
||||
: directDiskRowsByContainerId;
|
||||
if (!map.has(containerId)) {
|
||||
map.set(containerId, []);
|
||||
}
|
||||
map.get(containerId).push(row);
|
||||
}
|
||||
if (isEpisodeSubJob) {
|
||||
continue;
|
||||
}
|
||||
const childId = normalizeJobIdValue(row?.id);
|
||||
if (childId) {
|
||||
directChildRowById.set(childId, row);
|
||||
@@ -3737,8 +3776,9 @@ class HistoryService {
|
||||
const episodeCount = Number(selectedMetadata?.episodeCount || 0);
|
||||
const episodesLength = Array.isArray(selectedMetadata?.episodes) ? selectedMetadata.episodes.length : 0;
|
||||
const expectedTotal = episodeCount > 0 ? episodeCount : (episodesLength > 0 ? episodesLength : 0);
|
||||
const childIds = childRows
|
||||
.filter((row) => normalizeJobIdValue(row?.parent_job_id) === containerId)
|
||||
const containerChildRows = directDiskRowsByContainerId.get(containerId) || [];
|
||||
const containerEpisodeRows = directEpisodeRowsByContainerId.get(containerId) || [];
|
||||
const childIds = containerChildRows
|
||||
.map((row) => normalizeJobIdValue(row?.id))
|
||||
.filter(Boolean);
|
||||
let rawExistsAny = false;
|
||||
@@ -3851,6 +3891,22 @@ class HistoryService {
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const episodeRow of containerEpisodeRows) {
|
||||
const episodeRowId = normalizeJobIdValue(episodeRow?.id);
|
||||
if (!episodeRowId) {
|
||||
continue;
|
||||
}
|
||||
const outputs = Array.from(childOutputMap.get(episodeRowId) || []);
|
||||
for (const outputPath of outputs) {
|
||||
if (!outputPath || seenOutputs.has(outputPath)) {
|
||||
continue;
|
||||
}
|
||||
seenOutputs.add(outputPath);
|
||||
if (!includeFsChecks || fs.existsSync(outputPath)) {
|
||||
existingCount += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (existingCountFromSeriesBatch > existingCount) {
|
||||
existingCount = existingCountFromSeriesBatch;
|
||||
}
|
||||
@@ -4319,6 +4375,10 @@ class HistoryService {
|
||||
const childJobs = await Promise.all(
|
||||
childRows.map((row) => this.repairImportedOrphanJobClassification(row, settings))
|
||||
);
|
||||
const isSeriesContainer = String(job?.job_kind || '').trim().toLowerCase() === 'dvd_series_container';
|
||||
const detailChildJobs = isSeriesContainer
|
||||
? childJobs.filter((child) => !isSeriesBatchEpisodeSubJobRow(child))
|
||||
: childJobs;
|
||||
const parsedTail = Number(options.logTailLines);
|
||||
const logTailLines = Number.isFinite(parsedTail) && parsedTail > 0
|
||||
? Math.trunc(parsedTail)
|
||||
@@ -4330,7 +4390,7 @@ class HistoryService {
|
||||
const hasProcessLog = (!shouldLoadLogs && includeFsChecks) ? hasProcessLogFile(jobId) : false;
|
||||
const baseLogCount = hasProcessLog ? 1 : 0;
|
||||
const enrichedChildren = await Promise.all(
|
||||
childJobs.map(async (child) => {
|
||||
detailChildJobs.map(async (child) => {
|
||||
const base = {
|
||||
...enrichJobRow(child, settings, { includeFsChecks }),
|
||||
log_count: includeFsChecks ? (hasProcessLogFile(child.id) ? 1 : 0) : 0
|
||||
@@ -4365,7 +4425,6 @@ class HistoryService {
|
||||
})
|
||||
);
|
||||
|
||||
const isSeriesContainer = String(job?.job_kind || '').trim().toLowerCase() === 'dvd_series_container';
|
||||
let seriesChildSummary = null;
|
||||
if (isSeriesContainer && enrichedChildren.length > 0) {
|
||||
const total = enrichedChildren.length;
|
||||
|
||||
@@ -13172,6 +13172,19 @@ class PipelineService extends EventEmitter {
|
||||
let parentContainerJobId = normalizePositiveInteger(job.parent_job_id || null);
|
||||
const isDvdSeriesSelection = isDvdTmdbMetadataSelection;
|
||||
if (isDvdSeriesSelection) {
|
||||
const resolveDiscNumberFromJobRow = (row) => {
|
||||
const rowMkInfo = this.safeParseJson(row?.makemkv_info_json) || {};
|
||||
const rowAnalyzeContext = rowMkInfo?.analyzeContext && typeof rowMkInfo.analyzeContext === 'object'
|
||||
? rowMkInfo.analyzeContext
|
||||
: {};
|
||||
const rowSelectedMetadata = rowAnalyzeContext?.selectedMetadata && typeof rowAnalyzeContext.selectedMetadata === 'object'
|
||||
? rowAnalyzeContext.selectedMetadata
|
||||
: (rowMkInfo?.selectedMetadata && typeof rowMkInfo.selectedMetadata === 'object'
|
||||
? rowMkInfo.selectedMetadata
|
||||
: {});
|
||||
return normalizePositiveInteger(rowSelectedMetadata?.discNumber);
|
||||
};
|
||||
|
||||
if (!parentContainerJobId) {
|
||||
const existingContainer = await historyService.findSeriesContainerJob(effectiveTmdbId, effectiveSeasonNumber);
|
||||
if (existingContainer) {
|
||||
@@ -13212,6 +13225,38 @@ class PipelineService extends EventEmitter {
|
||||
parentContainerJobId = Number(containerJob?.id || 0) || null;
|
||||
}
|
||||
}
|
||||
|
||||
if (parentContainerJobId && effectiveDiscNumber) {
|
||||
const containerChildren = await historyService.listChildJobs(parentContainerJobId);
|
||||
const conflictingDiscChild = (Array.isArray(containerChildren) ? containerChildren : []).find((childRow) => {
|
||||
const childId = Number(childRow?.id || 0);
|
||||
if (!childId || childId === Number(jobId)) {
|
||||
return false;
|
||||
}
|
||||
const childDiscNumber = resolveDiscNumberFromJobRow(childRow);
|
||||
return childDiscNumber === effectiveDiscNumber;
|
||||
});
|
||||
|
||||
if (conflictingDiscChild) {
|
||||
const existingChildJobId = Number(conflictingDiscChild?.id || 0) || null;
|
||||
const error = new Error(
|
||||
`Disk ${effectiveDiscNumber} ist fuer diese Serie/Staffel bereits vorhanden (Job #${existingChildJobId || '?'}). Bitte andere Disk-Nummer waehlen.`
|
||||
);
|
||||
error.statusCode = 409;
|
||||
error.details = [
|
||||
{
|
||||
code: 'SERIES_DISC_ALREADY_EXISTS',
|
||||
containerJobId: Number(parentContainerJobId),
|
||||
existingJobId: existingChildJobId,
|
||||
discNumber: Number(effectiveDiscNumber),
|
||||
tmdbId: Number(effectiveTmdbId || 0) || null,
|
||||
seasonNumber: Number(effectiveSeasonNumber || 0) || null
|
||||
}
|
||||
];
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
if (parentContainerJobId) {
|
||||
const containerMkInfo = this.withAnalyzeContextMediaProfile({
|
||||
analyzeContext: {
|
||||
|
||||
Reference in New Issue
Block a user