feat: event cue (#473)

* feat: parse cue

* refactor: get delay from backend

* feat: add cue to UI

* refactor: remove deprecated delay logic

* refactor: extract studio clock specific logic

* refactor: extract utilities

* refactor: fix issue with missing key

* style: prevent cue overflow

* style: prevent whitespace wrap

* feat: add support for cues in integrations
This commit is contained in:
Carlos Valente
2023-08-17 21:43:11 +02:00
committed by GitHub
parent 51c31adaf1
commit 657cc22b44
62 changed files with 1363 additions and 1290 deletions
@@ -62,6 +62,21 @@ export class PlaybackService {
return success;
}
/**
* starts first event matching given cue
* @param {string} cue
* @return {boolean} success
*/
static startByCue(cue: string): boolean {
const event = EventLoader.getEventWithCue(cue);
const success = PlaybackService.loadEvent(event);
if (success) {
logger.info(LogOrigin.Playback, `Loaded event with ID ${event.id}`);
PlaybackService.start();
}
return success;
}
/**
* loads event matching given ID
* @param {string} eventId
@@ -90,6 +105,20 @@ export class PlaybackService {
return success;
}
/**
* loads first event matching given cue
* @param {string} cue
* @return {boolean} success
*/
static loadByCue(cue: string): boolean {
const event = EventLoader.getEventWithCue(cue);
const success = PlaybackService.loadEvent(event);
if (success) {
logger.info(LogOrigin.Playback, `Loaded event with ID ${event.id}`);
}
return success;
}
/**
* Loads event before currently selected
*/
@@ -8,9 +8,9 @@ import {
Playback,
SupportedEvent,
} from 'ontime-types';
import { generateId } from 'ontime-utils';
import { generateId, getCueCandidate } from 'ontime-utils';
import { DataProvider } from '../../classes/data-provider/DataProvider.js';
import { block as blockDef, delay as delayDef, event as eventDef } from '../../models/eventsDefinition.js';
import { block as blockDef, delay as delayDef } from '../../models/eventsDefinition.js';
import { MAX_EVENTS } from '../../settings.js';
import { EventLoader, eventLoader } from '../../classes/event-loader/EventLoader.js';
import { eventTimer } from '../TimerService.js';
@@ -26,6 +26,7 @@ import {
delayedRundownCacheKey,
} from './delayedRundown.utils.js';
import { logger } from '../../classes/Logger.js';
import { validateEvent } from '../../utils/parser.js';
import { clock } from '../Clock.js';
/**
@@ -164,30 +165,30 @@ export async function addEvent(eventData: Partial<OntimeEvent> | Partial<OntimeD
let newEvent: Partial<OntimeBaseEvent> = {};
const id = generateId();
// TODO: filter the parameters that exist in the event, use the parserUtils
switch (eventData.type) {
case SupportedEvent.Event:
newEvent = { ...eventDef, ...eventData, id };
break;
case SupportedEvent.Delay:
newEvent = { ...delayDef, ...eventData, id };
break;
case SupportedEvent.Block:
newEvent = { ...blockDef, ...eventData, id };
break;
}
let insertIndex = 0;
if (typeof newEvent?.after !== 'undefined') {
const index = DataProvider.getIndexOf(newEvent.after);
if (eventData?.after !== 'undefined') {
const index = DataProvider.getIndexOf(eventData.after);
if (index < 0) {
logger.warning(LogOrigin.Server, `Could not find event with id ${newEvent.after}`);
logger.warning(LogOrigin.Server, `Could not find event with id ${eventData.after}`);
} else {
insertIndex = index + 1;
}
delete newEvent.after;
}
switch (eventData.type) {
case SupportedEvent.Event: {
newEvent = validateEvent(eventData, getCueCandidate(DataProvider.getRundown(), eventData?.after)) as OntimeEvent;
break;
}
case SupportedEvent.Delay:
newEvent = { ...delayDef, duration: eventData.duration, id } as OntimeDelay;
break;
case SupportedEvent.Block:
newEvent = { ...blockDef, title: eventData.title, id } as OntimeBlock;
break;
}
delete eventData.after;
// modify rundown
await cachedAdd(insertIndex, newEvent as OntimeEvent | OntimeDelay | OntimeBlock);
@@ -204,6 +205,10 @@ export async function addEvent(eventData: Partial<OntimeEvent> | Partial<OntimeD
}
export async function editEvent(eventData: Partial<OntimeEvent> | Partial<OntimeBlock> | Partial<OntimeDelay>) {
if (eventData.type === SupportedEvent.Event && eventData?.cue === '') {
throw new Error(`Cue value invalid`);
}
const newEvent = await cachedEdit(eventData.id, eventData);
// notify timer service of changed events
@@ -1,4 +1,4 @@
import { EndAction, OntimeRundown, SupportedEvent, TimerType } from 'ontime-types';
import { EndAction, OntimeEvent, OntimeRundown, SupportedEvent, TimerType } from 'ontime-types';
import { calculateRuntimeDelays, calculateRuntimeDelaysFrom, getDelayAt } from '../delayedRundown.utils.js';
@@ -31,6 +31,7 @@ describe('calculateRuntimeDelays', () => {
type: SupportedEvent.Event,
revision: 0,
id: '659e1',
cue: '1',
},
{
duration: 600000,
@@ -64,6 +65,7 @@ describe('calculateRuntimeDelays', () => {
type: SupportedEvent.Event,
revision: 0,
id: '1c48f',
cue: '2',
},
{
duration: 1200000,
@@ -97,6 +99,7 @@ describe('calculateRuntimeDelays', () => {
type: SupportedEvent.Event,
revision: 0,
id: 'd48c2',
cue: '3',
},
{
title: '',
@@ -129,16 +132,17 @@ describe('calculateRuntimeDelays', () => {
type: SupportedEvent.Event,
revision: 0,
id: '2f185',
cue: '4',
},
];
const updatedRundown = calculateRuntimeDelays(rundown);
expect(rundown.length).toBe(updatedRundown.length);
expect(updatedRundown[0].delay).toBe(0);
expect(updatedRundown[2].delay).toBe(600000);
expect(updatedRundown[4].delay).toBe(600000 + 1200000);
expect(updatedRundown[6].delay).toBe(0);
expect((updatedRundown[0] as OntimeEvent).delay).toBe(0);
expect((updatedRundown[2] as OntimeEvent).delay).toBe(600000);
expect((updatedRundown[4] as OntimeEvent).delay).toBe(600000 + 1200000);
expect((updatedRundown[6] as OntimeEvent).delay).toBe(0);
});
});
@@ -171,6 +175,7 @@ describe('getDelayAt()', () => {
revision: 0,
id: '659e1',
delay: 0,
cue: '1',
},
{
duration: 600000,
@@ -205,6 +210,7 @@ describe('getDelayAt()', () => {
revision: 0,
id: '1c48f',
delay: 600000,
cue: '2',
},
{
duration: 1200000,
@@ -239,6 +245,7 @@ describe('getDelayAt()', () => {
revision: 0,
id: 'd48c2',
delay: 1800000,
cue: '3',
},
{
title: '',
@@ -272,6 +279,7 @@ describe('getDelayAt()', () => {
revision: 0,
id: '2f185',
delay: 0,
cue: '4',
},
];
@@ -331,6 +339,7 @@ describe('calculateRuntimeDelaysFrom()', () => {
revision: 0,
id: '659e1',
delay: 0,
cue: '1',
},
{
duration: 600000,
@@ -365,6 +374,7 @@ describe('calculateRuntimeDelaysFrom()', () => {
revision: 0,
id: '1c48f',
delay: 0,
cue: '2',
},
{
duration: 1200000,
@@ -399,6 +409,7 @@ describe('calculateRuntimeDelaysFrom()', () => {
revision: 0,
id: 'd48c2',
delay: 1800000,
cue: '3',
},
{
title: '',
@@ -432,14 +443,15 @@ describe('calculateRuntimeDelaysFrom()', () => {
revision: 0,
id: '2f185',
delay: 0,
cue: '4',
},
];
const updatedRundown = calculateRuntimeDelaysFrom('07986', delayedRundown);
// we only update from the 4th on
expect(updatedRundown[0].delay).toBe(0);
expect((updatedRundown[0] as OntimeEvent).delay).toBe(0);
// 1 + 3
expect(updatedRundown[4].delay).toBe(600000 + 1200000);
expect((updatedRundown[4] as OntimeEvent).delay).toBe(600000 + 1200000);
});
});