Skip to content

Commit 0d1552d

Browse files
authored
feat: Add getUpcomingParts to action context (#1524)
So that an action can be taken based on what items may be coming up (further ahead than the next part instance)
1 parent e123abc commit 0d1552d

File tree

4 files changed

+63
-2
lines changed

4 files changed

+63
-2
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { ReadonlyDeep } from 'type-fest'
12
import {
23
IBlueprintMutatablePart,
34
IBlueprintPart,
@@ -48,6 +49,13 @@ export interface IPartAndPieceActionContext {
4849
/** Gets the Segment. This primarily allows for accessing metadata */
4950
getSegment(segment: 'current' | 'next'): Promise<IBlueprintSegment | undefined>
5051

52+
/** Get a list of the upcoming Parts in the Rundown, in the order that they will be Taken
53+
*
54+
* @param limit The max number of parts returned. Default is 5.
55+
* @returns An array of Parts. If there is no next part, the array will be empty.
56+
*/
57+
getUpcomingParts(limit?: number): Promise<ReadonlyDeep<IBlueprintPart[]>>
58+
5159
/**
5260
* Creative actions
5361
*/

packages/job-worker/src/blueprints/__tests__/context-OnTakeContext.test.ts

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
11
/* eslint-disable @typescript-eslint/unbound-method */
22
import { IBlueprintMutatablePart, IBlueprintPiece } from '@sofie-automation/blueprints-integration'
3-
import { PlayoutModel } from '../../playout/model/PlayoutModel.js'
43
import { WatchedPackagesHelper } from '../context/watchedPackages.js'
54
import { JobContext, ProcessedShowStyleCompound } from '../../jobs/index.js'
65
import { mock } from 'jest-mock-extended'
76
import { PartAndPieceInstanceActionService } from '../context/services/PartAndPieceInstanceActionService.js'
87
import { OnTakeContext } from '../context/index.js'
8+
import { DBPart } from '@sofie-automation/corelib/dist/dataModel/Part'
9+
import { PartId, RundownId, SegmentId } from '@sofie-automation/corelib/dist/dataModel/Ids'
10+
import { protectString } from '@sofie-automation/corelib/dist/protectedString'
11+
import { PlayoutModelImpl } from '../../playout/model/implementation/PlayoutModelImpl.js'
912

1013
describe('Test blueprint api context', () => {
1114
async function getTestee() {
15+
const mockPlayoutModel = mock<PlayoutModelImpl>()
1216
const mockActionService = mock<PartAndPieceInstanceActionService>()
1317
const context = new OnTakeContext(
1418
{
1519
name: 'fakeContext',
1620
identifier: 'action',
1721
},
1822
mock<JobContext>(),
19-
mock<PlayoutModel>(),
23+
mockPlayoutModel,
2024
mock<ProcessedShowStyleCompound>(),
2125
mock<WatchedPackagesHelper>(),
2226
mockActionService
@@ -25,6 +29,7 @@ describe('Test blueprint api context', () => {
2529
return {
2630
context,
2731
mockActionService,
32+
mockPlayoutModel,
2833
}
2934
}
3035

@@ -99,6 +104,42 @@ describe('Test blueprint api context', () => {
99104
expect(mockActionService.getPartForPreviousPiece).toHaveBeenCalledWith({ _id: 'pieceId' })
100105
})
101106

107+
test('getUpcomingParts', async () => {
108+
const { context, mockPlayoutModel } = await getTestee()
109+
110+
mockPlayoutModel.getAllOrderedParts.mockReturnValue(
111+
mock([
112+
{
113+
_id: protectString<PartId>('part1'),
114+
title: 'Part 1',
115+
invalid: false,
116+
floated: false,
117+
_rank: 1,
118+
rundownId: protectString<RundownId>('rundown1'),
119+
externalId: 'ext1',
120+
segmentId: protectString<SegmentId>('seg1'),
121+
expectedDurationWithTransition: 1000,
122+
userEditOperations: [],
123+
} as DBPart,
124+
{
125+
_id: protectString<PartId>('part2'),
126+
title: 'Part 2',
127+
invalid: false,
128+
floated: false,
129+
_rank: 1,
130+
rundownId: protectString<RundownId>('rundown1'),
131+
externalId: 'ext1',
132+
segmentId: protectString<SegmentId>('seg1'),
133+
expectedDurationWithTransition: 1000,
134+
userEditOperations: [],
135+
} as unknown as DBPart,
136+
])
137+
)
138+
139+
const parts = await context.getUpcomingParts()
140+
expect(parts.map((i) => i.title)).toEqual(['Part 1', 'Part 2'])
141+
})
142+
102143
test('insertPiece', async () => {
103144
const { context, mockActionService } = await getTestee()
104145

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import { JobContext, ProcessedShowStyleCompound } from '../../jobs/index.js'
2525
import { executePeripheralDeviceAction, listPlayoutDevices } from '../../peripheralDevice.js'
2626
import { ActionPartChange, PartAndPieceInstanceActionService } from './services/PartAndPieceInstanceActionService.js'
2727
import { BlueprintQuickLookInfo } from '@sofie-automation/blueprints-integration/dist/context/quickLoopInfo'
28+
import { getOrderedPartsAfterPlayhead } from '../../playout/lookahead/util.js'
29+
import { convertPartToBlueprints } from './lib.js'
2830

2931
export class OnTakeContext extends ShowStyleUserContext implements IOnTakeContext, IEventContext {
3032
public isTakeAborted: boolean
@@ -52,6 +54,10 @@ export class OnTakeContext extends ShowStyleUserContext implements IOnTakeContex
5254
this.isTakeAborted = false
5355
}
5456

57+
async getUpcomingParts(limit: number = 5): Promise<ReadonlyDeep<IBlueprintPart[]>> {
58+
return getOrderedPartsAfterPlayhead(this._context, this._playoutModel, limit).map(convertPartToBlueprints)
59+
}
60+
5561
abortTake(): void {
5662
this.isTakeAborted = true
5763
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ import { executePeripheralDeviceAction, listPlayoutDevices } from '../../periphe
3232
import { ActionPartChange, PartAndPieceInstanceActionService } from './services/PartAndPieceInstanceActionService.js'
3333
import { BlueprintQuickLookInfo } from '@sofie-automation/blueprints-integration/dist/context/quickLoopInfo'
3434
import { setNextPartFromPart } from '../../playout/setNext.js'
35+
import { getOrderedPartsAfterPlayhead } from '../../playout/lookahead/util.js'
36+
import { convertPartToBlueprints } from './lib.js'
3537

3638
export class DatastoreActionExecutionContext
3739
extends ShowStyleUserContext
@@ -102,6 +104,10 @@ export class ActionExecutionContext extends ShowStyleUserContext implements IAct
102104
super(contextInfo, _context, showStyle, watchedPackages)
103105
}
104106

107+
async getUpcomingParts(limit: number = 5): Promise<ReadonlyDeep<IBlueprintPart[]>> {
108+
return getOrderedPartsAfterPlayhead(this._context, this._playoutModel, limit).map(convertPartToBlueprints)
109+
}
110+
105111
async getPartInstance(part: 'current' | 'next'): Promise<IBlueprintPartInstance | undefined> {
106112
return this.partAndPieceInstanceService.getPartInstance(part)
107113
}

0 commit comments

Comments
 (0)