diff --git a/client/src/App.css b/client/src/App.css index b28937f73..27fa5fcf3 100644 --- a/client/src/App.css +++ b/client/src/App.css @@ -7,6 +7,6 @@ body, html, .App { margin: 0px auto; - overflow: hidden; + overflow: clip; height: 100vh; } diff --git a/client/src/app/context/collapseAtom.js b/client/src/app/context/collapseAtom.js index 57ee2a9e4..ed6b63bc3 100644 --- a/client/src/app/context/collapseAtom.js +++ b/client/src/app/context/collapseAtom.js @@ -58,12 +58,3 @@ export const BatchOperation = atom(null, (get, set, payload) => { localStorage.setItem(PATH, JSON.stringify(options)); }); - -// change collapsed in all items -export const setAll = async (items, isCollapsed) => { - // clear storage - localStorage.removeItem(PATH); - - // call batch - BatchOperation({ items: items, isCollapsed: isCollapsed }); -}; diff --git a/client/src/app/hooks/useFetch.js b/client/src/app/hooks/useFetch.js index 3ddbdeaba..eceaf10d8 100644 --- a/client/src/app/hooks/useFetch.js +++ b/client/src/app/hooks/useFetch.js @@ -5,6 +5,7 @@ export const useFetch = (namespace, fn) => { const { data, status, isError, refetch } = useQuery(namespace, fn, { refetchInterval: refetchIntervalMs, cacheTime: Infinity, + notifyOnChangeProps: 'tracked', }); return { data, status, isError, refetch }; diff --git a/client/src/common/components/buttons/LockIconBtn.jsx b/client/src/common/components/buttons/LockIconBtn.jsx index d52030fd1..c499594d0 100644 --- a/client/src/common/components/buttons/LockIconBtn.jsx +++ b/client/src/common/components/buttons/LockIconBtn.jsx @@ -10,8 +10,9 @@ export default function LockIconBtn(props) { ref={ref} size={props.size || 'xs'} icon={} - colorScheme='pink' - color={'pink.300'} + color={active ? 'pink.100' : 'pink.300'} + borderColor={active ? undefined : 'pink.300'} + backgroundColor={active ? 'pink.300' : undefined} variant={active ? 'solid' : 'outline'} onClick={clickhandler} _focus={{ boxShadow: 'none' }} diff --git a/client/src/common/components/buttons/RollIconBtn.jsx b/client/src/common/components/buttons/RollIconBtn.jsx index f34b935c2..079e76f55 100644 --- a/client/src/common/components/buttons/RollIconBtn.jsx +++ b/client/src/common/components/buttons/RollIconBtn.jsx @@ -12,7 +12,6 @@ export default function RollIconBtn(props) { width={120} _focus={{ boxShadow: 'none' }} {...rest} - disabled /> ); } diff --git a/client/src/common/components/views/Paginator.jsx b/client/src/common/components/views/Paginator.jsx index 540fddf4f..9fcb89762 100644 --- a/client/src/common/components/views/Paginator.jsx +++ b/client/src/common/components/views/Paginator.jsx @@ -6,7 +6,7 @@ import { useInterval } from 'app/hooks/useInterval'; export default function Paginator(props) { const { events, selectedId } = props; const LIMIT_PER_PAGE = props.limit || 8; - const SCROLL_TIME = props.time * 1000 || 5000; + const SCROLL_TIME = props.time * 1000 || 10000; const SCROLL_PAST = false; const [numEvents, setNumEvents] = useState(0); const [page, setPage] = useState([]); diff --git a/client/src/common/input/EditableText.jsx b/client/src/common/input/EditableText.jsx index 73739d6c2..f41d8ad0a 100644 --- a/client/src/common/input/EditableText.jsx +++ b/client/src/common/input/EditableText.jsx @@ -33,9 +33,9 @@ export default function EditableText(props) { > - + ); diff --git a/client/src/common/input/EditableTimer.jsx b/client/src/common/input/EditableTimer.jsx index 2c771dbbf..2c39dd6d8 100644 --- a/client/src/common/input/EditableTimer.jsx +++ b/client/src/common/input/EditableTimer.jsx @@ -34,12 +34,12 @@ export default function EditableTimer(props) { if (value === '') return false; // Time now and time submitedVal - const original = stringFromMillis(time, false); + const original = stringFromMillis(time + delay, false); // check if time is different from before if (value === original) return false; - // conver to millis object + // convert to millis object const millis = timeStringToMillis(value, timeFormat); // validate with parent @@ -51,14 +51,8 @@ export default function EditableTimer(props) { return true; }; - const showOriginal = () => { - setValue(stringFromMillis(time, false)); - }; - return ( showOriginal} - onEdit={() => showOriginal} onChange={(v) => setValue(v)} onSubmit={(v) => validateValue(v)} value={value} diff --git a/client/src/features/control/PlaybackButtons.jsx b/client/src/features/control/PlaybackButtons.jsx index 4b46ab07b..8958bba51 100644 --- a/client/src/features/control/PlaybackButtons.jsx +++ b/client/src/features/control/PlaybackButtons.jsx @@ -41,10 +41,7 @@ const Transport = ({ selectedId, playbackControl }) => {
playbackControl('previous')} /> playbackControl('next')} /> - playbackControl('unload')} - disabled={!selectedId} - /> + playbackControl('unload')} /> playbackControl('reload')} disabled={!selectedId} diff --git a/client/src/features/control/PlaybackControl.jsx b/client/src/features/control/PlaybackControl.jsx index d5881f9a2..af1201774 100644 --- a/client/src/features/control/PlaybackControl.jsx +++ b/client/src/features/control/PlaybackControl.jsx @@ -90,6 +90,7 @@ export default function PlaybackControl() {
socket.emit('increment-timer', amount)} /> { return ( prevProps.timer.running === nextProps.timer.running && prevProps.timer.expectedFinish === nextProps.timer.expectedFinish && - prevProps.timer.startedAt === nextProps.timer.startedAt + prevProps.timer.startedAt === nextProps.timer.startedAt && + prevProps.playback === nextProps.playback ); }; -const PlaybackTimer = ({ timer, handleIncrement }) => { +const PlaybackTimer = (props) => { + const { timer, playback, handleIncrement } = props; const started = stringFromMillis(timer.startedAt, true); const finish = stringFromMillis(timer.expectedFinish, true); const isNegative = timer.running < 0; const isDelayed = false; - const isRolling = false; + const isRolling = playback === 'roll'; const incrementProps = { size: 'sm', @@ -31,7 +33,7 @@ const PlaybackTimer = ({ timer, handleIncrement }) => { <>
-
+
@@ -49,16 +51,32 @@ const PlaybackTimer = ({ timer, handleIncrement }) => { {finish}
- - - -
diff --git a/client/src/features/editors/Editor.module.css b/client/src/features/editors/Editor.module.css index d29ab4a52..d335b7aaa 100644 --- a/client/src/features/editors/Editor.module.css +++ b/client/src/features/editors/Editor.module.css @@ -18,11 +18,12 @@ /* 2/3 window, hide previews */ @media (max-width: 1250px) and (min-height: 700px) { .mainContainer { + height: 100%; grid-template-rows: 1fr 1fr; grid-template-columns: 48em 1fr 1fr; - grid-template-areas: + /* grid-template-areas: 'even play sett' - 'even mess sett'; + 'even mess sett'; */ } .info { @@ -40,6 +41,11 @@ 'play'; } + .messages, + .playback { + min-width: 31em; + } + .editor, .info, .settings { diff --git a/client/src/features/editors/list/ActionButtons.jsx b/client/src/features/editors/list/ActionButtons.jsx index 8c1d2bff4..ddd673728 100644 --- a/client/src/features/editors/list/ActionButtons.jsx +++ b/client/src/features/editors/list/ActionButtons.jsx @@ -17,7 +17,7 @@ export default function ActionButtons(props) { aria-label='Options' size='xs' icon={} - _expanded={{ bg: 'pink.300', color: 'white' }} + _expanded={{ bg: 'orange.300', color: 'white' }} _focus={{ boxShadow: 'none' }} backgroundColor={'orange.200'} color={'orange.500'} diff --git a/client/src/features/editors/list/EventBlock.jsx b/client/src/features/editors/list/EventBlock.jsx index 62cf829b5..9b26ea583 100644 --- a/client/src/features/editors/list/EventBlock.jsx +++ b/client/src/features/editors/list/EventBlock.jsx @@ -14,7 +14,8 @@ import { SelectCollapse, HandleCollapse } from 'app/context/collapseAtom'; import { useAtom } from 'jotai'; const ExpandedBlock = (props) => { - const { provided, data, next, delay, delayValue, actionHandler } = props; + const { provided, data, eventIndex, next, delay, delayValue, actionHandler } = + props; const oscid = data.id.length > 4 ? '...' : data.id; @@ -80,7 +81,9 @@ const ExpandedBlock = (props) => { actionHandler('update', { field: 'note', value: v }) } /> - {`OSC ID: ${oscid}`} + + {`/ontime/goto ${eventIndex + 1} << OSC >> /ontime/gotoid ${oscid}`} +
{ }; export default function EventBlock(props) { - const { data, selected, delay, index, actionHandler } = props; + const { data, selected, delay, index, eventIndex, actionHandler } = props; // const [collapsed, setCollapsed] = useState(checkLocalStorage(data.id)); @@ -200,6 +203,7 @@ export default function EventBlock(props) { ) : ( { if (cursor == null) setCursor(0); - else if (cursor >= 0) setCursor(cursor - 1); + else if (cursor > 0) setCursor(cursor - 1); }, 'Alt+KeyE': (event) => { event.preventDefault(); @@ -49,7 +49,7 @@ export default function EventList(props) { return () => { unsubscribe(); }; - }, [cursor, events.length, eventsHandler]); + }, [cursor, events, eventsHandler]); // handle incoming messages useEffect(() => { @@ -62,7 +62,6 @@ export default function EventList(props) { // Handle playstate socket.on('selected', (data) => { setSelected(data); - console.log('debug cursor setted', data); }); socket.on('next-id', (data) => { setNext(data); @@ -80,13 +79,20 @@ export default function EventList(props) { if (cursorSettings !== 'locked' || selected == null) return; if (selected.index == null) return; - setCursor(selected.index); - }, [selected, cursorSettings]); + let eventIndex = -1; + let gotoIndex = -1; + for (const e of events) { + gotoIndex++; + if (e.type === 'event') eventIndex++; + if (eventIndex === selected.index) break; + } + + setCursor(gotoIndex); + }, [events, selected, cursorSettings]); // attach scroll to cursor useEffect(() => { if (cursor == null || cursorRef.current == null) return; - console.log('debug cursor scrolling'); cursorRef.current.scrollIntoView({ behavior: 'smooth', @@ -117,8 +123,7 @@ export default function EventList(props) { console.log('EventList: events in event list', events); let cumulativeDelay = 0; - - console.log('debug selected', selected); + let eventIndex = -1; return (
@@ -131,20 +136,28 @@ export default function EventList(props) { ref={provided.innerRef} > {events.map((e, index) => { - let isCursor = cursor === index; - if (index === 0) cumulativeDelay = 0; + if (index === 0) { + cumulativeDelay = 0; + eventIndex = -1; + } if (e.type === 'delay' && e.duration != null) { cumulativeDelay += e.duration; - } else if (e.type === 'block') cumulativeDelay = 0; + } else if (e.type === 'block') { + cumulativeDelay = 0; + } else if (e.type === 'event') { + eventIndex++; + } + return (
{ const { type, index, + eventIndex, data, selected, next, @@ -71,6 +72,7 @@ const EventListItem = (props) => { return ( } - _expanded={{ bg: 'pink.300', color: 'white' }} + _expanded={{ bg: 'orange.300', color: 'white' }} _focus={{ boxShadow: 'none' }} backgroundColor={'orange.200'} color={'orange.500'} diff --git a/client/src/features/viewers/ViewWrapper.jsx b/client/src/features/viewers/ViewWrapper.jsx index 6e198eac3..738d6acfb 100644 --- a/client/src/features/viewers/ViewWrapper.jsx +++ b/client/src/features/viewers/ViewWrapper.jsx @@ -37,7 +37,7 @@ const withSocket = (Component) => { }); const [timer, setTimer] = useState({ clock: null, - currentSeconds: null, + running: null, startedAt: null, expectedFinish: null, }); @@ -221,7 +221,7 @@ const withSocket = (Component) => { // get clock string const timeManager = { ...timer, - finished: timer.running <= 0 && timer.startedAt, + finished: playback === 'start' && timer.running <= 0 && timer.startedAt, clock: stringFromMillis(timer.clock), playstate: playback, }; diff --git a/client/src/features/viewers/backstage/StageManager.jsx b/client/src/features/viewers/backstage/StageManager.jsx index 0fa299413..6ee5cadc8 100644 --- a/client/src/features/viewers/backstage/StageManager.jsx +++ b/client/src/features/viewers/backstage/StageManager.jsx @@ -42,7 +42,7 @@ export default function StageManager(props) { // Format messages const showPubl = publ.text !== '' && publ.visible; let stageTimer = formatDisplay(Math.abs(time.running), true); - if (time.running < 0) stageTimer = '-' + stageTimer; + if (time.running < 0) stageTimer = `-${stageTimer}`; // motion const titleVariants = { diff --git a/client/src/features/viewers/presenter/PresenterView.jsx b/client/src/features/viewers/presenter/PresenterView.jsx index 5d76d6df7..53a74faab 100644 --- a/client/src/features/viewers/presenter/PresenterView.jsx +++ b/client/src/features/viewers/presenter/PresenterView.jsx @@ -14,10 +14,9 @@ export default function PresenterView(props) { document.title = 'ontime - Speaker Screen'; }, []); - - const showOverlay = pres.text !== '' && pres.visible; - const isPlaying = time.playstate === 'start'; + const isPlaying = time.playstate !== 'pause'; + const normalisedTime = Math.max(time.running, 0); // motion const titleVariants = { @@ -61,7 +60,7 @@ export default function PresenterView(props) {
TIME UP
) : (
- +
)}
@@ -73,7 +72,7 @@ export default function PresenterView(props) { } > diff --git a/client/src/features/viewers/production/Pip.jsx b/client/src/features/viewers/production/Pip.jsx index c2dbe6d8d..15d6385a0 100644 --- a/client/src/features/viewers/production/Pip.jsx +++ b/client/src/features/viewers/production/Pip.jsx @@ -51,11 +51,8 @@ export default function Pip(props) { // Format messages const showInfo = general.backstageInfo !== '' && general.backstageInfo != null; - - const stageTimer = - time.currentSeconds != null && !isNaN(time.currentSeconds) - ? formatDisplay(time.currentSeconds, true) - : ''; + let stageTimer = formatDisplay(Math.abs(time.running), true); + if (time.running < 0) stageTimer = `-${stageTimer}`; return (
diff --git a/server/package.json b/server/package.json index 2b399881d..6ff8e68f8 100644 --- a/server/package.json +++ b/server/package.json @@ -10,7 +10,7 @@ "lowdb": "2.1.0", "multer": "^1.4.2", "nanoid": "^3.1.22", - "node-osc": "^6.0.1", + "node-osc": "6.0.2", "passport": "~0.4.1", "passport-local": "~1.0.0", "socket.io": "^4.0.0" diff --git a/server/src/classes/EventTimer.js b/server/src/classes/EventTimer.js index a81ee4388..911ea8e58 100644 --- a/server/src/classes/EventTimer.js +++ b/server/src/classes/EventTimer.js @@ -109,8 +109,29 @@ export class EventTimer extends Timer { update() { // if there is nothing selected, no nothing - if (this.selectedEventId == null) return; - super.update(); + if (this.selectedEventId == null && this.state !== 'roll') return; + + // only implement roll here + if (this.state !== 'roll') { + super.update(); + return; + } + + // get current time + const now = this._getCurrentTime(); + this.clock = now; + + if (this.selectedEventId && this.current > 0) { + // update timer as usual + this.current = this._finishAt - now; + } else { + // look for event if none is loaded + if (this.current <= 0 || this.secondaryTimer <= 0) this.rollLoad(); + + // count to next event + // TODO: replace with proper counter + if (this.secondaryTimer != null) this.secondaryTimer -= 1000; + } } start() { @@ -140,10 +161,11 @@ export class EventTimer extends Timer { else if (payload === 'next') this.next(); else if (payload === 'reload') this.reload(); else if (payload === 'unload') this.unload(); + else if (payload === 'roll') this.roll(); - // Not yet implemented - // else if (payload === 'roll') this.roll(); - + // TODO: Cleanup + // here tdo this.broadcastState; + // remove broadcast from functions this.broadcastThis('playstate', this.state); this.broadcastThis('selected-id', this.selectedEventId); this.broadcastThis('titles', this.titles); @@ -472,7 +494,7 @@ export class EventTimer extends Timer { if (eventIndex === -1) return; this.pause(); - this.loadEvent(eventIndex, true, true); + this.loadEvent(eventIndex, 'load', true); } // Loads a given event @@ -522,18 +544,12 @@ export class EventTimer extends Timer { if (e == null) return; // private title is always current - this.titles.titleNow = e.title; - this.titles.subtitleNow = e.subtitle; - this.titles.presenterNow = e.presenter; - this.selectedEventId = e.id; - // check if current is also public if (e.isPublic) { - this.titlesPublic.titleNow = e.title; - this.titlesPublic.subtitleNow = e.subtitle; - this.titlesPublic.presenterNow = e.presenter; - this.selectedPublicEventId = e.id; + this._loadThisTitles(e, 'now'); } else { + this._loadThisTitles(e, 'now-private'); + // assume there is no public event this.titlesPublic.titleNow = null; this.titlesPublic.subtitleNow = null; @@ -549,16 +565,77 @@ export class EventTimer extends Timer { this._eventlist[i].type === 'event' && this._eventlist[i].isPublic ) { - this.titlesPublic.titleNow = this._eventlist[i].title; - this.titlesPublic.subtitleNow = this._eventlist[i].subtitle; - this.titlesPublic.presenterNow = this._eventlist[i].presenter; - this.selectedPublicEventId = this._eventlist[i].id; + this._loadThisTitles(this._eventlist[i], 'now-public'); break; } } } } + _loadThisTitles(e, type) { + if (e == null) return; + + switch (type) { + // now, load to both public and private + case 'now': + // public + this.titlesPublic.titleNow = e.title; + this.titlesPublic.subtitleNow = e.subtitle; + this.titlesPublic.presenterNow = e.presenter; + this.selectedPublicEventId = e.id; + + // private + this.titles.titleNow = e.title; + this.titles.subtitleNow = e.subtitle; + this.titles.presenterNow = e.presenter; + this.selectedEventId = e.id; + + break; + case 'now-public': + this.titlesPublic.titleNow = e.title; + this.titlesPublic.subtitleNow = e.subtitle; + this.titlesPublic.presenterNow = e.presenter; + this.selectedPublicEventId = e.id; + break; + case 'now-private': + this.titles.titleNow = e.title; + this.titles.subtitleNow = e.subtitle; + this.titles.presenterNow = e.presenter; + this.selectedEventId = e.id; + break; + + // next, load to both public and private + case 'next': + // public + this.titlesPublic.titleNext = e.title; + this.titlesPublic.subtitleNext = e.subtitle; + this.titlesPublic.presenterNext = e.presenter; + this.nextPublicEventId = e.id; + + // private + this.titles.titleNext = e.title; + this.titles.subtitleNext = e.subtitle; + this.titles.presenterNext = e.presenter; + this.nextEventId = e.id; + break; + case 'next-public': + this.titlesPublic.titleNext = e.title; + this.titlesPublic.subtitleNext = e.subtitle; + this.titlesPublic.presenterNext = e.presenter; + this.nextPublicEventId = e.id; + break; + case 'next-private': + this.titles.titleNext = e.title; + this.titles.subtitleNext = e.subtitle; + this.titles.presenterNext = e.presenter; + this.nextEventId = e.id; + break; + + default: + break; + } + } + _loadTitlesNext() { // maybe there is nothing to load if (this.selectedEventIndex == null) return; @@ -583,19 +660,13 @@ export class EventTimer extends Timer { if (this._eventlist[i].type === 'event') { // if we have not set private if (!nextPrivate) { - this.titles.titleNext = this._eventlist[i].title; - this.titles.subtitleNext = this._eventlist[i].subtitle; - this.titles.presenterNext = this._eventlist[i].presenter; - this.nextEventId = this._eventlist[i].id; + this._loadThisTitles(this._eventlist[i], 'next-private'); nextPrivate = true; } // if event is public if (this._eventlist[i].isPublic) { - this.titlesPublic.titleNext = this._eventlist[i].title; - this.titlesPublic.subtitleNext = this._eventlist[i].subtitle; - this.titlesPublic.presenterNext = this._eventlist[i].presenter; - this.nextPublicEventId = this._eventlist[i].id; + this._loadThisTitles(this._eventlist[i], 'next-public'); nextPublic = true; } } @@ -642,6 +713,7 @@ export class EventTimer extends Timer { state = ${this.state} current = ${this.current} duration = ${this.duration} + secondaryTimer = ${this.secondaryTimer} Events ------------------------------ @@ -730,10 +802,77 @@ export class EventTimer extends Timer { this.broadcastState(); } + rollLoad() { + const now = this._getCurrentTime(); + this._resetTimers(true); + this._resetSelection(); + + let foundNow = null; + let nextIndex = null; + let nextStart = null; + + // loop through events, look for where we should be + for (const [index, e] of this._eventlist.entries()) { + if (!foundNow) { + if (e.timeStart <= now && now < e.timeEnd) { + // set flag + foundNow = true; + + // set timers + this._startedAt = e.timeStart; + this._finishAt = e.timeEnd; + this.duration = e.timeEnd - e.timeStart; + this.current = e.timeEnd - now; + + // set selection + this.selectedEventId = e.id; + this.selectedEventIndex = index; + + // set titles + this._loadTitlesNow(); + + // skip this entry for next + continue; + } + } + // check how far the start is from now + let wait = e.timeStart - now; + if (wait > 0) { + if (nextStart == null || wait < nextStart) { + nextStart = wait; + nextIndex = index; + } + } + } + + // nothing to play next, unload + if (!foundNow && !nextIndex) { + this.unload(); + return; + } + + if (nextIndex) { + // load titles + this._loadThisTitles(nextIndex, 'next'); + + if (!foundNow) { + // timer counts to nextStart + this.secondaryTimer = nextStart; + } + } + } + roll() { - console.log('roll: not yet implemented'); - return false; + // do we need to change + if (this.state === 'roll') return; + + // load into event + this.rollLoad(); + + // set state this.state = 'roll'; + + this.broadcastState(); } previous() { diff --git a/server/src/classes/Timer.js b/server/src/classes/Timer.js index 3a402ccd7..29a5ca793 100644 --- a/server/src/classes/Timer.js +++ b/server/src/classes/Timer.js @@ -8,6 +8,7 @@ export class Timer { clock = null; duration = null; current = null; + secondaryTimer = null; _finishAt = null; _finishedAt = null; _startedAt = null; @@ -50,6 +51,9 @@ export class Timer { // check playstate switch (this.state) { case 'start': + // ensure we have a start time + if (this._startedAt == null) this._startedAt = now; + // update current timer this.current = this._startedAt + this.duration + this._pausedTotal - now; @@ -110,8 +114,10 @@ export class Timer { ); } - _resetTimers() { + _resetTimers(total = false) { + if (total) this.duration = null; this.current = this.duration; + this.secondaryTimer = null; this._finishAt = null; this._finishedAt = null; this._startedAt = null; @@ -132,7 +138,7 @@ export class Timer { return { clock: this.clock, running: Timer.toSeconds(this.current), - currentSeconds: Timer.toSeconds(Math.max(this.current, 0)), + secondary: Timer.toSeconds(this.secondaryTimer), durationSeconds: Timer.toSeconds(this.duration), expectedFinish: this._getExpectedFinish(), startedAt: this._startedAt, diff --git a/server/src/controllers/OscController.js b/server/src/controllers/OscController.js index 89b1010f2..939ee829b 100644 --- a/server/src/controllers/OscController.js +++ b/server/src/controllers/OscController.js @@ -5,6 +5,9 @@ export const initiateOSC = (config) => { console.log(`OSC Server is listening on port ${config.port}`); }); + // error + oscServer.on('error', console.error); + oscServer.on('message', function (msg) { // message should look like /ontime/{path}/{args} where // ontime: fixed message for app @@ -62,7 +65,8 @@ export const initiateOSC = (config) => { console.log('calling goto with', args); try { let eventIndex = parseInt(args); - if (isNaN(eventIndex) || eventIndex <= 0) return; + if (isNaN(eventIndex) || eventIndex <= 0 || eventIndex == null) + return; global.timer.loadEvent(eventIndex - 1, undefined, true); } catch (error) { console.log('error calling goto: ', error); @@ -70,8 +74,9 @@ export const initiateOSC = (config) => { break; case 'gotoid': console.log('calling gotoid with', args); + if (args == null) return; try { - global.timer.loadEventById(args.toLowerCase()); + global.timer.loadEventById(args.toString().toLowerCase()); } catch (error) { console.log('error calling goto: ', error); } diff --git a/server/yarn.lock b/server/yarn.lock index 2e29b0705..ba9e9c7b2 100644 --- a/server/yarn.lock +++ b/server/yarn.lock @@ -438,10 +438,10 @@ negotiator@0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== -node-osc@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/node-osc/-/node-osc-6.0.1.tgz#6f2c39996c64460435b678dc91c128d3a9711031" - integrity sha512-UZBQGH4vVTw3Ub5/xcnhlrhL6bpaYz3hhNjO4eup4tknyP5qOi2GVVnEmEn/qaTgTvs7SVyytj3OHg9JWRD4Aw== +node-osc@6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/node-osc/-/node-osc-6.0.2.tgz#185d387928b186a84e8d0eebcae9e54a8bf50729" + integrity sha512-RW8PRLMh4H14veC5gZVUTcRkrk5pXd+b4vmitWL55c9ZI+5yEvMXkrokfnRH0u7DYveqw4h+uCPIUDifY/vjfA== dependencies: osc-min "^1.1.1"