Skip to content

Commit bf4e5df

Browse files
committed
Merge branch 'feat--Reduce-ingest-visual-noise' into bbc-main-autonext
2 parents 494cdee + 4740206 commit bf4e5df

4 files changed

Lines changed: 267 additions & 105 deletions

File tree

packages/webui/src/client/ui/RundownView/RundownTiming/RundownTimingProvider.tsx

Lines changed: 106 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { type PropsWithChildren } from 'react'
22
import { Meteor } from 'meteor/meteor'
33
import { withTracker } from '../../../lib/ReactMeteorData/react-meteor-data.js'
4+
import _ from 'underscore'
45
import { protectString } from '@sofie-automation/shared-lib/dist/lib/protectedString'
56
import type { DBRundownPlaylist } from '@sofie-automation/corelib/dist/dataModel/RundownPlaylist/RundownPlaylist'
67
import { RundownTiming, type TimeEventArgs } from './RundownTiming.js'
@@ -59,6 +60,31 @@ interface IRundownTimingProviderTrackedProps {
5960
partsInQuickLoop: Record<TimingId, boolean>
6061
}
6162

63+
function getPlaylistRenderSelector(playlist: DBRundownPlaylist | undefined) {
64+
if (!playlist) return undefined
65+
66+
const quickLoopStartId =
67+
playlist.quickLoop?.start && 'id' in playlist.quickLoop.start ? playlist.quickLoop.start.id : undefined
68+
const quickLoopEndId =
69+
playlist.quickLoop?.end && 'id' in playlist.quickLoop.end ? playlist.quickLoop.end.id : undefined
70+
71+
return {
72+
id: playlist._id,
73+
activationId: playlist.activationId,
74+
rundownIdsInOrder: playlist.rundownIdsInOrder,
75+
currentPartInstanceId: playlist.currentPartInfo?.partInstanceId,
76+
nextPartInstanceId: playlist.nextPartInfo?.partInstanceId,
77+
previousPartInstanceId: playlist.previousPartInfo?.partInstanceId,
78+
outOfOrderTiming: playlist.outOfOrderTiming,
79+
segmentsStartedPlayback: playlist.segmentsStartedPlayback,
80+
quickLoopRunning: playlist.quickLoop?.running,
81+
quickLoopStartType: playlist.quickLoop?.start?.type,
82+
quickLoopStartId,
83+
quickLoopEndType: playlist.quickLoop?.end?.type,
84+
quickLoopEndId,
85+
}
86+
}
87+
6288
/**
6389
* RundownTimingProvider is a container component that provides a timing context to all child elements.
6490
* It allows calculating a single
@@ -69,93 +95,101 @@ export const RundownTimingProvider = withTracker<
6995
PropsWithChildren<IRundownTimingProviderProps>,
7096
IRundownTimingProviderState,
7197
IRundownTimingProviderTrackedProps
72-
>(({ playlist }) => {
73-
if (!playlist) {
74-
return {
75-
rundowns: [],
76-
currentRundown: undefined,
77-
partInstances: [],
78-
partInstancesMap: new Map(),
79-
segments: [],
80-
segmentsMap: new Map(),
81-
partsInQuickLoop: {},
98+
>(
99+
({ playlist }) => {
100+
if (!playlist) {
101+
return {
102+
rundowns: [],
103+
currentRundown: undefined,
104+
partInstances: [],
105+
partInstancesMap: new Map(),
106+
segments: [],
107+
segmentsMap: new Map(),
108+
partsInQuickLoop: {},
109+
}
82110
}
83-
}
84111

85-
const partInstancesMap = new Map<PartId, MinimalPartInstance>()
86-
87-
const rundowns = RundownPlaylistCollectionUtil.getRundownsOrdered(playlist)
88-
const segments = RundownPlaylistClientUtil.getSegments(playlist)
89-
const segmentsMap = new Map<SegmentId, DBSegment>(segments.map((segment) => [segment._id, segment]))
90-
const unorderedParts = RundownPlaylistClientUtil.getUnorderedParts(playlist)
91-
const activePartInstances = RundownPlaylistClientUtil.getActivePartInstances(playlist, undefined, {
92-
projection: {
93-
_id: 1,
94-
rundownId: 1,
95-
segmentId: 1,
96-
isTemporary: 1,
97-
segmentPlayoutId: 1,
98-
takeCount: 1,
99-
part: 1,
100-
timings: 1,
101-
orphaned: 1,
102-
},
103-
}) as Array<
104-
Pick<
105-
PartInstance,
106-
| '_id'
107-
| 'rundownId'
108-
| 'segmentId'
109-
| 'isTemporary'
110-
| 'segmentPlayoutId'
111-
| 'takeCount'
112-
| 'part'
113-
| 'timings'
114-
| 'orphaned'
112+
const partInstancesMap = new Map<PartId, MinimalPartInstance>()
113+
114+
const rundowns = RundownPlaylistCollectionUtil.getRundownsOrdered(playlist)
115+
const segments = RundownPlaylistClientUtil.getSegments(playlist)
116+
const segmentsMap = new Map<SegmentId, DBSegment>(segments.map((segment) => [segment._id, segment]))
117+
const unorderedParts = RundownPlaylistClientUtil.getUnorderedParts(playlist)
118+
const activePartInstances = RundownPlaylistClientUtil.getActivePartInstances(playlist, undefined, {
119+
projection: {
120+
_id: 1,
121+
rundownId: 1,
122+
segmentId: 1,
123+
isTemporary: 1,
124+
segmentPlayoutId: 1,
125+
takeCount: 1,
126+
part: 1,
127+
timings: 1,
128+
orphaned: 1,
129+
},
130+
}) as Array<
131+
Pick<
132+
PartInstance,
133+
| '_id'
134+
| 'rundownId'
135+
| 'segmentId'
136+
| 'isTemporary'
137+
| 'segmentPlayoutId'
138+
| 'takeCount'
139+
| 'part'
140+
| 'timings'
141+
| 'orphaned'
142+
>
115143
>
116-
>
117144

118-
const { currentPartInstance } = findCurrentAndPreviousPartInstance(
119-
activePartInstances,
120-
playlist.currentPartInfo?.partInstanceId,
121-
playlist.previousPartInfo?.partInstanceId
122-
)
145+
const { currentPartInstance } = findCurrentAndPreviousPartInstance(
146+
activePartInstances,
147+
playlist.currentPartInfo?.partInstanceId,
148+
playlist.previousPartInfo?.partInstanceId
149+
)
123150

124-
const currentRundown = currentPartInstance
125-
? rundowns.find((r) => r._id === currentPartInstance.rundownId)
126-
: rundowns[0]
151+
const currentRundown = currentPartInstance
152+
? rundowns.find((r) => r._id === currentPartInstance.rundownId)
153+
: rundowns[0]
127154

128-
let partInstances: MinimalPartInstance[] = []
155+
let partInstances: MinimalPartInstance[] = []
129156

130-
const allPartIds: Set<PartId> = new Set()
157+
const allPartIds: Set<PartId> = new Set()
131158

132-
for (const partInstance of activePartInstances) {
133-
allPartIds.add(partInstance.part._id)
134-
}
159+
for (const partInstance of activePartInstances) {
160+
allPartIds.add(partInstance.part._id)
161+
}
135162

136-
partInstances = activePartInstances
163+
partInstances = activePartInstances
137164

138-
for (const part of unorderedParts) {
139-
if (allPartIds.has(part._id)) continue
140-
partInstances.push(wrapPartToTemporaryInstance(playlist.activationId ?? protectString(''), part))
141-
}
165+
for (const part of unorderedParts) {
166+
if (allPartIds.has(part._id)) continue
167+
partInstances.push(wrapPartToTemporaryInstance(playlist.activationId ?? protectString(''), part))
168+
}
142169

143-
partInstances = sortPartInstancesInSortedSegments(partInstances, segments)
170+
partInstances = sortPartInstancesInSortedSegments(partInstances, segments)
144171

145-
partInstances = deduplicatePartInstancesForQuickLoop(playlist, partInstances, currentPartInstance)
172+
partInstances = deduplicatePartInstancesForQuickLoop(playlist, partInstances, currentPartInstance)
146173

147-
const partsInQuickLoop = findPartInstancesInQuickLoop(playlist, partInstances)
174+
const partsInQuickLoop = findPartInstancesInQuickLoop(playlist, partInstances)
148175

149-
return {
150-
rundowns,
151-
currentRundown,
152-
partInstances,
153-
partInstancesMap,
154-
segments,
155-
segmentsMap,
156-
partsInQuickLoop,
176+
return {
177+
rundowns,
178+
currentRundown,
179+
partInstances,
180+
partInstancesMap,
181+
segments,
182+
segmentsMap,
183+
partsInQuickLoop,
184+
}
185+
},
186+
(_data, props, nextProps) => {
187+
if (props.refreshInterval !== nextProps.refreshInterval) return true
188+
if (props.defaultDuration !== nextProps.defaultDuration) return true
189+
190+
return !_.isEqual(getPlaylistRenderSelector(props.playlist), getPlaylistRenderSelector(nextProps.playlist))
157191
}
158-
})(
192+
)(
159193
class RundownTimingProvider extends React.Component<
160194
PropsWithChildren<IRundownTimingProviderProps> & IRundownTimingProviderTrackedProps,
161195
IRundownTimingProviderState

packages/webui/src/client/ui/SegmentContainer/withResolvedSegment.ts

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -131,23 +131,30 @@ export function withResolvedSegment<T extends IResolvedSegmentProps, IState = {}
131131

132132
// This registers a reactive dependency on infinites-capping pieces, so that the segment can be
133133
// re-evaluated when a piece like that appears.
134-
PieceInstances.find({
135-
rundownId: segment.rundownId,
136-
dynamicallyInserted: {
137-
$exists: true,
138-
},
139-
'infinite.fromPreviousPart': false,
140-
'piece.lifespan': {
141-
$in: [
142-
PieceLifespan.OutOnRundownEnd,
143-
PieceLifespan.OutOnRundownChange,
144-
PieceLifespan.OutOnShowStyleEnd,
145-
],
146-
},
147-
reset: {
148-
$ne: true,
134+
PieceInstances.find(
135+
{
136+
rundownId: segment.rundownId,
137+
dynamicallyInserted: {
138+
$exists: true,
139+
},
140+
'infinite.fromPreviousPart': false,
141+
'piece.lifespan': {
142+
$in: [
143+
PieceLifespan.OutOnRundownEnd,
144+
PieceLifespan.OutOnRundownChange,
145+
PieceLifespan.OutOnShowStyleEnd,
146+
],
147+
},
148+
reset: {
149+
$ne: true,
150+
},
149151
},
150-
}).fetch()
152+
{
153+
fields: {
154+
_id: 1,
155+
},
156+
}
157+
).count()
151158

152159
const [orderedAllPartIds, { currentPartInstance, nextPartInstance }] = slowDownReactivity(
153160
() =>
@@ -334,6 +341,7 @@ export function withResolvedSegment<T extends IResolvedSegmentProps, IState = {}
334341
)
335342
)
336343
}
344+
const segmentContainsNextOrCurrentPart = !!(data.parts && findNextOrCurrentPart(data.parts))
337345
// Check rundown changes that are important to the segment
338346
if (
339347
typeof props.playlist !== typeof nextProps.playlist ||
@@ -343,10 +351,10 @@ export function withResolvedSegment<T extends IResolvedSegmentProps, IState = {}
343351
((props.playlist.currentPartInfo?.partInstanceId !==
344352
nextProps.playlist.currentPartInfo?.partInstanceId ||
345353
props.playlist.nextPartInfo?.partInstanceId !== nextProps.playlist.nextPartInfo?.partInstanceId) &&
346-
data.parts &&
347-
findNextOrCurrentPart(data.parts)) ||
348-
props.playlist.holdState !== nextProps.playlist.holdState ||
349-
props.playlist.nextTimeOffset !== nextProps.playlist.nextTimeOffset ||
354+
segmentContainsNextOrCurrentPart) ||
355+
((props.playlist.holdState !== nextProps.playlist.holdState ||
356+
props.playlist.nextTimeOffset !== nextProps.playlist.nextTimeOffset) &&
357+
segmentContainsNextOrCurrentPart) ||
350358
props.playlist.activationId !== nextProps.playlist.activationId ||
351359
!_.isEqual(props.playlist.quickLoop?.start, nextProps.playlist.quickLoop?.start) ||
352360
!_.isEqual(props.playlist.quickLoop?.end, nextProps.playlist.quickLoop?.end) ||

packages/webui/src/client/ui/SegmentTimeline/Parts/SegmentTimelinePart.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -357,9 +357,10 @@ export class SegmentTimelinePartClass extends React.Component<Translated<WithTim
357357
const firstPartTimingId = props.firstPartInSegment
358358
? getPartInstanceTimingId(props.firstPartInSegment.instance)
359359
: undefined
360-
const lastPartTimingId = props.lastPartInSegment
361-
? getPartInstanceTimingId(props.lastPartInSegment.instance)
362-
: undefined
360+
const lastPartTimingId =
361+
props.isBudgetGap && props.lastPartInSegment
362+
? getPartInstanceTimingId(props.lastPartInSegment.instance)
363+
: undefined
363364

364365
return {
365366
partDuration: props.timingDurations.partDurations?.[timingId],
@@ -369,9 +370,6 @@ export class SegmentTimelinePartClass extends React.Component<Translated<WithTim
369370
firstPartDisplayStart: firstPartTimingId
370371
? props.timingDurations.partDisplayStartsAt?.[firstPartTimingId]
371372
: undefined,
372-
firstPartDisplayDuration: firstPartTimingId
373-
? props.timingDurations.partDisplayDurations?.[firstPartTimingId]
374-
: undefined,
375373
lastPartDisplayStart: lastPartTimingId
376374
? props.timingDurations.partDisplayStartsAt?.[lastPartTimingId]
377375
: undefined,
@@ -1137,13 +1135,18 @@ export const SegmentTimelinePart: React.ComponentType<IProps> = withTranslation(
11371135
const firstPartInSegmentId = props.firstPartInSegment
11381136
? getPartInstanceTimingId(props.firstPartInSegment.instance)
11391137
: undefined
1138+
const lastPartInSegmentId =
1139+
props.isBudgetGap && props.lastPartInSegment
1140+
? getPartInstanceTimingId(props.lastPartInSegment.instance)
1141+
: undefined
11401142
return [
11411143
(durations.partDurations || {})[timingId],
11421144
(durations.partDisplayStartsAt || {})[timingId],
11431145
(durations.partDisplayDurations || {})[timingId],
11441146
(durations.partsInQuickLoop || {})[timingId],
11451147
firstPartInSegmentId ? (durations.partDisplayStartsAt || {})[firstPartInSegmentId] : undefined,
1146-
firstPartInSegmentId ? (durations.partDisplayDurations || {})[firstPartInSegmentId] : undefined,
1148+
lastPartInSegmentId ? (durations.partDisplayStartsAt || {})[lastPartInSegmentId] : undefined,
1149+
lastPartInSegmentId ? (durations.partDisplayDurations || {})[lastPartInSegmentId] : undefined,
11471150
]
11481151
},
11491152
}

0 commit comments

Comments
 (0)