import Foundation /// Was abgespielt werden soll und wie. /// /// Die Entscheidung *ob* umgerechnet wird, fällt vorher — im /// `PlaybackDecider`, aus Profil und Leitung. Hier steht nur noch, was der /// Server daraufhin bereitstellen soll. Das ist die Trennung, die es vorher /// nicht gab: der Player hat Plex' Transcoder unmittelbar angesprochen und /// konnte deshalb mit keinem anderen Server reden. public struct PlaybackIntent: Sendable, Equatable { public let itemID: String /// Welche Fassung — ein Film kann mehrfach vorliegen. public let versionIndex: Int /// Die Datei innerhalb der Fassung. Plex adressiert Dateien, Jellyfin /// Quellen; beide finden sich hierüber wieder. public let file: MediaFile /// `nil` heißt: unverändert übertragen. public let transcode: TranscodeSettings? public let startTime: Duration /// Ob der Server im selben Netz steht. Plex rechnet dann anders. public let isLocalConnection: Bool public init( itemID: String, versionIndex: Int, file: MediaFile, transcode: TranscodeSettings? = nil, startTime: Duration = .zero, isLocalConnection: Bool = false ) { self.itemID = itemID self.versionIndex = versionIndex self.file = file self.transcode = transcode self.startTime = startTime self.isLocalConnection = isLocalConnection } } /// Wie weit heruntergerechnet werden soll. public struct TranscodeSettings: Sendable, Equatable { /// In Kilobit je Sekunde. `nil` heißt „so gut wie möglich". public let maximumBitrate: Int? /// Etwa „1280x720". `nil` lässt die Auflösung, wie sie ist. public let resolution: String? public init(maximumBitrate: Int?, resolution: String?) { self.maximumBitrate = maximumBitrate self.resolution = resolution } } /// Was der Server für diese Wiedergabe bereitgestellt hat. public struct PlaybackTarget: Sendable, Equatable { public let url: URL /// Die Sitzung, die der Server dafür angelegt hat. /// /// Zum Aufräumen: ohne dieses Kennzeichen rechnet der Transcoder weiter, /// wenn längst niemand mehr zusieht. public let sessionID: String? /// Welche Fassung gespielt wird. /// /// Jellyfin will sie bei jeder Fortschrittsmeldung zurückhaben, sonst /// ordnet es die Meldung keiner Wiedergabe zu. public let versionID: String? public init(url: URL, sessionID: String? = nil, versionID: String? = nil) { self.url = url self.sessionID = sessionID self.versionID = versionID } } /// In welchem Zustand sich die Wiedergabe befindet. public enum PlaybackReportState: String, Sendable { /// Der erste Bericht einer Wiedergabe. /// /// Eigener Fall, weil Jellyfin dafür einen eigenen Endpunkt hat: ohne ihn /// erscheint der Titel nirgends als „läuft gerade", und die Sitzung, unter /// der die weiteren Meldungen laufen, ist dem Server unbekannt. Plex /// unterscheidet das nicht und behandelt ihn wie „spielt". case started case playing case paused /// Beim Verlassen des Players. Erst dieser Wert nimmt den Titel auf dem /// Server aus „wird gerade abgespielt" heraus. case stopped case buffering } /// Wo man gerade steht. public struct PlaybackReport: Sendable, Equatable { public let itemID: String public let sessionID: String? public let versionID: String? public let state: PlaybackReportState public let time: Duration public let duration: Duration public init( itemID: String, sessionID: String? = nil, versionID: String? = nil, state: PlaybackReportState, time: Duration, duration: Duration ) { self.itemID = itemID self.sessionID = sessionID self.versionID = versionID self.state = state self.time = time self.duration = duration } } extension PlaybackReportState: Equatable {}