Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions meteor/__mocks__/defaultCollectionObjects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ export function defaultRundownPlaylist(_id: RundownPlaylistId, studioId: StudioI
type: 'none' as any,
},
rundownIdsInOrder: [],
tTimers: [
{ index: 1, label: '', mode: null, state: null },
{ index: 2, label: '', mode: null, state: null },
{ index: 3, label: '', mode: null, state: null },
],
}
}
export function defaultRundown(
Expand Down
1 change: 1 addition & 0 deletions meteor/server/__tests__/cronjobs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@ describe('cronjobs', () => {
type: PlaylistTimingType.None,
},
activationId: protectString(''),
tTimers: [] as any,
})

return {
Expand Down
1 change: 1 addition & 0 deletions meteor/server/api/__tests__/externalMessageQueue.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ describe('Test external message queue static methods', () => {
type: PlaylistTimingType.None,
},
rundownIdsInOrder: [protectString('rundown_1')],
tTimers: [] as any,
})
await Rundowns.mutableCollection.insertAsync({
_id: protectString('rundown_1'),
Expand Down
1 change: 1 addition & 0 deletions meteor/server/api/__tests__/peripheralDevice.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
type: PlaylistTimingType.None,
},
rundownIdsInOrder: [rundownID],
tTimers: [] as any,
})
await Rundowns.mutableCollection.insertAsync({
_id: rundownID,
Expand Down Expand Up @@ -494,7 +495,7 @@
).rejects.toThrowMeteor(418, `Error thrown, as requested`)
})

/*

Check warning on line 498 in meteor/server/api/__tests__/peripheralDevice.test.ts

View workflow job for this annotation

GitHub Actions / Typecheck and Lint Core

Some tests seem to be commented

Check warning on line 498 in meteor/server/api/__tests__/peripheralDevice.test.ts

View workflow job for this annotation

GitHub Actions / Typecheck and Lint Core

Some tests seem to be commented
test('timelineTriggerTime', () => {
if (DEBUG) setLogLevel(LogLevel.DEBUG)
let timelineTriggerTimeResult: PeripheralDeviceAPI.TimelineTriggerTimeResult = [
Expand Down Expand Up @@ -562,7 +563,7 @@
})

// Note: this test fails, due to a backwards-compatibility hack in #c579c8f0
// test('initialize with bad arguments', () => {

Check warning on line 566 in meteor/server/api/__tests__/peripheralDevice.test.ts

View workflow job for this annotation

GitHub Actions / Typecheck and Lint Core

Some tests seem to be commented

Check warning on line 566 in meteor/server/api/__tests__/peripheralDevice.test.ts

View workflow job for this annotation

GitHub Actions / Typecheck and Lint Core

Some tests seem to be commented
// let options: PeripheralDeviceInitOptions = {
// category: PeripheralDeviceCategory.INGEST,
// type: PeripheralDeviceType.MOS,
Expand All @@ -583,7 +584,7 @@
// }
// })

// test('setStatus with bad arguments', () => {

Check warning on line 587 in meteor/server/api/__tests__/peripheralDevice.test.ts

View workflow job for this annotation

GitHub Actions / Typecheck and Lint Core

Some tests seem to be commented

Check warning on line 587 in meteor/server/api/__tests__/peripheralDevice.test.ts

View workflow job for this annotation

GitHub Actions / Typecheck and Lint Core

Some tests seem to be commented
// try {
// Meteor.call(PeripheralDeviceAPIMethods.setStatus, 'wibbly', device.token, { statusCode: 0 })
// fail('expected to throw')
Expand Down
26 changes: 25 additions & 1 deletion meteor/server/migration/X_X_X.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { addMigrationSteps } from './databaseMigration'
import { CURRENT_SYSTEM_VERSION } from './currentSystemVersion'
import { MongoInternals } from 'meteor/mongo'
import { Studios } from '../collections'
import { RundownPlaylists, Studios } from '../collections'
import { ExpectedPackages } from '../collections'
import * as PackagesPreR53 from '@sofie-automation/corelib/dist/dataModel/Old/ExpectedPackagesR52'
import {
Expand Down Expand Up @@ -195,4 +195,28 @@ export const addSteps = addMigrationSteps(CURRENT_SYSTEM_VERSION, [
}
},
},
{
id: 'Add T-timers to RundownPlaylist',
canBeRunAutomatically: true,
validate: async () => {
const playlistCount = await RundownPlaylists.countDocuments({ tTimers: { $exists: false } })
if (playlistCount > 1) return `There are ${playlistCount} RundownPlaylists without T-timers`
return false
},
migrate: async () => {
await RundownPlaylists.mutableCollection.updateAsync(
{ tTimers: { $exists: false } } as any,
{
$set: {
tTimers: [
{ index: 1, label: '', mode: null, state: null },
{ index: 2, label: '', mode: null, state: null },
{ index: 3, label: '', mode: null, state: null },
],
},
},
{ multi: true }
)
},
},
])
8 changes: 8 additions & 0 deletions meteor/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1231,6 +1231,7 @@ __metadata:
"@sofie-automation/corelib": "npm:1.53.0-in-development"
"@sofie-automation/shared-lib": "npm:1.53.0-in-development"
amqplib: "npm:^0.10.5"
chrono-node: "npm:^2.9.0"
deepmerge: "npm:^4.3.1"
elastic-apm-node: "npm:^4.11.0"
mongodb: "npm:^6.12.0"
Expand Down Expand Up @@ -2940,6 +2941,13 @@ __metadata:
languageName: node
linkType: hard

"chrono-node@npm:^2.9.0":
version: 2.9.0
resolution: "chrono-node@npm:2.9.0"
checksum: 10/a30bbaa67f9a127e711db6e694ee4c89292d8f533dbfdc3d7cb34f479728e02e377f682e75ad84dd4b6a16016c248a5e85fb453943b96f93f5993f5ccddc6d08
languageName: node
linkType: hard

"ci-info@npm:^3.2.0":
version: 3.8.0
resolution: "ci-info@npm:3.8.0"
Expand Down
9 changes: 9 additions & 0 deletions packages/blueprints-integration/src/api/showStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,15 @@ export interface BlueprintResultPart {
}

export interface BlueprintSyncIngestNewData {
/** All parts in the rundown, including the new/updated part */
allParts: IBlueprintPartDB[]
/**
* An approximate index of the current part in the allParts array
* Note: this will not always be an integer, such as when the part is an adlib part
* `null` means the part could not be placed
*/
currentPartIndex: number | null

