@@ -94,6 +94,7 @@ export async function syncChangesToPartInstances(
9494/**
9595 * Internal worker for syncing changes to PartInstances
9696 * Exposed for testing purposes
97+ * Note: many methods are public so that they can be spied on in tests
9798 */
9899export class SyncChangesToPartInstancesWorker {
99100 readonly #context: JobContext
@@ -180,16 +181,16 @@ export class SyncChangesToPartInstancesWorker {
180181 }
181182
182183 async syncChangesToPartInstance ( instanceToSync : PartInstanceToSync ) : Promise < void > {
183- const { existingPartInstance, previousPartInstance, playStatus, newPart, piecesThatMayBeActive } =
184- instanceToSync
185- const pieceInstancesInPart = existingPartInstance . pieceInstances
184+ const { existingPartInstance } = instanceToSync
186185
187186 const existingResultPartInstance : BlueprintSyncIngestPartInstance = {
188187 partInstance : convertPartInstanceToBlueprints ( existingPartInstance . partInstance ) ,
189- pieceInstances : pieceInstancesInPart . map ( ( p ) => convertPieceInstanceToBlueprints ( p . pieceInstance ) ) ,
188+ pieceInstances : existingPartInstance . pieceInstances . map ( ( p ) =>
189+ convertPieceInstanceToBlueprints ( p . pieceInstance )
190+ ) ,
190191 }
191192
192- const part = newPart ?? existingPartInstance . partInstance . part
193+ const part = instanceToSync . newPart ?? existingPartInstance . partInstance . part
193194
194195 let playoutRundownModelForPart : PlayoutRundownModel | undefined = this . #playoutRundownModel
195196 // Handle a case where the part is in a different rundown than the playoutRundownModel:
@@ -205,10 +206,10 @@ export class SyncChangesToPartInstancesWorker {
205206 proposedPieceInstances = getPieceInstancesForPart (
206207 this . #context,
207208 this . #playoutModel,
208- previousPartInstance ,
209+ instanceToSync . previousPartInstance ,
209210 playoutRundownModelForPart ,
210211 part ,
211- await piecesThatMayBeActive ,
212+ await instanceToSync . piecesThatMayBeActive ,
212213 existingPartInstance . partInstance . _id
213214 )
214215 } catch ( e ) {
@@ -223,14 +224,9 @@ export class SyncChangesToPartInstancesWorker {
223224 throw e
224225 }
225226
226- logger . info ( `Syncing ingest changes for part: ${ part . _id } (orphaned: ${ ! ! newPart } )` )
227+ logger . info ( `Syncing ingest changes for part: ${ part . _id } (orphaned: ${ ! ! instanceToSync . newPart } )` )
227228
228- const newResultData = collectNewIngestDataToSync (
229- this . #ingestModel,
230- part . _id ,
231- instanceToSync ,
232- proposedPieceInstances
233- )
229+ const newResultData = this . collectNewIngestDataToSync ( part . _id , instanceToSync , proposedPieceInstances )
234230 const partInstanceSnapshot = existingPartInstance . snapshotMakeCopy ( )
235231
236232 const syncContext = new SyncIngestUpdateToPartInstanceContext (
@@ -244,7 +240,7 @@ export class SyncChangesToPartInstancesWorker {
244240 this . #playoutRundownModel. rundown ,
245241 existingPartInstance ,
246242 proposedPieceInstances ,
247- playStatus
243+ instanceToSync . playStatus
248244 )
249245 // TODO - how can we limit the frequency we run this? (ie, how do we know nothing affecting this has changed)
250246 try {
@@ -256,7 +252,7 @@ export class SyncChangesToPartInstancesWorker {
256252 syncContext ,
257253 existingResultPartInstance ,
258254 newResultData ,
259- playStatus
255+ instanceToSync . playStatus
260256 )
261257 } catch ( err ) {
262258 logger . error ( `Error in showStyleBlueprint.syncIngestUpdateToPartInstance: ${ stringifyError ( err ) } ` )
@@ -265,47 +261,20 @@ export class SyncChangesToPartInstancesWorker {
265261 existingPartInstance . snapshotRestore ( partInstanceSnapshot )
266262 }
267263
268- if ( playStatus === 'next' && syncContext . hasRemovedPartInstance ) {
264+ if ( instanceToSync . playStatus === 'next' && syncContext . hasRemovedPartInstance ) {
269265 // PartInstance was removed, so we need to remove it and re-select the next part
270-
271- if ( this . #playoutModel. playlist . nextPartInfo ?. manuallySelected && newPart ) {
272- await setNextPart (
273- this . #context,
274- this . #playoutModel,
275- {
276- part : newPart ,
277- consumesQueuedSegmentId : this . #playoutModel. playlist . nextPartInfo . consumesQueuedSegmentId ,
278- } ,
279- true ,
280- this . #playoutModel. playlist . nextTimeOffset || 0
281- )
282- } else {
283- // Clear the next part
284- await setNextPart ( this . #context, this . #playoutModel, null , false , 0 )
285- await ensureNextPartIsValid ( this . #context, this . #playoutModel)
286- }
266+ await this . recreateNextPartInstance ( instanceToSync . newPart )
287267
288268 // We don't need to continue syncing this partInstance, as it's been replaced
289269 return
290270 }
291271
292- if ( playStatus === 'next' ) {
272+ if ( instanceToSync . playStatus === 'next' ) {
293273 existingPartInstance . recalculateExpectedDurationWithTransition ( )
294274 }
295275
296276 // Save notes:
297- const notificationCategory = `syncIngestUpdateToPartInstance:${ existingPartInstance . partInstance . _id } `
298- this . #playoutModel. clearAllNotifications ( notificationCategory )
299- for ( const note of syncContext . notes ) {
300- this . #playoutModel. setNotification ( notificationCategory , {
301- ...convertNoteToNotification ( note , [ this . #blueprint. blueprintId ] ) ,
302- relatedTo : {
303- type : 'partInstance' ,
304- rundownId : existingPartInstance . partInstance . part . rundownId ,
305- partInstanceId : existingPartInstance . partInstance . _id ,
306- } ,
307- } )
308- }
277+ this . saveNotes ( syncContext , existingPartInstance )
309278
310279 // Make sure an adlib-testing part is still labeled correctly. This could happen if the partInstance used any recently updated adlibs
311280 validateAdlibTestingPartInstanceProperties ( this . #context, this . #playoutModel, existingPartInstance )
@@ -321,33 +290,69 @@ export class SyncChangesToPartInstancesWorker {
321290 )
322291 }
323292 }
324- }
325293
326- function collectNewIngestDataToSync (
327- ingestModel : IngestModelReadonly ,
328- partId : PartId ,
329- instanceToSync : PartInstanceToSync ,
330- proposedPieceInstances : PieceInstance [ ]
331- ) : BlueprintSyncIngestNewData {
332- const ingestPart = ingestModel . findPart ( partId )
333-
334- const referencedAdlibs : IBlueprintAdLibPieceDB [ ] = [ ]
335- for ( const adLibPieceId of _ . compact (
336- instanceToSync . existingPartInstance . pieceInstances . map ( ( p ) => p . pieceInstance . adLibSourceId )
337- ) ) {
338- const adLibPiece = ingestModel . findAdlibPiece ( adLibPieceId )
339- if ( adLibPiece ) referencedAdlibs . push ( convertAdLibPieceToBlueprints ( adLibPiece ) )
294+ collectNewIngestDataToSync (
295+ partId : PartId ,
296+ instanceToSync : PartInstanceToSync ,
297+ proposedPieceInstances : PieceInstance [ ]
298+ ) : BlueprintSyncIngestNewData {
299+ const ingestPart = this . #ingestModel. findPart ( partId )
300+
301+ const referencedAdlibs : IBlueprintAdLibPieceDB [ ] = [ ]
302+ for ( const adLibPieceId of _ . compact (
303+ instanceToSync . existingPartInstance . pieceInstances . map ( ( p ) => p . pieceInstance . adLibSourceId )
304+ ) ) {
305+ const adLibPiece = this . #ingestModel. findAdlibPiece ( adLibPieceId )
306+ if ( adLibPiece ) referencedAdlibs . push ( convertAdLibPieceToBlueprints ( adLibPiece ) )
307+ }
308+
309+ return {
310+ part : instanceToSync . newPart ? convertPartToBlueprints ( instanceToSync . newPart ) : undefined ,
311+ pieceInstances : proposedPieceInstances . map ( convertPieceInstanceToBlueprints ) ,
312+ adLibPieces :
313+ instanceToSync . newPart && ingestPart ? ingestPart . adLibPieces . map ( convertAdLibPieceToBlueprints ) : [ ] ,
314+ actions :
315+ instanceToSync . newPart && ingestPart ? ingestPart . adLibActions . map ( convertAdLibActionToBlueprints ) : [ ] ,
316+ referencedAdlibs : referencedAdlibs ,
317+ rundownPieces : this . #ingestModel. getGlobalPieces ( ) . map ( convertRundownPieceToBlueprints ) ,
318+ }
340319 }
341320
342- return {
343- part : instanceToSync . newPart ? convertPartToBlueprints ( instanceToSync . newPart ) : undefined ,
344- pieceInstances : proposedPieceInstances . map ( convertPieceInstanceToBlueprints ) ,
345- adLibPieces :
346- instanceToSync . newPart && ingestPart ? ingestPart . adLibPieces . map ( convertAdLibPieceToBlueprints ) : [ ] ,
347- actions :
348- instanceToSync . newPart && ingestPart ? ingestPart . adLibActions . map ( convertAdLibActionToBlueprints ) : [ ] ,
349- referencedAdlibs : referencedAdlibs ,
350- rundownPieces : ingestModel . getGlobalPieces ( ) . map ( convertRundownPieceToBlueprints ) ,
321+ async recreateNextPartInstance ( newPart : ReadonlyDeep < DBPart > | undefined ) : Promise < void > {
322+ if ( this . #playoutModel. playlist . nextPartInfo ?. manuallySelected && newPart ) {
323+ await setNextPart (
324+ this . #context,
325+ this . #playoutModel,
326+ {
327+ part : newPart ,
328+ consumesQueuedSegmentId : this . #playoutModel. playlist . nextPartInfo . consumesQueuedSegmentId ,
329+ } ,
330+ true ,
331+ this . #playoutModel. playlist . nextTimeOffset || 0
332+ )
333+ } else {
334+ // Clear the next part
335+ await setNextPart ( this . #context, this . #playoutModel, null , false , 0 )
336+ await ensureNextPartIsValid ( this . #context, this . #playoutModel)
337+ }
338+ }
339+
340+ saveNotes (
341+ syncContext : SyncIngestUpdateToPartInstanceContext ,
342+ existingPartInstance : PlayoutPartInstanceModel
343+ ) : void {
344+ const notificationCategory = `syncIngestUpdateToPartInstance:${ existingPartInstance . partInstance . _id } `
345+ this . #playoutModel. clearAllNotifications ( notificationCategory )
346+ for ( const note of syncContext . notes ) {
347+ this . #playoutModel. setNotification ( notificationCategory , {
348+ ...convertNoteToNotification ( note , [ this . #blueprint. blueprintId ] ) ,
349+ relatedTo : {
350+ type : 'partInstance' ,
351+ rundownId : existingPartInstance . partInstance . part . rundownId ,
352+ partInstanceId : existingPartInstance . partInstance . _id ,
353+ } ,
354+ } )
355+ }
351356 }
352357}
353358
0 commit comments