diff --git a/apps/server/src/api-data/db/__tests__/db.parser.test.ts b/apps/server/src/api-data/db/__tests__/db.parser.test.ts index eb58659b9..857133632 100644 --- a/apps/server/src/api-data/db/__tests__/db.parser.test.ts +++ b/apps/server/src/api-data/db/__tests__/db.parser.test.ts @@ -1,5 +1,7 @@ /* eslint-disable no-console -- we are mocking the console */ +import { SupportedEntry } from 'ontime-types'; + import { demoDb } from '../../../models/demoProject.js'; import { parseDatabaseModel } from '../db.parser.js'; @@ -22,9 +24,17 @@ describe('test parseDatabaseModel() with demo project (valid)', () => { const filteredDemoProject = structuredClone(demoDb); const { data } = parseDatabaseModel(filteredDemoProject); - it('has 17 events with 12 top level events', () => { - expect(data.rundowns.default.order.length).toBe(12); - expect(Object.keys(data.rundowns.default.entries).length).toBe(17); + it('has 14 entries, with 6 events and 4 top level groups', () => { + expect(data.rundowns.default.order.length).toBe(4); + expect(Object.keys(data.rundowns.default.entries).length).toBe(14); + let numEntries = 0; + data.rundowns.default.flatOrder.forEach((entryId) => { + const entry = data.rundowns.default.entries[entryId]; + if (entry.type === SupportedEntry.Event) { + numEntries++; + } + }); + expect(numEntries).toBe(6); }); it('is the same as the demo project since all data is valid', () => { @@ -32,7 +42,33 @@ describe('test parseDatabaseModel() with demo project (valid)', () => { delete filteredDemoProject.settings.version; // @ts-expect-error -- its ok delete data.settings.version; - expect(data).toMatchObject(filteredDemoProject); + + // remove time-related fields from the comparison + // these are not calculated in the parser + Object.values(filteredDemoProject.rundowns.default.entries).forEach((entry: any) => { + if (entry.type === SupportedEntry.Block) { + delete entry.timeStart; + delete entry.timeEnd; + delete entry.duration; + delete entry.isFirstLinked; + } + }); + Object.values(data.rundowns.default.entries).forEach((entry: any) => { + if (entry.type === SupportedEntry.Block) { + delete entry.timeStart; + delete entry.timeEnd; + delete entry.duration; + delete entry.isFirstLinked; + } + }); + + expect(data.automation).toMatchObject(filteredDemoProject.automation); + expect(data.customFields).toMatchObject(filteredDemoProject.customFields); + expect(data.project).toMatchObject(filteredDemoProject.project); + expect(data.rundowns).toMatchObject(filteredDemoProject.rundowns); + expect(data.settings).toMatchObject(filteredDemoProject.settings); + expect(data.urlPresets).toMatchObject(filteredDemoProject.urlPresets); + expect(data.viewSettings).toMatchObject(filteredDemoProject.viewSettings); }); }); diff --git a/apps/server/src/api-data/rundown/__tests__/rundown.dao.test.ts b/apps/server/src/api-data/rundown/__tests__/rundown.dao.test.ts index ee0864f42..c41a36194 100644 --- a/apps/server/src/api-data/rundown/__tests__/rundown.dao.test.ts +++ b/apps/server/src/api-data/rundown/__tests__/rundown.dao.test.ts @@ -97,12 +97,12 @@ describe('processRundown()', () => { it('generates metadata from given rundown', () => { const initResult = processRundown(demoDb.rundowns.default, demoDb.customFields); - expect(initResult.order.length).toBe(12); - expect(initResult.flatEntryOrder.length).toBe(17); - expect(initResult.timedEventOrder.length).toBe(14); - expect(initResult.playableEventOrder.length).toBe(14); - expect(initResult.firstStart).toBe(36000000); - expect(initResult.lastEnd).toBe(61800000); + expect(initResult.order.length).toBe(4); + expect(initResult.flatEntryOrder.length).toBe(14); + expect(initResult.timedEventOrder.length).toBe(6); + expect(initResult.playableEventOrder.length).toBe(6); + expect(initResult.firstStart).toBe(MILLIS_PER_HOUR * 10); + expect(initResult.lastEnd).toBe(MILLIS_PER_HOUR * 14); expect(initResult.totalDays).toBe(0); expect(initResult.totalDelay).toBe(0); }); diff --git a/apps/server/src/api-data/rundown/rundown.parser.ts b/apps/server/src/api-data/rundown/rundown.parser.ts index c04ea7b5c..af579e2ac 100644 --- a/apps/server/src/api-data/rundown/rundown.parser.ts +++ b/apps/server/src/api-data/rundown/rundown.parser.ts @@ -118,18 +118,22 @@ export function parseRundown( if (isOntimeEvent(nestedEvent)) { newNestedEvent = createEvent(nestedEvent, eventIndex); + // skip if event is invalid if (newNestedEvent == null) { emitError?.('Skipping event without payload'); continue; } + newNestedEvent.parent = event.id; cleanupCustomFields(newNestedEvent.custom, parsedCustomFields); eventIndex += 1; } else if (isOntimeDelay(nestedEvent)) { newNestedEvent = { ...delayDef, duration: nestedEvent.duration, id: nestedEventId }; + newNestedEvent.parent = event.id; } else if (isOntimeMilestone(nestedEvent)) { newNestedEvent = createMilestone({ ...nestedEvent, id: nestedEventId }); + newNestedEvent.parent = event.id; cleanupCustomFields(newNestedEvent.custom, parsedCustomFields); } diff --git a/apps/server/src/classes/data-provider/__tests__/DataProvider.utils.test.ts b/apps/server/src/classes/data-provider/__tests__/DataProvider.utils.test.ts index 3e7bebd85..301acda7c 100644 --- a/apps/server/src/classes/data-provider/__tests__/DataProvider.utils.test.ts +++ b/apps/server/src/classes/data-provider/__tests__/DataProvider.utils.test.ts @@ -54,10 +54,10 @@ describe('safeMerge', () => { expect(mergedData.project).toStrictEqual({ title: 'new title', - description: 'Turin 2022', - url: 'www.github.com/cpvalente/ontime', + description: demoDb.project.description, + url: demoDb.project.url, info: 'new backstage info', - logo: null, + logo: demoDb.project.logo, custom: [ { title: 'new custom title', diff --git a/apps/server/src/models/demoProject.ts b/apps/server/src/models/demoProject.ts index d65077794..3c45fa1ae 100644 --- a/apps/server/src/models/demoProject.ts +++ b/apps/server/src/models/demoProject.ts @@ -4,524 +4,311 @@ export const demoDb: DatabaseModel = { rundowns: { default: { id: 'default', - title: 'Eurovision Demo', - order: [ - 'block', - '01e85', - '1c420', - 'b7737', - 'd3a80', - '8276c', - '2340b', - 'cb90b', - '503c4', - '5e965', - 'bab4a', - 'd3eb1', - ], + title: 'Demo project', + order: ['e2163f', '7eaf99', 'f60403', '6b0edb'], flatOrder: [ - 'block', - '32d31', - '21cd2', - '0b371', - '3cd28', - 'e457f', - '01e85', - '1c420', - 'b7737', - 'd3a80', - '8276c', - '2340b', - 'cb90b', - '503c4', - '5e965', - 'bab4a', - 'd3eb1', + 'e2163f', + '7eaf99', + '9bf60f', + 'bf71a2', + 'c2697f', + 'fa593e', + 'a8b0b3', + 'f60403', + '0aaa7d', + '6b0edb', + '02afca', + '75ce86', + 'e10ed9', + '07df89', ], entries: { - block: { - type: SupportedEntry.Block, - entries: ['32d31', '21cd2', '0b371', '3cd28', 'e457f'], - id: 'block', - title: 'Test Block', - note: '', - targetDuration: null, - colour: 'hotpink', - revision: 0, - timeStart: null, - timeEnd: null, - duration: 0, - isFirstLinked: false, + e2163f: { + id: 'e2163f', + type: SupportedEntry.Milestone, + cue: 'Demo', + title: 'Clear all, or Create New Project to start fresh', + note: 'Go to Settings cog wheel top left of Editor, Project > Create', + colour: '#9d9d9d', custom: { - Song: 'Sekret', - Artist: 'Ronela Hajati', + Custom_Field: + 'Create Custom Fields to store specific text information or images.\n\nGo to Settings > Project data > Custom fields', + Images: 'https://www.getontime.no/images/icons/ontime-logo.png', }, + parent: null, + revision: 0, }, - '32d31': { - type: SupportedEntry.Event, - flag: false, - id: '32d31', - cue: 'SF1.01', - title: 'Albania', - note: 'SF1.01', - endAction: EndAction.None, - timerType: TimerType.CountDown, - countToEnd: false, - linkStart: false, - timeStrategy: TimeStrategy.LockEnd, + '7eaf99': { + id: '7eaf99', + type: SupportedEntry.Block, + title: 'Morning Sessions', + note: '', + entries: ['9bf60f', 'bf71a2', 'c2697f', 'fa593e', 'a8b0b3'], + targetDuration: null, + colour: '#339E4E', + custom: {}, + revision: 0, timeStart: 36000000, - timeEnd: 37200000, - duration: 1200000, - skip: false, - colour: '', - parent: null, - revision: 0, - delay: 0, - dayOffset: 0, - gap: 0, - timeWarning: 500000, - timeDanger: 100000, - triggers: [], - custom: { - Song: 'Sekret', - Artist: 'Ronela Hajati', - }, - }, - '21cd2': { - type: SupportedEntry.Event, - flag: false, - id: '21cd2', - cue: 'SF1.02', - title: 'Latvia', - note: 'SF1.02', - endAction: EndAction.None, - timerType: TimerType.CountDown, - countToEnd: false, - linkStart: false, - timeStrategy: TimeStrategy.LockEnd, - timeStart: 37500000, - timeEnd: 38700000, - duration: 1200000, - skip: false, - colour: '', - parent: null, - revision: 0, - delay: 0, - dayOffset: 0, - gap: 0, - timeWarning: 500000, - timeDanger: 100000, - triggers: [], - custom: { - Song: 'Eat Your Salad', - Artist: 'Citi Zeni', - }, - }, - '0b371': { - type: SupportedEntry.Event, - flag: false, - id: '0b371', - cue: 'SF1.03', - title: 'Lithuania', - note: 'SF1.03', - endAction: EndAction.None, - timerType: TimerType.CountDown, - countToEnd: false, - linkStart: false, - timeStrategy: TimeStrategy.LockEnd, - timeStart: 39000000, - timeEnd: 40200000, - duration: 1200000, - skip: false, - colour: '', - parent: null, - revision: 0, - delay: 0, - dayOffset: 0, - gap: 0, - timeWarning: 500000, - timeDanger: 100000, - triggers: [], - custom: { - Song: 'Sentimentai', - Artist: 'Monika Liu', - }, - }, - '3cd28': { - type: SupportedEntry.Event, - flag: false, - id: '3cd28', - cue: 'SF1.04', - title: 'Switzerland', - note: 'SF1.04', - endAction: EndAction.None, - timerType: TimerType.CountDown, - countToEnd: false, - linkStart: false, - timeStrategy: TimeStrategy.LockEnd, - timeStart: 40500000, - timeEnd: 41700000, - duration: 1200000, - skip: false, - colour: '', - parent: null, - revision: 0, - delay: 0, - dayOffset: 0, - gap: 0, - timeWarning: 500000, - timeDanger: 100000, - triggers: [], - custom: { - Song: 'Boys Do Cry', - Artist: 'Marius Bear', - }, - }, - e457f: { - type: SupportedEntry.Event, - flag: false, - id: 'e457f', - cue: 'SF1.05', - title: 'Slovenia', - note: 'SF1.05', - endAction: EndAction.None, - timerType: TimerType.CountDown, - countToEnd: false, - linkStart: false, - timeStrategy: TimeStrategy.LockEnd, - timeStart: 42000000, timeEnd: 43200000, - duration: 1200000, - skip: false, - colour: '', - parent: null, - revision: 0, - delay: 0, - dayOffset: 0, - gap: 0, - timeWarning: 500000, - timeDanger: 100000, - triggers: [], - custom: { - Song: 'Disko', - Artist: 'LPS', - }, - }, - /// <----- BLOCK - '01e85': { - // TODO: this should be a marker type - type: SupportedEntry.Block, - id: '01e85', - title: 'Lunch break', - note: '', - colour: '', - entries: [], - targetDuration: null, - custom: {}, - revision: 0, - timeStart: null, - timeEnd: null, - duration: 0, + duration: 7200000, isFirstLinked: false, }, - '1c420': { + '9bf60f': { + id: '9bf60f', type: SupportedEntry.Event, flag: false, - id: '1c420', - cue: 'SF1.06', - title: 'Ukraine', - note: 'SF1.06', + title: 'Pre-show Countdown', + timeStart: 36000000, + timeEnd: 39600000, + duration: 3600000, + timeStrategy: TimeStrategy.LockEnd, + linkStart: false, endAction: EndAction.None, timerType: TimerType.CountDown, countToEnd: false, - linkStart: false, - timeStrategy: TimeStrategy.LockEnd, - timeStart: 47100000, - timeEnd: 48300000, - duration: 1200000, skip: false, - colour: '', - parent: null, - revision: 0, + note: 'Music plays, holding slide on screens', + colour: '#77C785', delay: 0, dayOffset: 0, gap: 0, - timeWarning: 500000, - timeDanger: 100000, - triggers: [], + cue: '1', + parent: '7eaf99', + revision: 0, + timeWarning: 600000, + timeDanger: 300000, custom: { - Song: 'Stefania', - Artist: 'Kalush Orchestra', + Custom_Field: 'Put additional info here', }, + triggers: [], }, - b7737: { + bf71a2: { + id: 'bf71a2', + type: SupportedEntry.Milestone, + cue: 'Standby', + title: '10:45 - Presenters ready side stage', + note: '', + colour: '#A790F5', + revision: 0, + custom: {}, + parent: '7eaf99', + }, + c2697f: { + id: 'c2697f', type: SupportedEntry.Event, flag: false, - id: 'b7737', - cue: 'SF1.07', - title: 'Bulgaria', - note: 'SF1.07', + title: 'Welcome', + timeStart: 39600000, + timeEnd: 40200000, + duration: 600000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: true, endAction: EndAction.None, timerType: TimerType.CountDown, countToEnd: false, - linkStart: false, - timeStrategy: TimeStrategy.LockEnd, - timeStart: 48600000, + skip: false, + note: 'Emma Thompson', + colour: '#FFCC78', + delay: 0, + dayOffset: 0, + gap: 0, + cue: '1.1', + parent: '7eaf99', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + triggers: [], + }, + fa593e: { + id: 'fa593e', + type: SupportedEntry.Event, + flag: true, + title: 'Session 1', + timeStart: 40200000, + timeEnd: 43200000, + duration: 3000000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: true, + endAction: EndAction.None, + timerType: TimerType.CountDown, + countToEnd: false, + skip: false, + note: 'Liam Carter, Sophia Patel + PowerPoint', + colour: '#77C785', + delay: 0, + dayOffset: 0, + gap: 0, + cue: '1.2', + parent: '7eaf99', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + triggers: [], + }, + a8b0b3: { + id: 'a8b0b3', + type: SupportedEntry.Milestone, + cue: 'House', + title: '11:30 - House staff setup lunch in lobby', + note: '', + colour: '#A790F5', + revision: 0, + custom: {}, + parent: '7eaf99', + }, + f60403: { + id: 'f60403', + type: SupportedEntry.Block, + title: 'Lunch', + note: '', + entries: ['0aaa7d'], + targetDuration: null, + colour: '#3E75E8', + custom: {}, + revision: 0, + timeStart: 43200000, + timeEnd: 46800000, + duration: 3600000, + isFirstLinked: true, + }, + '0aaa7d': { + id: '0aaa7d', + type: SupportedEntry.Event, + flag: false, + title: 'Lunch / Countdown to next session', + timeStart: 43200000, + timeEnd: 46800000, + duration: 3600000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: true, + endAction: EndAction.None, + timerType: TimerType.CountDown, + countToEnd: false, + skip: false, + note: 'Buffet in lobby\nMusic plays, holding slide on screens', + colour: '#779BE7', + delay: 0, + dayOffset: 0, + gap: 0, + cue: '2.1', + parent: 'f60403', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, + triggers: [], + }, + '6b0edb': { + id: '6b0edb', + type: SupportedEntry.Block, + title: 'Afternoon Sessions', + note: '', + entries: ['02afca', '75ce86', 'e10ed9', '07df89'], + targetDuration: null, + colour: '#339E4E', + custom: {}, + revision: 0, + timeStart: 46800000, + timeEnd: 50400000, + duration: 3600000, + isFirstLinked: true, + }, + '02afca': { + id: '02afca', + type: SupportedEntry.Milestone, + cue: 'Standby', + title: '12:45 - Presenters ready side stage', + note: '', + colour: '#A790F5', + revision: 0, + custom: {}, + parent: '6b0edb', + }, + '75ce86': { + id: '75ce86', + type: SupportedEntry.Event, + flag: false, + title: 'Session 2', + timeStart: 46800000, timeEnd: 49800000, - duration: 1200000, - skip: false, - colour: '', - parent: null, - revision: 0, - delay: 0, - dayOffset: 0, - gap: 0, - timeWarning: 500000, - timeDanger: 100000, - triggers: [], - custom: { - Song: 'Intention', - Artist: 'Intelligent Music Project', - }, - }, - d3a80: { - type: SupportedEntry.Event, - flag: false, - id: 'd3a80', - cue: 'SF1.08', - title: 'Netherlands', - note: 'SF1.08', + duration: 3000000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: true, endAction: EndAction.None, timerType: TimerType.CountDown, countToEnd: false, - linkStart: false, - timeStrategy: TimeStrategy.LockEnd, - timeStart: 50100000, - timeEnd: 51300000, - duration: 1200000, skip: false, - colour: '', - parent: null, - revision: 0, + note: 'Ethan Brooks + PowerPoint + Video playback', + colour: '#77C785', delay: 0, dayOffset: 0, gap: 0, - timeWarning: 500000, - timeDanger: 100000, - triggers: [], - custom: { - Song: 'De Diepte', - Artist: 'S10', - }, - }, - '8276c': { - type: SupportedEntry.Event, - flag: false, - id: '8276c', - cue: 'SF1.09', - title: 'Moldova', - note: 'SF1.09', - endAction: EndAction.None, - timerType: TimerType.CountDown, - countToEnd: false, - linkStart: false, - timeStrategy: TimeStrategy.LockEnd, - timeStart: 51600000, - timeEnd: 52800000, - duration: 1200000, - skip: false, - colour: '', - parent: null, + cue: '3.1', + parent: '6b0edb', revision: 0, - delay: 0, - dayOffset: 0, - gap: 0, - timeWarning: 500000, - timeDanger: 100000, - triggers: [], - custom: { - Song: 'Trenuletul', - Artist: 'Zdob si Zdub', - }, - }, - '2340b': { - type: SupportedEntry.Event, - flag: false, - id: '2340b', - cue: 'SF1.10', - title: 'Portugal', - note: 'SF1.10', - endAction: EndAction.None, - timerType: TimerType.CountDown, - countToEnd: false, - linkStart: false, - timeStrategy: TimeStrategy.LockEnd, - timeStart: 53100000, - timeEnd: 54300000, - duration: 1200000, - skip: false, - colour: '', - parent: null, - revision: 0, - delay: 0, - dayOffset: 0, - gap: 0, - timeWarning: 500000, - timeDanger: 100000, - triggers: [], - custom: { - Song: 'Saudade Saudade', - Artist: 'Maro', - }, - }, - /// <----- BLOCK - cb90b: { - // TODO: This should be a marker type - type: SupportedEntry.Block, - id: 'cb90b', - title: 'Afternoon break', - note: '', - colour: '', - entries: [], - targetDuration: null, + timeWarning: 120000, + timeDanger: 60000, custom: {}, - revision: 0, - timeStart: null, - timeEnd: null, - duration: 0, - isFirstLinked: false, + triggers: [], }, - '503c4': { + e10ed9: { + id: 'e10ed9', type: SupportedEntry.Event, flag: false, - id: '503c4', - cue: 'SF1.11', - title: 'Croatia', - note: 'SF1.11', + title: 'Wrap up', + timeStart: 49800000, + timeEnd: 50400000, + duration: 600000, + timeStrategy: TimeStrategy.LockDuration, + linkStart: false, endAction: EndAction.None, timerType: TimerType.CountDown, countToEnd: false, - linkStart: false, - timeStrategy: TimeStrategy.LockEnd, - timeStart: 56100000, - timeEnd: 57300000, - duration: 1200000, skip: false, - colour: '', - parent: null, - revision: 0, + note: 'Lucas Bennett', + colour: '#FFCC78', delay: 0, dayOffset: 0, gap: 0, - timeWarning: 500000, - timeDanger: 100000, + cue: '3.2', + parent: '6b0edb', + revision: 0, + timeWarning: 120000, + timeDanger: 60000, + custom: {}, triggers: [], - custom: { - Song: 'Guilty Pleasure', - Artist: 'Mia Dimsic', - }, }, - '5e965': { - type: SupportedEntry.Event, - flag: false, - id: '5e965', - cue: 'SF1.12', - title: 'Denmark', - note: 'SF1.12', - endAction: EndAction.None, - timerType: TimerType.CountDown, - countToEnd: false, - linkStart: false, - timeStrategy: TimeStrategy.LockEnd, - timeStart: 57600000, - timeEnd: 58800000, - duration: 1200000, - skip: false, - colour: '', - parent: null, + '07df89': { + id: '07df89', + type: SupportedEntry.Milestone, + cue: 'Strike', + title: '14:00 - AV & Room strike', + note: '', + colour: '#A790F5', revision: 0, - delay: 0, - dayOffset: 0, - gap: 0, - timeWarning: 500000, - timeDanger: 100000, - triggers: [], - custom: { - Song: 'The Show', - Artist: 'Reddi', - }, - }, - bab4a: { - type: SupportedEntry.Event, - flag: false, - id: 'bab4a', - cue: 'SF1.13', - title: 'Austria', - note: 'SF1.13', - endAction: EndAction.None, - timerType: TimerType.CountDown, - countToEnd: false, - linkStart: false, - timeStrategy: TimeStrategy.LockEnd, - timeStart: 59100000, - timeEnd: 60300000, - duration: 1200000, - skip: false, - colour: '', - parent: null, - revision: 0, - delay: 0, - dayOffset: 0, - gap: 0, - timeWarning: 500000, - timeDanger: 100000, - triggers: [], - custom: { - Song: 'Halo', - Artist: 'LUM!X & Pia Maria', - }, - }, - d3eb1: { - type: SupportedEntry.Event, - flag: false, - id: 'd3eb1', - cue: 'SF1.14', - title: 'Greece', - note: 'SF1.14', - endAction: EndAction.None, - timerType: TimerType.CountDown, - countToEnd: false, - linkStart: false, - timeStrategy: TimeStrategy.LockEnd, - timeStart: 60600000, - timeEnd: 61800000, - duration: 1200000, - skip: false, - colour: '', - parent: null, - revision: 0, - delay: 0, - dayOffset: 0, - gap: 0, - timeWarning: 500000, - timeDanger: 100000, - triggers: [], - custom: { - Song: 'Die Together', - Artist: 'Amanda Tenfjord', - }, + custom: {}, + parent: '6b0edb', }, }, revision: 0, }, }, project: { - title: 'Eurovision Song Contest', - description: 'Turin 2022', - url: 'www.github.com/cpvalente/ontime', - info: 'Rehearsal Schedule - Turin 2022\nAll performers to wear full costumes for 1st rehearsal', - logo: null, - custom: [], + title: 'Ontime Demo Project', + description: 'Demo Project to get you started', + url: 'https://docs.getontime.no/', + info: 'Use Project info to share information to various Ontime views.\nie. Venue info, wifi, staff details, etc.', + logo: 'ontime-logo.png', + custom: [ + { + title: 'Custom data', + value: + 'Add additional, custom data fields to the project along with optional links to images. \nThe image will be rendered in the views', + url: '', + }, + ], }, settings: { version: '-', @@ -537,37 +324,30 @@ export const demoDb: DatabaseModel = { overrideStyles: false, warningColor: '#ffa528', }, - customFields: { - Song: { - label: 'Song', - type: 'text', - colour: '#339E4E', - }, - Artist: { - label: 'Artist', - type: 'text', - colour: '#3E75E8', - }, - }, urlPresets: [ - { - enabled: true, - alias: 'clock', - target: 'timer', - search: - 'showLeadingZeros=true&timerType=clock&hideClock=true&hideCards=true&hideProgress=true&hideMessage=true&hideSecondary=true&hideLogo=true', - }, { enabled: true, alias: 'minimal', target: 'timer', search: - 'showLeadingZeros=true&hideClock=true&hideCards=true&hideProgress=true&hideMessage=true&hideSecondary=true&hideLogo=true', + 'hideclock=true&hidecards=true&hideprogress=true&hidemessage=true&hidesecondary=true&hidelogo=true&font=arial+black&keycolour=00ff00&textcolour=ffffff', }, ], + customFields: { + Custom_Field: { + type: 'text', + colour: '#3E75E8', + label: 'Custom Field', + }, + Images: { + type: 'image', + colour: '#ED3333', + label: 'Images', + }, + }, automation: { enabledAutomations: false, - enabledOscIn: true, + enabledOscIn: false, oscPortIn: 8888, triggers: [], automations: {},