mirror of
https://github.com/yattee/yattee.git
synced 2026-07-20 22:32:01 +00:00
Remove Enable DASH setting; make DASH a last-resort format
Drop the dashEnabled toggle and its plumbing. Stream auto-selection now keeps DASH as a candidate but ranks it strictly below progressive and HLS formats, so DASH is only chosen when it is the only format available (including live-stream fallback after HLS). The manual quality selector hides DASH entirely on iOS/tvOS/macOS. Reconciles BackendSwitcher, which previously treated HLS/DASH equally, to use the same DASH-last ranking.
This commit is contained in:
@@ -20,7 +20,6 @@ enum SettingsKey: String, CaseIterable {
|
|||||||
case cellularQuality
|
case cellularQuality
|
||||||
case autoplay
|
case autoplay
|
||||||
case backgroundPlayback
|
case backgroundPlayback
|
||||||
case dashEnabled
|
|
||||||
case preferredAudioLanguage
|
case preferredAudioLanguage
|
||||||
case preferredSubtitlesLanguage
|
case preferredSubtitlesLanguage
|
||||||
case resumeAction
|
case resumeAction
|
||||||
|
|||||||
@@ -70,19 +70,6 @@ extension SettingsManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether DASH streams are enabled (MPV only).
|
|
||||||
/// Disabled by default as DASH can be unreliable with some Invidious instances.
|
|
||||||
var dashEnabled: Bool {
|
|
||||||
get {
|
|
||||||
if let cached = _dashEnabled { return cached }
|
|
||||||
return bool(for: .dashEnabled, default: false)
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
_dashEnabled = newValue
|
|
||||||
set(newValue, for: .dashEnabled)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var allowSoftwareDecodedFormats: Bool {
|
var allowSoftwareDecodedFormats: Bool {
|
||||||
get {
|
get {
|
||||||
if let cached = _allowSoftwareDecodedFormats { return cached }
|
if let cached = _allowSoftwareDecodedFormats { return cached }
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ final class SettingsManager {
|
|||||||
var _preferredQuality: VideoQuality?
|
var _preferredQuality: VideoQuality?
|
||||||
var _cellularQuality: VideoQuality?
|
var _cellularQuality: VideoQuality?
|
||||||
var _backgroundPlaybackEnabled: Bool?
|
var _backgroundPlaybackEnabled: Bool?
|
||||||
var _dashEnabled: Bool?
|
|
||||||
var _preferredAudioLanguage: String?
|
var _preferredAudioLanguage: String?
|
||||||
var _preferredSubtitlesLanguage: String?
|
var _preferredSubtitlesLanguage: String?
|
||||||
var _playerVolume: Float?
|
var _playerVolume: Float?
|
||||||
@@ -415,7 +414,6 @@ final class SettingsManager {
|
|||||||
_preferredQuality = nil
|
_preferredQuality = nil
|
||||||
_cellularQuality = nil
|
_cellularQuality = nil
|
||||||
_backgroundPlaybackEnabled = nil
|
_backgroundPlaybackEnabled = nil
|
||||||
_dashEnabled = nil
|
|
||||||
_preferredAudioLanguage = nil
|
_preferredAudioLanguage = nil
|
||||||
_preferredSubtitlesLanguage = nil
|
_preferredSubtitlesLanguage = nil
|
||||||
_playerVolume = nil
|
_playerVolume = nil
|
||||||
|
|||||||
@@ -12181,16 +12181,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings.playback.dash" : {
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Enable DASH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"settings.playback.macOS.autoResizePlayer" : {
|
"settings.playback.macOS.autoResizePlayer" : {
|
||||||
"comment" : "Toggle for automatically resizing player window to match video aspect ratio",
|
"comment" : "Toggle for automatically resizing player window to match video aspect ratio",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
|
|||||||
@@ -306,16 +306,13 @@ final class BackendSwitcher {
|
|||||||
filteredMuxed = muxedStreams
|
filteredMuxed = muxedStreams
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort: prefer non-HLS/DASH (progressive) formats, then by resolution
|
// Sort: prefer progressive formats, then HLS, and only fall back to DASH as a last
|
||||||
|
// resort (DASH should never be chosen when any other format is available).
|
||||||
let sortedMuxed = filteredMuxed.sorted { s1, s2 in
|
let sortedMuxed = filteredMuxed.sorted { s1, s2 in
|
||||||
let format1 = StreamFormat.detect(from: s1)
|
let rank1 = muxedFormatRank(StreamFormat.detect(from: s1))
|
||||||
let format2 = StreamFormat.detect(from: s2)
|
let rank2 = muxedFormatRank(StreamFormat.detect(from: s2))
|
||||||
let isAdaptive1 = format1 == .hls || format1 == .dash
|
if rank1 != rank2 {
|
||||||
let isAdaptive2 = format2 == .hls || format2 == .dash
|
return rank1 < rank2
|
||||||
|
|
||||||
// Prefer progressive formats for non-live content
|
|
||||||
if isAdaptive1 != isAdaptive2 {
|
|
||||||
return !isAdaptive1 // non-adaptive (false) comes first
|
|
||||||
}
|
}
|
||||||
return (s1.resolution ?? .p360) > (s2.resolution ?? .p360)
|
return (s1.resolution ?? .p360) > (s2.resolution ?? .p360)
|
||||||
}
|
}
|
||||||
@@ -332,6 +329,17 @@ final class BackendSwitcher {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Ranks muxed formats for fallback selection (lower = preferred).
|
||||||
|
/// Progressive formats win, then HLS; DASH is the last resort and is only
|
||||||
|
/// selected when it is the only format available.
|
||||||
|
private func muxedFormatRank(_ format: StreamFormat) -> Int {
|
||||||
|
switch format {
|
||||||
|
case .dash: return 2
|
||||||
|
case .hls: return 1
|
||||||
|
default: return 0 // progressive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns codec priority for video streams (higher = better for MPV).
|
/// Returns codec priority for video streams (higher = better for MPV).
|
||||||
/// AV1 > VP9 > H.264/AVC
|
/// AV1 > VP9 > H.264/AVC
|
||||||
private func videoCodecPriority(_ codec: String?) -> Int {
|
private func videoCodecPriority(_ codec: String?) -> Int {
|
||||||
|
|||||||
@@ -1901,7 +1901,6 @@ final class PlayerService {
|
|||||||
|
|
||||||
private func selectStreams(for backendType: PlayerBackendType, from streams: [Stream]) -> (video: Stream, audio: Stream?)? {
|
private func selectStreams(for backendType: PlayerBackendType, from streams: [Stream]) -> (video: Stream, audio: Stream?)? {
|
||||||
let supportedFormats = backendType.supportedFormats
|
let supportedFormats = backendType.supportedFormats
|
||||||
let dashEnabled = settingsManager?.dashEnabled ?? false
|
|
||||||
|
|
||||||
// Get user's original quality preference (before network adjustments)
|
// Get user's original quality preference (before network adjustments)
|
||||||
let userPreferredQuality = settingsManager?.preferredQuality ?? .auto
|
let userPreferredQuality = settingsManager?.preferredQuality ?? .auto
|
||||||
@@ -1932,7 +1931,6 @@ final class PlayerService {
|
|||||||
let muxedStreams = streams.filter { stream in
|
let muxedStreams = streams.filter { stream in
|
||||||
let format = StreamFormat.detect(from: stream)
|
let format = StreamFormat.detect(from: stream)
|
||||||
guard supportedFormats.contains(format) else { return false }
|
guard supportedFormats.contains(format) else { return false }
|
||||||
if format == .dash && !dashEnabled { return false }
|
|
||||||
// Only include HLS/DASH if they have video (audio-only HLS/DASH should be treated as audio streams)
|
// Only include HLS/DASH if they have video (audio-only HLS/DASH should be treated as audio streams)
|
||||||
if format == .hls || format == .dash {
|
if format == .hls || format == .dash {
|
||||||
return !stream.isAudioOnly
|
return !stream.isAudioOnly
|
||||||
@@ -1972,7 +1970,7 @@ final class PlayerService {
|
|||||||
LoggingService.shared.debug("Stream selection: Using HLS for live stream", category: .player)
|
LoggingService.shared.debug("Stream selection: Using HLS for live stream", category: .player)
|
||||||
return (hlsStream, nil)
|
return (hlsStream, nil)
|
||||||
}
|
}
|
||||||
if dashEnabled, let dashStream = muxedStreams.first(where: { StreamFormat.detect(from: $0) == .dash }) {
|
if let dashStream = muxedStreams.first(where: { StreamFormat.detect(from: $0) == .dash }) {
|
||||||
LoggingService.shared.debug("Stream selection: Using DASH for live stream", category: .player)
|
LoggingService.shared.debug("Stream selection: Using DASH for live stream", category: .player)
|
||||||
return (dashStream, nil)
|
return (dashStream, nil)
|
||||||
}
|
}
|
||||||
@@ -2065,16 +2063,13 @@ final class PlayerService {
|
|||||||
filteredMuxed = muxedStreams
|
filteredMuxed = muxedStreams
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort: prefer non-HLS/DASH (progressive) formats, then by resolution
|
// Sort: prefer progressive formats, then HLS, and only fall back to DASH as a last
|
||||||
|
// resort (DASH should never be chosen when any other format is available).
|
||||||
let sortedMuxed = filteredMuxed.sorted { s1, s2 in
|
let sortedMuxed = filteredMuxed.sorted { s1, s2 in
|
||||||
let format1 = StreamFormat.detect(from: s1)
|
let rank1 = muxedFormatRank(StreamFormat.detect(from: s1))
|
||||||
let format2 = StreamFormat.detect(from: s2)
|
let rank2 = muxedFormatRank(StreamFormat.detect(from: s2))
|
||||||
let isAdaptive1 = format1 == .hls || format1 == .dash
|
if rank1 != rank2 {
|
||||||
let isAdaptive2 = format2 == .hls || format2 == .dash
|
return rank1 < rank2
|
||||||
|
|
||||||
// Prefer progressive formats for non-live content
|
|
||||||
if isAdaptive1 != isAdaptive2 {
|
|
||||||
return !isAdaptive1 // non-adaptive (false) comes first
|
|
||||||
}
|
}
|
||||||
return (s1.resolution ?? .p360) > (s2.resolution ?? .p360)
|
return (s1.resolution ?? .p360) > (s2.resolution ?? .p360)
|
||||||
}
|
}
|
||||||
@@ -2091,6 +2086,17 @@ final class PlayerService {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Ranks muxed formats for fallback selection (lower = preferred).
|
||||||
|
/// Progressive formats win, then HLS; DASH is the last resort and is only
|
||||||
|
/// selected when it is the only format available.
|
||||||
|
private func muxedFormatRank(_ format: StreamFormat) -> Int {
|
||||||
|
switch format {
|
||||||
|
case .dash: return 2
|
||||||
|
case .hls: return 1
|
||||||
|
default: return 0 // progressive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns codec priority for video streams (higher = better).
|
/// Returns codec priority for video streams (higher = better).
|
||||||
/// Prefers hardware-decodable codecs for battery efficiency.
|
/// Prefers hardware-decodable codecs for battery efficiency.
|
||||||
private func videoCodecPriority(_ codec: String?) -> Int {
|
private func videoCodecPriority(_ codec: String?) -> Int {
|
||||||
|
|||||||
@@ -667,12 +667,11 @@ private struct PlayerSheetsModifier: ViewModifier {
|
|||||||
private var qualitySelectorSheet: some View {
|
private var qualitySelectorSheet: some View {
|
||||||
if let playerService {
|
if let playerService {
|
||||||
let supportedFormats = playerService.currentBackendType.supportedFormats
|
let supportedFormats = playerService.currentBackendType.supportedFormats
|
||||||
let dashEnabled = appEnvironment?.settingsManager.dashEnabled ?? false
|
|
||||||
QualitySelectorView(
|
QualitySelectorView(
|
||||||
streams: playerService.availableStreams.filter { stream in
|
streams: playerService.availableStreams.filter { stream in
|
||||||
let format = StreamFormat.detect(from: stream)
|
let format = StreamFormat.detect(from: stream)
|
||||||
// Filter out DASH streams if disabled in settings
|
// DASH is never offered for manual selection
|
||||||
if format == .dash && !dashEnabled {
|
if format == .dash {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return supportedFormats.contains(format)
|
return supportedFormats.contains(format)
|
||||||
|
|||||||
@@ -143,13 +143,13 @@ struct TVPlayerView: View {
|
|||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private var qualityPanelContent: some View {
|
private var qualityPanelContent: some View {
|
||||||
if let playerService {
|
if let playerService {
|
||||||
let dashEnabled = appEnvironment?.settingsManager.dashEnabled ?? false
|
|
||||||
let supportedFormats = playerService.currentBackendType.supportedFormats
|
let supportedFormats = playerService.currentBackendType.supportedFormats
|
||||||
|
|
||||||
QualitySelectorView(
|
QualitySelectorView(
|
||||||
streams: playerService.availableStreams.filter { stream in
|
streams: playerService.availableStreams.filter { stream in
|
||||||
let format = StreamFormat.detect(from: stream)
|
let format = StreamFormat.detect(from: stream)
|
||||||
if format == .dash && !dashEnabled {
|
// DASH is never offered for manual selection
|
||||||
|
if format == .dash {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return supportedFormats.contains(format)
|
return supportedFormats.contains(format)
|
||||||
|
|||||||
@@ -206,13 +206,6 @@ struct AdvancedSettingsView: View {
|
|||||||
Label(String(localized: "settings.advanced.mpv.edl"), systemImage: "arrow.trianglehead.merge")
|
Label(String(localized: "settings.advanced.mpv.edl"), systemImage: "arrow.trianglehead.merge")
|
||||||
}
|
}
|
||||||
|
|
||||||
Toggle(isOn: Binding(
|
|
||||||
get: { settingsManager.dashEnabled },
|
|
||||||
set: { settingsManager.dashEnabled = $0 }
|
|
||||||
)) {
|
|
||||||
Label(String(localized: "settings.playback.dash"), systemImage: "bolt.horizontal")
|
|
||||||
}
|
|
||||||
|
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
NavigationLink {
|
NavigationLink {
|
||||||
TVSidebarDetailContainer(
|
TVSidebarDetailContainer(
|
||||||
|
|||||||
Reference in New Issue
Block a user