diff --git a/Model/Applications/PipedAPI.swift b/Model/Applications/PipedAPI.swift index f08475ed..ada60ef7 100644 --- a/Model/Applications/PipedAPI.swift +++ b/Model/Applications/PipedAPI.swift @@ -4,6 +4,7 @@ import Siesta import SwiftyJSON final class PipedAPI: Service, ObservableObject, VideosAPI { + static var disallowedVideoCodecs = ["av01"] static var authorizedEndpoints = ["subscriptions", "subscribe", "unsubscribe", "user/playlists"] @Published var account: Account! @@ -500,17 +501,19 @@ final class PipedAPI: Service, ObservableObject, VideosAPI { let videoStreams = content.dictionaryValue["videoStreams"]?.arrayValue ?? [] videoStreams.forEach { videoStream in - guard let audioAssetUrl = audioStream.dictionaryValue["url"]?.url, - let videoAssetUrl = videoStream.dictionaryValue["url"]?.url - else { + let videoCodec = videoStream.dictionaryValue["codec"]?.string ?? "" + if Self.disallowedVideoCodecs.contains(where: videoCodec.contains) { return } - let audioAsset = AVURLAsset(url: audioAssetUrl) - let videoAsset = AVURLAsset(url: videoAssetUrl) + let audioAsset = AVURLAsset(url: audioStream.dictionaryValue["url"]!.url!) + let videoAsset = AVURLAsset(url: videoStream.dictionaryValue["url"]!.url!) let videoOnly = videoStream.dictionaryValue["videoOnly"]?.boolValue ?? true - let resolution = Stream.Resolution.from(resolution: videoStream.dictionaryValue["quality"]!.stringValue) + let quality = videoStream.dictionaryValue["quality"]?.string ?? "unknown" + let qualityComponents = quality.components(separatedBy: "p") + let fps = Int(qualityComponents[1].isEmpty ? "30" : qualityComponents[1]) + let resolution = Stream.Resolution.from(resolution: quality, fps: fps) let videoFormat = videoStream.dictionaryValue["format"]?.stringValue if videoOnly { diff --git a/Model/Stream.swift b/Model/Stream.swift index 0003c117..152e450b 100644 --- a/Model/Stream.swift +++ b/Model/Stream.swift @@ -5,32 +5,30 @@ import Foundation // swiftlint:disable:next final_class class Stream: Equatable, Hashable, Identifiable { enum Resolution: String, CaseIterable, Comparable, Defaults.Serializable { - case hd4320p60 - case hd4320p case hd2160p60 case hd2160p50 case hd2160p48 - case hd2160p + case hd2160p30 case hd1440p60 case hd1440p50 case hd1440p48 - case hd1440p + case hd1440p30 case hd1080p60 case hd1080p50 case hd1080p48 - case hd1080p + case hd1080p30 case hd720p60 case hd720p50 case hd720p48 - case hd720p - case sd480p - case sd360p - case sd240p - case sd144p + case hd720p30 + case sd480p30 + case sd360p30 + case sd240p30 + case sd144p30 case unknown var name: String { - "\(height)p\(refreshRate != -1 ? ", \(refreshRate) fps" : "")" + "\(height)p\(refreshRate != -1 && refreshRate != 30 ? ", \(refreshRate) fps" : "")" } var height: Int { @@ -48,11 +46,16 @@ class Stream: Equatable, Hashable, Identifiable { } let refreshRatePart = rawValue.components(separatedBy: "p")[1] + + if refreshRatePart.isEmpty { + return 30 + } + return Int(refreshRatePart.components(separatedBy: CharacterSet.decimalDigits.inverted).joined()) ?? -1 } - static func from(resolution: String) -> Resolution { - allCases.first { "\($0)".contains(resolution) } ?? .unknown + static func from(resolution: String, fps: Int? = nil) -> Resolution { + allCases.first { $0.rawValue.contains(resolution) && $0.refreshRate == (fps ?? 30) } ?? .unknown } static func < (lhs: Resolution, rhs: Resolution) -> Bool { @@ -157,7 +160,7 @@ class Stream: Equatable, Hashable, Identifiable { } var quality: String { - if resolution == .hd2160p { + if resolution == .hd2160p30 { return "4K (2160p)" } @@ -165,13 +168,7 @@ class Stream: Equatable, Hashable, Identifiable { } var shortQuality: String { - if resolution == .hd4320p60 || resolution == .hd4320p { - return "8K" - } else if resolution == .hd2160p60 || - resolution == .hd2160p50 || - resolution == .hd2160p48 || - resolution == .hd2160p - { + if resolution.height == 2160 { return "4K" } else if kind == .hls { return "HLS" diff --git a/Shared/Defaults.swift b/Shared/Defaults.swift index f8ac9e86..02e63738 100644 --- a/Shared/Defaults.swift +++ b/Shared/Defaults.swift @@ -93,25 +93,23 @@ extension Defaults.Keys { enum ResolutionSetting: String, CaseIterable, Defaults.Serializable { case best - case hd4320p60 - case hd4320p case hd2160p60 - case hd2160p + case hd2160p30 case hd1440p60 - case hd1440p + case hd1440p30 case hd1080p60 - case hd1080p + case hd1080p30 case hd720p60 - case hd720p - case sd480p - case sd360p - case sd240p - case sd144p + case hd720p30 + case sd480p30 + case sd360p30 + case sd240p30 + case sd144p30 var value: Stream.Resolution { switch self { case .best: - return .hd4320p60 + return .hd2160p60 default: return Stream.Resolution(rawValue: rawValue)! } @@ -121,13 +119,9 @@ enum ResolutionSetting: String, CaseIterable, Defaults.Serializable { switch self { case .best: return "Best available quality" - case .hd4320p60: - return "8K, 60fps" - case .hd4320p: - return "8K" case .hd2160p60: return "4K, 60fps" - case .hd2160p: + case .hd2160p30: return "4K" default: return value.name