@@ -54,11 +54,65 @@ import {
5454import { AdjustLabelFit } from '../util/AdjustLabelFit.js'
5555import { AutoNextStatus } from '../RundownView/RundownTiming/AutoNextStatus.js'
5656import { useTranslation } from 'react-i18next'
57+ import { DBShowStyleBase } from '@sofie-automation/corelib/dist/dataModel/ShowStyleBase'
58+ import { PieceInstance } from '@sofie-automation/corelib/dist/dataModel/PieceInstance.js'
5759
5860interface SegmentUi extends DBSegment {
5961 items : Array < PartUi >
6062}
6163
64+ /**
65+ * Determines whether a piece instance should display its AB resolver channel assignment on the Director screen.
66+ * Checks piece-level override first, then falls back to show style configuration.
67+ * Note: Future screens (presenter, camera) will have their own showOn* flags when implemented.
68+ */
69+ function shouldDisplayAbChannel (
70+ pieceInstance : PieceInstance ,
71+ showStyleBase : UIShowStyleBase ,
72+ config ?: DBShowStyleBase [ 'abChannelDisplay' ]
73+ ) : boolean {
74+ // Check piece-level override first (from blueprint)
75+ const piece = pieceInstance . piece as any
76+ if ( piece . displayAbChannel !== undefined ) {
77+ return piece . displayAbChannel
78+ }
79+
80+ // If no config, use sensible defaults but don't show (screen flag defaults to false)
81+ const effectiveConfig : NonNullable < DBShowStyleBase [ 'abChannelDisplay' ] > = config ?? {
82+ // Default: guess VT and LIVE_SPEAK types
83+ sourceLayerIds : [ ] ,
84+ sourceLayerTypes : [ SourceLayerType . VT , SourceLayerType . LIVE_SPEAK ] ,
85+ outputLayerIds : [ ] ,
86+
87+ // But don't show by default
88+ showOnDirectorScreen : false ,
89+ }
90+
91+ // Check if display is enabled for director screen
92+ if ( ! effectiveConfig . showOnDirectorScreen ) return false
93+
94+ const sourceLayer = showStyleBase . sourceLayers ?. [ pieceInstance . piece . sourceLayerId ]
95+
96+ // Check if output layer filter is specified and doesn't match
97+ if ( effectiveConfig . outputLayerIds . length > 0 ) {
98+ if ( ! effectiveConfig . outputLayerIds . includes ( pieceInstance . piece . outputLayerId ) ) {
99+ return false
100+ }
101+ }
102+
103+ // Check if source layer ID is explicitly listed
104+ if ( effectiveConfig . sourceLayerIds . includes ( pieceInstance . piece . sourceLayerId ) ) {
105+ return true
106+ }
107+
108+ // Check sourceLayer type match
109+ if ( sourceLayer ?. type && effectiveConfig . sourceLayerTypes . includes ( sourceLayer . type ) ) {
110+ return true
111+ }
112+
113+ return false
114+ }
115+
62116interface TimeMap {
63117 [ key : string ] : number
64118}
@@ -393,33 +447,31 @@ function DirectorScreenRender({
393447 )
394448 }
395449
396- // Compute current and next clip player ids (for VT pieces)
450+ // Compute current and next clip player ids (for pieces with AB sessions )
397451 const currentClipPlayer : string | undefined = useTracker ( ( ) => {
398452 if ( ! currentPartInstance || ! currentShowStyleBase || ! playlist ?. assignedAbSessions ) return undefined
453+ const config = currentShowStyleBase . abChannelDisplay
399454 const instances = PieceInstances . find ( {
400455 partInstanceId : currentPartInstance . instance . _id ,
401456 reset : { $ne : true } ,
402457 } ) . fetch ( )
403458 for ( const pi of instances ) {
404- const sl = currentShowStyleBase . sourceLayers ?. [ pi . piece . sourceLayerId ]
405- // Only consider VT and LIVE_SPEAK on the PGM output layer
406- const ol = currentShowStyleBase . outputLayers ?. [ pi . piece . outputLayerId ]
407- if ( ( sl ?. type === SourceLayerType . VT || sl ?. type === SourceLayerType . LIVE_SPEAK ) && ol ?. isPGM ) {
408- const ab = pi . piece . abSessions
409- if ( ! ab || ab . length === 0 ) continue
410- for ( const s of ab ) {
411- const pool = playlist . assignedAbSessions ?. [ s . poolName ]
412- if ( ! pool ) continue
413- const matches : ABSessionAssignment [ ] = [ ]
414- for ( const key in pool ) {
415- const a = pool [ key ]
416- if ( a && a . sessionName === s . sessionName ) matches . push ( a )
417- }
418- const live = matches . find ( ( m ) => ! m . lookahead )
419- const la = matches . find ( ( m ) => m . lookahead )
420- if ( live ) return String ( live . playerId )
421- if ( la ) return String ( la . playerId )
459+ // Use configuration to determine if this piece should display AB channel
460+ if ( ! shouldDisplayAbChannel ( pi , currentShowStyleBase , config ) ) continue
461+ const ab = pi . piece . abSessions
462+ if ( ! ab || ab . length === 0 ) continue
463+ for ( const s of ab ) {
464+ const pool = playlist . assignedAbSessions ?. [ s . poolName ]
465+ if ( ! pool ) continue
466+ const matches : ABSessionAssignment [ ] = [ ]
467+ for ( const key in pool ) {
468+ const a = pool [ key ]
469+ if ( a && a . sessionName === s . sessionName ) matches . push ( a )
422470 }
471+ const live = matches . find ( ( m ) => ! m . lookahead )
472+ const la = matches . find ( ( m ) => m . lookahead )
473+ if ( live ) return String ( live . playerId )
474+ if ( la ) return String ( la . playerId )
423475 }
424476 }
425477 return undefined
@@ -430,30 +482,28 @@ function DirectorScreenRender({
430482 // We need the ShowStyleBase to resolve sourceLayer types
431483 const ssb = UIShowStyleBases . findOne ( nextShowStyleBaseId )
432484 if ( ! ssb ) return undefined
485+ const config = ssb . abChannelDisplay
433486 const instances = PieceInstances . find ( {
434487 partInstanceId : nextPartInstance . instance . _id ,
435488 reset : { $ne : true } ,
436489 } ) . fetch ( )
437490 for ( const pi of instances ) {
438- const sl = ssb . sourceLayers ?. [ pi . piece . sourceLayerId ]
439- // Only consider VT and LIVE_SPEAK on the PGM output layer
440- const ol = ssb . outputLayers ?. [ pi . piece . outputLayerId ]
441- if ( ( sl ?. type === SourceLayerType . VT || sl ?. type === SourceLayerType . LIVE_SPEAK ) && ol ?. isPGM ) {
442- const ab = pi . piece . abSessions
443- if ( ! ab || ab . length === 0 ) continue
444- for ( const s of ab ) {
445- const pool = playlist . assignedAbSessions ?. [ s . poolName ]
446- if ( ! pool ) continue
447- const matches : ABSessionAssignment [ ] = [ ]
448- for ( const key in pool ) {
449- const a = pool [ key ]
450- if ( a && a . sessionName === s . sessionName ) matches . push ( a )
451- }
452- const live = matches . find ( ( m ) => ! m . lookahead )
453- const la = matches . find ( ( m ) => m . lookahead )
454- if ( live ) return String ( live . playerId )
455- if ( la ) return String ( la . playerId )
491+ // Use configuration to determine if this piece should display AB channel
492+ if ( ! shouldDisplayAbChannel ( pi , ssb , config ) ) continue
493+ const ab = pi . piece . abSessions
494+ if ( ! ab || ab . length === 0 ) continue
495+ for ( const s of ab ) {
496+ const pool = playlist . assignedAbSessions ?. [ s . poolName ]
497+ if ( ! pool ) continue
498+ const matches : ABSessionAssignment [ ] = [ ]
499+ for ( const key in pool ) {
500+ const a = pool [ key ]
501+ if ( a && a . sessionName === s . sessionName ) matches . push ( a )
456502 }
503+ const live = matches . find ( ( m ) => ! m . lookahead )
504+ const la = matches . find ( ( m ) => m . lookahead )
505+ if ( live ) return String ( live . playerId )
506+ if ( la ) return String ( la . playerId )
457507 }
458508 }
459509 return undefined
0 commit comments