Procházet zdrojové kódy

Merge branch 'beta' of https://github.com/MediaBrowser/Emby into beta

Luke Pulverenti před 9 roky
rodič
revize
efed1b0cf6
28 změnil soubory, kde provedl 695 přidání a 309 odebrání
  1. 2 2
      MediaBrowser.Api/GamesService.cs
  2. 4 6
      MediaBrowser.Api/Library/LibraryService.cs
  3. 2 2
      MediaBrowser.Api/Movies/MoviesService.cs
  4. 21 58
      MediaBrowser.Api/Movies/TrailersService.cs
  5. 10 41
      MediaBrowser.Api/Reports/ReportsService.cs
  6. 4 4
      MediaBrowser.Api/TvShowsService.cs
  7. 22 117
      MediaBrowser.Api/UserLibrary/ItemsService.cs
  8. 419 1
      MediaBrowser.Controller/Entities/Folder.cs
  9. 1 0
      MediaBrowser.Controller/Entities/InternalItemsQuery.cs
  10. 6 0
      MediaBrowser.Controller/Entities/Trailer.cs
  11. 4 5
      MediaBrowser.Controller/Entities/UserRootFolder.cs
  12. 30 10
      MediaBrowser.Controller/Entities/UserViewBuilder.cs
  13. 10 11
      MediaBrowser.Controller/Library/ILibraryManager.cs
  14. 1 1
      MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
  15. 2 2
      MediaBrowser.Providers/People/TvdbPersonImageProvider.cs
  16. 2 5
      MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
  17. 2 3
      MediaBrowser.Server.Implementations/Dto/DtoService.cs
  18. 2 2
      MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs
  19. 32 11
      MediaBrowser.Server.Implementations/Library/LibraryManager.cs
  20. 3 4
      MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs
  21. 1 1
      MediaBrowser.Server.Implementations/Library/MusicManager.cs
  22. 1 1
      MediaBrowser.Server.Implementations/Library/SearchEngine.cs
  23. 1 1
      MediaBrowser.Server.Implementations/Library/UserViewManager.cs
  24. 5 5
      MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
  25. 102 11
      MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
  26. 2 2
      MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs
  27. 1 1
      MediaBrowser.WebDashboard/Api/PackageCreator.cs
  28. 3 2
      MediaBrowser.XbmcMetadata/EntryPoint.cs

+ 2 - 2
MediaBrowser.Api/GamesService.cs

@@ -108,7 +108,7 @@ namespace MediaBrowser.Api
                 IncludeItemTypes = new[] { typeof(GameSystem).Name }
                 IncludeItemTypes = new[] { typeof(GameSystem).Name }
             };
             };
             var parentIds = new string[] { } ;
             var parentIds = new string[] { } ;
-            var gameSystems = _libraryManager.GetItems(query, parentIds)
+            var gameSystems = _libraryManager.GetItemList(query, parentIds)
                 .Cast<GameSystem>()
                 .Cast<GameSystem>()
                 .ToList();
                 .ToList();
 
 
@@ -129,7 +129,7 @@ namespace MediaBrowser.Api
                 IncludeItemTypes = new[] { typeof(Game).Name }
                 IncludeItemTypes = new[] { typeof(Game).Name }
             };
             };
             var parentIds = new string[] { };
             var parentIds = new string[] { };
-            var games = _libraryManager.GetItems(query, parentIds)
+            var games = _libraryManager.GetItemList(query, parentIds)
                 .Cast<Game>()
                 .Cast<Game>()
                 .ToList();
                 .ToList();
 
 

+ 4 - 6
MediaBrowser.Api/Library/LibraryService.cs

@@ -444,13 +444,11 @@ namespace MediaBrowser.Api.Library
 
 
         public void Post(PostUpdatedSeries request)
         public void Post(PostUpdatedSeries request)
         {
         {
-            var series = _libraryManager.GetItems(new InternalItemsQuery
+            var series = _libraryManager.GetItemList(new InternalItemsQuery
             {
             {
                 IncludeItemTypes = new[] { typeof(Series).Name }
                 IncludeItemTypes = new[] { typeof(Series).Name }
 
 
-            }).Items;
-
-            series = series.Where(i => string.Equals(request.TvdbId, i.GetProviderId(MetadataProviders.Tvdb), StringComparison.OrdinalIgnoreCase)).ToArray();
+            }).Where(i => string.Equals(request.TvdbId, i.GetProviderId(MetadataProviders.Tvdb), StringComparison.OrdinalIgnoreCase)).ToArray();
 
 
             if (series.Length > 0)
             if (series.Length > 0)
             {
             {
@@ -467,11 +465,11 @@ namespace MediaBrowser.Api.Library
 
 
         public void Post(PostUpdatedMovies request)
         public void Post(PostUpdatedMovies request)
         {
         {
-            var movies = _libraryManager.GetItems(new InternalItemsQuery
+            var movies = _libraryManager.GetItemList(new InternalItemsQuery
             {
             {
                 IncludeItemTypes = new[] { typeof(Movie).Name }
                 IncludeItemTypes = new[] { typeof(Movie).Name }
 
 
-            }).Items;
+            }).ToArray();
 
 
             if (!string.IsNullOrWhiteSpace(request.ImdbId))
             if (!string.IsNullOrWhiteSpace(request.ImdbId))
             {
             {

+ 2 - 2
MediaBrowser.Api/Movies/MoviesService.cs

@@ -146,7 +146,7 @@ namespace MediaBrowser.Api.Movies
             }
             }
 
 
             var parentIds = string.IsNullOrWhiteSpace(request.ParentId) ? new string[] { } : new[] { request.ParentId };
             var parentIds = string.IsNullOrWhiteSpace(request.ParentId) ? new string[] { } : new[] { request.ParentId };
-            var movies = _libraryManager.GetItems(query, parentIds);
+            var movies = _libraryManager.GetItemList(query, parentIds);
             movies = _libraryManager.ReplaceVideosWithPrimaryVersions(movies);
             movies = _libraryManager.ReplaceVideosWithPrimaryVersions(movies);
 
 
             var listEligibleForCategories = new List<BaseItem>();
             var listEligibleForCategories = new List<BaseItem>();
@@ -197,7 +197,7 @@ namespace MediaBrowser.Api.Movies
             }
             }
 
 
             var parentIds = new string[] { };
             var parentIds = new string[] { };
-            var list = _libraryManager.GetItems(query, parentIds)
+            var list = _libraryManager.GetItemList(query, parentIds)
                 .Where(i =>
                 .Where(i =>
                 {
                 {
                     // Strip out secondary versions
                     // Strip out secondary versions

+ 21 - 58
MediaBrowser.Api/Movies/TrailersService.cs

@@ -12,6 +12,9 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
+using MediaBrowser.Controller.Collections;
+using MediaBrowser.Controller.Localization;
+using MediaBrowser.Model.Serialization;
 
 
 namespace MediaBrowser.Api.Movies
 namespace MediaBrowser.Api.Movies
 {
 {
@@ -41,77 +44,37 @@ namespace MediaBrowser.Api.Movies
         private readonly ILibraryManager _libraryManager;
         private readonly ILibraryManager _libraryManager;
 
 
         private readonly IDtoService _dtoService;
         private readonly IDtoService _dtoService;
-        private readonly IChannelManager _channelManager;
+        private readonly ICollectionManager _collectionManager;
+        private readonly ILocalizationManager _localizationManager;
+        private readonly IJsonSerializer _json;
 
 
-        /// <summary>
-        /// Initializes a new instance of the <see cref="TrailersService"/> class.
-        /// </summary>
-        /// <param name="userManager">The user manager.</param>
-        /// <param name="userDataRepository">The user data repository.</param>
-        /// <param name="libraryManager">The library manager.</param>
-        public TrailersService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IDtoService dtoService, IChannelManager channelManager)
+        public TrailersService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IDtoService dtoService, ICollectionManager collectionManager, ILocalizationManager localizationManager, IJsonSerializer json)
         {
         {
             _userManager = userManager;
             _userManager = userManager;
             _userDataRepository = userDataRepository;
             _userDataRepository = userDataRepository;
             _libraryManager = libraryManager;
             _libraryManager = libraryManager;
             _dtoService = dtoService;
             _dtoService = dtoService;
-            _channelManager = channelManager;
+            _collectionManager = collectionManager;
+            _localizationManager = localizationManager;
+            _json = json;
         }
         }
 
 
-        public async Task<object> Get(Getrailers request)
+        public object Get(Getrailers request)
         {
         {
-            var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
-            var result = await GetAllTrailers(user).ConfigureAwait(false);
-
-            IEnumerable<BaseItem> items = result.Items;
-
-            // Apply filters
-            // Run them starting with the ones that are likely to reduce the list the most
-            foreach (var filter in request.GetFilters().OrderByDescending(f => (int)f))
-            {
-                items = ItemsService.ApplyFilter(items, filter, user, _userDataRepository);
-            }
+            var json = _json.SerializeToString(request);
+            var getItems = _json.DeserializeFromString<GetItems>(json);
 
 
-            items = _libraryManager.Sort(items, user, request.GetOrderBy(), request.SortOrder ?? SortOrder.Ascending);
+            getItems.IncludeItemTypes = "Trailer";
 
 
-            var itemsArray = items.ToList();
-
-            var pagedItems = ApplyPaging(request, itemsArray);
-
-            var dtoOptions = GetDtoOptions(request);
-
-            var returnItems = _dtoService.GetBaseItemDtos(pagedItems, dtoOptions, user).ToArray();
-
-            return new ItemsResult
+            return new ItemsService(_userManager, _libraryManager, _userDataRepository, _localizationManager, _dtoService, _collectionManager)
             {
             {
-                TotalRecordCount = itemsArray.Count,
-                Items = returnItems
-            };
-        }
+                AuthorizationContext = AuthorizationContext,
+                Logger = Logger,
+                Request = Request,
+                ResultFactory = ResultFactory,
+                SessionContext = SessionContext
 
 
-        private IEnumerable<BaseItem> ApplyPaging(Getrailers request, IEnumerable<BaseItem> items)
-        {
-            // Start at
-            if (request.StartIndex.HasValue)
-            {
-                items = items.Skip(request.StartIndex.Value);
-            }
-
-            // Return limit
-            if (request.Limit.HasValue)
-            {
-                items = items.Take(request.Limit.Value);
-            }
-
-            return items;
-        }
-
-        private async Task<QueryResult<BaseItem>> GetAllTrailers(User user)
-        {
-            return _libraryManager.GetItems(new InternalItemsQuery(user)
-            {
-                IncludeItemTypes = new[] {typeof (Trailer).Name}
-            });
+            }.Get(getItems);
         }
         }
     }
     }
 }
 }

+ 10 - 41
MediaBrowser.Api/Reports/ReportsService.cs

@@ -302,6 +302,16 @@ namespace MediaBrowser.Api.Reports
                 }
                 }
             }
             }
 
 
