0.13.1-1 Episode Detection

This commit is contained in:
2026-04-12 19:43:56 +00:00
parent bc193db50a
commit 850f05453c
19 changed files with 2046 additions and 119 deletions
+66 -4
View File
@@ -1159,6 +1159,70 @@ function normalizePositiveIntegerOrNull(value) {
return Math.trunc(parsed);
}
function resolveSeriesAssignmentEpisodeSpan(assignment = null) {
const source = assignment && typeof assignment === 'object' ? assignment : {};
const start = normalizePositiveIntegerOrNull(
source?.episodeNumberStart
?? source?.episodeNoStart
?? source?.episodeNumber
?? source?.number
?? null
);
const explicitEnd = normalizePositiveIntegerOrNull(
source?.episodeNumberEnd
?? source?.episodeNoEnd
?? null
);
const explicitSpan = normalizePositiveIntegerOrNull(
source?.episodeSpan
?? source?.episodeCount
?? null
);
if (start && explicitEnd && explicitEnd >= start) {
return Math.max(1, Math.trunc(explicitEnd - start + 1));
}
if (explicitSpan && explicitSpan > 0) {
return Math.max(1, Math.trunc(explicitSpan));
}
if (start) {
return 1;
}
return 0;
}
function countSelectedEpisodeSlotsFromPlan(plan = null) {
const sourcePlan = plan && typeof plan === 'object' ? plan : {};
const titles = Array.isArray(sourcePlan?.titles) ? sourcePlan.titles : [];
const selectedFromFlags = titles
.filter((title) => Boolean(title?.selectedForEncode || title?.encodeInput))
.map((title) => normalizePositiveIntegerOrNull(title?.id))
.filter(Boolean);
const selectedFromPlan = Array.isArray(sourcePlan?.selectedTitleIds)
? sourcePlan.selectedTitleIds
.map((value) => normalizePositiveIntegerOrNull(value))
.filter(Boolean)
: [];
const selectedFromInput = normalizePositiveIntegerOrNull(sourcePlan?.encodeInputTitleId);
const selectedTitleIds = Array.from(new Set([
...selectedFromFlags,
...selectedFromPlan,
...(selectedFromInput ? [selectedFromInput] : [])
]));
if (selectedTitleIds.length === 0) {
return 0;
}
const assignments = sourcePlan?.episodeAssignments && typeof sourcePlan.episodeAssignments === 'object'
? sourcePlan.episodeAssignments
: {};
let total = 0;
for (const titleId of selectedTitleIds) {
const assignment = assignments[String(titleId)] || assignments[titleId] || null;
const span = resolveSeriesAssignmentEpisodeSpan(assignment);
total += span > 0 ? span : 1;
}
return Math.max(0, total);
}
function isSeriesBatchEpisodeSubJobPlan(encodePlan = null) {
const plan = encodePlan && typeof encodePlan === 'object' ? encodePlan : {};
if (Boolean(plan?.seriesBatchChild) || Boolean(plan?.seriesBatchVirtualEpisode)) {
@@ -3816,8 +3880,7 @@ class HistoryService {
let selectedCount = 0;
const childPlan = parseJsonSafe(childRow?.encode_plan_json, null);
if (childPlan && typeof childPlan === 'object') {
const titles = Array.isArray(childPlan?.titles) ? childPlan.titles : [];
selectedCount = titles.filter((title) => title?.selectedForEncode || title?.encodeInput).length;
selectedCount = countSelectedEpisodeSlotsFromPlan(childPlan);
}
const handbrakeInfo = parseJsonSafe(childRow?.handbrake_info_json, null);
const hbStatus = String(handbrakeInfo?.status || '').trim().toUpperCase();
@@ -3958,8 +4021,7 @@ class HistoryService {
const episodesLength = Array.isArray(selected?.episodes) ? selected.episodes.length : 0;
const expectedFromMetadata = episodeCount > 0 ? episodeCount : (episodesLength > 0 ? episodesLength : 0);
const plan = parseJsonSafe(job?.encode_plan_json, null);
const titles = Array.isArray(plan?.titles) ? plan.titles : [];
const expectedFromPlan = titles.filter((title) => title?.selectedForEncode || title?.encodeInput).length;
const expectedFromPlan = countSelectedEpisodeSlotsFromPlan(plan);
const expectedFinal = expectedFromPlan > 0 ? expectedFromPlan : expectedFromMetadata;
const outputSet = outputsByJobId.get(jobId) || new Set();
const directOutput = String(job?.output_path || '').trim();