Skip to content

Commit 6ee0000

Browse files
committed
Merge branch 'release50'
2 parents 9480958 + bc833b5 commit 6ee0000

File tree

22 files changed

+225
-141
lines changed

22 files changed

+225
-141
lines changed

meteor/client/ui/Prompter/PrompterView.tsx

Lines changed: 79 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ export class PrompterViewInner extends MeteorReactComponent<Translated<IProps &
321321
}
322322
scrollToPartInstance(partInstanceId: PartInstanceId): void {
323323
const scrollMargin = this.calculateScrollPosition()
324-
const target = document.querySelector(`#partInstance_${partInstanceId}`)
324+
const target = document.querySelector(`[data-part-instance-id="${partInstanceId}"]`)
325325

326326
if (target) {
327327
Velocity(document.body, 'finish')
@@ -408,63 +408,60 @@ export class PrompterViewInner extends MeteorReactComponent<Translated<IProps &
408408
private checkCurrentTakeMarkers = () => {
409409
const playlist = this.props.rundownPlaylist
410410

411-
if (playlist !== undefined) {
412-
const positionTop = window.scrollY
413-
const positionBottom = positionTop + window.innerHeight
411+
if (playlist === undefined) return
412+
const positionTop = window.scrollY
413+
const positionBottom = positionTop + window.innerHeight
414414

415-
let currentPartElement: Element | null = null
416-
let currentPartElementAfter: Element | null = null
417-
let nextPartElementAfter: Element | null = null
415+
let currentPartElement: Element | null = null
416+
let currentPartElementAfter: Element | null = null
417+
let nextPartElementAfter: Element | null = null
418418

419-
const anchors: Array<Element> = Array.from(document.querySelectorAll('.scroll-anchor'))
419+
const anchors: Array<Element> = Array.from(document.querySelectorAll('.scroll-anchor'))
420420

421-
for (let index = 0; index < anchors.length; index++) {
422-
const current = anchors[index]
423-
const next = index + 1 < anchors.length ? anchors[index + 1] : null
421+
for (let index = 0; index < anchors.length; index++) {
422+
const current = anchors[index]
423+
const next = index + 1 < anchors.length ? anchors[index + 1] : null
424424

425-
if (playlist.currentPartInfo && current.classList.contains(`live`)) {
426-
currentPartElement = current
427-
currentPartElementAfter = next
428-
}
429-
if (playlist.nextPartInfo && current.classList.contains(`next`)) {
430-
nextPartElementAfter = next
431-
}
425+
if (playlist.currentPartInfo && current.classList.contains(`live`)) {
426+
currentPartElement = current
427+
currentPartElementAfter = next
428+
}
429+
if (playlist.nextPartInfo && current.classList.contains(`next`)) {
430+
nextPartElementAfter = next
432431
}
432+
}
433433

434-
const currentPositionStart = currentPartElement
435-
? currentPartElement.getBoundingClientRect().top + positionTop
436-
: null
437-
const currentPositionEnd = currentPartElementAfter
438-
? currentPartElementAfter.getBoundingClientRect().top + positionTop
439-
: null
440-
441-
const nextPositionEnd = nextPartElementAfter
442-
? nextPartElementAfter.getBoundingClientRect().top + positionTop
443-
: null
444-
445-
const takeIndicator = document.querySelector('.take-indicator')
446-
if (takeIndicator) {
447-
if (currentPositionEnd && currentPositionEnd < positionTop) {
448-
// Display take "^" indicator
449-
takeIndicator.classList.remove('hidden')
450-
takeIndicator.classList.add('top')
451-
} else if (currentPositionStart && currentPositionStart > positionBottom) {
452-
// Display take "v" indicator
453-
takeIndicator.classList.remove('hidden', 'top')
454-
} else {
455-
takeIndicator.classList.add('hidden')
456-
}
434+
const currentPositionStart = currentPartElement
435+
? currentPartElement.getBoundingClientRect().top + positionTop
436+
: null
437+
const currentPositionEnd = currentPartElementAfter
438+
? currentPartElementAfter.getBoundingClientRect().top + positionTop
439+
: null
440+
441+
const nextPositionEnd = nextPartElementAfter ? nextPartElementAfter.getBoundingClientRect().top + positionTop : null
442+
443+
const takeIndicator = document.querySelector('.take-indicator')
444+
if (takeIndicator) {
445+
if (currentPositionEnd && currentPositionEnd < positionTop) {
446+
// Display take "^" indicator
447+
takeIndicator.classList.remove('hidden')
448+
takeIndicator.classList.add('top')
449+
} else if (currentPositionStart && currentPositionStart > positionBottom) {
450+
// Display take "v" indicator
451+
takeIndicator.classList.remove('hidden', 'top')
452+
} else {
453+
takeIndicator.classList.add('hidden')
457454
}
455+
}
458456

459-
const nextIndicator = document.querySelector('.next-indicator')
460-
if (nextIndicator) {
461-
if (nextPositionEnd && nextPositionEnd < positionTop) {
462-
// Display next "^" indicator
463-
nextIndicator.classList.remove('hidden')
464-
nextIndicator.classList.add('top')
465-
} else {
466-
nextIndicator.classList.add('hidden')
467-
}
457+
const nextIndicator = document.querySelector('.next-indicator')
458+
if (nextIndicator) {
459+
if (nextPositionEnd && nextPositionEnd < positionTop) {
460+
// Display next "^" indicator
461+
nextIndicator.classList.remove('hidden')
462+
nextIndicator.classList.add('top')
463+
} else {
464+
nextIndicator.classList.add('hidden')
468465
}
469466
}
470467
}
@@ -737,24 +734,32 @@ export const Prompter = translateWithTracker<PropsWithChildren<IPrompterProps>,
737734
// Go through the anchors and use the first one that we find:
738735
for (const scrollAnchor of scrollAnchors) {
739736
const anchor = document.getElementById(scrollAnchor.anchorId)
740-
if (anchor) {
741-
const { top } = anchor.getBoundingClientRect()
742-
743-
if (scrollAnchor.offset !== null) {
744-
window.scrollBy({
745-
top: top - scrollAnchor.offset,
746-
})
747-
// We've scrolled, exit the function!
748-
return
749-
} else {
750-
// Note: config.margin does not have to be taken into account here,
751-
// the css margins magically does it for us.
752-
window.scrollBy({
753-
top: top - readPosition,
754-
})
755-
// We've scrolled, exit the function!
756-
return
757-
}
737+
if (!anchor) continue
738+
739+
const { top } = anchor.getBoundingClientRect()
740+
741+
if (scrollAnchor.offset !== null) {
742+
this.props.config.debug &&
743+
logger.debug(
744+
`Selected anchor ${scrollAnchor.anchorId} as anchor element in view, restoring position ${scrollAnchor.offset}`
745+
)
746+
747+
window.scrollBy({
748+
top: top - scrollAnchor.offset,
749+
})
750+
// We've scrolled, exit the function!
751+
return
752+
} else {
753+
this.props.config.debug &&
754+
logger.debug(`Selected anchor ${scrollAnchor.anchorId} as anchor element outside of view, jumping to it`)
755+
756+
// Note: config.margin does not have to be taken into account here,
757+
// the css margins magically does it for us.
758+
window.scrollBy({
759+
top: top - readPosition,
760+
})
761+
// We've scrolled, exit the function!
762+
return
758763
}
759764
}
760765
// None of the anchors where found at this point.
@@ -766,6 +771,7 @@ export const Prompter = translateWithTracker<PropsWithChildren<IPrompterProps>,
766771
.join(', ')}`
767772
)
768773

774+
// TODO: In the past 4 months this has been here, this hasn't logged a single line, should we keep it?
769775
// Below is for troubleshooting, see if the anchor is in prompterData:
770776
if (!this.props.prompterData) {
771777
logger.error(`Read anchor troubleshooting: no prompterData`)
@@ -847,9 +853,9 @@ export const Prompter = translateWithTracker<PropsWithChildren<IPrompterProps>,
847853
}
848854

849855
private getPartStatus(prompterData: PrompterData, part: PrompterDataPart) {
850-
if (prompterData.currentPartInstanceId === part.id) {
856+
if (prompterData.currentPartInstanceId === part.partInstanceId) {
851857
return 'live'
852-
} else if (prompterData.nextPartInstanceId === part.id) {
858+
} else if (prompterData.nextPartInstanceId === part.partInstanceId) {
853859
return 'next'
854860
} else {
855861
return null
@@ -881,9 +887,10 @@ export const Prompter = translateWithTracker<PropsWithChildren<IPrompterProps>,
881887
segment.parts.forEach((part) => {
882888
lines.push(
883889
<div
884-
id={`partInstance_${part.id}`}
890+
id={`part_${part.id}`}
885891
data-obj-id={segment.id + '_' + part.id}
886-
key={'partInstance_' + part.id}
892+
data-part-instance-id={part.partInstanceId}
893+
key={'part_' + part.id}
887894
className={ClassNames('prompter-part', 'scroll-anchor', this.getPartStatus(prompterData, part))}
888895
>
889896
{part.title || 'N/A'}

meteor/client/ui/Prompter/prompter.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ export interface PrompterDataSegment {
3535
parts: PrompterDataPart[]
3636
}
3737
export interface PrompterDataPart {
38-
id: PartInstanceId
38+
id: PartId
39+
partInstanceId: PartInstanceId
3940
title: string | undefined
4041
pieces: PrompterDataPiece[]
4142
}
@@ -183,7 +184,8 @@ export namespace PrompterAPI {
183184
for (let partIndex = 0; partIndex < partInstances.length; partIndex++) {
184185
const partInstance = partInstances[partIndex]
185186
const partData: PrompterDataPart = {
186-
id: partInstance._id,
187+
id: partInstance.part._id,
188+
partInstanceId: partInstance._id,
187189
title: partInstance.part.prompterTitle || partInstance.part.title,
188190
pieces: [],
189191
}

meteor/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "automation-core",
3-
"version": "1.50.4",
3+
"version": "1.50.5",
44
"private": true,
55
"engines": {
66
"node": ">=14.19.1"

meteor/yarn.lock

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2180,7 +2180,7 @@ __metadata:
21802180
resolution: "@sofie-automation/shared-lib@portal:../packages/shared-lib::locator=automation-core%40workspace%3A."
21812181
dependencies:
21822182
"@mos-connection/model": ^3.0.4
2183-
timeline-state-resolver-types: 9.0.1
2183+
timeline-state-resolver-types: 9.0.2
21842184
tslib: ^2.4.0
21852185
type-fest: ^2.19.0
21862186
languageName: node
@@ -12451,12 +12451,12 @@ __metadata:
1245112451
languageName: node
1245212452
linkType: hard
1245312453

12454-
"timeline-state-resolver-types@npm:9.0.1":
12455-
version: 9.0.1
12456-
resolution: "timeline-state-resolver-types@npm:9.0.1"
12454+
"timeline-state-resolver-types@npm:9.0.2":
12455+
version: 9.0.2
12456+
resolution: "timeline-state-resolver-types@npm:9.0.2"
1245712457
dependencies:
1245812458
tslib: ^2.5.1
12459-
checksum: b814088e1118f0c5f80459958c5008e9bc9cf4484f5d0f3858e4bcb5146685f42a8328ef4e4764c1f95e1670b33109a8dd74c4582d6204a3f61b57efb216e013
12459+
checksum: be24c805246cea986f19c051c3fa71d9730bbc5baa17dba83d910e0aa139a758571ece15ac96da833a815186705a146bf051a2985dc5abaf034bd9fed2a067e0
1246012460
languageName: node
1246112461
linkType: hard
1246212462

packages/blueprints-integration/CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,15 @@
33
All notable changes to this project will be documented in this file.
44
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
55

6+
## [1.50.5](https://github.com/nrkno/tv-automation-server-core/compare/v1.50.4...v1.50.5) (2024-09-19)
7+
8+
**Note:** Version bump only for package @sofie-automation/blueprints-integration
9+
10+
11+
12+
13+
14+
615
## [1.50.4](https://github.com/nrkno/tv-automation-server-core/compare/v1.50.3...v1.50.4) (2024-08-08)
716

817
**Note:** Version bump only for package @sofie-automation/blueprints-integration

packages/blueprints-integration/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sofie-automation/blueprints-integration",
3-
"version": "1.50.4",
3+
"version": "1.50.5",
44
"description": "Library to define the interaction between core and the blueprints.",
55
"main": "dist/index.js",
66
"typings": "dist/index.d.ts",
@@ -38,7 +38,7 @@
3838
"/LICENSE"
3939
],
4040
"dependencies": {
41-
"@sofie-automation/shared-lib": "1.50.4",
41+
"@sofie-automation/shared-lib": "1.50.5",
4242
"tslib": "^2.4.0",
4343
"type-fest": "^2.19.0"
4444
},

packages/corelib/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sofie-automation/corelib",
3-
"version": "1.50.4",
3+
"version": "1.50.5",
44
"private": true,
55
"description": "Internal library for some types shared by core and workers",
66
"main": "dist/index.js",
@@ -39,8 +39,8 @@
3939
"/LICENSE"
4040
],
4141
"dependencies": {
42-
"@sofie-automation/blueprints-integration": "1.50.4",
43-
"@sofie-automation/shared-lib": "1.50.4",
42+
"@sofie-automation/blueprints-integration": "1.50.5",
43+
"@sofie-automation/shared-lib": "1.50.5",
4444
"fast-clone": "^1.5.13",
4545
"i18next": "^21.9.1",
4646
"influx": "^5.9.3",

packages/corelib/src/playout/__tests__/infinites.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,41 @@ describe('Infinites', () => {
438438
// don't expect virtual Pieces in the results, but 'one' should be pruned too
439439
expect(resolvedInstances).toEqual([])
440440
})
441+
test('stop onSegmentChange continuation with planned onSegmentEnd start=0', () => {
442+
const pieceInstances = [
443+
createPieceInstance('one', { start: 0 }, 'one', PieceLifespan.OutOnSegmentChange, false, {
444+
fromPreviousPart: true,
445+
fromPreviousPlayhead: true,
446+
infiniteInstanceId: protectString('one_a'),
447+
infiniteInstanceIndex: 1,
448+
infinitePieceId: protectString('one_b'),
449+
}),
450+
createPieceInstance('two', { start: 0 }, 'one', PieceLifespan.OutOnSegmentEnd, false, {
451+
fromPreviousPart: false,
452+
infiniteInstanceId: protectString('two_a'),
453+
infiniteInstanceIndex: 0,
454+
infinitePieceId: protectString('two_b'),
455+
}),
456+
]
457+
458+
// Set the first as adlibbed during the previous part
459+
pieceInstances[0].dynamicallyInserted = 1
460+
461+
// Pieces should have preroll
462+
pieceInstances[0].piece.prerollDuration = 200
463+
pieceInstances[1].piece.prerollDuration = 200
464+
465+
const resolvedInstances = runAndTidyResult(pieceInstances, 500)
466+
467+
expect(resolvedInstances).toEqual([
468+
{
469+
_id: 'two',
470+
end: undefined,
471+
priority: 2,
472+
start: 0,
473+
},
474+
])
475+
})
441476
})
442477
describe('getPlayheadTrackingInfinitesForPart', () => {
443478
function runAndTidyResult(

packages/corelib/src/playout/processAndPrune.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,14 @@ function getPieceStartTimeAsReference(newPieceStart: number | 'now', newPiece: P
1515
}
1616

1717
function getPieceStartTimeWithinPart(p: PieceInstance): 'now' | number {
18-
if (p.piece.enable.start === 'now' || !p.dynamicallyInserted) {
19-
return p.piece.enable.start
20-
} else {
18+
// If the piece is dynamically inserted, then its preroll should be factored into its start time, but not for any infinite continuations
19+
const isStartOfAdlib =
20+
!!p.dynamicallyInserted && !(p.infinite?.fromPreviousPart || p.infinite?.fromPreviousPlayhead)
21+
22+
if (isStartOfAdlib && p.piece.enable.start !== 'now') {
2123
return p.piece.enable.start + (p.piece.prerollDuration ?? 0)
24+
} else {
25+
return p.piece.enable.start
2226
}
2327
}
2428

packages/documentation/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sofie-documentation",
3-
"version": "1.50.4",
3+
"version": "1.50.5",
44
"private": true,
55
"scripts": {
66
"docusaurus": "docusaurus",

0 commit comments

Comments
 (0)