From eddcc466022c063265dc6fa8e729bbdf6c18a467 Mon Sep 17 00:00:00 2001
From: Luke Pulverenti <luke.pulverenti@gmail.com>
Date: Sun, 16 Apr 2017 21:45:44 -0400
Subject: [PATCH] improve performance of getting channel list

---
 Emby.Server.Implementations/Dto/DtoService.cs |  5 +-
 .../LiveTv/LiveTvManager.cs                   | 33 ++++++++++--
 MediaBrowser.Api/SuggestionsService.cs        | 53 +++++++++++++------
 MediaBrowser.Api/TvShowsService.cs            | 14 ++++-
 .../LiveTv/ILiveTvManager.cs                  |  2 +-
 SharedVersion.cs                              |  2 +-
 6 files changed, 84 insertions(+), 25 deletions(-)

diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index e65e98f21c..7c0baf9c25 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -146,7 +146,7 @@ namespace Emby.Server.Implementations.Dto
 
             if (channelTuples.Count > 0)
             {
-                _livetvManager().AddChannelInfo(channelTuples, options, user);
+                await _livetvManager().AddChannelInfo(channelTuples, options, user).ConfigureAwait(false);
             }
 
             return list;
@@ -161,7 +161,8 @@ namespace Emby.Server.Implementations.Dto
             if (tvChannel != null)
             {
                 var list = new List<Tuple<BaseItemDto, LiveTvChannel>> { new Tuple<BaseItemDto, LiveTvChannel>(dto, tvChannel) };
-                _livetvManager().AddChannelInfo(list, options, user);
+                var task = _livetvManager().AddChannelInfo(list, options, user);
+                Task.WaitAll(task);
             }
             else if (item is LiveTvProgram)
             {
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
index 4ffea3571f..eee4a27250 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -2284,7 +2284,7 @@ namespace Emby.Server.Implementations.LiveTv
             };
         }
 
-        public void AddChannelInfo(List<Tuple<BaseItemDto, LiveTvChannel>> tuples, DtoOptions options, User user)
+        public async Task AddChannelInfo(List<Tuple<BaseItemDto, LiveTvChannel>> tuples, DtoOptions options, User user)
         {
             var now = DateTime.UtcNow;
 
@@ -2304,6 +2304,12 @@ namespace Emby.Server.Implementations.LiveTv
 
             RemoveFields(options);
 
+            var currentProgramsList = new List<BaseItem>();
+            var currentChannelsDict = new Dictionary<string, BaseItemDto>();
+
+            var addCurrentProgram = options.AddCurrentProgram;
+            var addMediaSources = options.Fields.Contains(ItemFields.MediaSources);
+
             foreach (var tuple in tuples)
             {
                 var dto = tuple.Item1;
@@ -2314,19 +2320,38 @@ namespace Emby.Server.Implementations.LiveTv
                 dto.ChannelType = channel.ChannelType;
                 dto.ServiceName = channel.ServiceName;
 
-                if (options.Fields.Contains(ItemFields.MediaSources))
+                currentChannelsDict[dto.Id] = dto;
+
+                if (addMediaSources)
                 {
                     dto.MediaSources = channel.GetMediaSources(true).ToList();
                 }
 
-                if (options.AddCurrentProgram)
+                if (addCurrentProgram)
                 {
                     var channelIdString = channel.Id.ToString("N");
                     var currentProgram = programs.FirstOrDefault(i => string.Equals(i.ChannelId, channelIdString));
 
                     if (currentProgram != null)
                     {
-                        dto.CurrentProgram = _dtoService.GetBaseItemDto(currentProgram, options, user);
+                        currentProgramsList.Add(currentProgram);
+                    }
+                }
+            }
+
+            if (addCurrentProgram)
+            {
+                var currentProgramDtos = await _dtoService.GetBaseItemDtos(currentProgramsList, options, user).ConfigureAwait(false);
+
+                foreach (var programDto in currentProgramDtos)
+                {
+                    if (!string.IsNullOrWhiteSpace(programDto.ChannelId))
+                    {
+                        BaseItemDto channelDto;
+                        if (currentChannelsDict.TryGetValue(programDto.ChannelId, out channelDto))
+                        {
+                            channelDto.CurrentProgram = programDto;
+                        }
                     }
                 }
             }
diff --git a/MediaBrowser.Api/SuggestionsService.cs b/MediaBrowser.Api/SuggestionsService.cs
index 7196c0f392..3e901e303d 100644
--- a/MediaBrowser.Api/SuggestionsService.cs
+++ b/MediaBrowser.Api/SuggestionsService.cs
@@ -12,6 +12,7 @@ using MediaBrowser.Controller.Library;
 namespace MediaBrowser.Api
 {
     [Route("/Users/{UserId}/Suggestions", "GET", Summary = "Gets items based on a query.")]
+    [Route("/Users/{UserId}/Suggestions", "POST", Summary = "Gets items based on a query.")]
     public class GetSuggestedItems : IReturn<QueryResult<BaseItem>>
     {
         public string MediaType { get; set; }
@@ -20,6 +21,7 @@ namespace MediaBrowser.Api
         public bool EnableTotalRecordCount { get; set; }
         public int? StartIndex { get; set; }
         public int? Limit { get; set; }
+        public string Name { get; set; }
 
         public string[] GetMediaTypes()
         {
@@ -54,6 +56,13 @@ namespace MediaBrowser.Api
             return ToOptimizedResult(result);
         }
 
+        public async Task<object> Post(GetSuggestedItems request)
+        {
+            var result = await GetResultItems(request).ConfigureAwait(false);
+
+            return ToOptimizedResult(result);
+        }
+
         private async Task<QueryResult<BaseItemDto>> GetResultItems(GetSuggestedItems request)
         {
             var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
@@ -77,7 +86,30 @@ namespace MediaBrowser.Api
 
         private QueryResult<BaseItem> GetItems(GetSuggestedItems request, User user, DtoOptions dtoOptions)
         {
-            var query = new InternalItemsQuery(user)
+            BaseItem similarToItem = null;
+
+            if (!string.IsNullOrWhiteSpace(request.Name))
+            {
+                // get item by name, then get similar items from that
+                similarToItem = _libraryManager.GetItemList(new InternalItemsQuery(user)
+                {
+                    SortBy = new string[] {ItemSortBy.Random},
+                    MediaTypes = request.GetMediaTypes(),
+                    IncludeItemTypes = request.GetIncludeItemTypes(),
+                    IsVirtualItem = false,
+                    Name = request.Name,
+                    Recursive = true,
+                    Limit = 1
+
+                }).FirstOrDefault();
+
+                if (similarToItem == null)
+                {
+                    return new QueryResult<BaseItem>();
+                }
+            }
+
+            return _libraryManager.GetItemsResult(new InternalItemsQuery(user)
             {
                 SortBy = new string[] { ItemSortBy.Random },
                 MediaTypes = request.GetMediaTypes(),
@@ -85,20 +117,11 @@ namespace MediaBrowser.Api
                 IsVirtualItem = false,
                 StartIndex = request.StartIndex,
                 Limit = request.Limit,
-                DtoOptions = dtoOptions
-            };
-
-            if (request.EnableTotalRecordCount)
-            {
-                return _libraryManager.GetItemsResult(query);
-            }
-
-            var items = _libraryManager.GetItemList(query).ToArray();
-
-            return new QueryResult<BaseItem>
-            {
-                Items = items
-            };
+                DtoOptions = dtoOptions,
+                EnableTotalRecordCount = request.EnableTotalRecordCount,
+                Recursive = true,
+                SimilarTo = similarToItem
+            });
         }
     }
 }
diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs
index d7f017e1dd..13adceed54 100644
--- a/MediaBrowser.Api/TvShowsService.cs
+++ b/MediaBrowser.Api/TvShowsService.cs
@@ -137,7 +137,7 @@ namespace MediaBrowser.Api
     }
 
     [Route("/Shows/{Id}/Episodes", "GET", Summary = "Gets episodes for a tv season")]
