fix: prevent rolling into events of 0 duration

This commit is contained in:
Carlos Valente
2025-10-01 07:05:31 +02:00
committed by Alex Christoffer Rasmussen
parent e22c7698c3
commit 81e00993f2
4 changed files with 38 additions and 7 deletions
@@ -1,10 +1,12 @@
import { dayInMs, MILLIS_PER_HOUR, MILLIS_PER_MINUTE } from 'ontime-utils';
import { loadRoll } from '../rollUtils.js';
import { makeRundown } from '../../api-data/rundown/__mocks__/rundown.mocks.js';
import { PlayableEvent } from 'ontime-types';
import { initRundown } from '../../api-data/rundown/rundown.service.js';
import { rundownCache } from '../../api-data/rundown/rundown.dao.js';
import { processRundown, rundownCache } from '../../api-data/rundown/rundown.dao.js';
import { makeOntimeEvent, makeRundown } from '../../api-data/rundown/__mocks__/rundown.mocks.js';
import { loadRoll } from '../rollUtils.js';
beforeAll(() => {
vi.mock('../../classes/data-provider/DataProvider.js', () => {
@@ -198,6 +200,24 @@ describe('loadRoll()', () => {
const state = loadRoll(rundown, metadata, now);
expect(state).toStrictEqual(expected);
});
it('should ignore events with 0 duration', () => {
const rundown = makeRundown({
entries: {
'1': makeOntimeEvent({ id: '1', timeStart: 70, timeEnd: 70, duration: 0 }),
'2': makeOntimeEvent({ id: '2', timeStart: 70, timeEnd: 170, duration: 100 }),
},
order: ['1', '2'],
});
const metadata = processRundown(rundown, {});
const now = 70;
const state = loadRoll(rundown, metadata, now);
expect(state).toStrictEqual({
event: rundown.entries['2'],
index: 1,
});
});
});
describe('loadRoll() handle edge cases with midnight', () => {
+1
View File
@@ -29,6 +29,7 @@ export function loadRoll(
for (let i = 0; i < metadata.playableEventOrder.length; i++) {
const event = rundown.entries[metadata.playableEventOrder[i]] as PlayableEvent;
// rolling into events of 0 duration would make the playback be stuck
if (event.duration === 0) {
continue;
}
@@ -1,5 +1,6 @@
import {
EndAction,
EntryId,
isOntimeEvent,
isPlayableEvent,
LogOrigin,
@@ -386,11 +387,12 @@ class RuntimeService {
* startSelected being a private function does not trigger emits
* and pass on runtime offset in case of roll mode
*/
private handleLoadNext(): boolean {
private handleLoadNext(fromId?: EntryId): boolean {
const state = runtimeState.getState();
const { playableEventOrder } = getRundownMetadata();
const nextId = findNextPlayableId(playableEventOrder, state.eventNow?.id);
const nextId = findNextPlayableId(playableEventOrder, fromId ?? state.eventNow?.id);
if (nextId) {
const nextEvent = getEntryWithId(nextId);
if (!nextEvent || !isOntimeEvent(nextEvent)) {
@@ -398,6 +400,14 @@ class RuntimeService {
}
if (state.timer.playback === Playback.Roll) {
if (nextEvent.duration === 0) {
/**
* when loading next in roll mode,
* we need to prevent loading events of 0 duration since
* this would make the playback be stuck
*/
return this.handleLoadNext(nextId);
}
return this.loadEvent(nextEvent, { firstStart: state.rundown.actualStart });
}
return this.loadEvent(nextEvent);
+2 -2
View File
@@ -626,7 +626,7 @@ export function roll(
: runtimeState.eventNow.timeEnd;
runtimeState.timer.expectedFinish = normalisedEndTime;
//account for offset
// account for offset
const offsetClock = runtimeState.clock - runtimeState.offset.absolute;
// state catch up
@@ -672,7 +672,7 @@ export function roll(
// we need to persist the current group state across loads
clearEventData();
//account for offset but we only keep it if passed to us
// account for offset but we only keep it if passed to us
runtimeState.offset.absolute = offset;
const offsetClock = runtimeState.clock - runtimeState.offset.absolute;