feat: time to next flag

This commit is contained in:
Carlos Valente
2025-07-13 16:52:35 +02:00
parent 637454f73d
commit 445cc9e845
43 changed files with 550 additions and 310 deletions
@@ -427,6 +427,7 @@ describe('getCustomFieldData()', () => {
linkStart: 'link start',
timeEnd: 'time end',
duration: 'duration',
flag: 'flag',
cue: 'cue',
title: 'title',
countToEnd: 'count to end',
@@ -479,6 +480,7 @@ describe('getCustomFieldData()', () => {
linkStart: 'link start',
timeEnd: 'time end',
duration: 'duration',
flag: 'flag',
cue: 'cue',
title: 'title',
countToEnd: 'count to end',
@@ -63,6 +63,7 @@ let rundownMetadata: RundownMetadata = {
playableEventOrder: [],
timedEventOrder: [],
flatEntryOrder: [],
flags: [],
};
const customFieldsMetadata: CustomFieldsMetadata = {
@@ -666,7 +667,7 @@ export function init(initialRundown: Readonly<Rundown>, initialCustomFields: Rea
processedData;
cachedRundown.entries = entries;
cachedRundown.order = order;
cachedRundown.flatOrder = metadata.flatEntryOrder; // TODO: remove in favour of the metadata flatEntryOrder
cachedRundown.flatOrder = metadata.flatEntryOrder;
cachedRundown.revision = rundown.revision;
customFieldsMetadata.assigned = assignedCustomFields;
rundownMetadata = metadata;
@@ -225,6 +225,7 @@ export function makeRundownMetadata(customFields: CustomFields) {
playableEventOrder: [],
timedEventOrder: [],
flatEntryOrder: [],
flags: [],
entries: {},
order: [],
@@ -300,6 +301,11 @@ function processEntry<T extends OntimeEntry>(
processedData.firstStart = currentEntry.timeStart;
}
// check if event is flagged
if (currentEntry.flag) {
processedData.flags.push(currentEntry.id);
}
currentEntry.gap = getTimeFrom(currentEntry, processedData.latestEvent);
if (currentEntry.gap === 0) {
@@ -10,6 +10,7 @@ export type RundownMetadata = {
playableEventOrder: EntryId[]; // flat order of playable events
timedEventOrder: EntryId[]; // flat order of timed events
flatEntryOrder: EntryId[]; // flat order of entries
flags: EntryId[]; // flat order of flagged entries
};
export type AssignedMap = Record<CustomFieldKey, EntryId[]>;
+1
View File
@@ -51,6 +51,7 @@ export class EventTimer {
}
}
// register a callback for the scheduled end
const endTime = state.timer.current - timerConfig.triggerAhead;
this.endCallback = setTimeout(() => this.update(), endTime);
return true;
@@ -810,6 +810,11 @@ function broadcastResult(_target: any, _propertyKey: string, descriptor: Propert
RuntimeService.previousState.blockNext = state.blockNext;
}
if (RuntimeService.previousState?.nextFlag !== state.nextFlag) {
batch.add('nextFlag', state.nextFlag);
RuntimeService.previousState.nextFlag = state.nextFlag;
}
if (hasImmediateChanges) {
saveRestoreState(state);
}
@@ -8,6 +8,7 @@ const baseState: RuntimeState = {
eventNext: null,
blockNow: null,
blockNext: null,
nextFlag: null,
runtime: {
selectedEventIndex: null,
numEvents: 0,
+33 -2
View File
@@ -1,6 +1,7 @@
import {
BlockState,
CurrentBlockState,
isOntimeBlock,
isOntimeEvent,
MaybeNumber,
MaybeString,
OffsetMode,
@@ -11,6 +12,7 @@ import {
runtimeStorePlaceholder,
TimerPhase,
TimerState,
UpcomingEntry,
} from 'ontime-types';
import { calculateDuration, checkIsNow, dayInMs, isPlaybackActive } from 'ontime-utils';
@@ -32,8 +34,9 @@ import { getCurrentRundown } from '../api-data/rundown/rundown.dao.js';
export type RuntimeState = {
clock: number; // realtime clock
blockNow: BlockState | null;
blockNow: CurrentBlockState | null;
blockNext: MaybeString;
nextFlag: UpcomingEntry | null;
eventNow: PlayableEvent | null;
eventNext: PlayableEvent | null;
runtime: Runtime;
@@ -53,6 +56,7 @@ const runtimeState: RuntimeState = {
clock: timeNow(),
blockNow: null,
blockNext: null,
nextFlag: null,
eventNow: null,
eventNext: null,
runtime: { ...runtimeStorePlaceholder.runtime },
@@ -111,6 +115,7 @@ export function clearState() {
runtimeState.blockNow = null;
runtimeState.blockNext = null;
runtimeState.nextFlag = null;
runtimeState.runtime.offset = 0;
runtimeState.runtime.relativeOffset = 0;
@@ -195,6 +200,7 @@ export function load(
loadNow(rundown, metadata, eventIndex);
loadNext(rundown, metadata, eventIndex);
loadBlock(rundown);
loadNextFlag(eventIndex, rundown, metadata);
// update state
runtimeState.timer.playback = Playback.Armed;
@@ -720,6 +726,31 @@ export function loadBlock(rundown: Rundown, state = runtimeState) {
}
}
/**
* find and load the next flag from the currently loaded event
*/
export function loadNextFlag(currentIndex: number, rundown: Rundown, metadata: RundownMetadata) {
runtimeState.nextFlag = null;
if (metadata.flags.length === 0) {
return;
}
for (let i = currentIndex; i < metadata.timedEventOrder.length; i++) {
const entryId = metadata.timedEventOrder[i];
if (metadata.flags.includes(entryId)) {
const event = rundown.entries[entryId];
if (!event || !isOntimeEvent(event)) {
continue;
}
runtimeState.nextFlag = { id: event.id, start: event.timeStart };
return;
}
}
return null;
}
export function setOffsetMode(mode: OffsetMode) {
runtimeState.runtime.offsetMode = mode;
}