+            if (!string.IsNullOrEmpty(request.MinPremiereDate))
+            {
+                query.MinPremiereDate = DateTime.Parse(request.MinPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
+            }
+
+            if (!string.IsNullOrEmpty(request.MaxPremiereDate))
+            {
+                query.MaxPremiereDate = DateTime.Parse(request.MaxPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
+            }
+
             if (request.HasQueryLimit == false)
             if (request.HasQueryLimit == false)
             {
             {
                 query.StartIndex = null;
                 query.StartIndex = null;
@@ -539,50 +549,9 @@ namespace MediaBrowser.Api.Reports
                 }
                 }
             }
             }
 
 
-            if (!string.IsNullOrEmpty(request.MinPremiereDate))
-            {
-                var date = DateTime.Parse(request.MinPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
-
-                if (!(i.PremiereDate.HasValue && i.PremiereDate.Value >= date))
-                {
-                    return false;
-                }
-            }
-
-            if (!string.IsNullOrEmpty(request.MaxPremiereDate))
-            {
-                var date = DateTime.Parse(request.MaxPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
-
-                if (!(i.PremiereDate.HasValue && i.PremiereDate.Value <= date))
-                {
-                    return false;
-                }
-            }
-
             return true;
             return true;
         }
         }
 
 
-        /// <summary> Applies the paging. </summary>
-        /// <param name="request"> The request. </param>
-        /// <param name="items"> The items. </param>
-        /// <returns> IEnumerable{BaseItem}. </returns>
-        private IEnumerable<BaseItem> ApplyPaging(BaseReportRequest request, IEnumerable<BaseItem> items)
-        {
-            // Start at
-            if (request.StartIndex.HasValue)
-            {
-                items = items.Skip(request.StartIndex.Value);
-            }
-
-            // Return limit
-            if (request.Limit.HasValue)
-            {
-                items = items.Take(request.Limit.Value);
-            }
-
-            return items;
-        }
-
         /// <summary> Gets query result. </summary>
         /// <summary> Gets query result. </summary>
         /// <param name="request"> The request. </param>
         /// <param name="request"> The request. </param>
         /// <returns> The query result. </returns>
         /// <returns> The query result. </returns>

+ 4 - 4
MediaBrowser.Api/TvShowsService.cs

@@ -277,7 +277,7 @@ namespace MediaBrowser.Api
 
 
             var parentIds = string.IsNullOrWhiteSpace(request.ParentId) ? new string[] { } : new[] { request.ParentId };
             var parentIds = string.IsNullOrWhiteSpace(request.ParentId) ? new string[] { } : new[] { request.ParentId };
 
 
-            var itemsResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user)
+            var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
             {
             {
                 IncludeItemTypes = new[] { typeof(Episode).Name },
                 IncludeItemTypes = new[] { typeof(Episode).Name },
                 SortBy = new[] { "PremiereDate", "AirTime", "SortName" },
                 SortBy = new[] { "PremiereDate", "AirTime", "SortName" },
@@ -286,15 +286,15 @@ namespace MediaBrowser.Api
                 StartIndex = request.StartIndex,
                 StartIndex = request.StartIndex,
                 Limit = request.Limit
                 Limit = request.Limit
 
 
-            }, parentIds);
+            }, parentIds).ToList();
 
 
             var options = GetDtoOptions(request);
             var options = GetDtoOptions(request);
 
 
-            var returnItems = _dtoService.GetBaseItemDtos(itemsResult.Items, options, user).ToArray();
+            var returnItems = _dtoService.GetBaseItemDtos(itemsResult, options, user).ToArray();
 
 
             var result = new ItemsResult
             var result = new ItemsResult
             {
             {
-                TotalRecordCount = itemsResult.TotalRecordCount,
+                TotalRecordCount = itemsResult.Count,
                 Items = returnItems
                 Items = returnItems
             };
             };
 
 

+ 22 - 117
MediaBrowser.Api/UserLibrary/ItemsService.cs

@@ -85,17 +85,16 @@ namespace MediaBrowser.Api.UserLibrary
         /// <returns>Task{ItemsResult}.</returns>
         /// <returns>Task{ItemsResult}.</returns>
         private async Task<ItemsResult> GetItems(GetItems request)
         private async Task<ItemsResult> GetItems(GetItems request)
         {
         {
-            var parentItem = string.IsNullOrEmpty(request.ParentId) ? null : _libraryManager.GetItemById(request.ParentId);
             var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
             var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
 
 
-            var result = await GetItemsToSerialize(request, user, parentItem).ConfigureAwait(false);
+            var result = await GetItemsToSerialize(request, user).ConfigureAwait(false);
 
 
             var dtoOptions = GetDtoOptions(request);
             var dtoOptions = GetDtoOptions(request);
 
 
             return new ItemsResult
             return new ItemsResult
             {
             {
-                TotalRecordCount = result.Item1.TotalRecordCount,
-                Items = _dtoService.GetBaseItemDtos(result.Item1.Items, dtoOptions, user).ToArray()
+                TotalRecordCount = result.TotalRecordCount,
+                Items = _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user).ToArray()
             };
             };
         }
         }
 
 
@@ -104,17 +103,16 @@ namespace MediaBrowser.Api.UserLibrary
         /// </summary>
         /// </summary>
         /// <param name="request">The request.</param>
         /// <param name="request">The request.</param>
         /// <param name="user">The user.</param>
         /// <param name="user">The user.</param>
-        /// <param name="parentItem">The parent item.</param>
         /// <returns>IEnumerable{BaseItem}.</returns>
         /// <returns>IEnumerable{BaseItem}.</returns>
-        private async Task<Tuple<QueryResult<BaseItem>, bool>> GetItemsToSerialize(GetItems request, User user, BaseItem parentItem)
+        private async Task<QueryResult<BaseItem>> GetItemsToSerialize(GetItems request, User user)
         {
         {
             var item = string.IsNullOrEmpty(request.ParentId) ?
             var item = string.IsNullOrEmpty(request.ParentId) ?
                 user == null ? _libraryManager.RootFolder : user.RootFolder :
                 user == null ? _libraryManager.RootFolder : user.RootFolder :
-                parentItem;
+                _libraryManager.GetItemById(request.ParentId);
 
 
             if (string.Equals(request.IncludeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase))
             if (string.Equals(request.IncludeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase))
             {
             {
-                item = user == null ? _libraryManager.RootFolder : user.RootFolder;
+                //item = user == null ? _libraryManager.RootFolder : user.RootFolder;
             }
             }
             else if (string.Equals(request.IncludeItemTypes, "BoxSet", StringComparison.OrdinalIgnoreCase))
             else if (string.Equals(request.IncludeItemTypes, "BoxSet", StringComparison.OrdinalIgnoreCase))
             {
             {
@@ -137,21 +135,21 @@ namespace MediaBrowser.Api.UserLibrary
                     result.Items = result.Items.OrderBy(i => ids.IndexOf(i.Id.ToString("N"))).ToArray();
                     result.Items = result.Items.OrderBy(i => ids.IndexOf(i.Id.ToString("N"))).ToArray();
                 }
                 }
 
 
-                return new Tuple<QueryResult<BaseItem>, bool>(result, true);
+                return result;
             }
             }
 
 
             if (request.Recursive)
             if (request.Recursive)
             {
             {
                 var result = await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
                 var result = await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
 
 
-                return new Tuple<QueryResult<BaseItem>, bool>(result, true);
+                return result;
             }
             }
 
 
             if (user == null)
             if (user == null)
             {
             {
                 var result = await ((Folder)item).GetItems(GetItemsQuery(request, null)).ConfigureAwait(false);
                 var result = await ((Folder)item).GetItems(GetItemsQuery(request, null)).ConfigureAwait(false);
 
 
-                return new Tuple<QueryResult<BaseItem>, bool>(result, true);
+                return result;
             }
             }
 
 
             var userRoot = item as UserRootFolder;
             var userRoot = item as UserRootFolder;