-    [Route("/Shows/Episodes", "GET", Summary = "Gets episodes for a tv season")]
+    [Route("/Shows/Episodes", "POST", Summary = "Gets episodes for a tv season")]
     public class GetEpisodes : IReturn<ItemsResult>, IHasItemFields, IHasDtoOptions
     {
         /// <summary>
@@ -205,7 +205,7 @@ namespace MediaBrowser.Api
     }
 
     [Route("/Shows/{Id}/Seasons", "GET", Summary = "Gets seasons for a tv series")]
-    [Route("/Shows/Seasons", "GET", Summary = "Gets seasons for a tv series")]
+    [Route("/Shows/Seasons", "POST", Summary = "Gets seasons for a tv series")]
     public class GetSeasons : IReturn<ItemsResult>, IHasItemFields, IHasDtoOptions
     {
         /// <summary>
@@ -459,6 +459,16 @@ namespace MediaBrowser.Api
             };
         }
 
+        public Task<object> Post(GetSeasons request)
+        {
+            return Get(request);
+        }
+
+        public Task<object> Post(GetEpisodes request)
+        {
+            return Get(request);
+        }
+
         private Series GetSeries(string seriesId, string seriesName, User user)
         {
             if (!string.IsNullOrWhiteSpace(seriesId))
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
index c8fa6be8ce..7e1dab4624 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
@@ -367,7 +367,7 @@ namespace MediaBrowser.Controller.LiveTv
         /// <param name="items">The items.</param>
         /// <param name="options">The options.</param>
         /// <param name="user">The user.</param>
-        void AddChannelInfo(List<Tuple<BaseItemDto, LiveTvChannel>> items, DtoOptions options, User user);
+        Task AddChannelInfo(List<Tuple<BaseItemDto, LiveTvChannel>> items, DtoOptions options, User user);
 
         /// <summary>
         /// Called when [recording file deleted].
diff --git a/SharedVersion.cs b/SharedVersion.cs
index 6e2c364202..105fb90776 100644
--- a/SharedVersion.cs
+++ b/SharedVersion.cs
@@ -1,3 +1,3 @@
 using System.Reflection;
 
-[assembly: AssemblyVersion("3.2.12.6")]
+[assembly: AssemblyVersion("3.2.12.7")]