@@ -107,6 +107,8 @@ export class RundownTimingCalculator {
107107 let remainingRundownDuration = 0
108108 let asPlayedRundownDuration = 0
109109 let asDisplayedRundownDuration = 0
110+ // the "wait" for a part is defined as its asPlayedDuration or its displayDuration or its expectedDuration
111+ const waitPerPart : Record < string , number > = { }
110112 let waitAccumulator = 0
111113 let currentRemaining = 0
112114 let startsAtAccumulator = 0
@@ -434,10 +436,13 @@ export class RundownTimingCalculator {
434436 0
435437 }
436438 if ( segmentUsesBudget ) {
437- waitAccumulator += Math . min ( waitDuration , Math . max ( segmentBudgetDurationLeft , 0 ) )
439+ const wait = Math . min ( waitDuration , Math . max ( segmentBudgetDurationLeft , 0 ) )
440+ waitAccumulator += wait
438441 segmentBudgetDurationLeft -= waitDuration
442+ waitPerPart [ unprotectString ( partId ) ] = wait + Math . max ( 0 , segmentBudgetDurationLeft )
439443 } else {
440444 waitAccumulator += waitDuration
445+ waitPerPart [ unprotectString ( partId ) ] = waitDuration
441446 }
442447
443448 // remaining is the sum of unplayed lines + whatever is left of the current segment
@@ -478,7 +483,9 @@ export class RundownTimingCalculator {
478483 } )
479484
480485 // This is where the waitAccumulator-generated data in the linearSegLines is used to calculate the countdowns.
486+ // at this point the "waitAccumulator" should be the total sum of all the "waits" in the rundown
481487 let localAccum = 0
488+ let timeTillEndLoop : undefined | number = undefined
482489 for ( let i = 0 ; i < this . linearParts . length ; i ++ ) {
483490 if ( i < nextAIndex ) {
484491 // this is a line before next line
@@ -515,6 +522,11 @@ export class RundownTimingCalculator {
515522 // and add the currentRemaining countdown, since we are currentRemaining + diff between next and
516523 // this away from this line.
517524 this . linearParts [ i ] [ 1 ] = ( this . linearParts [ i ] [ 1 ] || 0 ) - localAccum + currentRemaining
525+
526+ if ( ! partsInQuickLoop [ unprotectString ( this . linearParts [ i ] [ 0 ] ) ] ) {
527+ timeTillEndLoop = timeTillEndLoop ?? this . linearParts [ i ] [ 1 ] ?? undefined
528+ }
529+
518530 if ( nextRundownAnchor === undefined ) {
519531 nextRundownAnchor = getSegmentRundownAnchorFromPart (
520532 this . linearParts [ i ] [ 0 ] ,
@@ -525,13 +537,22 @@ export class RundownTimingCalculator {
525537 }
526538 }
527539 }
528- // contiunation of linearParts calculations for looping playlists
540+ // at this point the localAccumulator should be the sum of waits before the next line
541+ // continuation of linearParts calculations for looping playlists
529542 if ( isLoopRunning ( playlist ) ) {
543+ // we track the sum of all the "waits" that happen in the loop
544+ let waitInLoop = 0
545+ // if timeTillEndLoop was undefined then we can assume the end of the loop is the last line in the rundown
546+ timeTillEndLoop = timeTillEndLoop ?? waitAccumulator - localAccum + currentRemaining
530547 for ( let i = 0 ; i < nextAIndex ; i ++ ) {
531548 if ( ! partsInQuickLoop [ unprotectString ( this . linearParts [ i ] [ 0 ] ) ] ) continue
532- // offset the parts before the on air line by the countdown for the end of the rundown
533- this . linearParts [ i ] [ 1 ] =
534- ( this . linearParts [ i ] [ 1 ] || 0 ) + waitAccumulator - localAccum + currentRemaining
549+
550+ // this countdown is the wait until the loop ends + whatever waits occur before this part but inside the loop
551+ this . linearParts [ i ] [ 1 ] = timeTillEndLoop + waitInLoop
552+
553+ // add the wait from this part to the waitInLoop (the lookup here should still work by the definition of a "wait")
554+ waitInLoop += waitPerPart [ unprotectString ( this . linearParts [ i ] [ 0 ] ) ] ?? 0
555+
535556 if ( nextRundownAnchor === undefined ) {
536557 nextRundownAnchor = getSegmentRundownAnchorFromPart (
537558 this . linearParts [ i ] [ 0 ] ,
0 commit comments