diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 7913f547a2..4f1a29a4db 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1650,7 +1650,8 @@ namespace MediaBrowser.Api.Playback if (!string.IsNullOrWhiteSpace(request.AudioCodec)) { state.SupportedAudioCodecs = request.AudioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); - state.Request.AudioCodec = state.SupportedAudioCodecs.FirstOrDefault(); + state.Request.AudioCodec = state.SupportedAudioCodecs.FirstOrDefault(i => MediaEncoder.CanEncodeToAudioCodec(i)) + ?? state.SupportedAudioCodecs.FirstOrDefault(); } var item = LibraryManager.GetItemById(request.Id); diff --git a/MediaBrowser.Api/UserLibrary/GameGenresService.cs b/MediaBrowser.Api/UserLibrary/GameGenresService.cs index ebc9a970d7..a0883f98cc 100644 --- a/MediaBrowser.Api/UserLibrary/GameGenresService.cs +++ b/MediaBrowser.Api/UserLibrary/GameGenresService.cs @@ -16,10 +16,6 @@ namespace MediaBrowser.Api.UserLibrary [Route("/GameGenres", "GET", Summary = "Gets all Game genres from a given item, folder, or the entire library")] public class GetGameGenres : GetItemsByName { - public GetGameGenres() - { - MediaTypes = MediaType.Game; - } } [Route("/GameGenres/{Name}", "GET", Summary = "Gets a Game genre, by name")] diff --git a/MediaBrowser.Api/UserLibrary/MusicGenresService.cs b/MediaBrowser.Api/UserLibrary/MusicGenresService.cs index f02136e05f..887c999411 100644 --- a/MediaBrowser.Api/UserLibrary/MusicGenresService.cs +++ b/MediaBrowser.Api/UserLibrary/MusicGenresService.cs @@ -17,10 +17,6 @@ namespace MediaBrowser.Api.UserLibrary [Route("/MusicGenres", "GET", Summary = "Gets all music genres from a given item, folder, or the entire library")] public class GetMusicGenres : GetItemsByName { - public GetMusicGenres() - { - IncludeItemTypes = typeof(Audio).Name; - } } [Route("/MusicGenres/{Name}", "GET", Summary = "Gets a music genre, by name")] diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index f12c51ff34..210c115641 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -778,12 +778,6 @@ namespace MediaBrowser.Controller.Entities return true; } - if (query.PersonIds.Length > 0) - { - Logger.Debug("Query requires post-filtering due to PersonIds"); - return true; - } - if (query.IsInBoxSet.HasValue) { Logger.Debug("Query requires post-filtering due to IsInBoxSet"); @@ -846,20 +840,6 @@ namespace MediaBrowser.Controller.Entities return true; } - // Apply studio filter - if (query.StudioIds.Length > 0) - { - Logger.Debug("Query requires post-filtering due to StudioIds"); - return true; - } - - // Apply genre filter - if (query.GenreIds.Length > 0) - { - Logger.Debug("Query requires post-filtering due to GenreIds"); - return true; - } - // Apply person filter if (query.ItemIdsFromPersonFilters != null) { diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs index c87ac4e734..44b7417553 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Model.Dlna; +using System.Linq; +using MediaBrowser.Model.Dlna; namespace MediaBrowser.Controller.MediaEncoding { @@ -74,7 +75,7 @@ namespace MediaBrowser.Controller.MediaEncoding Level = info.VideoLevel; ItemId = info.ItemId; MediaSourceId = info.MediaSourceId; - AudioCodec = info.AudioCodec; + AudioCodec = info.TargetAudioCodec; MaxAudioChannels = info.MaxAudioChannels; AudioBitRate = info.AudioBitrate; AudioSampleRate = info.TargetAudioSampleRate; diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs index b28cffd6d6..0a15491b67 100644 --- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs +++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs @@ -160,7 +160,7 @@ namespace MediaBrowser.Dlna.Didl var contentFeatureList = new ContentFeatureBuilder(_profile).BuildVideoHeader(streamInfo.Container, streamInfo.VideoCodec, - streamInfo.AudioCodec, + streamInfo.TargetAudioCodec, targetWidth, targetHeight, streamInfo.TargetVideoBitDepth, @@ -307,7 +307,7 @@ namespace MediaBrowser.Dlna.Didl } var mediaProfile = _profile.GetVideoMediaProfile(streamInfo.Container, - streamInfo.AudioCodec, + streamInfo.TargetAudioCodec, streamInfo.VideoCodec, streamInfo.TargetAudioBitrate, targetWidth, @@ -441,7 +441,7 @@ namespace MediaBrowser.Dlna.Didl } var mediaProfile = _profile.GetAudioMediaProfile(streamInfo.Container, - streamInfo.AudioCodec, + streamInfo.TargetAudioCodec, targetChannels, targetAudioBitrate); diff --git a/MediaBrowser.Dlna/PlayTo/PlayToController.cs b/MediaBrowser.Dlna/PlayTo/PlayToController.cs index 982742c067..873ae5ae41 100644 --- a/MediaBrowser.Dlna/PlayTo/PlayToController.cs +++ b/MediaBrowser.Dlna/PlayTo/PlayToController.cs @@ -499,7 +499,7 @@ namespace MediaBrowser.Dlna.PlayTo { return new ContentFeatureBuilder(profile) .BuildAudioHeader(streamInfo.Container, - streamInfo.AudioCodec, + streamInfo.TargetAudioCodec, streamInfo.TargetAudioBitrate, streamInfo.TargetAudioSampleRate, streamInfo.TargetAudioChannels, @@ -513,7 +513,7 @@ namespace MediaBrowser.Dlna.PlayTo var list = new ContentFeatureBuilder(profile) .BuildVideoHeader(streamInfo.Container, streamInfo.VideoCodec, - streamInfo.AudioCodec, + streamInfo.TargetAudioCodec, streamInfo.TargetWidth, streamInfo.TargetHeight, streamInfo.TargetVideoBitDepth, diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 795057d673..41efa51b98 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -216,7 +216,15 @@ namespace MediaBrowser.Model.Dlna playlistItem.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; playlistItem.EstimateContentLength = transcodingProfile.EstimateContentLength; playlistItem.Container = transcodingProfile.Container; - playlistItem.AudioCodec = transcodingProfile.AudioCodec; + + if (string.IsNullOrEmpty(transcodingProfile.AudioCodec)) + { + playlistItem.AudioCodecs = new string[] { }; + } + else + { + playlistItem.AudioCodecs = transcodingProfile.AudioCodec.Split(','); + } playlistItem.SubProtocol = transcodingProfile.Protocol; List audioCodecProfiles = new List(); @@ -439,22 +447,7 @@ namespace MediaBrowser.Model.Dlna playlistItem.EstimateContentLength = transcodingProfile.EstimateContentLength; playlistItem.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; - // TODO: We should probably preserve the full list and sent it to the server that way - string[] supportedAudioCodecs = transcodingProfile.AudioCodec.Split(','); - string inputAudioCodec = audioStream == null ? null : audioStream.Codec; - foreach (string supportedAudioCodec in supportedAudioCodecs) - { - if (StringHelper.EqualsIgnoreCase(supportedAudioCodec, inputAudioCodec)) - { - playlistItem.AudioCodec = supportedAudioCodec; - break; - } - } - - if (string.IsNullOrEmpty(playlistItem.AudioCodec)) - { - playlistItem.AudioCodec = supportedAudioCodecs[0]; - } + playlistItem.AudioCodecs = transcodingProfile.AudioCodec.Split(','); playlistItem.VideoCodec = transcodingProfile.VideoCodec; playlistItem.CopyTimestamps = transcodingProfile.CopyTimestamps; @@ -488,7 +481,7 @@ namespace MediaBrowser.Model.Dlna List audioTranscodingConditions = new List(); foreach (CodecProfile i in options.Profile.CodecProfiles) { - if (i.Type == CodecType.VideoAudio && i.ContainsCodec(playlistItem.AudioCodec, transcodingProfile.Container)) + if (i.Type == CodecType.VideoAudio && i.ContainsCodec(playlistItem.TargetAudioCodec, transcodingProfile.Container)) { foreach (ProfileCondition c in i.Conditions) { diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index d35eb37a8b..43a31f6492 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -14,6 +14,11 @@ namespace MediaBrowser.Model.Dlna /// public class StreamInfo { + public StreamInfo() + { + AudioCodecs = new string[] { }; + } + public string ItemId { get; set; } public PlayMethod PlayMethod { get; set; } @@ -32,7 +37,7 @@ namespace MediaBrowser.Model.Dlna public bool CopyTimestamps { get; set; } public bool ForceLiveStream { get; set; } - public string AudioCodec { get; set; } + public string[] AudioCodecs { get; set; } public int? AudioStreamIndex { get; set; } @@ -191,12 +196,16 @@ namespace MediaBrowser.Model.Dlna { List list = new List(); + string audioCodecs = item.AudioCodecs.Length == 0 ? + string.Empty : + string.Join(",", item.AudioCodecs); + list.Add(new NameValuePair("DeviceProfileId", item.DeviceProfileId ?? string.Empty)); list.Add(new NameValuePair("DeviceId", item.DeviceId ?? string.Empty)); list.Add(new NameValuePair("MediaSourceId", item.MediaSourceId ?? string.Empty)); list.Add(new NameValuePair("Static", item.IsDirectStream.ToString().ToLower())); list.Add(new NameValuePair("VideoCodec", item.VideoCodec ?? string.Empty)); - list.Add(new NameValuePair("AudioCodec", item.AudioCodec ?? string.Empty)); + list.Add(new NameValuePair("AudioCodec", audioCodecs)); list.Add(new NameValuePair("AudioStreamIndex", item.AudioStreamIndex.HasValue ? StringHelper.ToStringCultureInvariant(item.AudioStreamIndex.Value) : string.Empty)); list.Add(new NameValuePair("SubtitleStreamIndex", item.SubtitleStreamIndex.HasValue && item.SubtitleDeliveryMethod != SubtitleDeliveryMethod.External ? StringHelper.ToStringCultureInvariant(item.SubtitleStreamIndex.Value) : string.Empty)); list.Add(new NameValuePair("VideoBitrate", item.VideoBitrate.HasValue ? StringHelper.ToStringCultureInvariant(item.VideoBitrate.Value) : string.Empty)); @@ -278,7 +287,7 @@ namespace MediaBrowser.Model.Dlna // HLS will preserve timestamps so we can just grab the full subtitle stream long startPositionTicks = StringHelper.EqualsIgnoreCase(SubProtocol, "hls") ? 0 - : (PlayMethod == PlayMethod.Transcode && !CopyTimestamps ? StartPositionTicks : 0); + : (PlayMethod == PlayMethod.Transcode && !CopyTimestamps ? StartPositionTicks : 0); // First add the selected track if (SubtitleStreamIndex.HasValue) @@ -555,9 +564,22 @@ namespace MediaBrowser.Model.Dlna { MediaStream stream = TargetAudioStream; - return IsDirectStream - ? (stream == null ? null : stream.Codec) - : AudioCodec; + string inputCodec = stream == null ? null : stream.Codec; + + if (IsDirectStream) + { + return inputCodec; + } + + foreach (string codec in AudioCodecs) + { + if (StringHelper.EqualsIgnoreCase(codec, inputCodec)) + { + return codec; + } + } + + return AudioCodecs.Length == 0 ? null : AudioCodecs[0]; } } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index d86e52b01c..77b42f7363 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -290,6 +290,9 @@ namespace MediaBrowser.Server.Implementations.Persistence "drop index if exists idx_TypeTopParentId6", "drop index if exists idx_ItemValues2", "drop index if exists Idx_ProviderIds", + "drop index if exists idx_ItemValues3", + "drop index if exists idx_ItemValues4", + "drop index if exists idx_ItemValues5", "create index if not exists idx_PresentationUniqueKey on TypedBaseItems(PresentationUniqueKey)", "create index if not exists idx_GuidTypeIsFolderIsVirtualItem on TypedBaseItems(Guid,Type,IsFolder,IsVirtualItem)", @@ -302,6 +305,9 @@ namespace MediaBrowser.Server.Implementations.Persistence // live tv programs "create index if not exists idx_TypeTopParentIdStartDate on TypedBaseItems(Type,TopParentId,StartDate)", + // covering index for getitemvalues + "create index if not exists idx_TypeTopParentIdGuid on TypedBaseItems(Type,TopParentId,Guid)", + // used by movie suggestions "create index if not exists idx_TypeTopParentIdGroup on TypedBaseItems(Type,TopParentId,PresentationUniqueKey)", "create index if not exists idx_TypeTopParentId5 on TypedBaseItems(TopParentId,IsVirtualItem)", @@ -314,8 +320,7 @@ namespace MediaBrowser.Server.Implementations.Persistence "create index if not exists idx_TypeTopParentId7 on TypedBaseItems(TopParentId,MediaType,IsVirtualItem,PresentationUniqueKey)", // items by name - "create index if not exists idx_ItemValues3 on ItemValues(ItemId,Type,CleanValue)", - "create index if not exists idx_ItemValues4 on ItemValues(ItemId,Type,Value,CleanValue)", + "create index if not exists idx_ItemValues6 on ItemValues(ItemId,Type,CleanValue)", // covering index "create index if not exists idx_UserDataKeys3 on UserDataKeys(ItemId,Priority,UserDataKey)" @@ -1704,14 +1709,14 @@ namespace MediaBrowser.Server.Implementations.Persistence builder.Append("+(Select Case When Abs(COALESCE(ProductionYear, 0) - @ItemProductionYear) < 5 Then 2 Else 0 End )"); //// genres - builder.Append("+ ((Select count(value) from ItemValues where ItemId=Guid and Type=2 and value in (select value from itemvalues where ItemId=@SimilarItemId and type=2)) * 10)"); + builder.Append("+ ((Select count(CleanValue) from ItemValues where ItemId=Guid and Type=2 and CleanValue in (select CleanValue from itemvalues where ItemId=@SimilarItemId and type=2)) * 10)"); //// tags - builder.Append("+ ((Select count(value) from ItemValues where ItemId=Guid and Type=4 and value in (select value from itemvalues where ItemId=@SimilarItemId and type=4)) * 10)"); + builder.Append("+ ((Select count(CleanValue) from ItemValues where ItemId=Guid and Type=4 and CleanValue in (select CleanValue from itemvalues where ItemId=@SimilarItemId and type=4)) * 10)"); - builder.Append("+ ((Select count(value) from ItemValues where ItemId=Guid and Type=5 and value in (select value from itemvalues where ItemId=@SimilarItemId and type=5)) * 10)"); + builder.Append("+ ((Select count(CleanValue) from ItemValues where ItemId=Guid and Type=5 and CleanValue in (select CleanValue from itemvalues where ItemId=@SimilarItemId and type=5)) * 10)"); - builder.Append("+ ((Select count(value) from ItemValues where ItemId=Guid and Type=3 and value in (select value from itemvalues where ItemId=@SimilarItemId and type=3)) * 3)"); + builder.Append("+ ((Select count(CleanValue) from ItemValues where ItemId=Guid and Type=3 and CleanValue in (select CleanValue from itemvalues where ItemId=@SimilarItemId and type=3)) * 3)"); //builder.Append("+ ((Select count(Name) from People where ItemId=Guid and Name in (select Name from People where ItemId=@SimilarItemId)) * 3)"); @@ -1863,10 +1868,10 @@ namespace MediaBrowser.Server.Implementations.Persistence } else { - //Logger.Debug("{2} query time: {0}ms. Query: {1}", - // Convert.ToInt32(elapsed), - // cmd.CommandText, - // methodName); + Logger.Debug("{2} query time: {0}ms. Query: {1}", + Convert.ToInt32(elapsed), + cmd.CommandText, + methodName); } } @@ -2078,11 +2083,11 @@ namespace MediaBrowser.Server.Implementations.Persistence } if (string.Equals(name, ItemSortBy.Artist, StringComparison.OrdinalIgnoreCase)) { - return new Tuple("(select value from itemvalues where ItemId=Guid and Type=0 LIMIT 1)", false); + return new Tuple("(select CleanValue from itemvalues where ItemId=Guid and Type=0 LIMIT 1)", false); } if (string.Equals(name, ItemSortBy.AlbumArtist, StringComparison.OrdinalIgnoreCase)) { - return new Tuple("(select value from itemvalues where ItemId=Guid and Type=1 LIMIT 1)", false); + return new Tuple("(select CleanValue from itemvalues where ItemId=Guid and Type=1 LIMIT 1)", false); } if (string.Equals(name, ItemSortBy.OfficialRating, StringComparison.OrdinalIgnoreCase)) { @@ -2090,7 +2095,7 @@ namespace MediaBrowser.Server.Implementations.Persistence } if (string.Equals(name, ItemSortBy.Studio, StringComparison.OrdinalIgnoreCase)) { - return new Tuple("(select value from itemvalues where ItemId=Guid and Type=3 LIMIT 1)", false); + return new Tuple("(select CleanValue from itemvalues where ItemId=Guid and Type=3 LIMIT 1)", false); } if (string.Equals(name, ItemSortBy.SeriesDatePlayed, StringComparison.OrdinalIgnoreCase)) { @@ -2592,6 +2597,12 @@ namespace MediaBrowser.Server.Implementations.Persistence } } + if (query.PersonIds.Length > 0) + { + // Todo: improve without having to do this + query.Person = query.PersonIds.Select(i => RetrieveItem(new Guid(i))).Where(i => i != null).Select(i => i.Name).FirstOrDefault(); + } + if (!string.IsNullOrWhiteSpace(query.Person)) { whereClauses.Add("Guid in (select ItemId from People where Name=@PersonName)"); @@ -2728,6 +2739,12 @@ namespace MediaBrowser.Server.Implementations.Persistence whereClauses.Add(clause); } + if (query.GenreIds.Length > 0) + { + // Todo: improve without having to do this + query.Genres = query.GenreIds.Select(i => RetrieveItem(new Guid(i))).Where(i => i != null).Select(i => i.Name).ToArray(); + } + if (query.Genres.Length > 0) { var clauses = new List(); @@ -2756,6 +2773,12 @@ namespace MediaBrowser.Server.Implementations.Persistence whereClauses.Add(clause); } + if (query.StudioIds.Length > 0) + { + // Todo: improve without having to do this + query.Studios = query.StudioIds.Select(i => RetrieveItem(new Guid(i))).Where(i => i != null).Select(i => i.Name).ToArray(); + } + if (query.Studios.Length > 0) { var clauses = new List(); @@ -3645,7 +3668,7 @@ namespace MediaBrowser.Server.Implementations.Persistence foreach (var type in typesToCount) { - var itemCountColumnQuery = "Select Count(Value) from ItemValues where ItemValues.CleanValue=CleanName AND Type=@ItemValueType AND ItemId in ("; + var itemCountColumnQuery = "Select Count(CleanValue) from ItemValues where ItemValues.CleanValue=CleanName AND Type=@ItemValueType AND ItemId in ("; itemCountColumnQuery += "select guid" + GetFromText(); var typeSubQuery = new InternalItemsQuery(query.User)