From 8d7e82a0f4b35d4c358b7b2271aaa765f9c5455a Mon Sep 17 00:00:00 2001 From: Julian Waller Date: Mon, 9 Oct 2023 12:06:14 +0100 Subject: [PATCH] chore: split blueprint-integration contexts into multiple files --- .../blueprints-integration/src/context.ts | 369 ------------------ .../src/context/adlibActionContext.ts | 106 +++++ .../src/context/baseContext.ts | 64 +++ .../src/context/eventContext.ts | 75 ++++ .../src/context/index.ts | 8 + .../src/context/packageInfoContext.ts | 12 + .../src/context/rundownContext.ts | 35 ++ .../src/context/showStyleContext.ts | 27 ++ .../src/context/studioContext.ts | 20 + .../src/context/syncIngestChangesContext.ts | 44 +++ 10 files changed, 391 insertions(+), 369 deletions(-) delete mode 100644 packages/blueprints-integration/src/context.ts create mode 100644 packages/blueprints-integration/src/context/adlibActionContext.ts create mode 100644 packages/blueprints-integration/src/context/baseContext.ts create mode 100644 packages/blueprints-integration/src/context/eventContext.ts create mode 100644 packages/blueprints-integration/src/context/index.ts create mode 100644 packages/blueprints-integration/src/context/packageInfoContext.ts create mode 100644 packages/blueprints-integration/src/context/rundownContext.ts create mode 100644 packages/blueprints-integration/src/context/showStyleContext.ts create mode 100644 packages/blueprints-integration/src/context/studioContext.ts create mode 100644 packages/blueprints-integration/src/context/syncIngestChangesContext.ts diff --git a/packages/blueprints-integration/src/context.ts b/packages/blueprints-integration/src/context.ts deleted file mode 100644 index 4601bb8bae..0000000000 --- a/packages/blueprints-integration/src/context.ts +++ /dev/null @@ -1,369 +0,0 @@ -import { DatastorePersistenceMode, Time } from './common' -import { IBlueprintExternalMessageQueueObj } from './message' -import { PackageInfo } from './packageInfo' -import { - IBlueprintMutatablePart, - IBlueprintPart, - IBlueprintPartInstance, - IBlueprintPiece, - IBlueprintPieceDB, - IBlueprintPieceInstance, - IBlueprintResolvedPieceInstance, - IBlueprintRundownPlaylist, - IBlueprintSegmentDB, - IBlueprintSegmentRundown, -} from './documents' -import { BlueprintMappings } from './studio' -import { TSR, OnGenerateTimelineObj } from './timeline' -import { PeripheralDeviceId } from '@sofie-automation/shared-lib/dist/core/model/Ids' -import { IBlueprintPlayoutDevice } from './lib' -import { ISourceLayer, IOutputLayer } from './showStyle' - -/** Common */ - -export interface ICommonContext { - /** - * Hash a string. Will return a unique string, to be used for all _id:s that are to be inserted in database - * @param originString A representation of the origin of the hash (for logging) - * @param originIsNotUnique If the originString is not guaranteed to be unique, set this to true - */ - getHashId: (originString: string, originIsNotUnique?: boolean) => string - /** Un-hash, is return the string that created the hash */ - unhashId: (hash: string) => string - - /** Log a message to the sofie log with level 'debug' */ - logDebug: (message: string) => void - /** Log a message to the sofie log with level 'info' */ - logInfo: (message: string) => void - /** Log a message to the sofie log with level 'warn' */ - logWarning: (message: string) => void - /** Log a message to the sofie log with level 'error' */ - logError: (message: string) => void -} - -export function isCommonContext(obj: unknown): obj is ICommonContext { - if (!obj || typeof obj !== 'object') { - return false - } - - const { getHashId, unhashId, logDebug, logInfo, logWarning, logError } = obj as ICommonContext - - return ( - typeof getHashId === 'function' && - typeof unhashId === 'function' && - typeof logDebug === 'function' && - typeof logInfo === 'function' && - typeof logWarning === 'function' && - typeof logError === 'function' - ) -} - -export interface IUserNotesContext extends ICommonContext { - /** Display a notification to the user of an error */ - notifyUserError(message: string, params?: { [key: string]: any }): void - /** Display a notification to the user of an warning */ - notifyUserWarning(message: string, params?: { [key: string]: any }): void - /** Display a notification to the user of a note */ - notifyUserInfo(message: string, params?: { [key: string]: any }): void -} - -export function isUserNotesContext(obj: unknown): obj is IUserNotesContext { - if (!isCommonContext(obj)) { - return false - } - - // eslint-disable-next-line @typescript-eslint/unbound-method - const { notifyUserError, notifyUserWarning, notifyUserInfo } = obj as IUserNotesContext - - return ( - typeof notifyUserError === 'function' && - typeof notifyUserWarning === 'function' && - typeof notifyUserInfo === 'function' - ) -} - -/** Studio */ - -export interface IStudioContext extends ICommonContext { - /** The id of the studio */ - readonly studioId: string - - /** Returns the Studio blueprint config. If StudioBlueprintManifest.preprocessConfig is provided, a config preprocessed by that function is returned, otherwise it is returned unprocessed */ - getStudioConfig: () => unknown - /** Returns a reference to a studio config value, that can later be resolved in Core */ - getStudioConfigRef(configKey: string): string - - /** Get the mappings for the studio */ - getStudioMappings: () => Readonly -} - -export interface IPackageInfoContext { - /** - * Get the PackageInfo items for an ExpectedPackage, if any have been reported by the package manager. - * Only info for packages with the `listenToPackageInfoUpdates` property set to true can be returned. - * The possible packageIds are scoped based on the ownership of the package. - * eg, baseline packages can be accessed when generating the baseline objects, piece/adlib packages can be access when regenerating the segment they are from - */ - getPackageInfo: (packageId: string) => Readonly - hackGetMediaObjectDuration: (mediaId: string) => Promise -} - -export interface IStudioBaselineContext extends IStudioContext, IPackageInfoContext {} - -export interface IStudioUserContext extends IUserNotesContext, IStudioContext {} - -/** Show Style Variant */ - -export interface IShowStyleContext extends ICommonContext, IStudioContext { - /** Returns a ShowStyle blueprint config. If ShowStyleBlueprintManifest.preprocessConfig is provided, a config preprocessed by that function is returned, otherwise it is returned unprocessed */ - getShowStyleConfig: () => unknown - /** Returns a reference to a showStyle config value, that can later be resolved in Core */ - getShowStyleConfigRef(configKey: string): string - /** Get source layers for the ShowStyle */ - getShowStyleSourceLayers(): Record - /** Get output layers for the ShowStyle */ - getShowStyleOutputLayers(): Record -} - -export interface IShowStyleUserContext extends IUserNotesContext, IShowStyleContext, IPackageInfoContext {} - -export interface IGetRundownContext extends IShowStyleUserContext { - /** Returns a list of the Playlists in the studio */ - getPlaylists: () => Promise> - /** Returns the Playlist in which the Rundown currently is in. If it's a new Rundown, this will return undefined. */ - getCurrentPlaylist: () => Promise | undefined> - /** Returns a randomized string, intended to be used as ids. */ - getRandomId: () => string -} - -/** Rundown */ - -export interface IRundownContext extends IShowStyleContext { - readonly rundownId: string - readonly playlistId: string - readonly rundown: Readonly -} - -export interface IRundownUserContext extends IUserNotesContext, IRundownContext {} - -export interface IRundownActivationContext extends IRundownContext { - /** Execute an action on a certain PeripheralDevice */ - executeTSRAction( - deviceId: PeripheralDeviceId, - actionId: string, - payload: Record - ): Promise - /** Returns a list of the PeripheralDevices */ - listPlayoutDevices(): Promise -} - -export interface ISegmentUserContext extends IUserNotesContext, IRundownContext, IPackageInfoContext { - /** Display a notification to the user of an error */ - notifyUserError: (message: string, params?: { [key: string]: any }, partExternalId?: string) => void - /** Display a notification to the user of an warning */ - notifyUserWarning: (message: string, params?: { [key: string]: any }, partExternalId?: string) => void - /** Display a notification to the user of a note */ - notifyUserInfo: (message: string, params?: { [key: string]: any }, partExternalId?: string) => void -} - -/** Actions */ -export interface IDataStoreActionExecutionContext extends IShowStyleUserContext, IEventContext { - /** - * Setting a value in the datastore allows us to overwrite parts of a timeline content object with that value - * @param key Key to use when referencing from the timeline object - * @param value Value to overwrite the timeline object's content with - * @param mode In temporary mode the value may be removed when the key is no longer on the timeline - */ - setTimelineDatastoreValue(key: string, value: any, mode: DatastorePersistenceMode): Promise - /** Deletes a previously set value from the datastore */ - removeTimelineDatastoreValue(key: string): Promise -} - -export interface IActionExecutionContext - extends IShowStyleUserContext, - IEventContext, - IDataStoreActionExecutionContext { - /** Data fetching */ - // getIngestRundown(): IngestRundown // TODO - for which part? - /** Get a PartInstance which can be modified */ - getPartInstance(part: 'current' | 'next'): Promise - /** Get the PieceInstances for a modifiable PartInstance */ - getPieceInstances(part: 'current' | 'next'): Promise - /** Get the resolved PieceInstances for a modifiable PartInstance */ - getResolvedPieceInstances(part: 'current' | 'next'): Promise - /** Get the last active piece on given layer */ - findLastPieceOnLayer( - sourceLayerId: string | string[], - options?: { - excludeCurrentPart?: boolean - originalOnly?: boolean - pieceMetaDataFilter?: any // Mongo query against properties inside of piece.metaData - } - ): Promise - /** Get the previous scripted piece on a given layer, looking backwards from the current part. */ - findLastScriptedPieceOnLayer( - sourceLayerId: string | string[], - options?: { - excludeCurrentPart?: boolean - pieceMetaDataFilter?: any - } - ): Promise - /** Gets the PartInstance for a PieceInstance retrieved from findLastPieceOnLayer. This primarily allows for accessing metadata of the PartInstance */ - getPartInstanceForPreviousPiece(piece: IBlueprintPieceInstance): Promise - /** Gets the Part for a Piece retrieved from findLastScriptedPieceOnLayer. This primarily allows for accessing metadata of the Part */ - getPartForPreviousPiece(piece: IBlueprintPieceDB): Promise - /** Fetch the showstyle config for the specified part */ - // getNextShowStyleConfig(): Readonly<{ [key: string]: ConfigItemValue }> - - /** Creative actions */ - /** Insert a pieceInstance. Returns id of new PieceInstance. Any timelineObjects will have their ids changed, so are not safe to reference from another piece */ - insertPiece(part: 'current' | 'next', piece: IBlueprintPiece): Promise - /** Update a piecesInstance */ - updatePieceInstance(pieceInstanceId: string, piece: Partial): Promise - /** Insert a queued part to follow the current part */ - queuePart(part: IBlueprintPart, pieces: IBlueprintPiece[]): Promise - /** Update a partInstance */ - updatePartInstance( - part: 'current' | 'next', - props: Partial - ): Promise - - /** Destructive actions */ - /** Stop any piecesInstances on the specified sourceLayers. Returns ids of piecesInstances that were affected */ - stopPiecesOnLayers(sourceLayerIds: string[], timeOffset?: number): Promise - /** Stop piecesInstances by id. Returns ids of piecesInstances that were removed */ - stopPieceInstances(pieceInstanceIds: string[], timeOffset?: number): Promise - /** Remove piecesInstances by id. Returns ids of piecesInstances that were removed. Note: For now we only allow removing from the next, but this might change to include current if there is justification */ - removePieceInstances(part: 'next', pieceInstanceIds: string[]): Promise - - /** Move the next part through the rundown. Can move by either a number of parts, or segments in either direction. */ - moveNextPart(partDelta: number, segmentDelta: number): Promise - /** Set flag to perform take after executing the current action. Returns state of the flag after each call. */ - takeAfterExecuteAction(take: boolean): Promise - /** Inform core that a take out of the current partinstance should be blocked until the specified time */ - blockTakeUntil(time: Time | null): Promise - - /** Misc actions */ - // updateAction(newManifest: Pick): void // only updates itself. to allow for the next one to do something different - // executePeripheralDeviceAction(deviceId: string, functionName: string, args: any[]): Promise - // openUIDialogue(message: string) // ????? - /** Returns a list of the PeripheralDevices */ - listPlayoutDevices(): Promise - /** Execute an action on a certain PeripheralDevice */ - executeTSRAction( - deviceId: PeripheralDeviceId, - actionId: string, - payload: Record - ): Promise -} - -/** Actions */ -export interface ISyncIngestUpdateToPartInstanceContext extends IRundownUserContext { - /** 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, - mutatedPiece?: Omit - ): IBlueprintPieceInstance - - /** Insert a pieceInstance. Returns id of new PieceInstance. Any timelineObjects will have their ids changed, so are not safe to reference from another piece */ - insertPieceInstance(piece: IBlueprintPiece): IBlueprintPieceInstance - /** Update a pieceInstance */ - updatePieceInstance(pieceInstanceId: string, piece: Partial): IBlueprintPieceInstance - /** Remove a pieceInstance */ - removePieceInstances(...pieceInstanceIds: string[]): string[] - - // Upcoming interface: - // /** Insert a AdlibInstance. Returns id of new AdlibInstance. Any timelineObjects will have their ids changed, so are not safe to reference from another piece */ - // insertAdlibInstance(adlibPiece: IBlueprintAdLibPiece): IBlueprintAdlibPieceInstance - // /** Update a AdlibInstance */ - // updateAdlibInstance(adlibInstanceId: string, adlibPiece: Partial>): IBlueprintAdlibPieceInstance - // /** Remove a AdlibInstance */ - // removeAdlibInstances(...adlibInstanceId: string[]): string[] - - // Upcoming interface: - // /** Insert a ActionInstance. Returns id of new ActionInstance. Any timelineObjects will have their ids changed, so are not safe to reference from another piece */ - // insertActionInstance(action: IBlueprintAdlibAction): IBlueprintAdlibActionInstance - // /** Update a ActionInstance */ - // updateActionInstance(actionInstanceId: string, action: Partial>): IBlueprintAdlibActionInstance - // /** Remove a ActionInstance */ - // removeActionInstances(...actionInstanceIds: string[]): string[] - - /** Update a partInstance */ - updatePartInstance(props: Partial): IBlueprintPartInstance - - /** Remove the partInstance. This is only valid when `playstatus: 'next'` */ - removePartInstance(): void -} - -/** Events */ - -export interface IEventContext { - getCurrentTime(): number -} - -export interface ITimelineEventContext extends IEventContext, IRundownContext { - readonly currentPartInstance: Readonly | undefined - readonly nextPartInstance: Readonly | undefined - readonly previousPartInstance: Readonly | undefined - - /** - * Get the full session id for an ab playback session. - * Note: sessionName should be unique within the segment unless pieces want to share a session - * @deprecated use the core provided AB implementation instead - */ - getPieceABSessionId(piece: IBlueprintPieceInstance, sessionName: string): string - /** - * Get the full session id for a timelineobject that belongs to an ab playback session - * sessionName should also be used in calls to getPieceABSessionId for the owning piece - * @deprecated use the core provided AB implementation instead - */ - getTimelineObjectAbSessionId( - obj: OnGenerateTimelineObj, - sessionName: string - ): string | undefined -} - -export interface IPartEventContext extends IEventContext, IRundownContext { - readonly part: Readonly -} - -export interface IRundownDataChangedEventContext extends IEventContext, IRundownContext { - formatDateAsTimecode(time: number): string - formatDurationAsTimecode(time: number): string - - /** Get all unsent and queued messages in the rundown */ - getAllUnsentQueuedMessages(): Promise> -} - -export interface IRundownTimingEventContext extends IRundownDataChangedEventContext { - readonly previousPart: Readonly | undefined - readonly currentPart: Readonly - readonly nextPart: Readonly | undefined - - /** - * Returns the first PartInstance in the Rundown within the current playlist activation. - * This allows for a start time for the Rundown to be determined - * @param allowUntimed Whether to consider a Part which has the untimed property set - */ - getFirstPartInstanceInRundown(allowUntimed?: boolean): Promise> - - /** - * Returns the partInstances in the Segment, limited to the playthrough of the segment that refPartInstance is part of - * @param refPartInstance PartInstance to use as the basis of the search - */ - getPartInstancesInSegmentPlayoutId( - refPartInstance: Readonly - ): Promise> - - /** - * Returns pieces in a partInstance - * @param id Id of partInstance to fetch items in - */ - getPieceInstances(...partInstanceIds: string[]): Promise> - - /** - * Returns a segment - * @param id Id of segment to fetch - */ - getSegment(id: string): Promise | undefined> -} diff --git a/packages/blueprints-integration/src/context/adlibActionContext.ts b/packages/blueprints-integration/src/context/adlibActionContext.ts new file mode 100644 index 0000000000..b5cf1ddb64 --- /dev/null +++ b/packages/blueprints-integration/src/context/adlibActionContext.ts @@ -0,0 +1,106 @@ +import type { DatastorePersistenceMode, Time } from '../common' +import type { IEventContext } from '.' +import type { IShowStyleUserContext } from './showStyleContext' +import type { + IBlueprintMutatablePart, + IBlueprintPart, + IBlueprintPartInstance, + IBlueprintPiece, + IBlueprintPieceDB, + IBlueprintPieceInstance, + IBlueprintResolvedPieceInstance, +} from '../documents' +import type { PeripheralDeviceId } from '@sofie-automation/shared-lib/dist/core/model/Ids' +import type { TSR } from '../timeline' +import type { IBlueprintPlayoutDevice } from '..' + +/** Actions */ +export interface IDataStoreActionExecutionContext extends IShowStyleUserContext, IEventContext { + /** + * Setting a value in the datastore allows us to overwrite parts of a timeline content object with that value + * @param key Key to use when referencing from the timeline object + * @param value Value to overwrite the timeline object's content with + * @param mode In temporary mode the value may be removed when the key is no longer on the timeline + */ + setTimelineDatastoreValue(key: string, value: any, mode: DatastorePersistenceMode): Promise + /** Deletes a previously set value from the datastore */ + removeTimelineDatastoreValue(key: string): Promise +} + +export interface IActionExecutionContext + extends IShowStyleUserContext, + IEventContext, + IDataStoreActionExecutionContext { + /** Data fetching */ + // getIngestRundown(): IngestRundown // TODO - for which part? + /** Get a PartInstance which can be modified */ + getPartInstance(part: 'current' | 'next'): Promise + /** Get the PieceInstances for a modifiable PartInstance */ + getPieceInstances(part: 'current' | 'next'): Promise + /** Get the resolved PieceInstances for a modifiable PartInstance */ + getResolvedPieceInstances(part: 'current' | 'next'): Promise + /** Get the last active piece on given layer */ + findLastPieceOnLayer( + sourceLayerId: string | string[], + options?: { + excludeCurrentPart?: boolean + originalOnly?: boolean + pieceMetaDataFilter?: any // Mongo query against properties inside of piece.metaData + } + ): Promise + /** Get the previous scripted piece on a given layer, looking backwards from the current part. */ + findLastScriptedPieceOnLayer( + sourceLayerId: string | string[], + options?: { + excludeCurrentPart?: boolean + pieceMetaDataFilter?: any + } + ): Promise + /** Gets the PartInstance for a PieceInstance retrieved from findLastPieceOnLayer. This primarily allows for accessing metadata of the PartInstance */ + getPartInstanceForPreviousPiece(piece: IBlueprintPieceInstance): Promise + /** Gets the Part for a Piece retrieved from findLastScriptedPieceOnLayer. This primarily allows for accessing metadata of the Part */ + getPartForPreviousPiece(piece: IBlueprintPieceDB): Promise + /** Fetch the showstyle config for the specified part */ + // getNextShowStyleConfig(): Readonly<{ [key: string]: ConfigItemValue }> + + /** Creative actions */ + /** Insert a pieceInstance. Returns id of new PieceInstance. Any timelineObjects will have their ids changed, so are not safe to reference from another piece */ + insertPiece(part: 'current' | 'next', piece: IBlueprintPiece): Promise + /** Update a piecesInstance */ + updatePieceInstance(pieceInstanceId: string, piece: Partial): Promise + /** Insert a queued part to follow the current part */ + queuePart(part: IBlueprintPart, pieces: IBlueprintPiece[]): Promise + /** Update a partInstance */ + updatePartInstance( + part: 'current' | 'next', + props: Partial + ): Promise + + /** Destructive actions */ + /** Stop any piecesInstances on the specified sourceLayers. Returns ids of piecesInstances that were affected */ + stopPiecesOnLayers(sourceLayerIds: string[], timeOffset?: number): Promise + /** Stop piecesInstances by id. Returns ids of piecesInstances that were removed */ + stopPieceInstances(pieceInstanceIds: string[], timeOffset?: number): Promise + /** Remove piecesInstances by id. Returns ids of piecesInstances that were removed. Note: For now we only allow removing from the next, but this might change to include current if there is justification */ + removePieceInstances(part: 'next', pieceInstanceIds: string[]): Promise + + /** Move the next part through the rundown. Can move by either a number of parts, or segments in either direction. */ + moveNextPart(partDelta: number, segmentDelta: number): Promise + /** Set flag to perform take after executing the current action. Returns state of the flag after each call. */ + takeAfterExecuteAction(take: boolean): Promise + /** Inform core that a take out of the current partinstance should be blocked until the specified time */ + blockTakeUntil(time: Time | null): Promise + + /** Misc actions */ + // updateAction(newManifest: Pick): void // only updates itself. to allow for the next one to do something different + // executePeripheralDeviceAction(deviceId: string, functionName: string, args: any[]): Promise + // openUIDialogue(message: string) // ????? + /** Returns a list of the PeripheralDevices */ + listPlayoutDevices(): Promise + /** Execute an action on a certain PeripheralDevice */ + executeTSRAction( + deviceId: PeripheralDeviceId, + actionId: string, + payload: Record + ): Promise +} diff --git a/packages/blueprints-integration/src/context/baseContext.ts b/packages/blueprints-integration/src/context/baseContext.ts new file mode 100644 index 0000000000..92f90b861d --- /dev/null +++ b/packages/blueprints-integration/src/context/baseContext.ts @@ -0,0 +1,64 @@ +/** + * Base context type that all others should extend from. + * This is to provide logging and some other utilities + */ +export interface ICommonContext { + /** + * Hash a string. Will return a unique string, to be used for all _id:s that are to be inserted in database + * @param originString A representation of the origin of the hash (for logging) + * @param originIsNotUnique If the originString is not guaranteed to be unique, set this to true + */ + getHashId: (originString: string, originIsNotUnique?: boolean) => string + /** Un-hash, is return the string that created the hash */ + unhashId: (hash: string) => string + + /** Log a message to the sofie log with level 'debug' */ + logDebug: (message: string) => void + /** Log a message to the sofie log with level 'info' */ + logInfo: (message: string) => void + /** Log a message to the sofie log with level 'warn' */ + logWarning: (message: string) => void + /** Log a message to the sofie log with level 'error' */ + logError: (message: string) => void +} + +export function isCommonContext(obj: unknown): obj is ICommonContext { + if (!obj || typeof obj !== 'object') { + return false + } + + const { getHashId, unhashId, logDebug, logInfo, logWarning, logError } = obj as ICommonContext + + return ( + typeof getHashId === 'function' && + typeof unhashId === 'function' && + typeof logDebug === 'function' && + typeof logInfo === 'function' && + typeof logWarning === 'function' && + typeof logError === 'function' + ) +} + +export interface IUserNotesContext extends ICommonContext { + /** Display a notification to the user of an error */ + notifyUserError(message: string, params?: { [key: string]: any }): void + /** Display a notification to the user of an warning */ + notifyUserWarning(message: string, params?: { [key: string]: any }): void + /** Display a notification to the user of a note */ + notifyUserInfo(message: string, params?: { [key: string]: any }): void +} + +export function isUserNotesContext(obj: unknown): obj is IUserNotesContext { + if (!isCommonContext(obj)) { + return false + } + + // eslint-disable-next-line @typescript-eslint/unbound-method + const { notifyUserError, notifyUserWarning, notifyUserInfo } = obj as IUserNotesContext + + return ( + typeof notifyUserError === 'function' && + typeof notifyUserWarning === 'function' && + typeof notifyUserInfo === 'function' + ) +} diff --git a/packages/blueprints-integration/src/context/eventContext.ts b/packages/blueprints-integration/src/context/eventContext.ts new file mode 100644 index 0000000000..271ba20871 --- /dev/null +++ b/packages/blueprints-integration/src/context/eventContext.ts @@ -0,0 +1,75 @@ +import type { OnGenerateTimelineObj, TSR } from '../timeline' +import type { IBlueprintPartInstance, IBlueprintPieceInstance, IBlueprintSegmentDB } from '../documents' +import type { IRundownContext } from './rundownContext' +import type { IBlueprintExternalMessageQueueObj } from '../message' + +export interface IEventContext { + getCurrentTime(): number +} + +export interface ITimelineEventContext extends IEventContext, IRundownContext { + readonly currentPartInstance: Readonly | undefined + readonly nextPartInstance: Readonly | undefined + readonly previousPartInstance: Readonly | undefined + + /** + * Get the full session id for an ab playback session. + * Note: sessionName should be unique within the segment unless pieces want to share a session + * @deprecated use the core provided AB implementation instead + */ + getPieceABSessionId(piece: IBlueprintPieceInstance, sessionName: string): string + /** + * Get the full session id for a timelineobject that belongs to an ab playback session + * sessionName should also be used in calls to getPieceABSessionId for the owning piece + * @deprecated use the core provided AB implementation instead + */ + getTimelineObjectAbSessionId( + obj: OnGenerateTimelineObj, + sessionName: string + ): string | undefined +} + +export interface IPartEventContext extends IEventContext, IRundownContext { + readonly part: Readonly +} + +export interface IRundownDataChangedEventContext extends IEventContext, IRundownContext { + formatDateAsTimecode(time: number): string + formatDurationAsTimecode(time: number): string + + /** Get all unsent and queued messages in the rundown */ + getAllUnsentQueuedMessages(): Promise> +} + +export interface IRundownTimingEventContext extends IRundownDataChangedEventContext { + readonly previousPart: Readonly | undefined + readonly currentPart: Readonly + readonly nextPart: Readonly | undefined + + /** + * Returns the first PartInstance in the Rundown within the current playlist activation. + * This allows for a start time for the Rundown to be determined + * @param allowUntimed Whether to consider a Part which has the untimed property set + */ + getFirstPartInstanceInRundown(allowUntimed?: boolean): Promise> + + /** + * Returns the partInstances in the Segment, limited to the playthrough of the segment that refPartInstance is part of + * @param refPartInstance PartInstance to use as the basis of the search + */ + getPartInstancesInSegmentPlayoutId( + refPartInstance: Readonly + ): Promise> + + /** + * Returns pieces in a partInstance + * @param id Id of partInstance to fetch items in + */ + getPieceInstances(...partInstanceIds: string[]): Promise> + + /** + * Returns a segment + * @param id Id of segment to fetch + */ + getSegment(id: string): Promise | undefined> +} diff --git a/packages/blueprints-integration/src/context/index.ts b/packages/blueprints-integration/src/context/index.ts new file mode 100644 index 0000000000..6d411bb400 --- /dev/null +++ b/packages/blueprints-integration/src/context/index.ts @@ -0,0 +1,8 @@ +export * from './adlibActionContext' +export * from './baseContext' +export * from './eventContext' +export * from './packageInfoContext' +export * from './rundownContext' +export * from './showStyleContext' +export * from './studioContext' +export * from './syncIngestChangesContext' diff --git a/packages/blueprints-integration/src/context/packageInfoContext.ts b/packages/blueprints-integration/src/context/packageInfoContext.ts new file mode 100644 index 0000000000..fd96343be7 --- /dev/null +++ b/packages/blueprints-integration/src/context/packageInfoContext.ts @@ -0,0 +1,12 @@ +import type { PackageInfo } from '../packageInfo' + +export interface IPackageInfoContext { + /** + * Get the PackageInfo items for an ExpectedPackage, if any have been reported by the package manager. + * Only info for packages with the `listenToPackageInfoUpdates` property set to true can be returned. + * The possible packageIds are scoped based on the ownership of the package. + * eg, baseline packages can be accessed when generating the baseline objects, piece/adlib packages can be access when regenerating the segment they are from + */ + getPackageInfo: (packageId: string) => Readonly + hackGetMediaObjectDuration: (mediaId: string) => Promise +} diff --git a/packages/blueprints-integration/src/context/rundownContext.ts b/packages/blueprints-integration/src/context/rundownContext.ts new file mode 100644 index 0000000000..8cd3dbaa05 --- /dev/null +++ b/packages/blueprints-integration/src/context/rundownContext.ts @@ -0,0 +1,35 @@ +import type { PeripheralDeviceId } from '@sofie-automation/shared-lib/dist/core/model/Ids' +import type { TSR } from '../timeline' +import type { IBlueprintSegmentRundown } from '../documents' +import type { IUserNotesContext } from './baseContext' +import type { IPackageInfoContext } from './packageInfoContext' +import type { IShowStyleContext } from './showStyleContext' +import type { IBlueprintPlayoutDevice } from '../lib' + +export interface IRundownContext extends IShowStyleContext { + readonly rundownId: string + readonly playlistId: string + readonly rundown: Readonly +} + +export interface IRundownUserContext extends IUserNotesContext, IRundownContext {} + +export interface IRundownActivationContext extends IRundownContext { + /** Execute an action on a certain PeripheralDevice */ + executeTSRAction( + deviceId: PeripheralDeviceId, + actionId: string, + payload: Record + ): Promise + /** Returns a list of the PeripheralDevices */ + listPlayoutDevices(): Promise +} + +export interface ISegmentUserContext extends IUserNotesContext, IRundownContext, IPackageInfoContext { + /** Display a notification to the user of an error */ + notifyUserError: (message: string, params?: { [key: string]: any }, partExternalId?: string) => void + /** Display a notification to the user of an warning */ + notifyUserWarning: (message: string, params?: { [key: string]: any }, partExternalId?: string) => void + /** Display a notification to the user of a note */ + notifyUserInfo: (message: string, params?: { [key: string]: any }, partExternalId?: string) => void +} diff --git a/packages/blueprints-integration/src/context/showStyleContext.ts b/packages/blueprints-integration/src/context/showStyleContext.ts new file mode 100644 index 0000000000..96197d0076 --- /dev/null +++ b/packages/blueprints-integration/src/context/showStyleContext.ts @@ -0,0 +1,27 @@ +import type { IOutputLayer, ISourceLayer } from '../showStyle' +import type { IBlueprintRundownPlaylist } from '../documents' +import type { ICommonContext, IUserNotesContext } from './baseContext' +import type { IPackageInfoContext } from './packageInfoContext' +import type { IStudioContext } from './studioContext' + +export interface IShowStyleContext extends ICommonContext, IStudioContext { + /** Returns a ShowStyle blueprint config. If ShowStyleBlueprintManifest.preprocessConfig is provided, a config preprocessed by that function is returned, otherwise it is returned unprocessed */ + getShowStyleConfig: () => unknown + /** Returns a reference to a showStyle config value, that can later be resolved in Core */ + getShowStyleConfigRef(configKey: string): string + /** Get source layers for the ShowStyle */ + getShowStyleSourceLayers(): Record + /** Get output layers for the ShowStyle */ + getShowStyleOutputLayers(): Record +} + +export interface IShowStyleUserContext extends IUserNotesContext, IShowStyleContext, IPackageInfoContext {} + +export interface IGetRundownContext extends IShowStyleUserContext { + /** Returns a list of the Playlists in the studio */ + getPlaylists: () => Promise> + /** Returns the Playlist in which the Rundown currently is in. If it's a new Rundown, this will return undefined. */ + getCurrentPlaylist: () => Promise | undefined> + /** Returns a randomized string, intended to be used as ids. */ + getRandomId: () => string +} diff --git a/packages/blueprints-integration/src/context/studioContext.ts b/packages/blueprints-integration/src/context/studioContext.ts new file mode 100644 index 0000000000..5ec53adbc6 --- /dev/null +++ b/packages/blueprints-integration/src/context/studioContext.ts @@ -0,0 +1,20 @@ +import type { BlueprintMappings } from '@sofie-automation/shared-lib/dist/core/model/Timeline' +import type { ICommonContext, IUserNotesContext } from './baseContext' +import type { IPackageInfoContext } from './packageInfoContext' + +export interface IStudioContext extends ICommonContext { + /** The id of the studio */ + readonly studioId: string + + /** Returns the Studio blueprint config. If StudioBlueprintManifest.preprocessConfig is provided, a config preprocessed by that function is returned, otherwise it is returned unprocessed */ + getStudioConfig: () => unknown + /** Returns a reference to a studio config value, that can later be resolved in Core */ + getStudioConfigRef(configKey: string): string + + /** Get the mappings for the studio */ + getStudioMappings: () => Readonly +} + +export interface IStudioBaselineContext extends IStudioContext, IPackageInfoContext {} + +export interface IStudioUserContext extends IUserNotesContext, IStudioContext {} diff --git a/packages/blueprints-integration/src/context/syncIngestChangesContext.ts b/packages/blueprints-integration/src/context/syncIngestChangesContext.ts new file mode 100644 index 0000000000..6b77477888 --- /dev/null +++ b/packages/blueprints-integration/src/context/syncIngestChangesContext.ts @@ -0,0 +1,44 @@ +import type { IRundownUserContext } from './rundownContext' +import type { + IBlueprintMutatablePart, + IBlueprintPartInstance, + IBlueprintPiece, + IBlueprintPieceInstance, +} from '../documents' + +export interface ISyncIngestUpdateToPartInstanceContext extends IRundownUserContext { + /** 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, + mutatedPiece?: Omit + ): IBlueprintPieceInstance + + /** Insert a pieceInstance. Returns id of new PieceInstance. Any timelineObjects will have their ids changed, so are not safe to reference from another piece */ + insertPieceInstance(piece: IBlueprintPiece): IBlueprintPieceInstance + /** Update a pieceInstance */ + updatePieceInstance(pieceInstanceId: string, piece: Partial): IBlueprintPieceInstance + /** Remove a pieceInstance */ + removePieceInstances(...pieceInstanceIds: string[]): string[] + + // Upcoming interface: + // /** Insert a AdlibInstance. Returns id of new AdlibInstance. Any timelineObjects will have their ids changed, so are not safe to reference from another piece */ + // insertAdlibInstance(adlibPiece: IBlueprintAdLibPiece): IBlueprintAdlibPieceInstance + // /** Update a AdlibInstance */ + // updateAdlibInstance(adlibInstanceId: string, adlibPiece: Partial>): IBlueprintAdlibPieceInstance + // /** Remove a AdlibInstance */ + // removeAdlibInstances(...adlibInstanceId: string[]): string[] + + // Upcoming interface: + // /** Insert a ActionInstance. Returns id of new ActionInstance. Any timelineObjects will have their ids changed, so are not safe to reference from another piece */ + // insertActionInstance(action: IBlueprintAdlibAction): IBlueprintAdlibActionInstance + // /** Update a ActionInstance */ + // updateActionInstance(actionInstanceId: string, action: Partial>): IBlueprintAdlibActionInstance + // /** Remove a ActionInstance */ + // removeActionInstances(...actionInstanceIds: string[]): string[] + + /** Update a partInstance */ + updatePartInstance(props: Partial): IBlueprintPartInstance + + /** Remove the partInstance. This is only valid when `playstatus: 'next'` */ + removePartInstance(): void +}