mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-09 01:13:55 +00:00
chore: organise delay and rundown utils (#749)
This commit is contained in:
@@ -34,7 +34,7 @@ import { httpIntegration } from '../services/integration-service/HttpIntegration
|
||||
import { logger } from '../classes/Logger.js';
|
||||
import { deleteAllEvents, notifyChanges } from '../services/rundown-service/RundownService.js';
|
||||
import { runtimeCacheStore } from '../stores/cachingStore.js';
|
||||
import { delayedRundownCacheKey } from '../services/rundown-service/delayedRundown.utils.js';
|
||||
import { delayedRundownCacheKey } from '../services/rundown-service/rundownCache.js';
|
||||
import { integrationService } from '../services/integration-service/IntegrationService.js';
|
||||
import { getProjectFiles } from '../utils/getFileListFromFolder.js';
|
||||
import { configService } from '../services/ConfigService.js';
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
reorderEvent,
|
||||
swapEvents,
|
||||
} from '../services/rundown-service/RundownService.js';
|
||||
import { getDelayedRundown, getRundownCache } from '../services/rundown-service/delayedRundown.utils.js';
|
||||
import { getDelayedRundown, getRundownCache } from '../services/rundown-service/rundownCache.js';
|
||||
|
||||
// Create controller for GET request to '/events'
|
||||
// Returns -
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
import { isOntimeBlock, isOntimeDelay, isOntimeEvent, OntimeRundown } from 'ontime-types';
|
||||
|
||||
import { deleteAtIndex } from '../utils/arrayUtils.js';
|
||||
|
||||
export function _applyDelay(eventId: string, rundown: OntimeRundown): OntimeRundown {
|
||||
const delayIndex = rundown.findIndex((event) => event.id === eventId);
|
||||
const delayEvent = rundown.at(delayIndex);
|
||||
|
||||
if (!delayEvent) {
|
||||
throw new Error('Given event ID not found');
|
||||
}
|
||||
|
||||
if (!isOntimeDelay(delayEvent)) {
|
||||
throw new Error('Given event ID is not a delay');
|
||||
}
|
||||
|
||||
const updatedRundown = [...rundown];
|
||||
const delayValue = delayEvent.duration;
|
||||
|
||||
if (delayValue === 0 || delayIndex === rundown.length - 1) {
|
||||
// nothing to apply
|
||||
return updatedRundown;
|
||||
}
|
||||
|
||||
for (let i = delayIndex + 1; i < rundown.length; i++) {
|
||||
const currentEvent = updatedRundown[i];
|
||||
|
||||
if (isOntimeBlock(currentEvent)) {
|
||||
break;
|
||||
} else if (isOntimeEvent(currentEvent)) {
|
||||
currentEvent.timeStart = Math.max(0, currentEvent.timeStart + delayValue);
|
||||
currentEvent.timeEnd = Math.max(currentEvent.duration, currentEvent.timeEnd + delayValue);
|
||||
if (currentEvent.delay) {
|
||||
currentEvent.delay = currentEvent.delay - delayValue;
|
||||
}
|
||||
currentEvent.revision += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return deleteAtIndex(delayIndex, updatedRundown);
|
||||
}
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
import { generateId, getCueCandidate } from 'ontime-utils';
|
||||
import { DataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
import { block as blockDef, delay as delayDef } from '../../models/eventsDefinition.js';
|
||||
import { MAX_EVENTS } from '../../settings.js';
|
||||
import { EventLoader } from '../../classes/event-loader/EventLoader.js';
|
||||
import { sendRefetch } from '../../adapters/websocketAux.js';
|
||||
import { runtimeCacheStore } from '../../stores/cachingStore.js';
|
||||
@@ -24,7 +23,7 @@ import {
|
||||
cachedReorder,
|
||||
cachedSwap,
|
||||
delayedRundownCacheKey,
|
||||
} from './delayedRundown.utils.js';
|
||||
} from './rundownCache.js';
|
||||
import { logger } from '../../classes/Logger.js';
|
||||
import { createEvent } from '../../utils/parser.js';
|
||||
import { stateMutations } from '../../state.js';
|
||||
@@ -44,11 +43,6 @@ export function forceReset() {
|
||||
* @return {unknown[]}
|
||||
*/
|
||||
export async function addEvent(eventData: Partial<OntimeEvent> | Partial<OntimeDelay> | Partial<OntimeBlock>) {
|
||||
const numEvents = DataProvider.getRundownLength();
|
||||
if (numEvents > MAX_EVENTS) {
|
||||
throw new Error(`Reached limit number of ${MAX_EVENTS} events`);
|
||||
}
|
||||
|
||||
let newEvent: Partial<OntimeBaseEvent> = {};
|
||||
const id = generateId();
|
||||
|
||||
|
||||
+7
-7
@@ -1,5 +1,5 @@
|
||||
import { OntimeBlock, OntimeDelay, OntimeEvent, OntimeRundown, SupportedEvent } from 'ontime-types';
|
||||
import { _applyDelay } from '../delayUtils.js';
|
||||
import { applyDelay } from '../delayUtils.js';
|
||||
|
||||
describe('_applyDelay() ', () => {
|
||||
describe('in a rundown without the delay field, persisted rundown', () => {
|
||||
@@ -20,7 +20,7 @@ describe('_applyDelay() ', () => {
|
||||
{ id: '5', type: SupportedEvent.Event, timeStart: 0, timeEnd: 10, duration: 10, revision: 1 } as OntimeEvent,
|
||||
];
|
||||
|
||||
const updatedRundown = _applyDelay(delayId, testRundown);
|
||||
const updatedRundown = applyDelay(delayId, testRundown);
|
||||
expect(updatedRundown).toStrictEqual(expected);
|
||||
});
|
||||
it('applies negative delays', () => {
|
||||
@@ -40,7 +40,7 @@ describe('_applyDelay() ', () => {
|
||||
{ id: '5', type: SupportedEvent.Event, timeStart: 0, timeEnd: 10, duration: 10, revision: 1 } as OntimeEvent,
|
||||
];
|
||||
|
||||
const updatedRundown = _applyDelay(delayId, testRundown);
|
||||
const updatedRundown = applyDelay(delayId, testRundown);
|
||||
expect(updatedRundown).toStrictEqual(expected);
|
||||
});
|
||||
it('maintains constant duration', () => {
|
||||
@@ -56,7 +56,7 @@ describe('_applyDelay() ', () => {
|
||||
{ id: '3', type: SupportedEvent.Event, timeStart: 0, timeEnd: 20, duration: 20, revision: 2 } as OntimeEvent,
|
||||
];
|
||||
|
||||
const updatedRundown = _applyDelay(delayId, testRundown);
|
||||
const updatedRundown = applyDelay(delayId, testRundown);
|
||||
expect(updatedRundown).toStrictEqual(expected);
|
||||
});
|
||||
});
|
||||
@@ -126,7 +126,7 @@ describe('_applyDelay() ', () => {
|
||||
} as OntimeEvent,
|
||||
];
|
||||
|
||||
const updatedRundown = _applyDelay(delayId, testRundown);
|
||||
const updatedRundown = applyDelay(delayId, testRundown);
|
||||
expect(updatedRundown).toStrictEqual(expected);
|
||||
});
|
||||
it('applies negative delays', () => {
|
||||
@@ -194,7 +194,7 @@ describe('_applyDelay() ', () => {
|
||||
} as OntimeEvent,
|
||||
];
|
||||
|
||||
const updatedRundown = _applyDelay(delayId, testRundown);
|
||||
const updatedRundown = applyDelay(delayId, testRundown);
|
||||
expect(updatedRundown).toStrictEqual(expected);
|
||||
});
|
||||
it('maintains constant duration', () => {
|
||||
@@ -242,7 +242,7 @@ describe('_applyDelay() ', () => {
|
||||
} as OntimeEvent,
|
||||
];
|
||||
|
||||
const updatedRundown = _applyDelay(delayId, testRundown);
|
||||
const updatedRundown = applyDelay(delayId, testRundown);
|
||||
expect(updatedRundown).toStrictEqual(expected);
|
||||
});
|
||||
});
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { EndAction, OntimeEvent, OntimeRundown, SupportedEvent, TimerType } from 'ontime-types';
|
||||
|
||||
import { calculateRuntimeDelays, calculateRuntimeDelaysFrom, getDelayAt } from '../delayedRundown.utils.js';
|
||||
import { calculateRuntimeDelays, getDelayAt, calculateRuntimeDelaysFrom } from '../delayUtils.js';
|
||||
|
||||
describe('calculateRuntimeDelays', () => {
|
||||
it('calculates all delays in a given rundown', () => {
|
||||
@@ -0,0 +1,135 @@
|
||||
import { OntimeRundown, isOntimeDelay, isOntimeBlock, isOntimeEvent } from 'ontime-types';
|
||||
|
||||
import { deleteAtIndex } from '../../utils/arrayUtils.js';
|
||||
|
||||
/**
|
||||
* Calculates all delays in a given rundown
|
||||
* @param rundown
|
||||
*/
|
||||
export function calculateRuntimeDelays(rundown: OntimeRundown) {
|
||||
let accumulatedDelay = 0;
|
||||
const updatedRundown = [...rundown];
|
||||
|
||||
for (const [index, event] of updatedRundown.entries()) {
|
||||
if (isOntimeDelay(event)) {
|
||||
accumulatedDelay += event.duration;
|
||||
} else if (isOntimeBlock(event)) {
|
||||
accumulatedDelay = 0;
|
||||
} else if (isOntimeEvent(event)) {
|
||||
updatedRundown[index] = {
|
||||
...event,
|
||||
delay: accumulatedDelay,
|
||||
};
|
||||
}
|
||||
}
|
||||
return updatedRundown;
|
||||
}
|
||||
/**
|
||||
* Calculate delays in rundown from a given index
|
||||
* @param eventIndex
|
||||
* @param rundown
|
||||
*/
|
||||
export function calculateRuntimeDelaysFromIndex(eventIndex: number, rundown: OntimeRundown) {
|
||||
if (eventIndex === -1) {
|
||||
throw new Error('ID not found at index');
|
||||
}
|
||||
|
||||
let accumulatedDelay = getDelayAt(eventIndex, rundown);
|
||||
const updatedRundown = [...rundown];
|
||||
|
||||
for (let i = eventIndex; i < rundown.length; i++) {
|
||||
const event = rundown[i];
|
||||
if (isOntimeDelay(event)) {
|
||||
accumulatedDelay += event.duration;
|
||||
} else if (isOntimeBlock(event)) {
|
||||
if (i === eventIndex) {
|
||||
accumulatedDelay = 0;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if (isOntimeEvent(event)) {
|
||||
updatedRundown[i] = {
|
||||
...event,
|
||||
delay: accumulatedDelay,
|
||||
};
|
||||
}
|
||||
}
|
||||
return updatedRundown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate delays in rundown from an event with given id
|
||||
* @param eventId
|
||||
* @param rundown
|
||||
*/
|
||||
export function calculateRuntimeDelaysFrom(eventId: string, rundown: OntimeRundown) {
|
||||
const index = rundown.findIndex((event) => event.id === eventId);
|
||||
return calculateRuntimeDelaysFromIndex(index, rundown);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates delay to an event at a given index
|
||||
* @param eventIndex
|
||||
* @param rundown
|
||||
*/
|
||||
export function getDelayAt(eventIndex: number, rundown: OntimeRundown): number {
|
||||
if (eventIndex < 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// we need to check the event before
|
||||
const event = rundown[eventIndex - 1];
|
||||
|
||||
if (isOntimeDelay(event)) {
|
||||
return event.duration + getDelayAt(eventIndex - 1, rundown);
|
||||
} else if (isOntimeBlock(event)) {
|
||||
return 0;
|
||||
} else if (isOntimeEvent(event)) {
|
||||
return event.delay ?? 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies delay from given event ID, deletes the delay event after
|
||||
* @param eventId
|
||||
* @param rundown
|
||||
* @returns
|
||||
*/
|
||||
export function applyDelay(eventId: string, rundown: OntimeRundown): OntimeRundown {
|
||||
const delayIndex = rundown.findIndex((event) => event.id === eventId);
|
||||
const delayEvent = rundown.at(delayIndex);
|
||||
|
||||
if (!delayEvent) {
|
||||
throw new Error('Given event ID not found');
|
||||
}
|
||||
|
||||
if (!isOntimeDelay(delayEvent)) {
|
||||
throw new Error('Given event ID is not a delay');
|
||||
}
|
||||
|
||||
const updatedRundown = [...rundown];
|
||||
const delayValue = delayEvent.duration;
|
||||
|
||||
if (delayValue === 0 || delayIndex === rundown.length - 1) {
|
||||
// nothing to apply
|
||||
return updatedRundown;
|
||||
}
|
||||
|
||||
for (let i = delayIndex + 1; i < rundown.length; i++) {
|
||||
const currentEvent = updatedRundown[i];
|
||||
|
||||
if (isOntimeBlock(currentEvent)) {
|
||||
break;
|
||||
} else if (isOntimeEvent(currentEvent)) {
|
||||
currentEvent.timeStart = Math.max(0, currentEvent.timeStart + delayValue);
|
||||
currentEvent.timeEnd = Math.max(currentEvent.duration, currentEvent.timeEnd + delayValue);
|
||||
if (currentEvent.delay) {
|
||||
currentEvent.delay = currentEvent.delay - delayValue;
|
||||
}
|
||||
currentEvent.revision += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return deleteAtIndex(delayIndex, updatedRundown);
|
||||
}
|
||||
+3
-92
@@ -15,8 +15,8 @@ import { DataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
import { getCached, runtimeCacheStore } from '../../stores/cachingStore.js';
|
||||
import { isProduction } from '../../setup.js';
|
||||
import { deleteAtIndex, insertAtIndex, reorderArray } from '../../utils/arrayUtils.js';
|
||||
import { _applyDelay } from '../delayUtils.js';
|
||||
import { createPatch } from '../../utils/parser.js';
|
||||
import { applyDelay, calculateRuntimeDelays, calculateRuntimeDelaysFromIndex, getDelayAt } from './delayUtils.js';
|
||||
|
||||
/**
|
||||
* Keep incremental revision number of rundown for runtime
|
||||
@@ -275,10 +275,10 @@ export async function cachedSwap(fromEventId: string, toEventId: string) {
|
||||
export async function cachedApplyDelay(eventId: string) {
|
||||
// update persisted rundown
|
||||
const rundown: OntimeRundown = DataProvider.getRundown();
|
||||
const persistedRundown = _applyDelay(eventId, rundown);
|
||||
const persistedRundown = applyDelay(eventId, rundown);
|
||||
|
||||
const delayedRundown = getDelayedRundown();
|
||||
const cachedRundown = _applyDelay(eventId, delayedRundown);
|
||||
const cachedRundown = applyDelay(eventId, delayedRundown);
|
||||
|
||||
// update
|
||||
runtimeCacheStore.setCached(delayedRundownCacheKey, cachedRundown);
|
||||
@@ -286,92 +286,3 @@ export async function cachedApplyDelay(eventId: string) {
|
||||
|
||||
rundownRevision++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates all delays in a given rundown
|
||||
* @param rundown
|
||||
*/
|
||||
export function calculateRuntimeDelays(rundown: OntimeRundown) {
|
||||
let accumulatedDelay = 0;
|
||||
const updatedRundown = [...rundown];
|
||||
|
||||
for (const [index, event] of updatedRundown.entries()) {
|
||||
if (isOntimeDelay(event)) {
|
||||
accumulatedDelay += event.duration;
|
||||
} else if (isOntimeBlock(event)) {
|
||||
accumulatedDelay = 0;
|
||||
} else if (isOntimeEvent(event)) {
|
||||
updatedRundown[index] = {
|
||||
...event,
|
||||
delay: accumulatedDelay,
|
||||
};
|
||||
}
|
||||
}
|
||||
return updatedRundown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate delays in rundown from a given index
|
||||
* @param eventIndex
|
||||
* @param rundown
|
||||
*/
|
||||
export function calculateRuntimeDelaysFromIndex(eventIndex: number, rundown: OntimeRundown) {
|
||||
if (eventIndex === -1) {
|
||||
throw new Error('ID not found at index');
|
||||
}
|
||||
|
||||
let accumulatedDelay = getDelayAt(eventIndex, rundown);
|
||||
const updatedRundown = [...rundown];
|
||||
|
||||
for (let i = eventIndex; i < rundown.length; i++) {
|
||||
const event = rundown[i];
|
||||
if (isOntimeDelay(event)) {
|
||||
accumulatedDelay += event.duration;
|
||||
} else if (isOntimeBlock(event)) {
|
||||
if (i === eventIndex) {
|
||||
accumulatedDelay = 0;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if (isOntimeEvent(event)) {
|
||||
updatedRundown[i] = {
|
||||
...event,
|
||||
delay: accumulatedDelay,
|
||||
};
|
||||
}
|
||||
}
|
||||
return updatedRundown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate delays in rundown from an event with given id
|
||||
* @param eventId
|
||||
* @param rundown
|
||||
*/
|
||||
export function calculateRuntimeDelaysFrom(eventId: string, rundown: OntimeRundown) {
|
||||
const index = rundown.findIndex((event) => event.id === eventId);
|
||||
return calculateRuntimeDelaysFromIndex(index, rundown);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates delay to an event at a given index
|
||||
* @param eventIndex
|
||||
* @param rundown
|
||||
*/
|
||||
export function getDelayAt(eventIndex: number, rundown: OntimeRundown): number {
|
||||
if (eventIndex < 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// we need to check the event before
|
||||
const event = rundown[eventIndex - 1];
|
||||
|
||||
if (isOntimeDelay(event)) {
|
||||
return event.duration + getDelayAt(eventIndex - 1, rundown);
|
||||
} else if (isOntimeBlock(event)) {
|
||||
return 0;
|
||||
} else if (isOntimeEvent(event)) {
|
||||
return event.delay ?? 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export const MAX_EVENTS = 32768;
|
||||
@@ -22,7 +22,6 @@ import {
|
||||
import { block as blockDef, delay as delayDef } from '../models/eventsDefinition.js';
|
||||
import { dbModel } from '../models/dataModel.js';
|
||||
import { createEvent } from './parser.js';
|
||||
import { MAX_EVENTS } from '../settings.js';
|
||||
|
||||
/**
|
||||
* Parse events array of an entry
|
||||
@@ -38,12 +37,6 @@ export const parseRundown = (data: Partial<DatabaseModel>): OntimeRundown => {
|
||||
let eventIndex = 0;
|
||||
const ids = [];
|
||||
for (const event of data.rundown) {
|
||||
// cap number of events
|
||||
if (rundown.length >= MAX_EVENTS) {
|
||||
console.log(`ERROR: Reached limit number of ${MAX_EVENTS} events`);
|
||||
break;
|
||||
}
|
||||
|
||||
// double check unique ids
|
||||
if (ids.includes(event?.id)) {
|
||||
console.log('ERROR: ID collision on import, skipping');
|
||||
|
||||
Reference in New Issue
Block a user