mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-16 04:43:35 +00:00
block end calculation (#1683)
This commit is contained in:
committed by
Carlos Valente
parent
e811a82be2
commit
e9dda817e5
@@ -771,11 +771,12 @@ function broadcastResult(_target: any, _propertyKey: string, descriptor: Propert
|
||||
!deepEqual(RuntimeService.previousState?.runtime, state.runtime);
|
||||
|
||||
/**
|
||||
* the currentBlock object has no ticking values so we only need to check for equality
|
||||
* the currentBlock object has the potential to tick on expected end
|
||||
* TODO: the value shows up one tick to late
|
||||
*/
|
||||
const shouldBlockUpdate =
|
||||
!deepEqual(RuntimeService?.previousState.blockNow, state.blockNow) ||
|
||||
!deepEqual(RuntimeService?.previousState.blockNext, state.blockNext);
|
||||
RuntimeService?.previousState.blockNext !== state.blockNext;
|
||||
|
||||
/**
|
||||
* Many other values are calculated based on the clock
|
||||
@@ -806,7 +807,7 @@ function broadcastResult(_target: any, _propertyKey: string, descriptor: Propert
|
||||
batch.add('blockNow', state.blockNow);
|
||||
batch.add('blockNext', state.blockNext);
|
||||
RuntimeService.previousState.blockNow = structuredClone(state.blockNow);
|
||||
RuntimeService.previousState.blockNext = structuredClone(state.blockNext);
|
||||
RuntimeService.previousState.blockNext = state.blockNext;
|
||||
}
|
||||
|
||||
if (hasImmediateChanges) {
|
||||
|
||||
@@ -1,12 +1,65 @@
|
||||
import { MaybeNumber, TimerPhase } from 'ontime-types';
|
||||
import { dayInMs, isPlaybackActive } from 'ontime-utils';
|
||||
import { isOntimeEvent, MaybeNumber, OntimeBlock, OntimeEvent, Rundown, TimerPhase } from 'ontime-types';
|
||||
import { calculateTimeUntilStart, dayInMs, isPlaybackActive } from 'ontime-utils';
|
||||
import type { RuntimeState } from '../stores/runtimeState.js';
|
||||
import { shouldCrashDev } from '../utils/development.js';
|
||||
|
||||
/**
|
||||
* handle events that span over midnight
|
||||
*/
|
||||
export const normaliseEndTime = (start: number, end: number) => (end < start ? end + dayInMs : end);
|
||||
|
||||
/**
|
||||
* Calculates the expected time of the group to end.
|
||||
* Should only be called if a block is running
|
||||
* TODO: take a look at how it handles relative offset mode
|
||||
*/
|
||||
export function getExpectedBlockFinish(state: RuntimeState, rundown: Rundown): MaybeNumber {
|
||||
const { blockNow, eventNow, timer, clock } = state;
|
||||
|
||||
if (blockNow === null) return null;
|
||||
// if the group doesn't have a start time there is no end time either
|
||||
if (blockNow.startedAt === null) return null;
|
||||
if (eventNow === null) return null;
|
||||
if (timer.current === null) return null;
|
||||
|
||||
const { entries } = rundown;
|
||||
const orderInBlock = (entries[blockNow.id] as OntimeBlock).entries;
|
||||
|
||||
const indexInBlock = orderInBlock.findIndex((id) => eventNow.id === id);
|
||||
shouldCrashDev(indexInBlock < 0, 'Running event is not in current block');
|
||||
|
||||
if (indexInBlock === orderInBlock.length - 1) return timer.expectedFinish;
|
||||
|
||||
let totalGap = 0;
|
||||
let isLinkedToLoaded = true;
|
||||
|
||||
for (let i = indexInBlock + 1; i < orderInBlock.length; i++) {
|
||||
const entry = entries[orderInBlock[i]];
|
||||
if (isOntimeEvent(entry)) {
|
||||
totalGap += entry.gap;
|
||||
isLinkedToLoaded = isLinkedToLoaded && entry.linkStart;
|
||||
}
|
||||
}
|
||||
const lastEntry = entries[orderInBlock.at(-1)!] as OntimeEvent;
|
||||
const { offsetMode, offset, plannedStart, actualStart } = state.runtime;
|
||||
|
||||
const timeUntilLastEvent = calculateTimeUntilStart({
|
||||
timeStart: lastEntry.timeStart,
|
||||
dayOffset: lastEntry.dayOffset,
|
||||
delay: lastEntry.delay,
|
||||
currentDay: eventNow.dayOffset,
|
||||
totalGap,
|
||||
isLinkedToLoaded,
|
||||
clock,
|
||||
offsetMode,
|
||||
offset,
|
||||
plannedStart,
|
||||
actualStart,
|
||||
});
|
||||
|
||||
return clock + timeUntilLastEvent + lastEntry.duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates expected finish time of a running timer
|
||||
* @param {RuntimeState} state runtime state
|
||||
|
||||
@@ -18,6 +18,7 @@ import { timeNow } from '../utils/time.js';
|
||||
import type { RestorePoint } from '../services/RestoreService.js';
|
||||
import {
|
||||
getCurrent,
|
||||
getExpectedBlockFinish,
|
||||
getExpectedEnd,
|
||||
getExpectedFinish,
|
||||
getRuntimeOffset,
|
||||
@@ -27,11 +28,12 @@ import { loadRoll, normaliseRollStart } from '../services/rollUtils.js';
|
||||
import { timerConfig } from '../setup/config.js';
|
||||
import { RundownMetadata } from '../api-data/rundown/rundown.types.js';
|
||||
import { getPlayableIndexFromTimedIndex } from '../api-data/rundown/rundown.utils.js';
|
||||
import { getCurrentRundown } from '../api-data/rundown/rundown.dao.js';
|
||||
|
||||
export type RuntimeState = {
|
||||
clock: number; // realtime clock
|
||||
blockNow: BlockState | null;
|
||||
blockNext: BlockState | null;
|
||||
blockNext: MaybeString;
|
||||
eventNow: PlayableEvent | null;
|
||||
eventNext: PlayableEvent | null;
|
||||
runtime: Runtime;
|
||||
@@ -90,6 +92,8 @@ export function clearEventData() {
|
||||
runtimeState.runtime.expectedEnd = null;
|
||||
runtimeState.runtime.selectedEventIndex = null;
|
||||
|
||||
if (runtimeState.blockNow) runtimeState.blockNow.expectedEnd = null;
|
||||
|
||||
runtimeState.timer.playback = Playback.Stop;
|
||||
runtimeState.clock = timeNow();
|
||||
runtimeState.timer = { ...runtimeStorePlaceholder.timer };
|
||||
@@ -509,6 +513,11 @@ export function update(): UpdateResult {
|
||||
runtimeState.timer.expectedFinish = getExpectedFinish(runtimeState);
|
||||
}
|
||||
|
||||
if (runtimeState.blockNow) {
|
||||
const expectedBlockFinish = getExpectedBlockFinish(runtimeState, getCurrentRundown());
|
||||
runtimeState.blockNow.expectedEnd = expectedBlockFinish;
|
||||
}
|
||||
|
||||
return { hasTimerFinished: finishedNow, hasSecondaryTimerFinished: false };
|
||||
|
||||
function updateIfIdle() {
|
||||
@@ -690,7 +699,7 @@ export function loadBlock(rundown: Rundown, state = runtimeState) {
|
||||
let foundEventNow = false;
|
||||
for (const id of rundown.order) {
|
||||
if (foundEventNow && isOntimeBlock(rundown.entries[id])) {
|
||||
state.blockNext = { id, startedAt: null }; // the id is set here, the start time is set in other placed that handel starting events
|
||||
state.blockNext = id; // the id is set here, the start time is set in other placed that handel starting events
|
||||
break;
|
||||
}
|
||||
if (id === state.eventNow.id) {
|
||||
@@ -707,7 +716,7 @@ export function loadBlock(rundown: Rundown, state = runtimeState) {
|
||||
|
||||
//we went into a new block - and it is different from the one we might have come from
|
||||
if ((state.blockNow != null && state.blockNow.id != currentBlockId) || state.blockNow == null) {
|
||||
state.blockNow = { id: currentBlockId, startedAt: null }; // the id is set here, the start time is set in other placed that handel starting events
|
||||
state.blockNow = { id: currentBlockId, startedAt: null, expectedEnd: null }; // the id is set here, the start time is set in other placed that handel starting events
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user