@@ -160,26 +158,24 @@ namespace MediaBrowser.Api.UserLibrary
             {
             {
                 var result = await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
                 var result = await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false);
 
 
-                return new Tuple<QueryResult<BaseItem>, bool>(result, true);
+                return result;
             }
             }
 
 
             IEnumerable<BaseItem> items = ((Folder)item).GetChildren(user, true);
             IEnumerable<BaseItem> items = ((Folder)item).GetChildren(user, true);
 
 
             var itemsArray = items.ToArray();
             var itemsArray = items.ToArray();
 
 
-            return new Tuple<QueryResult<BaseItem>, bool>(new QueryResult<BaseItem>
+            return new QueryResult<BaseItem>
             {
             {
                 Items = itemsArray,
                 Items = itemsArray,
                 TotalRecordCount = itemsArray.Length
                 TotalRecordCount = itemsArray.Length
-
-            }, false);
+            };
         }
         }
 
 
         private InternalItemsQuery GetItemsQuery(GetItems request, User user)
         private InternalItemsQuery GetItemsQuery(GetItems request, User user)
         {
         {
-            var query = new InternalItemsQuery
+            var query = new InternalItemsQuery(user)
             {
             {
-                User = user,
                 IsPlayed = request.IsPlayed,
                 IsPlayed = request.IsPlayed,
                 MediaTypes = request.GetMediaTypes(),
                 MediaTypes = request.GetMediaTypes(),
                 IncludeItemTypes = request.GetIncludeItemTypes(),
                 IncludeItemTypes = request.GetIncludeItemTypes(),
@@ -234,7 +230,8 @@ namespace MediaBrowser.Api.UserLibrary
                 MinPlayers = request.MinPlayers,
                 MinPlayers = request.MinPlayers,
                 MaxPlayers = request.MaxPlayers,
                 MaxPlayers = request.MaxPlayers,
                 MinCommunityRating = request.MinCommunityRating,
                 MinCommunityRating = request.MinCommunityRating,
-                MinCriticRating = request.MinCriticRating
+                MinCriticRating = request.MinCriticRating,
+                ParentId = string.IsNullOrWhiteSpace(request.ParentId) ? (Guid?)null : new Guid(request.ParentId)
             };
             };
 
 
             if (!string.IsNullOrWhiteSpace(request.Ids))
             if (!string.IsNullOrWhiteSpace(request.Ids))
@@ -278,89 +275,17 @@ namespace MediaBrowser.Api.UserLibrary
                 }
                 }
             }
             }
 
 
-            return query;
-        }
-
-        /// <summary>
-        /// Applies filtering
-        /// </summary>
-        /// <param name="items">The items.</param>
-        /// <param name="filter">The filter.</param>
-        /// <param name="user">The user.</param>
-        /// <param name="repository">The repository.</param>
-        /// <returns>IEnumerable{BaseItem}.</returns>
-        internal static IEnumerable<BaseItem> ApplyFilter(IEnumerable<BaseItem> items, ItemFilter filter, User user, IUserDataManager repository)
-        {
-            // Avoid implicitly captured closure
-            var currentUser = user;
-
-            switch (filter)
+            if (!string.IsNullOrEmpty(request.MinPremiereDate))
             {
             {
-                case ItemFilter.IsFavoriteOrLikes:
-                    return items.Where(item =>
-                    {
-                        var userdata = repository.GetUserData(user.Id, item.GetUserDataKey());
-
-                        if (userdata == null)
-                        {
-                            return false;
-                        }
-
-                        var likes = userdata.Likes ?? false;
-                        var favorite = userdata.IsFavorite;
-
-                        return likes || favorite;
-                    });
-
-                case ItemFilter.Likes:
-                    return items.Where(item =>
-                    {
-                        var userdata = repository.GetUserData(user.Id, item.GetUserDataKey());
-
-                        return userdata != null && userdata.Likes.HasValue && userdata.Likes.Value;
-                    });
-
-                case ItemFilter.Dislikes:
-                    return items.Where(item =>
-                    {
-                        var userdata = repository.GetUserData(user.Id, item.GetUserDataKey());
-
-                        return userdata != null && userdata.Likes.HasValue && !userdata.Likes.Value;
-                    });
-
-                case ItemFilter.IsFavorite:
-                    return items.Where(item =>
-                    {
-                        var userdata = repository.GetUserData(user.Id, item.GetUserDataKey());
-
-                        return userdata != null && userdata.IsFavorite;
-                    });
-
-                case ItemFilter.IsResumable:
-                    return items.Where(item =>
-                    {
-                        var userdata = repository.GetUserData(user.Id, item.GetUserDataKey());
-
-                        return userdata != null && userdata.PlaybackPositionTicks > 0;
-                    });
-
-                case ItemFilter.IsPlayed:
-                    return items.Where(item => item.IsPlayed(currentUser));
-
-                case ItemFilter.IsUnplayed:
-                    return items.Where(item => item.IsUnplayed(currentUser));
-
-                case ItemFilter.IsFolder:
-                    return items.Where(item => item.IsFolder);
-
-                case ItemFilter.IsNotFolder:
-                    return items.Where(item => !item.IsFolder);
+                query.MinPremiereDate = DateTime.Parse(request.MinPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
+            }
 
 
-                case ItemFilter.IsRecentlyAdded:
-                    return items.Where(item => (DateTime.UtcNow - item.DateCreated).TotalDays <= 10);
+            if (!string.IsNullOrEmpty(request.MaxPremiereDate))
+            {
+                query.MaxPremiereDate = DateTime.Parse(request.MaxPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
             }
             }
 
 
-            return items;
+            return query;
         }
         }
 
 
         private bool ApplyAdditionalFilters(GetItems request, BaseItem i, User user, ILibraryManager libraryManager)
         private bool ApplyAdditionalFilters(GetItems request, BaseItem i, User user, ILibraryManager libraryManager)
@@ -582,26 +507,6 @@ namespace MediaBrowser.Api.UserLibrary
                 }
                 }
             }
             }
 
 
-            if (!string.IsNullOrEmpty(request.MinPremiereDate))
-            {
-                var date = DateTime.Parse(request.MinPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
-
-                if (!(i.PremiereDate.HasValue && i.PremiereDate.Value >= date))
-                {
-                    return false;
-                }
-            }
-
-            if (!string.IsNullOrEmpty(request.MaxPremiereDate))
-            {
-                var date = DateTime.Parse(request.MaxPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
-
-                if (!(i.PremiereDate.HasValue && i.PremiereDate.Value <= date))
-                {
-                    return false;
-                }
-            }
-
             return true;
             return true;
         }
         }
     }
     }

+ 419 - 1
MediaBrowser.Controller/Entities/Folder.cs

@@ -15,6 +15,8 @@ using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using CommonIO;
 using CommonIO;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Playlists;
 using MediaBrowser.Model.Channels;
 using MediaBrowser.Model.Channels;
 
 
 namespace MediaBrowser.Controller.Entities
 namespace MediaBrowser.Controller.Entities
@@ -795,6 +797,417 @@ namespace MediaBrowser.Controller.Entities
             return item;
             return item;
         }
         }
 
 
