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
+36 -13
View File
@@ -4,7 +4,16 @@
import fs from 'fs';
import xlsx from 'node-xlsx';
import { generateId, calculateDuration } from 'ontime-utils';
import { DatabaseModel, EventData, OntimeEvent, OntimeRundown, UserFields } from 'ontime-types';
import {
DatabaseModel,
EndAction,
EventData,
OntimeEvent,
OntimeRundown,
SupportedEvent,
TimerType,
UserFields,
} from 'ontime-types';
import { event as eventDef } from '../models/eventsDefinition.js';
import { dbModel } from '../models/dataModel.js';
import { deleteFile, makeString } from './parserUtils.js';
@@ -38,6 +47,7 @@ export const parseExcel = async (excelData) => {
let timeStartIndex: number | null = null;
let timeEndIndex: number | null = null;
let titleIndex: number | null = null;
let cueIndex: number | null = null;
let presenterIndex: number | null = null;
let subtitleIndex: number | null = null;
let isPublicIndex: number | null = null;
@@ -91,6 +101,8 @@ export const parseExcel = async (excelData) => {
event.timeEnd = parseExcelDate(column);
} else if (j === titleIndex) {
event.title = column;
} else if (j === cueIndex) {
event.cue = column;
} else if (j === presenterIndex) {
event.presenter = column;
} else if (j === subtitleIndex) {
@@ -102,9 +114,17 @@ export const parseExcel = async (excelData) => {
} else if (j === notesIndex) {
event.note = column;
} else if (j === endActionIndex) {
event.endAction = column;
if (column === '') {
event.endAction = EndAction.None;
} else {
event.endAction = column;
}
} else if (j === timerTypeIndex) {
event.timerType = column;
if (column === '') {
event.timerType = TimerType.CountDown;
} else {
event.timerType = column;
}
} else if (j === colourIndex) {
event.colour = column;
} else if (j === user0Index) {
@@ -130,6 +150,7 @@ export const parseExcel = async (excelData) => {
} else {
if (typeof column === 'string') {
const col = column.toLowerCase();
// look for keywords
// need to make sure it is a string first
switch (col) {
@@ -157,6 +178,10 @@ export const parseExcel = async (excelData) => {
case 'finish':
timeEndIndex = j;
break;
case 'cue':
case 'page':
cueIndex = j;
break;
case 'event title':
case 'title':
titleIndex = j;
@@ -243,7 +268,7 @@ export const parseExcel = async (excelData) => {
if (Object.keys(event).length > 0) {
// if any data was found, push to array
// take care of it in the next step
rundown.push({ ...event, type: 'event' });
rundown.push({ ...event, type: SupportedEvent.Event } as OntimeEvent);
}
});
return {
@@ -284,7 +309,6 @@ export const parseJson = async (jsonData, enforce = false): Promise<DatabaseMode
// Import user fields if any
returnData.userFields = parseUserFields(jsonData);
// Import OSC settings if any
// @ts-expect-error -- we are unable to type just yet
returnData.osc = parseOsc(jsonData, enforce);
// Import HTTP settings if any
// returnData.http = parseHttp(jsonData, enforce);
@@ -295,12 +319,15 @@ export const parseJson = async (jsonData, enforce = false): Promise<DatabaseMode
/**
* @description Enforces formatting for events
* @param {object} eventArgs - attributes of event
* @param cueFallback
* @returns {object|null} - formatted object or null in case is invalid
*/
export const validateEvent = (eventArgs) => {
export const validateEvent = (eventArgs: Partial<OntimeEvent>, cueFallback: string) => {
// ensure id is defined and unique
const id = eventArgs.id || generateId();
const cue = eventArgs.cue || cueFallback;
let event = null;
// return if object is empty
@@ -336,12 +363,9 @@ export const validateEvent = (eventArgs) => {
user7: makeString(e.user7, d.user7),
user8: makeString(e.user8, d.user8),
user9: makeString(e.user9, d.user9),
// deciding not to validate colour
// this adds flexibility to the user to write hex codes, rgb,
// but also colour names like blue and red
// CSS.supports is only available in frontend
colour: makeString(e.colour, d.colour),
id,
cue,
type: 'event',
};
}
@@ -357,7 +381,7 @@ type ResponseError = { error: true; message: string };
* @param {string} file - reference to file
* @return {object} - parse result message
*/
export const fileHandler = async (file): ResponseOK | ResponseError => {
export const fileHandler = async (file): Promise<ResponseOK | ResponseError> => {
let res: Partial<ResponseOK | ResponseError> = {};
// check which file type are we dealing with
@@ -376,8 +400,7 @@ export const fileHandler = async (file): ResponseOK | ResponseError => {
res.data.userFields = parseUserFields(dataFromExcel);
res.message = 'success';
} else {
const errorMessage = 'No sheet found named ontime or event schedule';
console.log(errorMessage);
const errorMessage = 'No sheet found named "ontime" or "event schedule"';
res = {
error: true,
message: errorMessage,