mirror of
				https://github.com/yattee/yattee.git
				synced 2025-10-31 12:41:57 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			122 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Swift
		
	
	
	
	
	
			
		
		
	
	
			122 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Swift
		
	
	
	
	
	
| 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])
 | |
| 
 | |
|     enum Format: String, CaseIterable, Identifiable, Defaults.Serializable {
 | |
|         case hls
 | |
|         case stream
 | |
|         case mp4
 | |
|         case avc1
 | |
|         case av1
 | |
|         case webm
 | |
| 
 | |
|         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 .hls:
 | |
|                 return nil
 | |
|             case .stream:
 | |
|                 return nil
 | |
|             case .mp4:
 | |
|                 return .mp4
 | |
|             case .webm:
 | |
|                 return .webm
 | |
|             case .avc1:
 | |
|                 return .avc1
 | |
|             case .av1:
 | |
|                 return .av1
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     var id = UUID().uuidString
 | |
| 
 | |
|     var name: String?
 | |
|     var backend: PlayerBackendType
 | |
|     var resolution: ResolutionSetting
 | |
|     var formats: [Format]
 | |
| 
 | |
|     var description: String {
 | |
|         if let name, !name.isEmpty { return name }
 | |
|         return "\(backend.label) - \(resolution.description) - \(formatsDescription)"
 | |
|     }
 | |
| 
 | |
|     var formatsDescription: String {
 | |
|         if formats.count == Format.allCases.count {
 | |
|             return "Any format".localized()
 | |
|         } else if formats.count <= 3 {
 | |
|             return formats.map(\.description).joined(separator: ", ")
 | |
|         }
 | |
| 
 | |
|         return String(format: "%@ formats".localized(), String(formats.count))
 | |
|     }
 | |
| 
 | |
|     func isPreferred(_ stream: Stream) -> Bool {
 | |
|         if formats.contains(.hls), stream.kind == .hls {
 | |
|             return true
 | |
|         }
 | |
| 
 | |
|         let resolutionMatch = !stream.resolution.isNil && resolution.value >= stream.resolution
 | |
| 
 | |
|         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? {
 | |
|         guard let value else { return nil }
 | |
| 
 | |
|         return [
 | |
|             "id": value.id,
 | |
|             "name": value.name ?? "",
 | |
|             "backend": value.backend.rawValue,
 | |
|             "resolution": value.resolution.rawValue,
 | |
|             "formats": value.formats.map { $0.rawValue }.joined(separator: Self.formatsSeparator)
 | |
|         ]
 | |
|     }
 | |
| 
 | |
|     func deserialize(_ object: Serializable?) -> Value? {
 | |
|         guard let object,
 | |
|               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) }
 | |
| 
 | |
|         return .init(id: id, name: name, backend: backend, resolution: resolution, formats: formats)
 | |
|     }
 | |
| }
 | 