+        public QueryResult<BaseItem> QueryRecursive(InternalItemsQuery query)
+        {
+            var user = query.User;
+
+            if (RequiresPostFiltering(query))
+            {
+                IEnumerable<BaseItem> items;
+                Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager);
+
+                if (query.User == null)
+                {
+                    items = GetRecursiveChildren(filter);
+                }
+                else
+                {
+                    items = GetRecursiveChildren(user, filter);
+                }
+
+                return PostFilterAndSort(items, query);
+            }
+
+            if (!(this is UserRootFolder) && !(this is AggregateFolder))
+            {
+                query.ParentId = query.ParentId ?? Id;
+            }
+
+            return LibraryManager.GetItemsResult(query);
+        }
+
+        private bool RequiresPostFiltering(InternalItemsQuery query)
+        {
+            if (LinkedChildren.Count > 0)
+            {
+                if (!(this is ICollectionFolder))
+                {
+                    Logger.Debug("Query requires post-filtering due to LinkedChildren");
+                    return true;
+                }
+            }
+
+            if (query.SortBy != null && query.SortBy.Length > 0)
+            {
+                if (query.SortBy.Contains(ItemSortBy.DatePlayed, StringComparer.OrdinalIgnoreCase))
+                {
+                    Logger.Debug("Query requires post-filtering due to ItemSortBy.DatePlayed");
+                    return true;
+                }
+                if (query.SortBy.Contains(ItemSortBy.IsFavoriteOrLiked, StringComparer.OrdinalIgnoreCase))
+                {
+                    Logger.Debug("Query requires post-filtering due to ItemSortBy.IsFavoriteOrLiked");
+                    return true;
+                }
+                if (query.SortBy.Contains(ItemSortBy.IsPlayed, StringComparer.OrdinalIgnoreCase))
+                {
+                    Logger.Debug("Query requires post-filtering due to ItemSortBy.IsPlayed");
+                    return true;
+                }
+                if (query.SortBy.Contains(ItemSortBy.IsUnplayed, StringComparer.OrdinalIgnoreCase))
+                {
+                    Logger.Debug("Query requires post-filtering due to ItemSortBy.IsUnplayed");
+                    return true;
+                }
+                if (query.SortBy.Contains(ItemSortBy.AiredEpisodeOrder, StringComparer.OrdinalIgnoreCase))
+                {
+                    Logger.Debug("Query requires post-filtering due to ItemSortBy.AiredEpisodeOrder");
+                    return true;
+                }
+                if (query.SortBy.Contains(ItemSortBy.Album, StringComparer.OrdinalIgnoreCase))
+                {
+                    Logger.Debug("Query requires post-filtering due to ItemSortBy.Album");
+                    return true;
+                }
+                if (query.SortBy.Contains(ItemSortBy.AlbumArtist, StringComparer.OrdinalIgnoreCase))
+                {
+                    Logger.Debug("Query requires post-filtering due to ItemSortBy.AlbumArtist");
+                    return true;
+                }
+                if (query.SortBy.Contains(ItemSortBy.Artist, StringComparer.OrdinalIgnoreCase))
+                {
+                    Logger.Debug("Query requires post-filtering due to ItemSortBy.Artist");
+                    return true;
+                }
+                if (query.SortBy.Contains(ItemSortBy.Budget, StringComparer.OrdinalIgnoreCase))
+                {
+                    Logger.Debug("Query requires post-filtering due to ItemSortBy.Budget");
+                    return true;
+                }
+                if (query.SortBy.Contains(ItemSortBy.CriticRating, StringComparer.OrdinalIgnoreCase))
+                {
+                    Logger.Debug("Query requires post-filtering due to ItemSortBy.CriticRating");
+                    return true;
+                }
+                if (query.SortBy.Contains(ItemSortBy.DateLastContentAdded, StringComparer.OrdinalIgnoreCase))
+                {
+                    Logger.Debug("Query requires post-filtering due to ItemSortBy.DateLastContentAdded");
+                    return true;
+                }
+                if (query.SortBy.Contains(ItemSortBy.GameSystem, StringComparer.OrdinalIgnoreCase))
+                {
+                    Logger.Debug("Query requires post-filtering due to ItemSortBy.GameSystem");
+                    return true;
+                }
+                if (query.SortBy.Contains(ItemSortBy.Metascore, StringComparer.OrdinalIgnoreCase))
+                {
+                    Logger.Debug("Query requires post-filtering due to ItemSortBy.Metascore");
+                    return true;
+                }
+                if (query.SortBy.Contains(ItemSortBy.OfficialRating, StringComparer.OrdinalIgnoreCase))
+                {
+                    Logger.Debug("Query requires post-filtering due to ItemSortBy.OfficialRating");
+                    return true;
+                }
+                if (query.SortBy.Contains(ItemSortBy.PlayCount, StringComparer.OrdinalIgnoreCase))
+                {
+                    Logger.Debug("Query requires post-filtering due to ItemSortBy.PlayCount");
+                    return true;
+                }
+                if (query.SortBy.Contains(ItemSortBy.Players, StringComparer.OrdinalIgnoreCase))
+                {
+                    Logger.Debug("Query requires post-filtering due to ItemSortBy.Players");
+                    return true;
+                }
+                if (query.SortBy.Contains(ItemSortBy.Revenue, StringComparer.OrdinalIgnoreCase))
+                {
+                    Logger.Debug("Query requires post-filtering due to ItemSortBy.Revenue");
+                    return true;
+                }
+                if (query.SortBy.Contains(ItemSortBy.SeriesSortName, StringComparer.OrdinalIgnoreCase))
+                {
+                    Logger.Debug("Query requires post-filtering due to ItemSortBy.SeriesSortName");
+                    return true;
+                }
+                if (query.SortBy.Contains(ItemSortBy.StartDate, StringComparer.OrdinalIgnoreCase))
+                {
+                    Logger.Debug("Query requires post-filtering due to ItemSortBy.StartDate");
+                    return true;
+                }
+                if (query.SortBy.Contains(ItemSortBy.Studio, StringComparer.OrdinalIgnoreCase))
+                {
+                    Logger.Debug("Query requires post-filtering due to ItemSortBy.Studio");
+                    return true;
+                }
+                if (query.SortBy.Contains(ItemSortBy.VideoBitRate, StringComparer.OrdinalIgnoreCase))
+                {
+                    Logger.Debug("Query requires post-filtering due to ItemSortBy.VideoBitRate");
+                    return true;
+                }
+            }
+
+            if (query.PersonIds.Length > 0)
+            {
+                Logger.Debug("Query requires post-filtering due to PersonIds");
+                return true;
+            }
+
+            if (query.IsLiked.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to IsLiked");
+                return true;
+            }
+
+            if (query.IsFavoriteOrLiked.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to IsFavoriteOrLiked");
+                return true;
+            }
+
+            if (query.IsFavorite.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to IsFavorite");
+                return true;
+            }
+
+            if (query.IsResumable.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to IsResumable");
+                return true;
+            }
+
+            if (query.IsPlayed.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to IsPlayed");
+                return true;
+            }
+
+            if (query.IsInBoxSet.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to IsInBoxSet");
+                return true;
+            }
+
+            // Filter by Video3DFormat
+            if (query.Is3D.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to Is3D");
+                return true;
+            }
+
+            if (query.HasOverview.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to HasOverview");
+                return true;
+            }
+
+            if (query.HasImdbId.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to HasImdbId");
+                return true;
+            }
+
+            if (query.HasTmdbId.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to HasTmdbId");
+                return true;
+            }
+
+            if (query.HasTvdbId.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to HasTvdbId");
+                return true;
+            }
+
+            if (query.IsYearMismatched.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to IsYearMismatched");
+                return true;
+            }
+
+            if (query.HasOfficialRating.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to HasOfficialRating");
+                return true;
+            }
+
+            if (query.IsPlaceHolder.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to IsPlaceHolder");
+                return true;
+            }
+
+            if (query.HasSpecialFeature.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to HasSpecialFeature");
+                return true;
+            }
+
+            if (query.HasSubtitles.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to HasSubtitles");
+                return true;
+            }
+
+            if (query.HasTrailer.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to HasTrailer");
+                return true;
+            }
+
+            if (query.HasThemeSong.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to HasThemeSong");
+                return true;
+            }
+
+            if (query.HasThemeVideo.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to HasThemeVideo");
+                return true;
+            }
+
+            // Filter by VideoType
+            if (query.VideoTypes.Length > 0)
+            {
+                Logger.Debug("Query requires post-filtering due to VideoTypes");
+                return true;
+            }
+
+            if (query.ImageTypes.Length > 0)
+            {
+                Logger.Debug("Query requires post-filtering due to ImageTypes");
+                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 year filter
+            if (query.Years.Length > 0)
+            {
+                Logger.Debug("Query requires post-filtering due to Years");
+                return true;
+            }
+
+            // Apply official rating filter
+            if (query.OfficialRatings.Length > 0)
+            {
+                Logger.Debug("Query requires post-filtering due to OfficialRatings");
+                return true;
+            }
+
+            // Apply person filter
+            if (query.ItemIdsFromPersonFilters != null)
+            {
+                Logger.Debug("Query requires post-filtering due to ItemIdsFromPersonFilters");
+                return true;
+            }
+
+            if (query.MinPlayers.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to MinPlayers");
+                return true;
+            }
+
+            if (query.MaxPlayers.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to MaxPlayers");
+                return true;
+            }
+
+            if (query.MinCommunityRating.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to MinCommunityRating");
+                return true;
+            }
+
+            if (query.MinIndexNumber.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to MinIndexNumber");
+                return true;
+            }
+
+            if (query.Years.Length > 0)
+            {
+                Logger.Debug("Query requires post-filtering due to Years");
+                return true;
+            }
+
+            if (query.OfficialRatings.Length > 0)
+            {
+                Logger.Debug("Query requires post-filtering due to OfficialRatings");
+                return true;
+            }
+
+            if (query.IsMissing.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to IsMissing");
+                return true;
+            }
+
+            if (query.IsUnaired.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to IsUnaired");
+                return true;
+            }
+
+            if (query.IsVirtualUnaired.HasValue)
+            {
+                Logger.Debug("Query requires post-filtering due to IsVirtualUnaired");
+                return true;
+            }
+
+            if (UserViewBuilder.CollapseBoxSetItems(query, this, query.User))
+            {
+                Logger.Debug("Query requires post-filtering due to CollapseBoxSetItems");
+                return true;
+            }
+
+            if (!string.IsNullOrWhiteSpace(query.AdjacentTo))
+            {
+                Logger.Debug("Query requires post-filtering due to AdjacentTo");
+                return true;
+            }
+
+            if (!string.IsNullOrWhiteSpace(query.NameContains))
+            {
+                Logger.Debug("Query requires post-filtering due to NameContains");
+                return true;
+            }
+
+            if (!string.IsNullOrWhiteSpace(query.NameLessThan))
+            {
+                Logger.Debug("Query requires post-filtering due to NameLessThan");
+                return true;
+            }
+
+            if (!string.IsNullOrWhiteSpace(query.NameStartsWith))
+            {
+                Logger.Debug("Query requires post-filtering due to NameStartsWith");
+                return true;
+            }
+
+            if (!string.IsNullOrWhiteSpace(query.NameStartsWithOrGreater))
+            {
+                Logger.Debug("Query requires post-filtering due to NameStartsWithOrGreater");
+                return true;
+            }
+
+            return false;
+        }
+
         public virtual async Task<QueryResult<BaseItem>> GetItems(InternalItemsQuery query)
         public virtual async Task<QueryResult<BaseItem>> GetItems(InternalItemsQuery query)
         {
         {
             if (SourceType == SourceType.Channel)
             if (SourceType == SourceType.Channel)
@@ -823,7 +1236,12 @@ namespace MediaBrowser.Controller.Entities
                     };
                     };
                 }
                 }
             }
             }
