mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-20 06:29:07 +00:00
Time to end (#804)
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { dayInMs } from 'ontime-utils';
|
import { dayInMs } from 'ontime-utils';
|
||||||
import { OntimeEvent, TimerType } from 'ontime-types';
|
import { EndAction, OntimeEvent, Playback, TimeStrategy, TimerType } from 'ontime-types';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getCurrent,
|
getCurrent,
|
||||||
@@ -205,6 +205,10 @@ describe('getExpectedFinish()', () => {
|
|||||||
_timer: {
|
_timer: {
|
||||||
pausedAt: null,
|
pausedAt: null,
|
||||||
},
|
},
|
||||||
|
runtime: {
|
||||||
|
actualStart: 79200000,
|
||||||
|
plannedEnd: 600000,
|
||||||
|
},
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
const calculatedFinish = getExpectedFinish(state);
|
const calculatedFinish = getExpectedFinish(state);
|
||||||
@@ -356,6 +360,9 @@ describe('getCurrent()', () => {
|
|||||||
startedAt: null,
|
startedAt: null,
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
},
|
},
|
||||||
|
runtime: {
|
||||||
|
plannedEnd: null,
|
||||||
|
},
|
||||||
_timer: {
|
_timer: {
|
||||||
pausedAt: null,
|
pausedAt: null,
|
||||||
},
|
},
|
||||||
@@ -378,6 +385,9 @@ describe('getCurrent()', () => {
|
|||||||
startedAt: 10,
|
startedAt: 10,
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
},
|
},
|
||||||
|
runtime: {
|
||||||
|
plannedEnd: 100,
|
||||||
|
},
|
||||||
_timer: {
|
_timer: {
|
||||||
pausedAt: null,
|
pausedAt: null,
|
||||||
},
|
},
|
||||||
@@ -386,6 +396,7 @@ describe('getCurrent()', () => {
|
|||||||
const current = getCurrent(state);
|
const current = getCurrent(state);
|
||||||
expect(current).toBe(70);
|
expect(current).toBe(70);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('current time is the time to end + added time', () => {
|
it('current time is the time to end + added time', () => {
|
||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
@@ -399,6 +410,9 @@ describe('getCurrent()', () => {
|
|||||||
startedAt: 10,
|
startedAt: 10,
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
},
|
},
|
||||||
|
runtime: {
|
||||||
|
plannedEnd: 100,
|
||||||
|
},
|
||||||
_timer: {
|
_timer: {
|
||||||
pausedAt: null,
|
pausedAt: null,
|
||||||
},
|
},
|
||||||
@@ -407,9 +421,40 @@ describe('getCurrent()', () => {
|
|||||||
const current = getCurrent(state);
|
const current = getCurrent(state);
|
||||||
expect(current).toBe(77);
|
expect(current).toBe(77);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('handles events that start the day after', () => {
|
||||||
|
const state = {
|
||||||
|
eventNow: {
|
||||||
|
timeStart: 60000, // 00:01:00
|
||||||
|
timeEnd: 600000, // 00:10:00
|
||||||
|
timerType: TimerType.TimeToEnd,
|
||||||
|
},
|
||||||
|
clock: 79500000, // 22:05:00
|
||||||
|
timer: {
|
||||||
|
addedTime: 0,
|
||||||
|
duration: Infinity, // not relevant,
|
||||||
|
startedAt: 79200000, // 22:00:00
|
||||||
|
finishedAt: null,
|
||||||
|
},
|
||||||
|
runtime: {
|
||||||
|
plannedStart: 60000, // 00:01:00
|
||||||
|
plannedEnd: 79200000, // 22:00:00
|
||||||
|
},
|
||||||
|
_timer: {
|
||||||
|
pausedAt: null,
|
||||||
|
},
|
||||||
|
} as RuntimeState;
|
||||||
|
|
||||||
|
const current = getCurrent(state);
|
||||||
|
// day - clock + start time
|
||||||
|
const expectedCurrent = dayInMs - 79500000 + 60000;
|
||||||
|
expect(current).toBe(expectedCurrent);
|
||||||
|
});
|
||||||
|
|
||||||
it('handles events that finish the day after', () => {
|
it('handles events that finish the day after', () => {
|
||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
|
timeStart: 79200000, // 22:00:00
|
||||||
timeEnd: 600000, // 00:10:00
|
timeEnd: 600000, // 00:10:00
|
||||||
timerType: TimerType.TimeToEnd,
|
timerType: TimerType.TimeToEnd,
|
||||||
},
|
},
|
||||||
@@ -420,26 +465,9 @@ describe('getCurrent()', () => {
|
|||||||
startedAt: 79200000, // 22:00:00
|
startedAt: 79200000, // 22:00:00
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
},
|
},
|
||||||
_timer: {
|
runtime: {
|
||||||
pausedAt: null,
|
actualStart: 79200000,
|
||||||
},
|
plannedEnd: 600000,
|
||||||
} as RuntimeState;
|
|
||||||
|
|
||||||
const current = getCurrent(state);
|
|
||||||
expect(current).toBe(600000 + dayInMs - 79500000);
|
|
||||||
});
|
|
||||||
it('does not update ', () => {
|
|
||||||
const state = {
|
|
||||||
eventNow: {
|
|
||||||
timeEnd: 600000, // 00:10:00
|
|
||||||
timerType: TimerType.TimeToEnd,
|
|
||||||
},
|
|
||||||
clock: 79500000, // 22:05:00
|
|
||||||
timer: {
|
|
||||||
addedTime: 0,
|
|
||||||
duration: Infinity, // not relevant,
|
|
||||||
startedAt: 79200000, // 22:00:00
|
|
||||||
finishedAt: null,
|
|
||||||
},
|
},
|
||||||
_timer: {
|
_timer: {
|
||||||
pausedAt: null,
|
pausedAt: null,
|
||||||
@@ -447,7 +475,7 @@ describe('getCurrent()', () => {
|
|||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
const current = getCurrent(state);
|
const current = getCurrent(state);
|
||||||
expect(current).toBe(600000 + dayInMs - 79500000);
|
expect(current).toBe(dayInMs - 79500000 + 600000);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1548,4 +1576,108 @@ describe('getRuntimeOffset()', () => {
|
|||||||
const offset = getRuntimeOffset(state);
|
const offset = getRuntimeOffset(state);
|
||||||
expect(offset).toBe(79521653 - 81000000);
|
expect(offset).toBe(79521653 - 81000000);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('handles time-to-end', () => {
|
||||||
|
const state = {
|
||||||
|
clock: 80000000, // 22:13:20
|
||||||
|
eventNow: {
|
||||||
|
id: 'd6a2ce',
|
||||||
|
type: 'event',
|
||||||
|
title: '',
|
||||||
|
timeStart: 77400000, // 21:30:00
|
||||||
|
timeEnd: 81000000, // 22:30:00
|
||||||
|
duration: 3600000, // 01:00:00
|
||||||
|
timeStrategy: TimeStrategy.LockEnd,
|
||||||
|
linkStart: null,
|
||||||
|
endAction: EndAction.None,
|
||||||
|
timerType: TimerType.TimeToEnd,
|
||||||
|
isPublic: true,
|
||||||
|
skip: false,
|
||||||
|
note: '',
|
||||||
|
colour: '',
|
||||||
|
cue: '1',
|
||||||
|
revision: 0,
|
||||||
|
timeWarning: 120000,
|
||||||
|
timeDanger: 60000,
|
||||||
|
custom: {},
|
||||||
|
delay: 0,
|
||||||
|
},
|
||||||
|
runtime: {
|
||||||
|
selectedEventIndex: 0,
|
||||||
|
numEvents: 1,
|
||||||
|
offset: null,
|
||||||
|
plannedStart: 77400000, // 21:30:00
|
||||||
|
plannedEnd: 81000000, // 22:30:00
|
||||||
|
actualStart: 78000000, // 21:40:00
|
||||||
|
expectedEnd: 81600000, // 22:40:00
|
||||||
|
},
|
||||||
|
timer: {
|
||||||
|
addedTime: 0,
|
||||||
|
current: 1600000,
|
||||||
|
duration: 3600000,
|
||||||
|
elapsed: 2000000,
|
||||||
|
expectedFinish: 81600000,
|
||||||
|
finishedAt: null,
|
||||||
|
playback: Playback.Play,
|
||||||
|
secondaryTimer: null,
|
||||||
|
startedAt: 78000000,
|
||||||
|
},
|
||||||
|
_timer: { pausedAt: null, secondaryTarget: null, finishedNow: false },
|
||||||
|
} as RuntimeState;
|
||||||
|
|
||||||
|
const offset = getRuntimeOffset(state);
|
||||||
|
expect(offset).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles time-to-end with delays', () => {
|
||||||
|
const state = {
|
||||||
|
clock: 82000000, // 22:46:40
|
||||||
|
eventNow: {
|
||||||
|
id: 'd6a2ce',
|
||||||
|
type: 'event',
|
||||||
|
title: '',
|
||||||
|
timeStart: 77400000, // 21:30:00
|
||||||
|
timeEnd: 81000000, // 22:30:00
|
||||||
|
duration: 3600000, // 01:00:00
|
||||||
|
timeStrategy: TimeStrategy.LockEnd,
|
||||||
|
linkStart: null,
|
||||||
|
endAction: EndAction.None,
|
||||||
|
timerType: TimerType.TimeToEnd,
|
||||||
|
isPublic: true,
|
||||||
|
skip: false,
|
||||||
|
note: '',
|
||||||
|
colour: '',
|
||||||
|
cue: '1',
|
||||||
|
revision: 0,
|
||||||
|
timeWarning: 120000,
|
||||||
|
timeDanger: 60000,
|
||||||
|
custom: {},
|
||||||
|
delay: 0,
|
||||||
|
},
|
||||||
|
runtime: {
|
||||||
|
selectedEventIndex: 0,
|
||||||
|
numEvents: 1,
|
||||||
|
offset: null,
|
||||||
|
plannedStart: 77400000, // 21:30:00
|
||||||
|
plannedEnd: 81000000, // 22:30:00
|
||||||
|
actualStart: 78000000, // 21:40:00
|
||||||
|
expectedEnd: 81600000, // 22:40:00
|
||||||
|
},
|
||||||
|
timer: {
|
||||||
|
addedTime: 0,
|
||||||
|
current: -400000,
|
||||||
|
duration: 3600000,
|
||||||
|
elapsed: 4000000,
|
||||||
|
expectedFinish: 81600000,
|
||||||
|
finishedAt: null,
|
||||||
|
playback: Playback.Play,
|
||||||
|
secondaryTimer: null,
|
||||||
|
startedAt: 78000000,
|
||||||
|
},
|
||||||
|
_timer: { pausedAt: null, secondaryTarget: null, finishedNow: false },
|
||||||
|
} as RuntimeState;
|
||||||
|
|
||||||
|
const offset = getRuntimeOffset(state);
|
||||||
|
expect(offset).toBe(-400000);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -53,16 +53,23 @@ export function getExpectedFinish(state: RuntimeState): MaybeNumber {
|
|||||||
* @param {RuntimeState} state runtime state
|
* @param {RuntimeState} state runtime state
|
||||||
* @returns {number} current time for timer
|
* @returns {number} current time for timer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function getCurrent(state: RuntimeState): number {
|
export function getCurrent(state: RuntimeState): number {
|
||||||
const { startedAt, duration, addedTime } = state.timer;
|
const { startedAt, duration, addedTime } = state.timer;
|
||||||
const { timerType, timeEnd } = state.eventNow;
|
const { timerType, timeStart, timeEnd } = state.eventNow;
|
||||||
const { pausedAt } = state._timer;
|
const { pausedAt } = state._timer;
|
||||||
const { clock } = state;
|
const { clock } = state;
|
||||||
|
|
||||||
if (timerType === TimerType.TimeToEnd) {
|
if (timerType === TimerType.TimeToEnd) {
|
||||||
const isNextDay = startedAt > timeEnd;
|
const isEventOverMidnight = timeStart > timeEnd;
|
||||||
const correctDay = isNextDay ? dayInMs : 0;
|
const hasFinishedRundownForToday = state.runtime.plannedEnd && clock > state.runtime.plannedEnd;
|
||||||
return timeEnd + addedTime + correctDay - clock;
|
|
||||||
|
if (hasFinishedRundownForToday && !isEventOverMidnight) {
|
||||||
|
return dayInMs - clock + state.eventNow.timeStart + addedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
const correctDay = isEventOverMidnight ? dayInMs : 0;
|
||||||
|
return correctDay - clock + timeEnd + addedTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (startedAt === null) {
|
if (startedAt === null) {
|
||||||
@@ -301,8 +308,9 @@ export function getRuntimeOffset(state: RuntimeState): MaybeNumber {
|
|||||||
if (state.runtime.actualStart === null) {
|
if (state.runtime.actualStart === null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { clock } = state;
|
const { clock } = state;
|
||||||
const { timeStart } = state.eventNow;
|
const { timeStart, timerType } = state.eventNow;
|
||||||
const { addedTime, current, startedAt } = state.timer;
|
const { addedTime, current, startedAt } = state.timer;
|
||||||
|
|
||||||
// if we havent started, the offset is the difference to the schedule
|
// if we havent started, the offset is the difference to the schedule
|
||||||
@@ -311,6 +319,11 @@ export function getRuntimeOffset(state: RuntimeState): MaybeNumber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const overtime = Math.min(current, 0);
|
const overtime = Math.min(current, 0);
|
||||||
|
// in time-to-end, offset is overtime
|
||||||
|
if (timerType === TimerType.TimeToEnd) {
|
||||||
|
return overtime;
|
||||||
|
}
|
||||||
|
|
||||||
const startOffset = startedAt - timeStart;
|
const startOffset = startedAt - timeStart;
|
||||||
const pausedTime = state._timer.pausedAt === null ? 0 : clock - state._timer.pausedAt;
|
const pausedTime = state._timer.pausedAt === null ? 0 : clock - state._timer.pausedAt;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user