feat: add editable playback queue

This commit is contained in:
2026-10-18 00:15:05 +02:00
parent d4704af442
commit ce903e2367
10 changed files with 510 additions and 33 deletions
+34
View File
@@ -17,6 +17,36 @@ struct CastPlaybackCheck {
require(predicate(), message)
}
static func queued(_ model: PlayerModel, source: URL, port: UInt16, gates: URL) async throws {
model.openFiles([source, source, source])
try await until(model, "queue local source plays") { model.state.status == PLAYER_PLAYING && model.canSeek }
model.cast(to: CastDevice(id: "loopback", name: "Loopback TV", host: "127.0.0.1", port: port))
try await until(model, "queue receiver starts") {
model.castDevice?.id == "loopback" && !model.castConnecting && model.state.status == PLAYER_PLAYING
}
let initial = model.queue.currentID
model.advanceQueue(1)
try await until(model, "manual queue next retains receiver") {
model.queue.currentID != initial && model.castDevice?.id == "loopback" &&
!model.castConnecting && model.state.status == PLAYER_PLAYING
}
let middle = model.queue.currentID
try Data().write(to: gates.appendingPathComponent("next"), options: .atomic)
try await until(model, "receiver EOF automatically advances queue without disconnecting") {
model.queue.currentID != middle && model.castDevice?.id == "loopback" &&
!model.castConnecting && model.state.status == PLAYER_PLAYING
}
require(!model.queue.canNext, "receiver automatic advance selects final queue entry")
try Data().write(to: gates.appendingPathComponent("advanced"), options: .atomic)
try await until(model, "final receiver EOF stops without wrapping") { model.state.status == PLAYER_ENDED }
require(model.castDevice?.id == "loopback" && !model.queue.canNext,
"final receiver EOF preserves receiver and last selection")
model.stopCasting()
try await until(model, "Cast restoration keeps local queue") { model.castDevice == nil && !model.isBusy }
require(model.queue.items.count == 3 && !model.queue.canNext,
"Cast restoration does not replace queue")
}
static func interrupted(_ model: PlayerModel, source: URL, port: UInt16,
scenario: String, gates: URL, defaults: UserDefaults) async throws {
func signal(_ name: String) throws {
@@ -183,6 +213,10 @@ struct CastPlaybackCheck {
let model = PlayerModel(defaults: defaults)
defer { model.shutdown() }
if CommandLine.arguments.count == 5 {
if CommandLine.arguments[3] == "queue" {
try await queued(model, source: source, port: port, gates: URL(fileURLWithPath: CommandLine.arguments[4]))
return
}
try await interrupted(model, source: source, port: port, scenario: CommandLine.arguments[3],
gates: URL(fileURLWithPath: CommandLine.arguments[4]), defaults: defaults)
return