-            
+
+            if (query.Recursive)
+            {
+                return QueryRecursive(query);
+            }
+
             var user = query.User;
             var user = query.User;
 
 
             Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager);
             Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager);

+ 1 - 0
MediaBrowser.Controller/Entities/InternalItemsQuery.cs

@@ -83,6 +83,7 @@ namespace MediaBrowser.Controller.Entities
         public string[] OfficialRatings { get; set; }
         public string[] OfficialRatings { get; set; }
 
 
         public DateTime? MinPremiereDate { get; set; }
         public DateTime? MinPremiereDate { get; set; }
+        public DateTime? MaxPremiereDate { get; set; }
         public DateTime? MinStartDate { get; set; }
         public DateTime? MinStartDate { get; set; }
         public DateTime? MaxStartDate { get; set; }
         public DateTime? MaxStartDate { get; set; }
         public DateTime? MinEndDate { get; set; }
         public DateTime? MinEndDate { get; set; }

+ 6 - 0
MediaBrowser.Controller/Entities/Trailer.cs

@@ -35,6 +35,12 @@ namespace MediaBrowser.Controller.Entities
 
 
         public List<string> Keywords { get; set; }
         public List<string> Keywords { get; set; }
 
 
+        [IgnoreDataMember]
+        public bool IsLocalTrailer
+        {
+            get { return TrailerTypes.Contains(TrailerType.LocalTrailer); }
+        }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the taglines.
         /// Gets or sets the taglines.
         /// </summary>
         /// </summary>

+ 4 - 5
MediaBrowser.Controller/Entities/UserRootFolder.cs

@@ -19,13 +19,9 @@ namespace MediaBrowser.Controller.Entities
     {
     {
         public override async Task<QueryResult<BaseItem>> GetItems(InternalItemsQuery query)
         public override async Task<QueryResult<BaseItem>> GetItems(InternalItemsQuery query)
         {
         {
-            var user = query.User;
-            Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager);
-            
             if (query.Recursive)
             if (query.Recursive)
             {
             {
-                var items = query.User.RootFolder.GetRecursiveChildren(query.User, filter);
-                return PostFilterAndSort(items, query);
+                return QueryRecursive(query);
             }
             }
 
 
             var result = await UserViewManager.GetUserViews(new UserViewQuery
             var result = await UserViewManager.GetUserViews(new UserViewQuery
@@ -35,6 +31,9 @@ namespace MediaBrowser.Controller.Entities
 
 
             }, CancellationToken.None).ConfigureAwait(false);
             }, CancellationToken.None).ConfigureAwait(false);
 
 
+            var user = query.User;
+            Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager);
+            
             return PostFilterAndSort(result.Where(filter), query);
             return PostFilterAndSort(result.Where(filter), query);
         }
         }
 
 

+ 30 - 10
MediaBrowser.Controller/Entities/UserViewBuilder.cs

@@ -50,15 +50,15 @@ namespace MediaBrowser.Controller.Entities
         {
         {
             var user = query.User;
             var user = query.User;
 
 
-            if (query.IncludeItemTypes != null &&
-                query.IncludeItemTypes.Length == 1 &&
-                string.Equals(query.IncludeItemTypes[0], "Playlist", StringComparison.OrdinalIgnoreCase))
-            {
-                if (!string.Equals(viewType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))
-                {
-                    return await FindPlaylists(queryParent, user, query).ConfigureAwait(false);
-                }
-            }
+            //if (query.IncludeItemTypes != null &&
+            //    query.IncludeItemTypes.Length == 1 &&
+            //    string.Equals(query.IncludeItemTypes[0], "Playlist", StringComparison.OrdinalIgnoreCase))
+            //{
+            //    if (!string.Equals(viewType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))
+            //    {
+            //        return await FindPlaylists(queryParent, user, query).ConfigureAwait(false);
+            //    }
+            //}
 
 
             switch (viewType)
             switch (viewType)
             {
             {
@@ -766,7 +766,7 @@ namespace MediaBrowser.Controller.Entities
             return items;
             return items;
         }
         }
 
 
-        private static bool CollapseBoxSetItems(InternalItemsQuery query,
+        public static bool CollapseBoxSetItems(InternalItemsQuery query,
             BaseItem queryParent,
             BaseItem queryParent,
             User user)
             User user)
         {
         {
@@ -1689,6 +1689,26 @@ namespace MediaBrowser.Controller.Entities
                 }
                 }
             }
             }
 
 
+            if (query.MinPremiereDate.HasValue)
+            {
+                var val = query.MinPremiereDate.Value;
+
+                if (!(item.PremiereDate.HasValue && item.PremiereDate.Value >= val))
+                {
+                    return false;
+                }
+            }
+
+            if (query.MaxPremiereDate.HasValue)
+            {
+                var val = query.MaxPremiereDate.Value;
+
+                if (!(item.PremiereDate.HasValue && item.PremiereDate.Value <= val))
+                {
+                    return false;
+                }
+            }
+
             return true;
             return true;
         }
         }
 
 

+ 10 - 11
MediaBrowser.Controller/Library/ILibraryManager.cs

@@ -152,13 +152,6 @@ namespace MediaBrowser.Controller.Library
         /// <returns>BaseItem.</returns>
         /// <returns>BaseItem.</returns>
         BaseItem GetItemById(Guid id);
         BaseItem GetItemById(Guid id);
 
 
-        /// <summary>
-        /// Gets the items.
-        /// </summary>
-        /// <param name="query">The query.</param>
-        /// <returns>QueryResult&lt;BaseItem&gt;.</returns>
-        QueryResult<BaseItem> GetItems(InternalItemsQuery query);
-
         /// <summary>
         /// <summary>
         /// Gets the memory item by identifier.
         /// Gets the memory item by identifier.
         /// </summary>
         /// </summary>
@@ -547,22 +540,28 @@ namespace MediaBrowser.Controller.Library
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         Task<ItemImageInfo> ConvertImageToLocal(IHasImages item, ItemImageInfo image, int imageIndex);
         Task<ItemImageInfo> ConvertImageToLocal(IHasImages item, ItemImageInfo image, int imageIndex);
 
 
+        /// <summary>
+        /// Gets the items.
+        /// </summary>
+        /// <param name="query">The query.</param>
+        /// <returns>QueryResult&lt;BaseItem&gt;.</returns>
+        IEnumerable<BaseItem> GetItemList(InternalItemsQuery query);
+
         /// <summary>
         /// <summary>
         /// Gets the items.
         /// Gets the items.
         /// </summary>
         /// </summary>
         /// <param name="query">The query.</param>
         /// <param name="query">The query.</param>
         /// <param name="parentIds">The parent ids.</param>
         /// <param name="parentIds">The parent ids.</param>
         /// <returns>List&lt;BaseItem&gt;.</returns>
         /// <returns>List&lt;BaseItem&gt;.</returns>
-        IEnumerable<BaseItem> GetItems(InternalItemsQuery query, IEnumerable<string> parentIds);
+        IEnumerable<BaseItem> GetItemList(InternalItemsQuery query, IEnumerable<string> parentIds);
 
 
         /// <summary>
         /// <summary>
         /// Gets the items result.
         /// Gets the items result.
         /// </summary>
         /// </summary>
         /// <param name="query">The query.</param>
         /// <param name="query">The query.</param>
