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:
Arkadiusz Fal
2026-05-20 07:14:31 +02:00
parent 88fafc5ada
commit 6dfa63c263
9 changed files with 39 additions and 59 deletions

View File

@@ -20,7 +20,6 @@ enum SettingsKey: String, CaseIterable {
case cellularQuality
case autoplay
case backgroundPlayback
case dashEnabled
case preferredAudioLanguage
case preferredSubtitlesLanguage
case resumeAction

View File

@@ -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 {
get {
if let cached = _allowSoftwareDecodedFormats { return cached }

View File

@@ -34,7 +34,6 @@ final class SettingsManager {
var _preferredQuality: VideoQuality?
var _cellularQuality: VideoQuality?
var _backgroundPlaybackEnabled: Bool?
var _dashEnabled: Bool?
var _preferredAudioLanguage: String?
var _preferredSubtitlesLanguage: String?
var _playerVolume: Float?
@@ -415,7 +414,6 @@ final class SettingsManager {
_preferredQuality = nil
_cellularQuality = nil
_backgroundPlaybackEnabled = nil
_dashEnabled = nil
_preferredAudioLanguage = nil
_preferredSubtitlesLanguage = nil
_playerVolume = nil

View File

@@ -12181,16 +12181,6 @@
}
}
},
"settings.playback.dash" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Enable DASH"
}
}
}
},
"settings.playback.macOS.autoResizePlayer" : {
"comment" : "Toggle for automatically resizing player window to match video aspect ratio",
"localizations" : {

View File

@@ -306,16 +306,13 @@ final class BackendSwitcher {
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 format1 = StreamFormat.detect(from: s1)
let format2 = StreamFormat.detect(from: s2)
let isAdaptive1 = format1 == .hls || format1 == .dash
let isAdaptive2 = format2 == .hls || format2 == .dash
// Prefer progressive formats for non-live content
if isAdaptive1 != isAdaptive2 {
return !isAdaptive1 // non-adaptive (false) comes first
let rank1 = muxedFormatRank(StreamFormat.detect(from: s1))
let rank2 = muxedFormatRank(StreamFormat.detect(from: s2))
if rank1 != rank2 {
return rank1 < rank2
}
return (s1.resolution ?? .p360) > (s2.resolution ?? .p360)
}
@@ -332,6 +329,17 @@ final class BackendSwitcher {
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).
/// AV1 > VP9 > H.264/AVC
private func videoCodecPriority(_ codec: String?) -> Int {

View File

@@ -1901,7 +1901,6 @@ final class PlayerService {
private func selectStreams(for backendType: PlayerBackendType, from streams: [Stream]) -> (video: Stream, audio: Stream?)? {
let supportedFormats = backendType.supportedFormats
let dashEnabled = settingsManager?.dashEnabled ?? false
// Get user's original quality preference (before network adjustments)
let userPreferredQuality = settingsManager?.preferredQuality ?? .auto
@@ -1932,7 +1931,6 @@ final class PlayerService {
let muxedStreams = streams.filter { stream in
let format = StreamFormat.detect(from: stream)
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)
if format == .hls || format == .dash {
return !stream.isAudioOnly
@@ -1972,7 +1970,7 @@ final class PlayerService {
LoggingService.shared.debug("Stream selection: Using HLS for live stream", category: .player)
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)
return (dashStream, nil)
}
@@ -2065,16 +2063,13 @@ final class PlayerService {
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 format1 = StreamFormat.detect(from: s1)
let format2 = StreamFormat.detect(from: s2)
let isAdaptive1 = format1 == .hls || format1 == .dash
let isAdaptive2 = format2 == .hls || format2 == .dash
// Prefer progressive formats for non-live content
if isAdaptive1 != isAdaptive2 {
return !isAdaptive1 // non-adaptive (false) comes first
let rank1 = muxedFormatRank(StreamFormat.detect(from: s1))
let rank2 = muxedFormatRank(StreamFormat.detect(from: s2))
if rank1 != rank2 {
return rank1 < rank2
}
return (s1.resolution ?? .p360) > (s2.resolution ?? .p360)
}
@@ -2091,6 +2086,17 @@ final class PlayerService {
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).
/// Prefers hardware-decodable codecs for battery efficiency.
private func videoCodecPriority(_ codec: String?) -> Int {

View File

@@ -667,12 +667,11 @@ private struct PlayerSheetsModifier: ViewModifier {
private var qualitySelectorSheet: some View {
if let playerService {
let supportedFormats = playerService.currentBackendType.supportedFormats
let dashEnabled = appEnvironment?.settingsManager.dashEnabled ?? false
QualitySelectorView(
streams: playerService.availableStreams.filter { stream in
let format = StreamFormat.detect(from: stream)
// Filter out DASH streams if disabled in settings
if format == .dash && !dashEnabled {
// DASH is never offered for manual selection
if format == .dash {
return false
}
return supportedFormats.contains(format)

View File

@@ -143,13 +143,13 @@ struct TVPlayerView: View {
@ViewBuilder
private var qualityPanelContent: some View {
if let playerService {
let dashEnabled = appEnvironment?.settingsManager.dashEnabled ?? false
let supportedFormats = playerService.currentBackendType.supportedFormats
QualitySelectorView(
streams: playerService.availableStreams.filter { stream in
let format = StreamFormat.detect(from: stream)
if format == .dash && !dashEnabled {
// DASH is never offered for manual selection
if format == .dash {
return false
}
return supportedFormats.contains(format)

View File

@@ -206,13 +206,6 @@ struct AdvancedSettingsView: View {
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)
NavigationLink {
TVSidebarDetailContainer(