From 26af459ac86787fb546901c8acc945b2c0335e1e Mon Sep 17 00:00:00 2001 From: Axel Boberg Date: Sat, 30 Mar 2024 08:21:54 +0100 Subject: [PATCH] Move the trigger of item scheduling to the main thread and add an indicator that an item is scheduled to the rundown Signed-off-by: Axel Boberg --- api/items.js | 4 +- lib/api/items.js | 41 ++++++++++++++++++- .../app/components/RundownItem/index.jsx | 22 +++++++--- plugins/scheduler/index.js | 1 + 4 files changed, 57 insertions(+), 11 deletions(-) diff --git a/api/items.js b/api/items.js index 5532982..4368745 100644 --- a/api/items.js +++ b/api/items.js @@ -225,9 +225,8 @@ async function playItem (id) { const delay = parseInt(clone?.data?.delay) if (delay && !Number.isNaN(delay)) { - commands.executeCommand('scheduler.delay', `play:${id}`, delay, 'items.playItem', clone) + commands.executeCommand('items.scheduleItem', clone, delay) } else { - commands.executeCommand('scheduler.abort', `play:${id}`) commands.executeCommand('items.playItem', clone) } } @@ -239,7 +238,6 @@ exports.playItem = playItem * @param { String } id */ async function stopItem (id) { - commands.executeCommand('scheduler.abort', `play:${id}`) commands.executeCommand('items.stopItem', id) } exports.stopItem = stopItem diff --git a/lib/api/items.js b/lib/api/items.js index f04fec5..e8a4c8f 100644 --- a/lib/api/items.js +++ b/lib/api/items.js @@ -17,15 +17,18 @@ function factory (api, workspace) { * @param { Item } item */ function playItem (item) { - if (!item.id) { + if (!item?.id) { throw new ApiError('Invalid item object', 'ERR_API_ITEMS_INVALID_ITEM') } + api.commands.executeCommand('scheduler.abort', undefined, `play:${item.id}`) + workspace.state.apply({ items: { [item.id]: { state: 'playing', - didStartPlayingAt: Date.now() + didStartPlayingAt: Date.now(), + willStartPlayingAt: Date.now() } } }) @@ -33,11 +36,44 @@ function factory (api, workspace) { api.events.emit('item.play', item) } + /** + * Schedule an item to be + * played after a certain delay + * + * @param { Item } itemId + * @param { Number } delay + */ + function scheduleItem (item, delay) { + if (!item?.id) { + throw new ApiError('Invalid item object', 'ERR_API_ITEMS_INVALID_ITEM') + } + + if (delay == null) { + playItem(item) + return + } + + workspace.state.apply({ + items: { + [item.id]: { + state: 'scheduled', + wasScheduledAt: Date.now(), + willStartPlayingAt: Date.now() + delay + } + } + }) + + api.commands.executeCommand('scheduler.delay', undefined, `play:${item.id}`, delay, 'items.playItem', item) + api.events.emit('item.schedule', item) + } + /** * Stop an item by its id * @param { String } id */ function stopItem (id) { + api.commands.executeCommand('scheduler.abort', undefined, `play:${id}`) + const item = getItem(id) if (!item) { return @@ -105,6 +141,7 @@ function factory (api, workspace) { api.commands.registerAsyncCommand('items.playItem', playItem) api.commands.registerAsyncCommand('items.stopItem', stopItem) + api.commands.registerAsyncCommand('items.scheduleItem', scheduleItem) api.commands.registerAsyncCommand('items.getItem', getItem) api.commands.registerAsyncCommand('items.deleteItems', deleteItems) diff --git a/plugins/rundown/app/components/RundownItem/index.jsx b/plugins/rundown/app/components/RundownItem/index.jsx index a934bb7..fe366b0 100644 --- a/plugins/rundown/app/components/RundownItem/index.jsx +++ b/plugins/rundown/app/components/RundownItem/index.jsx @@ -17,7 +17,7 @@ export function RundownItem ({ index, item }) { ] React.useEffect(() => { - if (item?.state !== 'playing') { + if (item?.state !== 'playing' && item?.state !== 'scheduled') { setProgress(0) return } @@ -29,14 +29,24 @@ export function RundownItem ({ index, item }) { return } - const progress = (Date.now() - item?.didStartPlayingAt) / item?.data?.duration + let progress = 0 + + switch (item?.state) { + case 'playing': + progress = (Date.now() - item?.didStartPlayingAt) / item?.data?.duration + break + case 'scheduled': + progress = (item?.willStartPlayingAt - Date.now()) / (item?.willStartPlayingAt - item?.wasScheduledAt) + break + } + if (Number.isNaN(progress)) { return } - setProgress(Math.min(progress, 1)) + setProgress(Math.max(Math.min(progress, 1), 0)) - if (progress >= 1) { + if (progress >= 1 && item?.state === 'playing') { return } window.requestAnimationFrame(loop) @@ -44,7 +54,7 @@ export function RundownItem ({ index, item }) { loop() return () => { shouldLoop = false } - }, [item?.state, item?.didStartPlayingAt]) + }, [item?.state, item?.didStartPlayingAt, item?.willStartPlayingAt]) return (
@@ -84,7 +94,7 @@ export function RundownItem ({ index, item }) {
{ - item?.state === 'playing' && + ['playing', 'scheduled'].includes(item?.state) &&
}
diff --git a/plugins/scheduler/index.js b/plugins/scheduler/index.js index 32f2f4e..eb44de4 100644 --- a/plugins/scheduler/index.js +++ b/plugins/scheduler/index.js @@ -54,6 +54,7 @@ exports.activate = async () => { bridge.commands.executeCommand(command, ...args) } } + events.set(id, event) })