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
+50
View File
@@ -51,6 +51,54 @@ struct SystemPlaybackChecks {
"disabled compact progress leaves only the title")
}
static func checkQueue(directory: URL, defaults: UserDefaults) {
let model = PlayerModel(defaults: defaults)
defer { model.shutdown() }
model.setVolume(0)
let video = directory.appendingPathComponent("av.mp4")
let audio = directory.appendingPathComponent("audio.wav")
model.openFiles([video, audio])
until("queue opens its naturally sorted first file") {
model.queue.currentURL == audio && model.state.status == PLAYER_PLAYING && model.canSeek && !model.isBusy
}
let current = model.queue.currentID!
require(model.setPlayback(playing: false), "pause queue before editing")
until("queue pause acknowledged") { model.state.status == PLAYER_PAUSED && model.playbackIntent == nil }
let revision = model.state.revision
model.addToQueue([video])
model.moveQueueItems(fromOffsets: IndexSet(integer: 0), toOffset: 2)
require(model.queue.currentID == current && model.state.revision == revision &&
model.state.status == PLAYER_PAUSED, "append and reorder do not reopen current playback")
model.removeQueueItem(model.queue.items.last!.id)
require(model.queue.currentID == current && model.state.revision == revision,
"removing another queue entry leaves native playback untouched")
model.removeQueueItem(current)
until("removing final current entry stops despite earlier remaining entries") {
model.queue.currentID == nil && model.state.status == PLAYER_EMPTY
}
require(model.queue.items.count == 1, "stopping at queue end preserves earlier entries")
model.selectQueueItem(model.queue.items[0].id)
until("explicit queue selection opens remaining entry") {
model.queue.currentURL == video && model.state.status == PLAYER_PLAYING && model.canSeek && !model.isBusy
}
model.openFiles([video, audio])
until("replacement queue starts with audio") {
model.queue.currentURL == audio && model.state.status == PLAYER_PLAYING && model.canSeek && !model.isBusy
}
require(model.seekRelative(model.duration - model.state.position - 0.2), "queue seeks near first EOF")
until("natural EOF advances to next queue file") {
model.queue.currentURL == video && model.state.status == PLAYER_PLAYING && model.canSeek && !model.isBusy
}
require(model.seekRelative(model.duration - model.state.position - 0.2), "queue seeks near final EOF")
until("final queue EOF stops without wrapping") { model.state.status == PLAYER_ENDED }
require(model.queue.currentURL == video && !model.queue.canNext, "final EOF retains last selection")
model.openFiles([directory.appendingPathComponent("hdr.mkv"), video])
model.selectQueueItem(model.queue.items.first { $0.url.lastPathComponent == "hdr.mkv" }!.id)
until("queued playback error is acknowledged") { model.state.status == PLAYER_ERROR && !model.isBusy }
require(model.queue.currentURL?.lastPathComponent == "hdr.mkv",
"playback failure stops on failed queue entry rather than skipping")
}
static func main() {
checkCompactProgress()
_ = NSApplication.shared
@@ -58,6 +106,8 @@ struct SystemPlaybackChecks {
let suite = "terebi.system-playback-check.\(UUID().uuidString)"
let defaults = UserDefaults(suiteName: suite)!
defer { defaults.removePersistentDomain(forName: suite) }
checkQueue(directory: URL(fileURLWithPath: CommandLine.arguments[1], isDirectory: true), defaults: defaults)
defaults.removePersistentDomain(forName: suite)
let initialModel = PlayerModel(defaults: defaults)
require(!initialModel.showsBufferInfo, "buffer readout defaults off before playback")
initialModel.setShowsBufferInfo(true)