diff --git a/Model/Player/Backends/AVPlayerBackend.swift b/Model/Player/Backends/AVPlayerBackend.swift index 53d60b5d..14c1a48d 100644 --- a/Model/Player/Backends/AVPlayerBackend.swift +++ b/Model/Player/Backends/AVPlayerBackend.swift @@ -60,7 +60,7 @@ final class AVPlayerBackend: PlayerBackend { addPlayerTimeControlStatusObserver() } - func bestPlayable(_ streams: [Stream]) -> Stream? { + func bestPlayable(_ streams: [Stream], maxResolution _: ResolutionSetting) -> Stream? { streams.first { $0.kind == .hls } ?? streams.filter { $0.kind == .adaptive }.max { $0.resolution < $1.resolution } ?? streams.first diff --git a/Model/Player/Backends/MPVBackend.swift b/Model/Player/Backends/MPVBackend.swift index f9c86514..5837b4e2 100644 --- a/Model/Player/Backends/MPVBackend.swift +++ b/Model/Player/Backends/MPVBackend.swift @@ -52,8 +52,10 @@ final class MPVBackend: PlayerBackend { clientTimer.eventHandler = getClientUpdates } - func bestPlayable(_ streams: [Stream]) -> Stream? { - streams.filter { $0.kind == .adaptive }.max { $0.resolution < $1.resolution } ?? + func bestPlayable(_ streams: [Stream], maxResolution: ResolutionSetting) -> Stream? { + streams + .filter { $0.kind == .adaptive && $0.resolution <= maxResolution.value } + .max { $0.resolution < $1.resolution } ?? streams.first { $0.kind == .hls } ?? streams.first } diff --git a/Model/Player/Backends/PlayerBackend.swift b/Model/Player/Backends/PlayerBackend.swift index 95a36185..4c869173 100644 --- a/Model/Player/Backends/PlayerBackend.swift +++ b/Model/Player/Backends/PlayerBackend.swift @@ -16,7 +16,7 @@ protocol PlayerBackend { var isPlaying: Bool { get } var playerItemDuration: CMTime? { get } - func bestPlayable(_ streams: [Stream]) -> Stream? + func bestPlayable(_ streams: [Stream], maxResolution: ResolutionSetting) -> Stream? func canPlay(_ stream: Stream) -> Bool func playStream( diff --git a/Model/Player/PlayerQueue.swift b/Model/Player/PlayerQueue.swift index 4c45d148..6c4978ad 100644 --- a/Model/Player/PlayerQueue.swift +++ b/Model/Player/PlayerQueue.swift @@ -94,13 +94,7 @@ extension PlayerModel { streams = streams.filter { backend.canPlay($0) } - switch quality { - case .best: - return backend.bestPlayable(streams) - default: - let sorted = streams.filter { $0.kind != .hls }.sorted { $0.resolution > $1.resolution }.sorted { $0.kind < $1.kind } - return sorted.first(where: { $0.resolution.height <= quality.value.height }) - } + return backend.bestPlayable(streams, maxResolution: quality) } func advanceToNextItem() { diff --git a/Model/Stream.swift b/Model/Stream.swift index 8b237fbb..822720e7 100644 --- a/Model/Stream.swift +++ b/Model/Stream.swift @@ -5,7 +5,18 @@ import Foundation // swiftlint:disable:next final_class class Stream: Equatable, Hashable, Identifiable { enum Resolution: String, CaseIterable, Comparable, Defaults.Serializable { - case hd2160p, hd1440p60, hd1440p, hd1080p60, hd1080p, hd720p60, hd720p, sd480p, sd360p, sd240p, sd144p, unknown + case hd2160p + case hd1440p60 + case hd1440p + case hd1080p60 + case hd1080p + case hd720p60 + case hd720p + case sd480p + case sd360p + case sd240p + case sd144p + case unknown var name: String { "\(height)p\(refreshRate != -1 ? ", \(refreshRate) fps" : "")" diff --git a/Shared/Defaults.swift b/Shared/Defaults.swift index 7ca9eb85..bd01acb1 100644 --- a/Shared/Defaults.swift +++ b/Shared/Defaults.swift @@ -95,12 +95,23 @@ extension Defaults.Keys { } enum ResolutionSetting: String, CaseIterable, Defaults.Serializable { - case best, hd720p, sd480p, sd360p, sd240p, sd144p + case best + case hd2160p + case hd1440p60 + case hd1440p + case hd1080p60 + case hd1080p + case hd720p60 + case hd720p + case sd480p + case sd360p + case sd240p + case sd144p var value: Stream.Resolution { switch self { case .best: - return .hd720p + return .hd2160p default: return Stream.Resolution(rawValue: rawValue)! } @@ -110,6 +121,8 @@ enum ResolutionSetting: String, CaseIterable, Defaults.Serializable { switch self { case .best: return "Best available quality" + case .hd2160p: + return "4K, 60fps" default: return value.name }