import Foundation import HaloDownloads import MediaKit /// Welche Qualitätsstufen für einen Titel zur Wahl stehen — und wie sie heißen. /// /// **Als eigener Typ, weil es die Frage inzwischen an zwei Stellen gibt:** am /// Knopf einer einzelnen Folge und an der Leiste, mit der man mehrere auf /// einmal lädt. Dieselbe Entscheidung zweimal zu schreiben hiesse, dass sie /// sich auseinanderentwickelt — und die erste Kopie wäre die mit dem Fehler. /// /// Kein `View`: hier steht keine Zeile SwiftUI, nur die Frage, was angeboten /// werden darf und wie es beschriftet ist. struct DownloadQualityChoice { let item: MediaItem var mediaIndex: Int = 0 let backend: (any MediaBackend)? /// Nur Stufen, die unter der Auflösung der Datei liegen. /// /// Und nur, wenn der Server verkleinerte Fassungen überhaupt herausgibt. /// Jellyfin nennt die Adresse dafür erst nach einer eigenen Anfrage — die /// Wahl anzubieten und dann abzulehnen wäre eine leere Zusage. var available: [DownloadQuality] { let alle = DownloadQuality.available(forSourceHeight: currentMedia?.pixelHeight) guard allowsCompressed else { return [.original] } return alle } /// Die Beschriftung samt Auflösung und geschätzter Größe. /// /// Beim Original steht dabei, was es überhaupt ist: „Original · 720p". /// Ohne diese Angabe ist die Wahl blind — man weiß nicht, ob man gerade /// herunterrechnet oder nicht. func label(for quality: DownloadQuality) -> String { let originalBytes = currentMedia?.files.first?.size ?? 0 let bytes = quality.estimatedBytes( durationMilliseconds: item.duration, originalBytes: originalBytes ) var name = String(localized: quality.localizedName) if quality == .original, let resolution = currentMedia?.resolutionLabel { name += " · \(resolution)" } guard bytes > 0 else { return name } let size = bytes.formatted(.byteCount(style: .file)) return quality == .original ? "\(name) · \(size)" : String(localized: "downloads.quality.approx \(name) \(size)") } private var currentMedia: MediaVersion? { item.versions.indices.contains(mediaIndex) ? item.versions[mediaIndex] : item.preferredVersion } private var allowsCompressed: Bool { backend?.compressedDownloadURL( itemID: item.id, versionIndex: mediaIndex, maximumBitrate: 8_000, resolution: nil ) != nil } }