1
0
mirror of https://github.com/yattee/yattee.git synced 2024-12-12 21:30:32 +05:30
yattee/Model/QualityProfile.swift

127 lines
3.9 KiB
Swift
Raw Permalink Normal View History

2022-08-14 22:36:22 +05:30
import Defaults
import Foundation
struct QualityProfile: Hashable, Identifiable, Defaults.Serializable {
static var bridge = QualityProfileBridge()
static var defaultProfile = Self(id: "default", backend: .mpv, resolution: .hd720p60, formats: [.stream], order: Array(Format.allCases.indices))
2022-08-14 22:36:22 +05:30
enum Format: String, CaseIterable, Identifiable, Defaults.Serializable {
case avc1
case stream
2022-08-14 22:36:22 +05:30
case webm
case mp4
case av1
case hls
2022-08-14 22:36:22 +05:30
var id: String {
rawValue
}
var description: String {
switch self {
case .stream:
return "Stream"
case .webm:
return "WebM"
default:
return rawValue.uppercased()
}
}
var streamFormat: Stream.Format? {
switch self {
case .avc1:
return .avc1
case .stream:
return nil
case .webm:
return .webm
case .mp4:
return .mp4
case .av1:
return .av1
case .hls:
return nil
2022-08-14 22:36:22 +05:30
}
}
}
var id = UUID().uuidString
var name: String?
var backend: PlayerBackendType
var resolution: ResolutionSetting
var formats: [Format]
var order: [Int]
2022-08-14 22:36:22 +05:30
var description: String {
2022-09-28 19:57:01 +05:30
if let name, !name.isEmpty { return name }
return "\(backend.label) - \(resolution.description) - \(formatsDescription)"
}
var formatsDescription: String {
switch formats.count {
case Format.allCases.count:
2022-09-27 20:14:15 +05:30
return "Any format".localized()
case 0:
return "No format selected".localized()
case 1 ... 3:
return formats.map(\.description).joined(separator: ", ")
default:
return String(format: "%@ formats".localized(), String(formats.count))
}
2022-08-14 22:36:22 +05:30
}
func isPreferred(_ stream: Stream) -> Bool {
if formats.contains(.hls), stream.kind == .hls {
return true
}
let defaultResolution = Stream.Resolution.custom(height: 720, refreshRate: 30)
let resolutionMatch = resolution.value ?? defaultResolution >= stream.resolution
2022-08-14 22:36:22 +05:30
if resolutionMatch, formats.contains(.stream), stream.kind == .stream {
return true
}
let formatMatch = formats.compactMap(\.streamFormat).contains(stream.format)
return resolutionMatch && formatMatch
}
}
struct QualityProfileBridge: Defaults.Bridge {
static let formatsSeparator = ","
typealias Value = QualityProfile
typealias Serializable = [String: String]
func serialize(_ value: Value?) -> Serializable? {
2022-09-28 19:57:01 +05:30
guard let value else { return nil }
2022-08-14 22:36:22 +05:30
return [
"id": value.id,
"name": value.name ?? "",
"backend": value.backend.rawValue,
"resolution": value.resolution.rawValue,
"formats": value.formats.map(\.rawValue).joined(separator: Self.formatsSeparator),
"order": value.order.map { String($0) }.joined(separator: Self.formatsSeparator) // New line
2022-08-14 22:36:22 +05:30
]
}
func deserialize(_ object: Serializable?) -> Value? {
2022-09-28 19:57:01 +05:30
guard let object,
2022-08-14 22:36:22 +05:30
let id = object["id"],
let backend = PlayerBackendType(rawValue: object["backend"] ?? ""),
let resolution = ResolutionSetting(rawValue: object["resolution"] ?? "")
else {
return nil
}
let name = object["name"]
let formats = (object["formats"] ?? "").components(separatedBy: Self.formatsSeparator).compactMap { QualityProfile.Format(rawValue: $0) }
let order = (object["order"] ?? "").components(separatedBy: Self.formatsSeparator).compactMap { Int($0) }
2022-08-14 22:36:22 +05:30
return .init(id: id, name: name, backend: backend, resolution: resolution, formats: formats, order: order)
2022-08-14 22:36:22 +05:30
}
}