// source: BlueprintSyncIngestDataSource
/** The new part */
part: IBlueprintPartDB | undefined
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { IPartAndPieceActionContext } from './partsAndPieceActionContext.js'
import { IExecuteTSRActionsContext } from './executeTsrActionContext.js'
import { IBlueprintPart, IBlueprintPartInstance, IBlueprintPiece } from '../index.js'
import { IRouteSetMethods } from './routeSetContext.js'
import { ITTimersContext } from './tTimersContext.js'

/** Actions */
export interface IDataStoreMethods {
Expand All @@ -26,7 +27,8 @@ export interface IActionExecutionContext
IDataStoreMethods,
IPartAndPieceActionContext,
IExecuteTSRActionsContext,
IRouteSetMethods {
IRouteSetMethods,
ITTimersContext {
/** Fetch the showstyle config for the specified part */
// getNextShowStyleConfig(): Readonly<{ [key: string]: ConfigItemValue }>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,19 @@ import {
IBlueprintPieceDB,
IBlueprintPieceInstance,
IBlueprintResolvedPieceInstance,
IBlueprintSegment,
IBlueprintSegmentDB,
IEventContext,
IShowStyleUserContext,
} from '../index.js'
import { BlueprintQuickLookInfo } from './quickLoopInfo.js'
import { ReadonlyDeep } from 'type-fest'
import type { ITTimersContext } from './tTimersContext.js'

/**
* Context in which 'current' is the part currently on air, and 'next' is the partInstance being set as Next
* This is similar to `IPartAndPieceActionContext`, but has more limits on what is allowed to be changed.
*/
export interface IOnSetAsNextContext extends IShowStyleUserContext, IEventContext {
export interface IOnSetAsNextContext extends IShowStyleUserContext, IEventContext, ITTimersContext {
/** Information about the current loop, if there is one */
readonly quickLoopInfo: BlueprintQuickLookInfo | null

Expand Down Expand Up @@ -55,7 +56,7 @@ export interface IOnSetAsNextContext extends IShowStyleUserContext, IEventContex
/** Gets the Part for a Piece retrieved from findLastScriptedPieceOnLayer. This primarily allows for accessing metadata of the Part */
getPartForPreviousPiece(piece: IBlueprintPieceDB): Promise<IBlueprintPart | undefined>
/** Gets the Segment. This primarily allows for accessing metadata */
getSegment(segment: 'current' | 'next'): Promise<IBlueprintSegment | undefined>
getSegment(segment: 'current' | 'next'): Promise<IBlueprintSegmentDB | undefined>

/** Get a list of the upcoming Parts in the Rundown, in the order that they will be Taken
*
Expand Down
4 changes: 3 additions & 1 deletion packages/blueprints-integration/src/context/onTakeContext.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { IBlueprintPart, IBlueprintPiece, IEventContext, IShowStyleUserContext, Time } from '../index.js'
import { IPartAndPieceActionContext } from './partsAndPieceActionContext.js'
import { IExecuteTSRActionsContext } from './executeTsrActionContext.js'
import { ITTimersContext } from './tTimersContext.js'

/**
* Context in which 'current' is the partInstance we're leaving, and 'next' is the partInstance we're taking
Expand All @@ -9,7 +10,8 @@ export interface IOnTakeContext
extends IPartAndPieceActionContext,
IShowStyleUserContext,
IEventContext,
IExecuteTSRActionsContext {
IExecuteTSRActionsContext,
ITTimersContext {
/** Inform core that a take out of the taken partinstance should be blocked until the specified time */
blockTakeUntil(time: Time | null): Promise<void>
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
IBlueprintPieceDB,
IBlueprintPieceInstance,
IBlueprintResolvedPieceInstance,
IBlueprintSegment,
IBlueprintSegmentDB,
Time,
} from '../index.js'
import { BlueprintQuickLookInfo } from './quickLoopInfo.js'
Expand Down Expand Up @@ -50,7 +50,7 @@ export interface IPartAndPieceActionContext {
/** Gets the Part for a Piece retrieved from findLastScriptedPieceOnLayer. This primarily allows for accessing metadata of the Part */
getPartForPreviousPiece(piece: IBlueprintPieceDB): Promise<IBlueprintPart | undefined>
/** Gets the Segment. This primarily allows for accessing metadata */
getSegment(segment: 'current' | 'next'): Promise<IBlueprintSegment | undefined>
getSegment(segment: 'current' | 'next'): Promise<IBlueprintSegmentDB | undefined>

/** Get a list of the upcoming Parts in the Rundown, in the order that they will be Taken
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { IPackageInfoContext } from './packageInfoContext.js'
import type { IShowStyleContext } from './showStyleContext.js'
import type { IExecuteTSRActionsContext } from './executeTsrActionContext.js'
import type { IDataStoreMethods } from './adlibActionContext.js'
import { ITTimersContext } from './tTimersContext.js'

export interface IRundownContext extends IShowStyleContext {
readonly rundownId: string
Expand All @@ -13,7 +14,11 @@ export interface IRundownContext extends IShowStyleContext {

export interface IRundownUserContext extends IUserNotesContext, IRundownContext {}

export interface IRundownActivationContext extends IRundownContext, IExecuteTSRActionsContext, IDataStoreMethods {
export interface IRundownActivationContext
extends IRundownContext,
IExecuteTSRActionsContext,
IDataStoreMethods,
ITTimersContext {
/** Info about the RundownPlaylist state before the Activation / Deactivation event */
readonly previousState: IRundownActivationContextState
readonly currentState: IRundownActivationContextState
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import type {
IBlueprintPieceInstance,
} from '../documents/index.js'
import type { IEventContext } from './eventContext.js'
import type { ITTimersContext } from './tTimersContext.js'

export interface ISyncIngestUpdateToPartInstanceContext extends IRundownUserContext, IEventContext {
export interface ISyncIngestUpdateToPartInstanceContext extends IRundownUserContext, ITTimersContext, IEventContext {
/** Sync a pieceInstance. Inserts the pieceInstance if new, updates if existing. Optionally pass in a mutated Piece, to override the content of the instance */
syncPieceInstance(
pieceInstanceId: string,
Expand Down
119 changes: 119 additions & 0 deletions packages/blueprints-integration/src/context/tTimersContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
export type IPlaylistTTimerIndex = 1 | 2 | 3

export interface ITTimersContext {
/**
* Get a T-timer by its index
* Note: Index is 1-based (1, 2, 3)
* @param index Number of the timer to retrieve
*/
getTimer(index: IPlaylistTTimerIndex): IPlaylistTTimer

/**
* Clear all T-timers
*/
clearAllTimers(): void
}

export interface IPlaylistTTimer {
readonly index: IPlaylistTTimerIndex

/** The label of the T-timer */
readonly label: string

/**
* The current state of the T-timer
* Null if the T-timer is not initialized
*/
readonly state: IPlaylistTTimerState | null

/** Set the label of the T-timer */
setLabel(label: string): void

/** Clear the T-timer back to an uninitialized state */
clearTimer(): void

/**
* Start a countdown timer
* @param duration Duration of the countdown in milliseconds
* @param options Options for the countdown
*/
startCountdown(duration: number, options?: { stopAtZero?: boolean; startPaused?: boolean }): void

/**
* Start a timeOfDay timer, counting towards the target time
* This will throw if it is unable to parse the target time
* @param targetTime The target time, as a string (e.g. "14:30", "2023-12-31T23:59:59Z") or a timestamp number
*/
startTimeOfDay(targetTime: string | number, options?: { stopAtZero?: boolean }): void

/**
* Start a free-running timer
*/
startFreeRun(options?: { startPaused?: boolean }): void

/**
* If the current mode supports being paused, pause the timer
* Note: This is supported by the countdown and freerun modes
* @returns True if the timer was paused, false if it could not be paused
*/
pause(): boolean

/**
* If the current mode supports being paused, resume the timer
* This is the opposite of `pause()`
* @returns True if the timer was resumed, false if it could not be resumed
*/
resume(): boolean

/**
* If the timer can be restarted, restore it to its initial/restarted state
* Note: This is supported by the countdown and timeOfDay modes
* @returns True if the timer was restarted, false if it could not be restarted
*/
restart(): boolean
}

export type IPlaylistTTimerState =
| IPlaylistTTimerStateCountdown
| IPlaylistTTimerStateFreeRun
| IPlaylistTTimerStateTimeOfDay

export interface IPlaylistTTimerStateCountdown {
/** The mode of the T-timer */
readonly mode: 'countdown'
/** The current time of the countdown, in milliseconds */
readonly currentTime: number
/** The total duration of the countdown, in milliseconds */
readonly duration: number
/** Whether the timer is currently paused */
readonly paused: boolean

/** If the countdown is set to stop at zero, or continue into negative values */
readonly stopAtZero: boolean
}
export interface IPlaylistTTimerStateFreeRun {
/** The mode of the T-timer */
readonly mode: 'freeRun'
/** The current time of the freerun, in milliseconds */
readonly currentTime: number
/** Whether the timer is currently paused */
readonly paused: boolean
}

export interface IPlaylistTTimerStateTimeOfDay {
/** The mode of the T-timer */
readonly mode: 'timeOfDay'
/** The current remaining time of the timer, in milliseconds */
readonly currentTime: number
/** The target timestamp of the timer, in milliseconds */
readonly targetTime: number

/**
* The raw target string of the timer, as provided when setting the timer
* (e.g. "14:30", "2023-12-31T23:59:59Z", or a timestamp number)
*/
readonly targetRaw: string | number

/** If the countdown is set to stop at zero, or continue into negative values */
readonly stopAtZero: boolean
}
Loading
Loading