-        /// <param name="parentIds">The parent ids.</param>
         /// <returns>QueryResult&lt;BaseItem&gt;.</returns>
         /// <returns>QueryResult&lt;BaseItem&gt;.</returns>
-        QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query, IEnumerable<string> parentIds);
-
+        QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query);
+        
         /// <summary>
         /// <summary>
         /// Ignores the file.
         /// Ignores the file.
         /// </summary>
         /// </summary>

+ 1 - 1
MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs

@@ -493,7 +493,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
                 Limit = limit,
                 Limit = limit,
                 StartIndex = startIndex
                 StartIndex = startIndex
 
 
-            }, new string[] { });
+            });
 
 
             var serverItems = itemsResult.Items.Select(i => new ServerItem
             var serverItems = itemsResult.Items.Select(i => new ServerItem
             {
             {

+ 2 - 2
MediaBrowser.Providers/People/TvdbPersonImageProvider.cs

@@ -59,12 +59,12 @@ namespace MediaBrowser.Providers.People
             // Avoid implicitly captured closure
             // Avoid implicitly captured closure
             var itemName = item.Name;
             var itemName = item.Name;
 
 
-            var seriesWithPerson = _libraryManager.GetItems(new InternalItemsQuery
+            var seriesWithPerson = _libraryManager.GetItemList(new InternalItemsQuery
             {
             {
                 IncludeItemTypes = new[] { typeof(Series).Name },
                 IncludeItemTypes = new[] { typeof(Series).Name },
                 Person = itemName
                 Person = itemName
 
 
-            }).Items.Cast<Series>()
+            }).Cast<Series>()
                 .Where(i => TvdbSeriesProvider.IsValidSeries(i.ProviderIds))
                 .Where(i => TvdbSeriesProvider.IsValidSeries(i.ProviderIds))
                 .ToList();
                 .ToList();
 
 

+ 2 - 5
MediaBrowser.Server.Implementations/Channels/ChannelManager.cs

@@ -510,15 +510,12 @@ namespace MediaBrowser.Server.Implementations.Channels
 
 
         public IEnumerable<ChannelFeatures> GetAllChannelFeatures()
         public IEnumerable<ChannelFeatures> GetAllChannelFeatures()
         {
         {
-            var inputItems = _libraryManager.GetItems(new InternalItemsQuery
+            return _libraryManager.GetItemList(new InternalItemsQuery
             {
             {
                 IncludeItemTypes = new[] { typeof(Channel).Name },
                 IncludeItemTypes = new[] { typeof(Channel).Name },
                 SortBy = new[] { ItemSortBy.SortName }
                 SortBy = new[] { ItemSortBy.SortName }
 
 
-            }).Items;
-
-            return inputItems
-                .Select(i => GetChannelFeatures(i.Id.ToString("N")));
+            }).Select(i => GetChannelFeatures(i.Id.ToString("N")));
         }
         }
 
 
         public ChannelFeatures GetChannelFeatures(string id)
         public ChannelFeatures GetChannelFeatures(string id)

+ 2 - 3
MediaBrowser.Server.Implementations/Dto/DtoService.cs

@@ -183,7 +183,7 @@ namespace MediaBrowser.Server.Implementations.Dto
 
 
             if (person != null)
             if (person != null)
             {
             {
-                var items = _libraryManager.GetItems(new InternalItemsQuery(user)
+                var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
                 {
                 {
                     Person = byName.Name
                     Person = byName.Name
 
 
@@ -1655,8 +1655,7 @@ namespace MediaBrowser.Server.Implementations.Dto
             {
             {
                 IsFolder = false,
                 IsFolder = false,
                 Recursive = true,
                 Recursive = true,
-                IsVirtualUnaired = false,
-                IsMissing = false,
+                ExcludeLocationTypes = new[] { LocationType.Virtual },
                 User = user
                 User = user
 
 
             }).Result.Items;
             }).Result.Items;

+ 2 - 2
MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs

@@ -106,13 +106,13 @@ namespace MediaBrowser.Server.Implementations.Intros
 
 
             if (trailerTypes.Count > 0)
             if (trailerTypes.Count > 0)
             {
             {
-                var trailerResult = _libraryManager.GetItems(new InternalItemsQuery
+                var trailerResult = _libraryManager.GetItemList(new InternalItemsQuery
                 {
                 {
                     IncludeItemTypes = new[] { typeof(Trailer).Name },
                     IncludeItemTypes = new[] { typeof(Trailer).Name },
                     TrailerTypes = trailerTypes.ToArray()
                     TrailerTypes = trailerTypes.ToArray()
                 });
                 });
 
 
-                candidates.AddRange(trailerResult.Items.Select(i => new ItemWithTrailer
+                candidates.AddRange(trailerResult.Select(i => new ItemWithTrailer
                 {
                 {
                     Item = i,
                     Item = i,
                     Type = i.SourceType == SourceType.Channel ? ItemWithTrailerType.ChannelTrailer : ItemWithTrailerType.ItemWithTrailer,
                     Type = i.SourceType == SourceType.Channel ? ItemWithTrailerType.ChannelTrailer : ItemWithTrailerType.ItemWithTrailer,

+ 32 - 11
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -813,7 +813,7 @@ namespace MediaBrowser.Server.Implementations.Library
             {
             {
                 return null;
                 return null;
             }
             }
-            
+
             return RootFolder.FindByPath(path);
             return RootFolder.FindByPath(path);
         }
         }
 
 
@@ -1305,7 +1305,7 @@ namespace MediaBrowser.Server.Implementations.Library
             return item;
             return item;
         }
         }
 
 
-        public QueryResult<BaseItem> GetItems(InternalItemsQuery query)
+        public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query)
         {
         {
             if (query.User != null)
             if (query.User != null)
             {
             {
@@ -1314,12 +1314,7 @@ namespace MediaBrowser.Server.Implementations.Library
 
 
             var result = ItemRepository.GetItemIdsList(query);
             var result = ItemRepository.GetItemIdsList(query);
 
 
-            var items = result.Select(GetItemById).Where(i => i != null).ToArray();
-
-            return new QueryResult<BaseItem>
-            {
-                Items = items
-            };
+            return result.Select(GetItemById).Where(i => i != null);
         }
         }
 
 
         public QueryResult<BaseItem> QueryItems(InternalItemsQuery query)
         public QueryResult<BaseItem> QueryItems(InternalItemsQuery query)
@@ -1342,7 +1337,7 @@ namespace MediaBrowser.Server.Implementations.Library
             return ItemRepository.GetItemIdsList(query);
             return ItemRepository.GetItemIdsList(query);
         }
         }
 
 
-        public IEnumerable<BaseItem> GetItems(InternalItemsQuery query, IEnumerable<string> parentIds)
+        public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query, IEnumerable<string> parentIds)
         {
         {
             var parents = parentIds.Select(i => GetItemById(new Guid(i))).Where(i => i != null).ToList();
             var parents = parentIds.Select(i => GetItemById(new Guid(i))).Where(i => i != null).ToList();
 
 
@@ -1351,13 +1346,39 @@ namespace MediaBrowser.Server.Implementations.Library
             return GetItemIds(query).Select(GetItemById).Where(i => i != null);
             return GetItemIds(query).Select(GetItemById).Where(i => i != null);
         }
         }
 
 
+        public QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query)
+        {
+            if (query.Recursive && query.ParentId.HasValue)
+            {
+                var parent = GetItemById(query.ParentId.Value);
+                if (parent != null)
+                {
+                    SetTopParentIdsOrAncestors(query, new List<BaseItem> { parent });
+                    query.ParentId = null;
+                }
+            }
+
+            if (query.User != null)
+            {
+                AddUserToQuery(query, query.User);
+            }
+
+            var initialResult = ItemRepository.GetItemIds(query);
+
+            return new QueryResult<BaseItem>
+            {
+                TotalRecordCount = initialResult.TotalRecordCount,
+                Items = initialResult.Items.Select(GetItemById).Where(i => i != null).ToArray()
+            };
+        }
+
         public QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query, IEnumerable<string> parentIds)
         public QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query, IEnumerable<string> parentIds)
         {
         {
             var parents = parentIds.Select(i => GetItemById(new Guid(i))).Where(i => i != null).ToList();
             var parents = parentIds.Select(i => GetItemById(new Guid(i))).Where(i => i != null).ToList();
 
 
             SetTopParentIdsOrAncestors(query, parents);
             SetTopParentIdsOrAncestors(query, parents);
 
 
-            return GetItems(query);
+            return GetItemsResult(query);
         }
         }
 
 
         private void SetTopParentIdsOrAncestors(InternalItemsQuery query, List<BaseItem> parents)
         private void SetTopParentIdsOrAncestors(InternalItemsQuery query, List<BaseItem> parents)
@@ -2545,7 +2566,7 @@ namespace MediaBrowser.Server.Implementations.Library
             // Remove this image to prevent it from retrying over and over
             // Remove this image to prevent it from retrying over and over
             item.RemoveImage(image);
             item.RemoveImage(image);
             await item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false);
             await item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false);
-            
+
             throw new InvalidOperationException();
             throw new InvalidOperationException();
         }
         }
     }
     }

