Skip to content

Commit 230e18d

Browse files
committed
Allow control from config and blueprints
1 parent 863c043 commit 230e18d

File tree

4 files changed

+115
-38
lines changed

4 files changed

+115
-38
lines changed

packages/blueprints-integration/src/documents/piece.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ export interface IBlueprintPiece<TPrivateData = unknown, TPublicData = unknown>
4545
* Whether to stop this piece before the 'keepalive' period of the part
4646
*/
4747
excludeDuringPartKeepalive?: boolean
48+
49+
/**
50+
* Whether to display AB resolver channel assignment on Director screen.
51+
* If set, overrides show style configuration for this piece.
52+
*/
53+
displayAbChannel?: boolean
4854
}
4955
export interface IBlueprintPieceDB<TPrivateData = unknown, TPublicData = unknown>
5056
extends IBlueprintPiece<TPrivateData, TPublicData> {

packages/corelib/src/dataModel/ShowStyleBase.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,19 @@ export interface DBShowStyleBase {
4848
/** Config values are used by the Blueprints */
4949
blueprintConfigWithOverrides: ObjectWithOverrides<IBlueprintConfig>
5050

51+
/** Configuration for displaying AB resolver channel assignments across different screens */
52+
abChannelDisplay?: {
53+
/** Source layer IDs that should show AB channel info */
54+
sourceLayerIds: string[]
55+
/** Configure by source layer type */
56+
sourceLayerTypes: SourceLayerType[]
57+
/** Only show for specific output layers (e.g., only PGM) */
58+
outputLayerIds: string[]
59+
/** Enable display on Director screen */
60+
showOnDirectorScreen: boolean
61+
// Future: showOnPresenterScreen, showOnCameraScreen when those views are implemented
62+
}
63+
5164
_rundownVersionHash: string
5265

5366
/** Details on the last blueprint used to generate the defaults values for this */

packages/meteor-lib/src/api/showStyles.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { ShowStyleBaseId, ShowStyleVariantId, StudioId } from '@sofie-automation/corelib/dist/dataModel/Ids'
2-
import { HotkeyDefinition, OutputLayers, SourceLayers } from '@sofie-automation/corelib/dist/dataModel/ShowStyleBase'
2+
import {
3+
HotkeyDefinition,
4+
OutputLayers,
5+
SourceLayers,
6+
type DBShowStyleBase,
7+
} from '@sofie-automation/corelib/dist/dataModel/ShowStyleBase'
38
import { DBShowStyleVariant } from '@sofie-automation/corelib/dist/dataModel/ShowStyleVariant'
49

510
export interface NewShowStylesAPI {
@@ -44,6 +49,9 @@ export interface UIShowStyleBase {
4449
outputLayers: OutputLayers
4550
/** "Layers" in the GUI */
4651
sourceLayers: SourceLayers
52+
53+
/** Configuration for displaying AB resolver channels on various screens */
54+
abChannelDisplay?: DBShowStyleBase['abChannelDisplay']
4755
}
4856

4957
export interface CreateAdlibTestingRundownOption {

packages/webui/src/client/ui/ClockView/DirectorScreen.tsx

Lines changed: 87 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,65 @@ import {
5454
import { AdjustLabelFit } from '../util/AdjustLabelFit.js'
5555
import { AutoNextStatus } from '../RundownView/RundownTiming/AutoNextStatus.js'
5656
import { 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

5860
interface 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+
62116
interface 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

Comments
 (0)