Skip to content

Commit 007a9da

Browse files
authored
feat: replace wasActive in onRundownActivate with context (Sofie-Automation#1514)
feat: replace `wasActive` in onRundownActivate with previousState&currentState in RundownActivationContext. Also changed the algorithm in handleResetRundownPlaylist, so that activateRundownPlaylist always runs This is to provide better context for blueprints, so that they can determine if a RundownPlaylist is being Activated from idle, from Rehersal or a Reset
1 parent 76dfbd2 commit 007a9da

File tree

7 files changed

+96
-29
lines changed

7 files changed

+96
-29
lines changed

packages/blueprints-integration/src/api/showStyle.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,13 @@ export interface ShowStyleBlueprintManifest<TRawConfig = IBlueprintConfig, TProc
195195

196196
// Events
197197

198-
onRundownActivate?: (context: IRundownActivationContext, wasActive: boolean) => Promise<void>
198+
/**
199+
* Called when a RundownPlaylist has been activated
200+
*/
201+
onRundownActivate?: (context: IRundownActivationContext) => Promise<void>
202+
/** Called upon the first take in a RundownPlaylist */
199203
onRundownFirstTake?: (context: IPartEventContext) => Promise<void>
204+
/** Called when a RundownPlaylist has been deactivated */
200205
onRundownDeActivate?: (context: IRundownActivationContext) => Promise<void>
201206

202207
/** Called before a Take action */

packages/blueprints-integration/src/context/rundownContext.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ export interface IRundownContext extends IShowStyleContext {
1313

1414
export interface IRundownUserContext extends IUserNotesContext, IRundownContext {}
1515

16-
export interface IRundownActivationContext extends IRundownContext, IExecuteTSRActionsContext, IDataStoreMethods {}
16+
export interface IRundownActivationContext extends IRundownContext, IExecuteTSRActionsContext, IDataStoreMethods {
17+
/** Info about the RundownPlaylist state before the Activation / Deactivation event */
18+
readonly previousState: IRundownActivationContextState
19+
readonly currentState: IRundownActivationContextState
20+
}
1721

1822
export interface ISegmentUserContext extends IUserNotesContext, IRundownContext, IPackageInfoContext {
1923
/** Display a notification to the user of an error */
@@ -23,3 +27,13 @@ export interface ISegmentUserContext extends IUserNotesContext, IRundownContext,
2327
/** Display a notification to the user of a note */
2428
notifyUserInfo: (message: string, params?: { [key: string]: any }, partExternalId?: string) => void
2529
}
30+
31+
/** Info about the RundownPlaylist state at a point in time */
32+
export interface IRundownActivationContextState {
33+
/** If the playlist was active */
34+
active: boolean
35+
/** If the playlist was in rehearsal mode */
36+
rehearsal: boolean
37+
/** Timestamp when the playlist was last reset. Used to silence a few errors upon reset.*/
38+
resetTime?: number
39+
}

packages/corelib/src/worker/studio.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,9 @@ export type ActivateHoldProps = RundownPlayoutPropsBase
238238
export type DeactivateHoldProps = RundownPlayoutPropsBase
239239
export type PrepareRundownForBroadcastProps = RundownPlayoutPropsBase
240240
export interface ResetRundownPlaylistProps extends RundownPlayoutPropsBase {
241+
/** If set, also activate the RundownPlaylist */
241242
activate?: 'active' | 'rehearsal'
243+
/** If true and `activate` is set, deactivates any other active Playlists and activates this one. */
242244
forceActivate?: boolean
243245
}
244246
export interface ActivateRundownPlaylistProps extends RundownPlayoutPropsBase {

packages/job-worker/src/blueprints/context/RundownActivationContext.ts

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
DatastorePersistenceMode,
33
IBlueprintPlayoutDevice,
44
IRundownActivationContext,
5+
IRundownActivationContextState,
56
TSR,
67
} from '@sofie-automation/blueprints-integration'
78
import { PeripheralDeviceId } from '@sofie-automation/shared-lib/dist/core/model/Ids'
@@ -17,22 +18,38 @@ export class RundownActivationContext extends RundownEventContext implements IRu
1718
private readonly _playoutModel: PlayoutModel
1819
private readonly _context: JobContext
1920

21+
private readonly _previousState: IRundownActivationContextState
22+
private readonly _currentState: IRundownActivationContextState
23+
2024
constructor(
2125
context: JobContext,
22-
playoutModel: PlayoutModel,
23-
showStyleCompound: ReadonlyDeep<ProcessedShowStyleCompound>,
24-
rundown: ReadonlyDeep<DBRundown>
26+
options: {
27+
playoutModel: PlayoutModel
28+
showStyle: ReadonlyDeep<ProcessedShowStyleCompound>
29+
rundown: ReadonlyDeep<DBRundown>
30+
previousState: IRundownActivationContextState
31+
currentState: IRundownActivationContextState
32+
}
2533
) {
2634
super(
2735
context.studio,
2836
context.getStudioBlueprintConfig(),
29-
showStyleCompound,
30-
context.getShowStyleBlueprintConfig(showStyleCompound),
31-
rundown
37+
options.showStyle,
38+
context.getShowStyleBlueprintConfig(options.showStyle),
39+
options.rundown
3240
)
3341

3442
this._context = context
35-
this._playoutModel = playoutModel
43+
this._playoutModel = options.playoutModel
44+
this._previousState = options.previousState
45+
this._currentState = options.currentState
46+
}
47+
48+
get previousState(): IRundownActivationContextState {
49+
return this._previousState
50+
}
51+
get currentState(): IRundownActivationContextState {
52+
return this._currentState
3653
}
3754

3855
async listPlayoutDevices(): Promise<IBlueprintPlayoutDevice[]> {

packages/job-worker/src/playout/activePlaylistActions.ts

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { getCurrentTime } from '../lib/index.js'
88
import { logger } from '../logging.js'
99
import { getActiveRundownPlaylistsInStudioFromDb } from '../studio/lib.js'
1010
import { cleanTimelineDatastore } from './datastore.js'
11-
import { resetRundownPlaylist } from './lib.js'
11+
import { getActivationContextState, resetRundownPlaylist } from './lib.js'
1212
import { PlayoutModel } from './model/PlayoutModel.js'
1313
import { selectNextPart } from './selectNextPart.js'
1414
import { setNextPart } from './setNext.js'
@@ -17,12 +17,12 @@ import { updateStudioTimeline, updateTimeline } from './timeline/generate.js'
1717
export async function activateRundownPlaylist(
1818
context: JobContext,
1919
playoutModel: PlayoutModel,
20-
rehearsal: boolean
20+
rehearsal: boolean,
21+
forceReset?: boolean
2122
): Promise<void> {
2223
logger.info('Activating rundown ' + playoutModel.playlist._id + (rehearsal ? ' (Rehearsal)' : ''))
2324

2425
rehearsal = !!rehearsal
25-
const wasActive = !!playoutModel.playlist.activationId
2626

2727
const anyOtherActiveRundowns = await getActiveRundownPlaylistsInStudioFromDb(
2828
context,
@@ -37,8 +37,10 @@ export async function activateRundownPlaylist(
3737
JSON.stringify(otherActiveIds)
3838
)
3939
}
40+
// Get the ActivationContext state, for later use. (This must be done before any actions are done on the PlayoutModel)
41+
const previousState = getActivationContextState(playoutModel)
4042

41-
if (!playoutModel.playlist.activationId) {
43+
if (!playoutModel.playlist.activationId || forceReset) {
4244
// Reset the playlist if it wasnt already active
4345
await resetRundownPlaylist(context, playoutModel)
4446
}
@@ -93,37 +95,58 @@ export async function activateRundownPlaylist(
9395

9496
await updateTimeline(context, playoutModel)
9597

98+
// Get the ActivationContext state, for later use. (This must be done after all actions are done on the PlayoutModel)
99+
const currentState = getActivationContextState(playoutModel)
100+
96101
playoutModel.deferBeforeSave(async () => {
97102
if (!rundown) return // if the proper rundown hasn't been found, there's little point doing anything else
98103
const showStyle = await context.getShowStyleCompound(rundown.showStyleVariantId, rundown.showStyleBaseId)
99104
const blueprint = await context.getShowStyleBlueprint(showStyle._id)
100105

101106
try {
102107
if (blueprint.blueprint.onRundownActivate) {
103-
const blueprintContext = new RundownActivationContext(context, playoutModel, showStyle, rundown)
104-
105-
await blueprint.blueprint.onRundownActivate(blueprintContext, wasActive)
108+
const blueprintContext = new RundownActivationContext(context, {
109+
playoutModel,
110+
showStyle,
111+
rundown,
112+
previousState,
113+
currentState,
114+
})
115+
116+
await blueprint.blueprint.onRundownActivate(blueprintContext)
106117
}
107118
} catch (err) {
108119
logger.error(`Error in showStyleBlueprint.onRundownActivate: ${stringifyError(err)}`)
109120
}
110121
})
111122
}
112123
export async function deactivateRundownPlaylist(context: JobContext, playoutModel: PlayoutModel): Promise<void> {
124+
// Get the ActivationContext state, for later use. (This must be done before any actions are done on the PlayoutModel)
125+
const previousState = getActivationContextState(playoutModel)
126+
113127
const rundown = await deactivateRundownPlaylistInner(context, playoutModel)
114128

115129
await updateStudioTimeline(context, playoutModel)
116130

117131
await cleanTimelineDatastore(context, playoutModel)
118132

133+
// Get the ActivationContext state, for later use. (This must be done after all actions are done on the PlayoutModel)
134+
const currentState = getActivationContextState(playoutModel)
135+
119136
playoutModel.deferBeforeSave(async () => {
120137
if (rundown) {
121138
const showStyle = await context.getShowStyleCompound(rundown.showStyleVariantId, rundown.showStyleBaseId)
122139
const blueprint = await context.getShowStyleBlueprint(showStyle._id)
123140

124141
try {
125142
if (blueprint.blueprint.onRundownDeActivate) {
126-
const blueprintContext = new RundownActivationContext(context, playoutModel, showStyle, rundown)
143+
const blueprintContext = new RundownActivationContext(context, {
144+
playoutModel,
145+
showStyle,
146+
rundown,
147+
previousState,
148+
currentState,
149+
})
127150
await blueprint.blueprint.onRundownDeActivate(blueprintContext)
128151
}
129152
} catch (err) {

packages/job-worker/src/playout/activePlaylistJobs.ts

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
import { JobContext } from '../jobs/index.js'
1010
import { runJobWithPlayoutModel } from './lock.js'
1111
import { resetRundownPlaylist } from './lib.js'
12-
import { updateTimeline } from './timeline/generate.js'
1312
import { getActiveRundownPlaylistsInStudioFromDb } from '../studio/lib.js'
1413
import {
1514
activateRundownPlaylist,
@@ -53,9 +52,7 @@ export async function handlePrepareRundownPlaylistForBroadcast(
5352
await checkNoOtherPlaylistsActive(context, playlist)
5453
},
5554
async (playoutModel) => {
56-
await resetRundownPlaylist(context, playoutModel)
57-
58-
await activateRundownPlaylist(context, playoutModel, true) // Activate rundownPlaylist (rehearsal)
55+
await activateRundownPlaylist(context, playoutModel, true, true) // Activate rundownPlaylist (rehearsal)
5956
}
6057
)
6158
}
@@ -110,14 +107,16 @@ export async function handleResetRundownPlaylist(context: JobContext, data: Rese
110107
}
111108
},
112109
async (playoutModel) => {
113-
await resetRundownPlaylist(context, playoutModel)
110+
if (playoutModel.playlist.activationId || data.activate !== undefined) {
111+
const goToRehearsal =
112+
data.activate === undefined
113+
? (playoutModel.playlist.rehearsal ?? false)
114+
: data.activate === 'rehearsal'
114115

115-
if (data.activate) {
116-
// Do the activation
117-
await activateRundownPlaylist(context, playoutModel, data.activate !== 'active') // Activate rundown
118-
} else if (playoutModel.playlist.activationId) {
119-
// Only update the timeline if this is the active playlist
120-
await updateTimeline(context, playoutModel)
116+
await activateRundownPlaylist(context, playoutModel, goToRehearsal, true) // Activate rundown
117+
} else {
118+
// If the Playlist is inactive, and we are not activating it, just reset it:
119+
await resetRundownPlaylist(context, playoutModel)
121120
}
122121
}
123122
)

packages/job-worker/src/playout/lib.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { TimelineObjGeneric } from '@sofie-automation/corelib/dist/dataModel/Timeline'
22
import { applyToArray, clone } from '@sofie-automation/corelib/dist/lib'
3-
import { TSR } from '@sofie-automation/blueprints-integration'
3+
import { TSR, IRundownActivationContextState } from '@sofie-automation/blueprints-integration'
44
import { JobContext } from '../jobs/index.js'
55
import { DBPartInstance } from '@sofie-automation/corelib/dist/dataModel/PartInstance'
66
import { PartInstanceId } from '@sofie-automation/corelib/dist/dataModel/Ids'
@@ -203,3 +203,10 @@ export async function updateTimelineFromStudioPlayoutModel(
203203
await updateStudioTimeline(context, studioPlayoutModel)
204204
}
205205
}
206+
export function getActivationContextState(playoutModel: PlayoutModel): IRundownActivationContextState {
207+
return {
208+
active: playoutModel.playlist.activationId ? true : false,
209+
rehearsal: playoutModel.playlist.rehearsal ? true : false,
210+
resetTime: playoutModel.playlist.resetTime,
211+
}
212+
}

0 commit comments

Comments
 (0)