+ 3 - 4
MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs

@@ -4,6 +4,7 @@ using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Channels;
 using MediaBrowser.Model.Channels;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using System;
 using System;
+using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
@@ -28,16 +29,14 @@ namespace MediaBrowser.Server.Implementations.Library
                 .Cast<IHasTrailers>()
                 .Cast<IHasTrailers>()
                 .ToList();
                 .ToList();
 
 
-            var trailerResult = _libraryManager.GetItems(new InternalItemsQuery
+            var trailers = _libraryManager.GetItemList(new InternalItemsQuery
             {
             {
                 IncludeItemTypes = new[] { typeof(Trailer).Name },
                 IncludeItemTypes = new[] { typeof(Trailer).Name },
                 ExcludeTrailerTypes = new[]
                 ExcludeTrailerTypes = new[]
                 {
                 {
                     TrailerType.LocalTrailer
                     TrailerType.LocalTrailer
                 }
                 }
-
-            });
-            var trailers = trailerResult.Items;
+            }).ToArray();
 
 
             var numComplete = 0;
             var numComplete = 0;
 
 

+ 1 - 1
MediaBrowser.Server.Implementations/Library/MusicManager.cs

@@ -80,7 +80,7 @@ namespace MediaBrowser.Server.Implementations.Library
         {
         {
             var genreList = genres.ToList();
             var genreList = genres.ToList();
 
 
-            var inputItems = _libraryManager.GetItems(new InternalItemsQuery(user)
+            var inputItems = _libraryManager.GetItemList(new InternalItemsQuery(user)
             {
             {
                 IncludeItemTypes = new[] { typeof(Audio).Name },
                 IncludeItemTypes = new[] { typeof(Audio).Name },
 
 

+ 1 - 1
MediaBrowser.Server.Implementations/Library/SearchEngine.cs

@@ -157,7 +157,7 @@ namespace MediaBrowser.Server.Implementations.Library
 
 
             AddIfMissing(excludeItemTypes, typeof(CollectionFolder).Name);
             AddIfMissing(excludeItemTypes, typeof(CollectionFolder).Name);
 
 
-            var mediaItems = _libraryManager.GetItems(new InternalItemsQuery(user)
+            var mediaItems = _libraryManager.GetItemList(new InternalItemsQuery(user)
             {
             {
                 NameContains = searchTerm,
                 NameContains = searchTerm,
                 ExcludeItemTypes = excludeItemTypes.ToArray(),
                 ExcludeItemTypes = excludeItemTypes.ToArray(),

+ 1 - 1
MediaBrowser.Server.Implementations/Library/UserViewManager.cs

@@ -278,7 +278,7 @@ namespace MediaBrowser.Server.Implementations.Library
 
 
             } : new string[] { };
             } : new string[] { };
 
 
-            return _libraryManager.GetItems(new InternalItemsQuery(user)
+            return _libraryManager.GetItemList(new InternalItemsQuery(user)
             {
             {
                 IncludeItemTypes = includeItemTypes,
                 IncludeItemTypes = includeItemTypes,
                 SortOrder = SortOrder.Descending,
                 SortOrder = SortOrder.Descending,

+ 5 - 5
MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -135,11 +135,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
         {
         {
             var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
             var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
 
 
-            var channels = _libraryManager.GetItems(new InternalItemsQuery
+            var channels = _libraryManager.GetItemList(new InternalItemsQuery
             {
             {
                 IncludeItemTypes = new[] { typeof(LiveTvChannel).Name }
                 IncludeItemTypes = new[] { typeof(LiveTvChannel).Name }
 
 
-            }).Items.Cast<LiveTvChannel>();
+            }).Cast<LiveTvChannel>();
 
 
             if (user != null)
             if (user != null)
             {
             {
@@ -1430,7 +1430,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 internalQuery.ChannelIds = new[] { query.ChannelId };
                 internalQuery.ChannelIds = new[] { query.ChannelId };
             }
             }
 
 
-            var queryResult = _libraryManager.GetItems(internalQuery, new string[] { });
+            var queryResult = _libraryManager.GetItemList(internalQuery, new string[] { });
             IEnumerable<ILiveTvRecording> recordings = queryResult.Cast<ILiveTvRecording>();
             IEnumerable<ILiveTvRecording> recordings = queryResult.Cast<ILiveTvRecording>();
 
 
             if (!string.IsNullOrWhiteSpace(query.Id))
             if (!string.IsNullOrWhiteSpace(query.Id))
@@ -1865,7 +1865,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
 
             var now = DateTime.UtcNow;
             var now = DateTime.UtcNow;
 
 
-            var programs = _libraryManager.GetItems(new InternalItemsQuery(user)
+            var programs = _libraryManager.GetItemList(new InternalItemsQuery(user)
             {
             {
                 IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
                 IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
                 ChannelIds = new[] { id },
                 ChannelIds = new[] { id },
@@ -1889,7 +1889,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
 
             var now = DateTime.UtcNow;
             var now = DateTime.UtcNow;
 
 
-            var programs = _libraryManager.GetItems(new InternalItemsQuery(user)
+            var programs = _libraryManager.GetItemList(new InternalItemsQuery(user)
             {
             {
                 IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
                 IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
                 ChannelIds = new[] { channel.Id.ToString("N") },
                 ChannelIds = new[] { channel.Id.ToString("N") },

+ 102 - 11
MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs

@@ -19,6 +19,7 @@ using System.Runtime.Serialization;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Channels;
+using MediaBrowser.Controller.Playlists;
 using MediaBrowser.Model.LiveTv;
 using MediaBrowser.Model.LiveTv;
 
 
 namespace MediaBrowser.Server.Implementations.Persistence
 namespace MediaBrowser.Server.Implementations.Persistence
@@ -729,10 +730,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
                     var topParent = item.GetTopParent();
                     var topParent = item.GetTopParent();
                     if (topParent != null)
                     if (topParent != null)
                     {
                     {
+                        //Logger.Debug("Item {0} has top parent {1}", item.Id, topParent.Id);
                         _saveItemCommand.GetParameter(index++).Value = topParent.Id.ToString("N");
                         _saveItemCommand.GetParameter(index++).Value = topParent.Id.ToString("N");
                     }
                     }
                     else
                     else
                     {
                     {
+                        //Logger.Debug("Item {0} has null top parent", item.Id);
                         _saveItemCommand.GetParameter(index++).Value = null;
                         _saveItemCommand.GetParameter(index++).Value = null;
                     }
                     }
 
 
@@ -1583,11 +1586,19 @@ namespace MediaBrowser.Server.Implementations.Persistence
 
 
         private string MapOrderByField(string name)
         private string MapOrderByField(string name)
         {
         {
-            if (string.Equals(name, "airtime", StringComparison.OrdinalIgnoreCase))
+            if (string.Equals(name, ItemSortBy.AirTime, StringComparison.OrdinalIgnoreCase))
             {
             {
                 // TODO
                 // TODO
                 return "SortName";
                 return "SortName";
             }
             }
+            if (string.Equals(name, ItemSortBy.Runtime, StringComparison.OrdinalIgnoreCase))
+            {
+                return "RuntimeTicks";
+            }
+            if (string.Equals(name, ItemSortBy.Random, StringComparison.OrdinalIgnoreCase))
+            {
+                return "RANDOM()";
+            }
 
 
             return name;
             return name;
         }
         }
@@ -1783,6 +1794,16 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 }
                 }
                 cmd.Parameters.Add(cmd, "@SchemaVersion", DbType.Int32).Value = LatestSchemaVersion;
                 cmd.Parameters.Add(cmd, "@SchemaVersion", DbType.Int32).Value = LatestSchemaVersion;
             }
             }
+            if (query.IsHD.HasValue)
+            {
+                whereClauses.Add("IsHD=@IsHD");
+                cmd.Parameters.Add(cmd, "@IsHD", DbType.Boolean).Value = query.IsHD;
+            }
+            if (query.IsLocked.HasValue)
+            {
+                whereClauses.Add("IsLocked=@IsLocked");
+                cmd.Parameters.Add(cmd, "@IsLocked", DbType.Boolean).Value = query.IsLocked;
+            }
             if (query.IsOffline.HasValue)
             if (query.IsOffline.HasValue)
             {
             {
                 whereClauses.Add("IsOffline=@IsOffline");
                 whereClauses.Add("IsOffline=@IsOffline");
@@ -1861,6 +1882,30 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 cmd.Parameters.Add(cmd, "@Path", DbType.String).Value = query.Path;
                 cmd.Parameters.Add(cmd, "@Path", DbType.String).Value = query.Path;
             }
             }
 
 
+            if (query.MinCommunityRating.HasValue)
+            {
+                whereClauses.Add("CommunityRating>=@MinCommunityRating");
+                cmd.Parameters.Add(cmd, "@MinCommunityRating", DbType.Double).Value = query.MinCommunityRating.Value;
+            }
+
+            if (query.MinIndexNumber.HasValue)
+            {
+                whereClauses.Add("IndexNumber>=@MinIndexNumber");
+                cmd.Parameters.Add(cmd, "@MinIndexNumber", DbType.Int32).Value = query.MinIndexNumber.Value;
+            }
+
+            //if (query.MinPlayers.HasValue)
+            //{
+            //    whereClauses.Add("Players>=@MinPlayers");
+            //    cmd.Parameters.Add(cmd, "@MinPlayers", DbType.Int32).Value = query.MinPlayers.Value;
+            //}
+
+            //if (query.MaxPlayers.HasValue)
+            //{
+            //    whereClauses.Add("Players<=@MaxPlayers");
+            //    cmd.Parameters.Add(cmd, "@MaxPlayers", DbType.Int32).Value = query.MaxPlayers.Value;
+            //}
+
             if (query.MinEndDate.HasValue)
             if (query.MinEndDate.HasValue)
             {
             {
                 whereClauses.Add("EndDate>=@MinEndDate");
                 whereClauses.Add("EndDate>=@MinEndDate");
@@ -1879,16 +1924,21 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 cmd.Parameters.Add(cmd, "@MinStartDate", DbType.Date).Value = query.MinStartDate.Value;
                 cmd.Parameters.Add(cmd, "@MinStartDate", DbType.Date).Value = query.MinStartDate.Value;
             }
             }
 
 
+            if (query.MaxStartDate.HasValue)
+            {
+                whereClauses.Add("StartDate<=@MaxStartDate");
+                cmd.Parameters.Add(cmd, "@MaxStartDate", DbType.Date).Value = query.MaxStartDate.Value;
+            }
+
             if (query.MinPremiereDate.HasValue)
             if (query.MinPremiereDate.HasValue)
             {
             {
                 whereClauses.Add("PremiereDate>=@MinPremiereDate");
                 whereClauses.Add("PremiereDate>=@MinPremiereDate");
                 cmd.Parameters.Add(cmd, "@MinPremiereDate", DbType.Date).Value = query.MinPremiereDate.Value;
                 cmd.Parameters.Add(cmd, "@MinPremiereDate", DbType.Date).Value = query.MinPremiereDate.Value;
             }
             }
-
-            if (query.MaxStartDate.HasValue)
+            if (query.MaxPremiereDate.HasValue)
             {
             {
-                whereClauses.Add("StartDate<=@MaxStartDate");
-                cmd.Parameters.Add(cmd, "@MaxStartDate", DbType.Date).Value = query.MaxStartDate.Value;
+                whereClauses.Add("PremiereDate<=@MaxPremiereDate");
+                cmd.Parameters.Add(cmd, "@MaxPremiereDate", DbType.Date).Value = query.MaxPremiereDate.Value;
             }
             }
 
 
             if (query.SourceTypes.Length == 1)
             if (query.SourceTypes.Length == 1)
@@ -1972,16 +2022,44 @@ namespace MediaBrowser.Server.Implementations.Persistence
 
 
             if (query.Genres.Length > 0)
             if (query.Genres.Length > 0)
             {
             {
-                var genres = new List<string>();
+                var clauses = new List<string>();
+                var index = 0;
+                foreach (var item in query.Genres)
+                {
+                    clauses.Add("Genres like @Genres" + index);
+                    cmd.Parameters.Add(cmd, "@Genres" + index, DbType.String).Value = "%" + item + "%";
+                    index++;
+                }
+                var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
+                whereClauses.Add(clause);
+            }
+
+            if (query.Tags.Length > 0)
+            {
+                var clauses = new List<string>();
                 var index = 0;
                 var index = 0;
-                foreach (var genre in query.Genres)
+                foreach (var item in query.Tags)
                 {
                 {
-                    genres.Add("Genres like @Genres" + index);
-                    cmd.Parameters.Add(cmd, "@Genres" + index, DbType.String).Value = "%" + genre + "%";
+                    clauses.Add("Tags like @Tags" + index);
+                    cmd.Parameters.Add(cmd, "@Tags" + index, DbType.String).Value = "%" + item + "%";
                     index++;
                     index++;
                 }
                 }
-                var genreCaluse = "(" + string.Join(" OR ", genres.ToArray()) + ")";
-                whereClauses.Add(genreCaluse);
+                var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
+                whereClauses.Add(clause);
+            }
+
+            if (query.Studios.Length > 0)
+            {
+                var clauses = new List<string>();
+                var index = 0;
+                foreach (var item in query.Studios)
+                {
+                    clauses.Add("Studios like @Studios" + index);
+                    cmd.Parameters.Add(cmd, "@Studios" + index, DbType.String).Value = "%" + item + "%";
+                    index++;
+                }
+                var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
+                whereClauses.Add(clause);
             }
             }
 
 
             if (query.MaxParentalRating.HasValue)
             if (query.MaxParentalRating.HasValue)
@@ -2020,6 +2098,17 @@ namespace MediaBrowser.Server.Implementations.Persistence
 
 
                 whereClauses.Add("LocationType not in (" + val + ")");
                 whereClauses.Add("LocationType not in (" + val + ")");
             }
             }
+            if (query.MediaTypes.Length == 1)
+            {
+                whereClauses.Add("MediaType=@MediaTypes");
+                cmd.Parameters.Add(cmd, "@MediaTypes", DbType.String).Value = query.MediaTypes[0].ToString();
+            }
+            if (query.MediaTypes.Length > 1)
+            {
+                var val = string.Join(",", query.MediaTypes.Select(i => "'" + i + "'").ToArray());
+
+                whereClauses.Add("MediaType in (" + val + ")");
+            }
 
 
             var enableItemsByName = query.IncludeItemsByName ?? query.IncludeItemTypes.Length > 0;
             var enableItemsByName = query.IncludeItemsByName ?? query.IncludeItemTypes.Length > 0;
 
 
@@ -2113,6 +2202,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
             typeof(MusicGenre),
             typeof(MusicGenre),
             typeof(MusicVideo),
             typeof(MusicVideo),
             typeof(Movie),
             typeof(Movie),
+            typeof(Playlist),
+            typeof(AudioPodcast),
             typeof(Trailer),
             typeof(Trailer),
             typeof(BoxSet),
             typeof(BoxSet),
             typeof(Episode),
             typeof(Episode),

+ 2 - 2
MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs

@@ -36,7 +36,7 @@ namespace MediaBrowser.Server.Implementations.TV
                 ? new string[] { }
                 ? new string[] { }
                 : new[] { request.ParentId };
                 : new[] { request.ParentId };
 
 
-            var items = _libraryManager.GetItems(new InternalItemsQuery(user)
+            var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
             {
             {
                 IncludeItemTypes = new[] { typeof(Series).Name },
                 IncludeItemTypes = new[] { typeof(Series).Name },
                 SortOrder = SortOrder.Ascending
                 SortOrder = SortOrder.Ascending
@@ -58,7 +58,7 @@ namespace MediaBrowser.Server.Implementations.TV
                 throw new ArgumentException("User not found");
                 throw new ArgumentException("User not found");
             }
             }
 
 
-            var items = _libraryManager.GetItems(new InternalItemsQuery(user)
+            var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
             {
             {
                 IncludeItemTypes = new[] { typeof(Series).Name },
                 IncludeItemTypes = new[] { typeof(Series).Name },
                 SortOrder = SortOrder.Ascending
                 SortOrder = SortOrder.Ascending

+ 1 - 1
MediaBrowser.WebDashboard/Api/PackageCreator.cs

@@ -282,7 +282,7 @@ namespace MediaBrowser.WebDashboard.Api
                     {
                     {
                         var lang = localizationCulture.Split('-').FirstOrDefault();
                         var lang = localizationCulture.Split('-').FirstOrDefault();
 
 
-                        html = html.Replace("<html>", "<html data-culture=\"" + localizationCulture + "\" lang=\"" + lang + "\">");
+                        html = html.Replace("<html", "<html data-culture=\"" + localizationCulture + "\" lang=\"" + lang + "\"");
                     }
                     }
 
 
                     if (enableMinification)
                     if (enableMinification)

+ 3 - 2
MediaBrowser.XbmcMetadata/EntryPoint.cs

@@ -8,6 +8,7 @@ using MediaBrowser.Model.Logging;
 using MediaBrowser.XbmcMetadata.Configuration;
 using MediaBrowser.XbmcMetadata.Configuration;
 using MediaBrowser.XbmcMetadata.Savers;
 using MediaBrowser.XbmcMetadata.Savers;
 using System;
 using System;
+using System.Linq;
 
 
 namespace MediaBrowser.XbmcMetadata
 namespace MediaBrowser.XbmcMetadata
 {
 {
@@ -49,11 +50,11 @@ namespace MediaBrowser.XbmcMetadata
                         return;
                         return;
                     }
                     }
 
 
-                    var items = _libraryManager.GetItems(new InternalItemsQuery
+                    var items = _libraryManager.GetItemList(new InternalItemsQuery
                     {
                     {
                         Person = person.Name
                         Person = person.Name
 
 
-                    }).Items;
+                    }).ToList();
 
 
                     foreach (var item in items)
                     foreach (var item in items)
                     {
                     {