Sfoglia il codice sorgente

Only reselect audio streams when user preference is respected (#13832)

gnattu 1 mese fa
parent
commit
32fe92d8f5

+ 10 - 0
Emby.Server.Implementations/Library/MediaSourceManager.cs

@@ -427,6 +427,7 @@ namespace Emby.Server.Implementations.Library
                 if (source.MediaStreams.Any(i => i.Type == MediaStreamType.Audio && i.Index == index))
                 {
                     source.DefaultAudioStreamIndex = index;
+                    source.DefaultAudioIndexSource = AudioIndexSource.User;
                     return;
                 }
             }
@@ -434,6 +435,15 @@ namespace Emby.Server.Implementations.Library
             var preferredAudio = NormalizeLanguage(user.AudioLanguagePreference);
 
             source.DefaultAudioStreamIndex = MediaStreamSelector.GetDefaultAudioStreamIndex(source.MediaStreams, preferredAudio, user.PlayDefaultAudioTrack);
+            if (user.PlayDefaultAudioTrack)
+            {
+                source.DefaultAudioIndexSource |= AudioIndexSource.Default;
+            }
+
+            if (preferredAudio.Count > 0)
+            {
+                source.DefaultAudioIndexSource |= AudioIndexSource.Language;
+            }
         }
 
         public void SetDefaultAudioAndSubtitleStreamIndices(BaseItem item, MediaSourceInfo source, User user)

+ 7 - 0
Jellyfin.Api/Helpers/MediaInfoHelper.cs

@@ -129,6 +129,13 @@ public class MediaInfoHelper
             var mediaSourcesClone = JsonSerializer.Deserialize<MediaSourceInfo[]>(JsonSerializer.SerializeToUtf8Bytes(mediaSources));
             if (mediaSourcesClone is not null)
             {
+                // Carry over the default audio index source.
+                // This field is not intended to be exposed to API clients, but it is used internally by the server
+                for (int i = 0; i < mediaSourcesClone.Length && i < mediaSources.Length; i++)
+                {
+                    mediaSourcesClone[i].DefaultAudioIndexSource = mediaSources[i].DefaultAudioIndexSource;
+                }
+
                 result.MediaSources = mediaSourcesClone;
             }
 

+ 28 - 4
MediaBrowser.Model/Dlna/StreamBuilder.cs

@@ -665,15 +665,39 @@ namespace MediaBrowser.Model.Dlna
 
             // Collect candidate audio streams
             ICollection<MediaStream> candidateAudioStreams = audioStream is null ? [] : [audioStream];
-            if (!options.AudioStreamIndex.HasValue || options.AudioStreamIndex < 0)
+            // When the index is explicitly required by client or the default is specified by user, don't do any stream reselection.
+            if (!item.DefaultAudioIndexSource.HasFlag(AudioIndexSource.User) && (options.AudioStreamIndex is null or < 0))
             {
-                if (audioStream?.IsDefault == true)
+                // When user has no preferences allow stream selection on all streams.
+                if (item.DefaultAudioIndexSource == AudioIndexSource.None && audioStream is not null)
                 {
-                    candidateAudioStreams = item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio && stream.IsDefault).ToArray();
+                    candidateAudioStreams = item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio).ToArray();
+                    if (audioStream.IsDefault)
+                    {
+                        // If default is picked, only allow selection within default streams.
+                        candidateAudioStreams = candidateAudioStreams.Where(stream => stream.IsDefault).ToArray();
+                    }
                 }
-                else
+
+                if (item.DefaultAudioIndexSource.HasFlag(AudioIndexSource.Language))
                 {
+                    // If user has language preference, only allow stream selection within the same language.
                     candidateAudioStreams = item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio && stream.Language == audioStream?.Language).ToArray();
+                    if (item.DefaultAudioIndexSource.HasFlag(AudioIndexSource.Default))
+                    {
+                        var defaultStreamsInPreferredLanguage = candidateAudioStreams.Where(stream => stream.IsDefault).ToArray();
+
+                        // If the user also prefers default streams, try limit selection within default tracks in the same language.
+                        // If there is no default stream in the preferred language, allow selection on all default streams to match the "Play default audio track regardless of language" setting.
+                        candidateAudioStreams = defaultStreamsInPreferredLanguage.Length > 0
+                            ? defaultStreamsInPreferredLanguage
+                            : item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio && stream.IsDefault).ToArray();
+                    }
+                }
+                else if (item.DefaultAudioIndexSource.HasFlag(AudioIndexSource.Default))
+                {
+                    // If user prefers default streams, only allow stream selection on default streams.
+                    candidateAudioStreams = item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio && stream.IsDefault).ToArray();
                 }
             }
 

+ 4 - 0
MediaBrowser.Model/Dto/MediaSourceInfo.cs

@@ -24,6 +24,7 @@ namespace MediaBrowser.Model.Dto
             SupportsDirectPlay = true;
             SupportsProbing = true;
             UseMostCompatibleTranscodingProfile = false;
+            DefaultAudioIndexSource = AudioIndexSource.None;
         }
 
         public MediaProtocol Protocol { get; set; }
@@ -118,6 +119,9 @@ namespace MediaBrowser.Model.Dto
         [JsonIgnore]
         public TranscodeReason TranscodeReasons { get; set; }
 
+        [JsonIgnore]
+        public AudioIndexSource DefaultAudioIndexSource { get; set; }
+
         public int? DefaultAudioStreamIndex { get; set; }
 
         public int? DefaultSubtitleStreamIndex { get; set; }

+ 30 - 0
MediaBrowser.Model/MediaInfo/AudioIndexSource.cs

@@ -0,0 +1,30 @@
+using System;
+
+namespace MediaBrowser.Model.MediaInfo;
+
+/// <summary>
+/// How is the audio index determined.
+/// </summary>
+[Flags]
+public enum AudioIndexSource
+{
+    /// <summary>
+    /// The default index when no preference is specified.
+    /// </summary>
+    None = 0,
+
+    /// <summary>
+    /// The index is calculated whether the track is marked as default or not.
+    /// </summary>
+    Default = 1 << 0,
+
+    /// <summary>
+    /// The index is calculated whether the track is in preferred language or not.
+    /// </summary>
+    Language = 1 << 1,
+
+    /// <summary>
+    /// The index is specified by the user.
+    /// </summary>
+    User = 1 << 2
+}