From 4bceae65ab8c6fc8e7e2765e7f5b701b73b9ad9c Mon Sep 17 00:00:00 2001 From: Carlos Valente <34649812+cpvalente@users.noreply.github.com> Date: Wed, 26 Apr 2023 22:02:04 +0200 Subject: [PATCH] fix v2 roll timer (#363) * fix: roll update skips elapsed time * refactor: remove unused data * style: fix style in roll state --- .../src/features/viewers/ViewWrapper.tsx | 5 +- .../features/viewers/countdown/Countdown.tsx | 2 +- .../src/classes/event-loader/EventLoader.ts | 8 +- apps/server/src/services/PlaybackService.ts | 4 +- apps/server/src/services/TimerService.ts | 23 ++---- .../src/services/__tests__/rollUtils.test.js | 79 ++----------------- apps/server/src/services/rollUtils.ts | 9 --- 7 files changed, 24 insertions(+), 106 deletions(-) diff --git a/apps/client/src/features/viewers/ViewWrapper.tsx b/apps/client/src/features/viewers/ViewWrapper.tsx index 15deca090..d256c105f 100644 --- a/apps/client/src/features/viewers/ViewWrapper.tsx +++ b/apps/client/src/features/viewers/ViewWrapper.tsx @@ -1,10 +1,11 @@ import { ReactNode, useMemo } from 'react'; import { Playback, TitleBlock } from 'ontime-types'; +import { useStore } from 'zustand'; import useEventData from '../../common/hooks-query/useEventData'; import useRundown from '../../common/hooks-query/useRundown'; import useViewSettings from '../../common/hooks-query/useViewSettings'; -import { useRuntimeStore } from '../../common/stores/runtime'; +import { runtime } from '../../common/stores/runtime'; import { useViewOptionsStore } from '../../common/stores/viewOptions'; export type TitleManager = TitleBlock & { showNow: boolean; showNext: boolean }; @@ -27,7 +28,7 @@ const withData = (Component: ReactNode) => { }, [eventsData]); // websocket data - const data = useRuntimeStore(); + const data = useStore(runtime); const { timer, titles, titlesPublic, publicMessage, timerMessage, lowerMessage, playback, onAir } = data; const publicSelectedId = data.loaded.selectedPublicEventId; const selectedId = data.loaded.selectedEventId; diff --git a/apps/client/src/features/viewers/countdown/Countdown.tsx b/apps/client/src/features/viewers/countdown/Countdown.tsx index da08026a1..a3fc38f9d 100644 --- a/apps/client/src/features/viewers/countdown/Countdown.tsx +++ b/apps/client/src/features/viewers/countdown/Countdown.tsx @@ -90,7 +90,7 @@ export default function Countdown(props: CountdownProps) { return null; } - const standby = time.playback !== Playback.Play && selectedId === follow?.id; + const standby = time.playback !== Playback.Play && time.playback !== Playback.Roll && selectedId === follow?.id; const isRunningFinished = time.finished && runningMessage === TimerMessage.running; const isSelected = runningMessage === TimerMessage.running; const delayedTimerStyles = delay > 0 ? 'aux-timers__value--delayed' : ''; diff --git a/apps/server/src/classes/event-loader/EventLoader.ts b/apps/server/src/classes/event-loader/EventLoader.ts index e39c7a53f..0074bb429 100644 --- a/apps/server/src/classes/event-loader/EventLoader.ts +++ b/apps/server/src/classes/event-loader/EventLoader.ts @@ -152,8 +152,10 @@ export class EventLoader { return null; } - const { nowIndex, timers, timeToNext, nextEvent, nextPublicEvent, currentEvent, currentPublicEvent } = - getRollTimers(timedEvents, timeNow); + const { nowIndex, timeToNext, nextEvent, nextPublicEvent, currentEvent, currentPublicEvent } = getRollTimers( + timedEvents, + timeNow, + ); this.loadedEvent = currentEvent; this.loaded.selectedEventIndex = nowIndex; @@ -166,7 +168,7 @@ export class EventLoader { this._loadThisTitles(nextEvent, 'next-private'); this._loadThisTitles(nextPublicEvent, 'next-public'); - return { currentEvent, nextEvent, timeToNext, timers }; + return { currentEvent, nextEvent, timeToNext }; } /** diff --git a/apps/server/src/services/PlaybackService.ts b/apps/server/src/services/PlaybackService.ts index 8f92199c2..5831a2376 100644 --- a/apps/server/src/services/PlaybackService.ts +++ b/apps/server/src/services/PlaybackService.ts @@ -197,14 +197,14 @@ export class PlaybackService { return; } - const { currentEvent, nextEvent, timers } = rollTimers; + const { currentEvent, nextEvent } = rollTimers; if (!currentEvent && !nextEvent) { logger.warning('SERVER', 'Roll: no events found'); PlaybackService.stop(); return; } - eventTimer.roll(currentEvent, nextEvent, timers); + eventTimer.roll(currentEvent, nextEvent); const newState = eventTimer.playback; logger.info('PLAYBACK', `Play Mode ${newState.toUpperCase()}`); diff --git a/apps/server/src/services/TimerService.ts b/apps/server/src/services/TimerService.ts index 1d1f4c108..e19da9512 100644 --- a/apps/server/src/services/TimerService.ts +++ b/apps/server/src/services/TimerService.ts @@ -8,16 +8,6 @@ import { integrationService } from './integration-service/IntegrationService.js' import { getCurrent, getElapsed, getExpectedFinish } from './timerUtils.js'; import { clock } from './Clock.js'; -/** - * Aux type - */ -type Timer = { - _startedAt: number; - _finishAt: number; - duration: number; - current: number; -}; - export class TimerService { private readonly _interval: NodeJS.Timer; @@ -274,6 +264,7 @@ export class TimerService { this.timer.current = updatedTimer; this.timer.secondaryTimer = updatedSecondaryTimer; + this.timer.elapsed = getElapsed(this.timer.startedAt, this.timer.clock); if (isFinished) { this.timer.selectedEventId = null; @@ -344,9 +335,8 @@ export class TimerService { * Loads roll information into timer service * @param {OntimeEvent | null} currentEvent -- both current event and next event cant be null * @param {OntimeEvent | null} nextEvent -- both current event and next event cant be null - * @param {Timer} timers */ - roll(currentEvent: OntimeEvent | null, nextEvent: OntimeEvent | null, timers: Timer) { + roll(currentEvent: OntimeEvent | null, nextEvent: OntimeEvent | null) { this._clear(); this.timer.clock = clock.timeNow(); @@ -355,11 +345,11 @@ export class TimerService { this.timer.secondaryTimer = null; this.secondaryTarget = null; - this.loadedTimerId = currentEvent.id; + // when we load a timer in roll, we do the same things as before + // but also pre-populate some data as to the running state + this.load(currentEvent); this.timer.startedAt = currentEvent.timeStart; this.timer.expectedFinish = currentEvent.timeEnd; - this.timer.duration = timers.duration; - this.timer.current = timers.current; } else if (nextEvent) { // account for day after const nextStart = nextEvent.timeStart < this.timer.clock ? nextEvent.timeStart + DAY_TO_MS : nextEvent.timeStart; @@ -367,14 +357,13 @@ export class TimerService { this.timer.secondaryTimer = nextStart - this.timer.clock; this.secondaryTarget = nextStart; } - this.playback = Playback.Roll; this._onRoll(); this.update(); } _onRoll() { - this._onLoad(); + eventStore.set('playback', this.playback); } shutdown() { diff --git a/apps/server/src/services/__tests__/rollUtils.test.js b/apps/server/src/services/__tests__/rollUtils.test.js index dbe47954a..498dde448 100644 --- a/apps/server/src/services/__tests__/rollUtils.test.js +++ b/apps/server/src/services/__tests__/rollUtils.test.js @@ -1,4 +1,10 @@ -import { DAY_TO_MS, getRollTimers, normaliseEndTime, sortArrayByProperty, updateRoll } from '../rollUtils.ts'; +import { + DAY_TO_MS, + getRollTimers, + normaliseEndTime, + sortArrayByProperty, + updateRoll, +} from '../rollUtils.ts'; // test sortArrayByProperty() describe('sort simple arrays of objects', () => { @@ -96,7 +102,6 @@ describe('test that roll loads selection in right order', () => { publicIndex: null, nextIndex: 0, publicNextIndex: 4, - timers: null, timeToNext: 5, nextEvent: eventlist[0], nextPublicEvent: eventlist[4], @@ -116,12 +121,6 @@ describe('test that roll loads selection in right order', () => { publicIndex: null, nextIndex: 1, publicNextIndex: 4, - timers: { - _startedAt: eventlist[0].timeStart, - _finishAt: eventlist[0].timeEnd, - current: 5, - duration: eventlist[0].timeEnd - eventlist[0].timeStart, - }, timeToNext: 5, nextEvent: eventlist[1], nextPublicEvent: eventlist[4], @@ -141,12 +140,6 @@ describe('test that roll loads selection in right order', () => { publicIndex: null, nextIndex: 2, publicNextIndex: 4, - timers: { - _startedAt: eventlist[1].timeStart, - _finishAt: eventlist[1].timeEnd, - current: 5, - duration: eventlist[1].timeEnd - eventlist[1].timeStart, - }, timeToNext: 5, nextEvent: eventlist[2], nextPublicEvent: eventlist[4], @@ -166,12 +159,6 @@ describe('test that roll loads selection in right order', () => { publicIndex: null, nextIndex: 3, publicNextIndex: 4, - timers: { - _startedAt: eventlist[2].timeStart, - _finishAt: eventlist[2].timeEnd, - current: 10, - duration: eventlist[2].timeEnd - eventlist[2].timeStart, - }, timeToNext: 10, nextEvent: eventlist[3], nextPublicEvent: eventlist[4], @@ -191,12 +178,6 @@ describe('test that roll loads selection in right order', () => { publicIndex: 4, nextIndex: 5, publicNextIndex: 6, - timers: { - _startedAt: eventlist[4].timeStart, - _finishAt: eventlist[4].timeEnd, - current: 1, - duration: eventlist[4].timeEnd - eventlist[4].timeStart, - }, timeToNext: 1, nextEvent: eventlist[5], nextPublicEvent: eventlist[6], @@ -216,12 +197,6 @@ describe('test that roll loads selection in right order', () => { publicIndex: 6, nextIndex: 7, publicNextIndex: null, - timers: { - _startedAt: eventlist[6].timeStart, - _finishAt: eventlist[6].timeEnd, - current: 7, - duration: eventlist[6].timeEnd - eventlist[6].timeStart, - }, timeToNext: 7, nextEvent: eventlist[7], nextPublicEvent: null, @@ -241,12 +216,6 @@ describe('test that roll loads selection in right order', () => { publicIndex: 6, nextIndex: null, publicNextIndex: null, - timers: { - _startedAt: eventlist[7].timeStart, - _finishAt: eventlist[7].timeEnd, - current: 5, - duration: eventlist[7].timeEnd - eventlist[7].timeStart, - }, timeToNext: null, nextEvent: null, nextPublicEvent: null, @@ -266,7 +235,6 @@ describe('test that roll loads selection in right order', () => { publicIndex: null, nextIndex: 0, publicNextIndex: 4, - timers: null, timeToNext: DAY_TO_MS - now + eventlist[0].timeStart, nextEvent: eventlist[0], nextPublicEvent: eventlist[4], @@ -294,7 +262,6 @@ describe('test that roll loads selection in right order', () => { publicIndex: null, nextIndex: 0, publicNextIndex: 0, - timers: null, timeToNext: DAY_TO_MS - now + singleEventList[0].timeStart, nextEvent: singleEventList[0], nextPublicEvent: singleEventList[0], @@ -337,7 +304,6 @@ describe('test that roll behaviour with overlapping times', () => { publicIndex: null, nextIndex: 0, publicNextIndex: 1, - timers: null, timeToNext: 10, nextEvent: eventlist[0], nextPublicEvent: eventlist[1], @@ -357,12 +323,6 @@ describe('test that roll behaviour with overlapping times', () => { publicIndex: 1, nextIndex: 2, publicNextIndex: null, - timers: { - _startedAt: eventlist[1].timeStart, - _finishAt: eventlist[1].timeEnd, - current: 10, - duration: eventlist[1].timeEnd - eventlist[1].timeStart, - }, timeToNext: 0, nextEvent: eventlist[2], nextPublicEvent: null, @@ -382,12 +342,6 @@ describe('test that roll behaviour with overlapping times', () => { publicIndex: 1, nextIndex: 2, publicNextIndex: null, - timers: { - _startedAt: eventlist[1].timeStart, - _finishAt: eventlist[1].timeEnd, - current: 5, - duration: eventlist[1].timeEnd - eventlist[1].timeStart, - }, timeToNext: -5, nextEvent: eventlist[2], nextPublicEvent: null, @@ -407,12 +361,6 @@ describe('test that roll behaviour with overlapping times', () => { publicIndex: 1, nextIndex: null, publicNextIndex: null, - timers: { - _startedAt: eventlist[2].timeStart, - _finishAt: eventlist[2].timeEnd, - current: 10, - duration: eventlist[2].timeEnd - eventlist[2].timeStart, - }, timeToNext: null, nextEvent: null, nextPublicEvent: null, @@ -432,12 +380,6 @@ describe('test that roll behaviour with overlapping times', () => { publicIndex: 1, nextIndex: null, publicNextIndex: null, - timers: { - _startedAt: eventlist[2].timeStart, - _finishAt: eventlist[2].timeEnd, - current: 5, - duration: eventlist[2].timeEnd - eventlist[2].timeStart, - }, timeToNext: null, nextEvent: null, nextPublicEvent: null, @@ -468,12 +410,6 @@ describe('test that roll behaviour multi day event edge cases', () => { publicIndex: null, nextIndex: null, publicNextIndex: null, - timers: { - _startedAt: eventlist[0].timeStart, - _finishAt: eventlist[0].timeEnd, - current: eventlist[0].timeEnd + DAY_TO_MS - now, - duration: DAY_TO_MS - eventlist[0].timeStart + eventlist[0].timeEnd, - }, timeToNext: null, nextEvent: null, nextPublicEvent: null, @@ -501,7 +437,6 @@ describe('test that roll behaviour multi day event edge cases', () => { publicIndex: null, nextIndex: 0, publicNextIndex: null, - timers: null, timeToNext: eventlist[0].timeStart - now, nextEvent: eventlist[0], nextPublicEvent: null, diff --git a/apps/server/src/services/rollUtils.ts b/apps/server/src/services/rollUtils.ts index f5b252f5c..ef2562898 100644 --- a/apps/server/src/services/rollUtils.ts +++ b/apps/server/src/services/rollUtils.ts @@ -44,7 +44,6 @@ export const getRollTimers = (rundown: OntimeEvent[], timeNow: number) => { let publicNextIndex: number | null = null; // index of next public event let timeToNext: number | null = null; // counter: time for next event let publicTimeToNext: number | null = null; // counter: time for next public event - let timers: Timer | null = null; const orderedEvents = sortArrayByProperty(rundown, 'timeStart'); const lastEvent = orderedEvents[orderedEvents.length - 1]; @@ -104,13 +103,6 @@ export const getRollTimers = (rundown: OntimeEvent[], timeNow: number) => { currentEvent = event; nowIndex = rundown.findIndex((rundownEvent) => rundownEvent.id === event.id); nowId = event.id; - - timers = { - _startedAt: event.timeStart, - _finishAt: event.timeEnd, - duration: normalEnd - event.timeStart, - current: normalEnd - timeNow, - }; nowFound = true; // it could also be public @@ -156,7 +148,6 @@ export const getRollTimers = (rundown: OntimeEvent[], timeNow: number) => { publicIndex, nextIndex, publicNextIndex, - timers, timeToNext, nextEvent, nextPublicEvent,