Orbit Companion: queue switches just before the end (from release 0.108.79)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -139,6 +139,8 @@ internal object OrbitCompanion {
|
||||
catchUpShelves(screen.channels(), nowMs).flatMap { it.entries }.firstOrNull { it.channel.number == number && it.show.startMs == startMs }
|
||||
|
||||
const val QUEUE_MAX = 5
|
||||
/** How long before the programme's end the queue takes over. */
|
||||
const val QUEUE_LEAD_MS = 2_500L
|
||||
var queue by mutableStateOf<List<Queued>>(emptyList())
|
||||
|
||||
/** Queue [number] live after the programme on now, or a Catch Up programme ([catchUpStartMs]); null when it can't be. */
|
||||
@@ -169,8 +171,12 @@ internal object OrbitCompanion {
|
||||
fun follow(screen: CompanionScreen, anchor: Pair<Int, Long>?, nowMs: Long): Pair<Int, Long>? {
|
||||
val head = queue.firstOrNull() ?: return null
|
||||
val channel = screen.channels().firstOrNull { it.number == screen.selected() } ?: return anchor
|
||||
val on = screen.selected() to channel.at(nowMs + screen.offset()).startMs
|
||||
if (anchor == null || !screen.watching() || anchor.first != on.first || anchor == on) return on
|
||||
val programme = channel.at(nowMs + screen.offset())
|
||||
val on = screen.selected() to programme.startMs
|
||||
// It switches a moment before the end (Paul, 6 November 2026: the next programme began loading first, then the queue
|
||||
// took over), so the channel's own next programme never starts.
|
||||
val ending = anchor == on && programme.endMs - (nowMs + screen.offset()) <= QUEUE_LEAD_MS
|
||||
if (anchor == null || !screen.watching() || anchor.first != on.first || (anchor == on && !ending)) return on
|
||||
queue = queue.drop(1)
|
||||
val offset = head.catchUpStartMs?.let { start -> catchUpEntry(screen, head.number, start, nowMs)?.offsetFrom(nowMs) }
|
||||
if (head.catchUpStartMs == null || offset != null) screen.tune(head.number, offset ?: 0)
|
||||
|
||||
@@ -210,15 +210,17 @@ class PhoneLinkTest {
|
||||
assertEquals(guideTitleParts(companionChannels[1].at(end).media.item.title).first, OrbitCompanion.queue[0].title)
|
||||
var anchor = OrbitCompanion.follow(screen, null, now)
|
||||
assertEquals(101 to start, anchor)
|
||||
anchor = OrbitCompanion.follow(screen, anchor, end - 1_000); assertTrue(tuned.isEmpty())
|
||||
anchor = OrbitCompanion.follow(screen, anchor, end - 10_000); assertTrue(tuned.isEmpty())
|
||||
// Changing channel moves the wait to the new programme instead of playing.
|
||||
selected = 308; anchor = OrbitCompanion.follow(screen, anchor, end - 500); assertTrue(tuned.isEmpty())
|
||||
selected = 101; anchor = OrbitCompanion.follow(screen, anchor, end - 400); assertTrue(tuned.isEmpty())
|
||||
selected = 308; anchor = OrbitCompanion.follow(screen, anchor, end - 9_000); assertTrue(tuned.isEmpty())
|
||||
selected = 101; anchor = OrbitCompanion.follow(screen, anchor, end - 8_000); assertTrue(tuned.isEmpty())
|
||||
// Not watching: it waits.
|
||||
watching = false; anchor = OrbitCompanion.follow(screen, anchor, end + 1_000); assertTrue(tuned.isEmpty())
|
||||
watching = true; anchor = OrbitCompanion.follow(screen, anchor, end + 2_000); assertTrue(tuned.isEmpty())
|
||||
val nextEnd = companionChannels[0].at(end + 2_000).endMs
|
||||
OrbitCompanion.follow(screen, anchor, nextEnd + 1_000)
|
||||
anchor = OrbitCompanion.follow(screen, anchor, nextEnd - 5_000); assertTrue(tuned.isEmpty())
|
||||
// A moment before the end, so the channel's own next programme never starts.
|
||||
OrbitCompanion.follow(screen, anchor, nextEnd - 2_000)
|
||||
assertEquals(listOf(308 to 0L), tuned); assertTrue(OrbitCompanion.queue.isEmpty())
|
||||
// Five at most.
|
||||
repeat(5) { assertNotNull(OrbitCompanion.enqueue(screen, 101, null, now)) }
|
||||
|
||||
Reference in New Issue
Block a user