fix: advance NEXT past unplayable cuts

This commit is contained in:
2026-07-28 17:26:48 +09:00
parent ea96a08ad5
commit 18d40e892f
9 changed files with 323 additions and 38 deletions

View File

@@ -804,22 +804,22 @@ public sealed partial class MainWindow
// the newly appended row is then guaranteed to be in the future tail.
if (string.IsNullOrWhiteSpace(status.OnAirSceneName) ||
string.IsNullOrWhiteSpace(workflow.OnAirCutCode) ||
string.IsNullOrWhiteSpace(workflow.CurrentEntryId) ||
workflow.CurrentCueIndexZeroBased < 0)
string.IsNullOrWhiteSpace(workflow.OnAirEntryId) ||
workflow.OnAirCueIndexZeroBased < 0)
{
return false;
}
var playlist = _controller.Current.Playlist;
var currentIndex = workflow.CurrentCueIndexZeroBased;
var currentIndex = workflow.OnAirCueIndexZeroBased;
return currentIndex < playlist.Count &&
string.Equals(
playlist[currentIndex].RowId,
workflow.CurrentEntryId,
workflow.OnAirEntryId,
StringComparison.Ordinal) &&
playlist.Count(row => string.Equals(
row.RowId,
workflow.CurrentEntryId,
workflow.OnAirEntryId,
StringComparison.Ordinal)) == 1;
}
@@ -849,8 +849,8 @@ public sealed partial class MainWindow
return true;
}
if (string.IsNullOrWhiteSpace(workflow.CurrentEntryId) ||
workflow.CurrentCueIndexZeroBased < 0)
if (string.IsNullOrWhiteSpace(workflow.OnAirEntryId) ||
workflow.OnAirCueIndexZeroBased < 0)
{
return false;
}
@@ -860,7 +860,7 @@ public sealed partial class MainWindow
.Select(static (row, index) => (row, index))
.Where(candidate => string.Equals(
candidate.row.RowId,
workflow.CurrentEntryId,
workflow.OnAirEntryId,
StringComparison.Ordinal))
.Select(static candidate => candidate.index)
.Take(2)
@@ -871,7 +871,7 @@ public sealed partial class MainWindow
}
var currentIndex = currentMatches[0];
if (currentIndex != workflow.CurrentCueIndexZeroBased)
if (currentIndex != workflow.OnAirCueIndexZeroBased)
{
return false;
}
@@ -895,22 +895,22 @@ public sealed partial class MainWindow
// evidence does not establish a safe checkbox contract for that phase.
if (string.IsNullOrWhiteSpace(status.OnAirSceneName) ||
string.IsNullOrWhiteSpace(workflow.OnAirCutCode) ||
string.IsNullOrWhiteSpace(workflow.CurrentEntryId) ||
workflow.CurrentCueIndexZeroBased < 0)
string.IsNullOrWhiteSpace(workflow.OnAirEntryId) ||
workflow.OnAirCueIndexZeroBased < 0)
{
return false;
}
var playlist = _controller.Current.Playlist;
var currentIndex = workflow.CurrentCueIndexZeroBased;
var currentIndex = workflow.OnAirCueIndexZeroBased;
return currentIndex < playlist.Count &&
string.Equals(
playlist[currentIndex].RowId,
workflow.CurrentEntryId,
workflow.OnAirEntryId,
StringComparison.Ordinal) &&
playlist.Count(row => string.Equals(
row.RowId,
workflow.CurrentEntryId,
workflow.OnAirEntryId,
StringComparison.Ordinal)) == 1;
}
@@ -1132,6 +1132,8 @@ public sealed partial class MainWindow
"송출 어댑터를 사용할 수 없습니다.");
return snapshot with
{
OnAirCueIndexZeroBased = workflow?.OnAirCueIndexZeroBased ?? -1,
OnAirEntryId = workflow?.OnAirEntryId,
IsTakeOutCompletionPending = status?.IsTakeOutCompletionPending ?? false,
RefreshNextAtUtc = refresh.NextAtUtc,
RefreshLastSuccessAtUtc = refresh.LastSuccessAtUtc,

View File

@@ -805,9 +805,12 @@
if (selectedIndices.length === 0) return false;
const playout = state.playout;
if (!playout || playout.phase === "idle") return true;
const currentIndex = Number(playout.currentCueIndexZeroBased);
return Number.isSafeInteger(currentIndex) && currentIndex >= 0 &&
selectedIndices.every(function (index) { return index > currentIndex; });
const onAirIndex = Number(playout.onAirCueIndexZeroBased);
const protectedIndex = Number.isSafeInteger(onAirIndex) && onAirIndex >= 0
? onAirIndex
: Number(playout.currentCueIndexZeroBased);
return Number.isSafeInteger(protectedIndex) && protectedIndex >= 0 &&
selectedIndices.every(function (index) { return index > protectedIndex; });
}
function isCutSelectionLocked(state) {
@@ -832,19 +835,30 @@
playout.currentEntryId.length > 0 ? playout.currentEntryId : null;
const currentIndex = playout && Number.isInteger(playout.currentCueIndexZeroBased)
? playout.currentCueIndexZeroBased : -1;
const hasExplicitOnAirIdentity = playout && (
Object.prototype.hasOwnProperty.call(playout, "onAirEntryId") ||
Object.prototype.hasOwnProperty.call(playout, "onAirCueIndexZeroBased"));
const onAirEntryId = playout && typeof playout.onAirEntryId === "string" &&
playout.onAirEntryId.length > 0 ? playout.onAirEntryId : null;
const onAirIndex = playout && Number.isInteger(playout.onAirCueIndexZeroBased)
? playout.onAirCueIndexZeroBased : -1;
const isCurrent = hasActiveScene && (currentEntryId !== null
? currentEntryId === row.rowId
: currentIndex === position);
const pageCount = isCurrent && Number.isInteger(playout.pageCount) &&
const isOnAir = phase === "program" && (hasExplicitOnAirIdentity
? (onAirEntryId !== null ? onAirEntryId === row.rowId : onAirIndex === position)
: isCurrent);
const ownsPage = phase === "program" ? isOnAir : isCurrent;
const pageCount = ownsPage && Number.isInteger(playout.pageCount) &&
playout.pageCount > 0 ? playout.pageCount : 0;
const pageIndex = isCurrent && Number.isInteger(playout.pageIndexZeroBased) &&
const pageIndex = ownsPage && Number.isInteger(playout.pageIndexZeroBased) &&
playout.pageIndexZeroBased >= 0 && playout.pageIndexZeroBased < pageCount
? playout.pageIndexZeroBased : -1;
return {
isSelected: row.isSelected === true,
isCurrent: isCurrent,
isOnAir: isCurrent && phase === "program",
isOnAir: isOnAir,
pageText: pageIndex >= 0
? String(pageIndex + 1) + "/" + String(pageCount)
: row.pageText,