import Foundation /// Eine Mediathek auf dem Server. public struct PlexLibrary: Sendable, Equatable, Decodable, Identifiable { public enum Kind: String, Sendable, Codable { case movie, show, artist, photo /// Live-TV und Aufnahmen. case livetv } /// Die Nummer des Abschnitts, als Zeichenkette. Steckt in fast jedem /// weiteren Pfad. public let key: String public let title: String public let type: String public let uuid: String? public let art: String? public let thumb: String? public let updatedAt: Int? public var id: String { key } public var kind: Kind? { Kind(rawValue: type) } /// Ob Flixy diese Mediathek darstellen kann. Musik und Fotos sind laut /// Plan nicht vorgesehen — sie erscheinen deshalb gar nicht erst in der /// Seitenleiste, statt dort auf einen leeren Bildschirm zu führen. public var isSupported: Bool { kind == .movie || kind == .show } public init( key: String, title: String, type: String, uuid: String? = nil, art: String? = nil, thumb: String? = nil, updatedAt: Int? = nil ) { self.key = key self.title = title self.type = type self.uuid = uuid self.art = art self.thumb = thumb self.updatedAt = updatedAt } } /// Eine Reihe auf der Startseite. /// /// Plex nennt sie „Hub" und liefert sie fertig zusammengestellt — Weiterschauen, /// Zuletzt hinzugefügt, Sammlungen. Die App muss diese Reihen also nicht selbst /// bauen, sondern nur darstellen. public struct PlexHub: Sendable, Equatable, Decodable, Identifiable { /// Stabiler Bezeichner wie `home.continue` oder `movie.recentlyadded`. /// Danach richtet sich die Sortierung in den Einstellungen. public let hubIdentifier: String public let title: String public let type: String? public let key: String? public let size: Int? /// Ob es mehr Einträge gibt, als die Reihe zeigt — Grundlage für ein /// „Alle anzeigen" am Ende. public let more: Bool public let items: [PlexItem] public var id: String { hubIdentifier } private enum CodingKeys: String, CodingKey { case hubIdentifier, title, type, key, size, more case items = "Metadata" } public init(from decoder: any Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) self.title = try values.decode(String.self, forKey: .title) // Ältere Serverfassungen liefern keinen `hubIdentifier`. Der Titel ist // dann der einzige verfügbare Schlüssel — schlechter, aber besser als // eine Antwort, die gar nicht lesbar ist. self.hubIdentifier = try values.decodeIfPresent(String.self, forKey: .hubIdentifier) ?? title self.type = try values.decodeIfPresent(String.self, forKey: .type) self.key = try values.decodeIfPresent(String.self, forKey: .key) self.size = try values.decodeIfPresent(Int.self, forKey: .size) self.more = try values.decodeIfPresent(Bool.self, forKey: .more) ?? false self.items = try values.decodeIfPresent([PlexItem].self, forKey: .items) ?? [] } public init( hubIdentifier: String, title: String, type: String? = nil, key: String? = nil, size: Int? = nil, more: Bool = false, items: [PlexItem] = [] ) { self.hubIdentifier = hubIdentifier self.title = title self.type = type self.key = key self.size = size self.more = more self.items = items } }