Luke Pulverenti před 9 roky
rodič
revize
0bd1f36ece
30 změnil soubory, kde provedl 431 přidání a 244 odebrání
  1. 4 2
      MediaBrowser.Api/PluginService.cs
  2. 11 23
      MediaBrowser.Api/TvShowsService.cs
  3. 10 7
      MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs
  4. 1 1
      MediaBrowser.Controller/Entities/AggregateFolder.cs
  5. 20 1
      MediaBrowser.Controller/Entities/BaseItem.cs
  6. 31 14
      MediaBrowser.Controller/Entities/Folder.cs
  7. 5 1
      MediaBrowser.Controller/Entities/InternalItemsQuery.cs
  8. 9 0
      MediaBrowser.Controller/Entities/Person.cs
  9. 14 0
      MediaBrowser.Controller/Entities/TV/Episode.cs
  10. 15 0
      MediaBrowser.Controller/Entities/UserView.cs
  11. 11 1
      MediaBrowser.Controller/Library/ILibraryManager.cs
  12. 9 0
      MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
  13. 7 0
      MediaBrowser.Controller/Persistence/IItemRepository.cs
  14. 9 15
      MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
  15. 6 3
      MediaBrowser.Model/Configuration/ServerConfiguration.cs
  16. 1 0
      MediaBrowser.Server.Implementations/Collections/CollectionManager.cs
  17. 4 10
      MediaBrowser.Server.Implementations/Dto/DtoService.cs
  18. 3 5
      MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs
  19. 42 16
      MediaBrowser.Server.Implementations/Library/LibraryManager.cs
  20. 3 5
      MediaBrowser.Server.Implementations/Library/MusicManager.cs
  21. 4 23
      MediaBrowser.Server.Implementations/Library/SearchEngine.cs
  22. 13 21
      MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
  23. 8 0
      MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs
  24. 144 8
      MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
  25. 1 0
      MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs
  26. 10 38
      MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs
  27. 1 1
      MediaBrowser.Server.Startup.Common/ApplicationHost.cs
  28. 1 1
      MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj
  29. 34 0
      MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs
  30. 0 48
      MediaBrowser.Server.Startup.Common/Migrations/Release5767.cs

+ 4 - 2
MediaBrowser.Api/PluginService.cs

@@ -278,9 +278,11 @@ namespace MediaBrowser.Api
         /// </summary>
         /// <param name="request"></param>
         /// <returns></returns>
-        public async Task Post(RegisterAppstoreSale request)
+        public void Post(RegisterAppstoreSale request)
         {
-            await _securityManager.RegisterAppStoreSale(request.Parameters);
+            var task = _securityManager.RegisterAppStoreSale(request.Parameters);
+
+            Task.WaitAll(task);
         }
 
         /// <summary>

+ 11 - 23
MediaBrowser.Api/TvShowsService.cs

@@ -275,38 +275,26 @@ namespace MediaBrowser.Api
 
             var minPremiereDate = DateTime.Now.Date.AddDays(-1).ToUniversalTime();
 
-            IEnumerable<BaseItem> items;
+            var parentIds = string.IsNullOrWhiteSpace(request.ParentId) ? new string[] { } : new[] { request.ParentId };
 
-            if (string.IsNullOrWhiteSpace(request.ParentId))
+            var itemsResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user)
             {
-                items = _libraryManager.GetItems(new InternalItemsQuery(user)
-                {
-                    IncludeItemTypes = new[] { typeof(Episode).Name },
-                    SortBy = new[] { "PremiereDate", "SortName" },
-                    SortOrder = SortOrder.Ascending,
-                    MinPremiereDate = minPremiereDate
-
-                }, user);
-            }
-            else
-            {
-                items = GetAllLibraryItems(request.UserId, _userManager, _libraryManager, request.ParentId, i => i is Episode && (i.PremiereDate ?? DateTime.MinValue) >= minPremiereDate);
-            }
-
-            var itemsList = _libraryManager
-                .Sort(items, user, new[] { "PremiereDate", "AirTime", "SortName" }, SortOrder.Ascending)
-                .Cast<Episode>()
-                .ToList();
+                IncludeItemTypes = new[] { typeof(Episode).Name },
+                SortBy = new[] { "PremiereDate", "AirTime", "SortName" },
+                SortOrder = SortOrder.Ascending,
+                MinPremiereDate = minPremiereDate,
+                StartIndex = request.StartIndex,
+                Limit = request.Limit
 
-            var pagedItems = ApplyPaging(itemsList, request.StartIndex, request.Limit);
+            }, user, parentIds);
 
             var options = GetDtoOptions(request);
 
-            var returnItems = _dtoService.GetBaseItemDtos(pagedItems, options, user).ToArray();
+            var returnItems = _dtoService.GetBaseItemDtos(itemsResult.Items, options, user).ToArray();
 
             var result = new ItemsResult
             {
-                TotalRecordCount = itemsList.Count,
+                TotalRecordCount = itemsResult.TotalRecordCount,
                 Items = returnItems
             };
 

+ 10 - 7
MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs

@@ -8,8 +8,10 @@ using MediaBrowser.Model.Serialization;
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Net;
 using System.Threading;
 using System.Threading.Tasks;
+using MediaBrowser.Model.Net;
 
 namespace MediaBrowser.Common.Implementations.Security
 {
@@ -219,10 +221,6 @@ namespace MediaBrowser.Common.Implementations.Security
                     {
                         SupporterKey = reg.key;
                     }
-                    else
-                    {
-                        throw new PaymentRequiredException();
-                    }
                 }
 
             }
@@ -231,10 +229,15 @@ namespace MediaBrowser.Common.Implementations.Security
                 SaveAppStoreInfo(parameters);
                 throw;
             }
-            catch (PaymentRequiredException)
+            catch (HttpException e)
             {
-                SaveAppStoreInfo(parameters);
-                throw;
+                _logger.ErrorException("Error registering appstore purchase {0}", e, parameters ?? "NO PARMS SENT");
+
+                if (e.StatusCode.HasValue && e.StatusCode.Value == HttpStatusCode.PaymentRequired)
+                {
+                    throw new PaymentRequiredException();
+                }
+                throw new ApplicationException("Error registering store sale");
             }
             catch (Exception e)
             {

+ 1 - 1
MediaBrowser.Controller/Entities/AggregateFolder.cs

@@ -128,7 +128,7 @@ namespace MediaBrowser.Controller.Entities
         /// <returns>IEnumerable{BaseItem}.</returns>
         protected override IEnumerable<BaseItem> GetNonCachedChildren(IDirectoryService directoryService)
         {
-            return base.GetNonCachedChildren(directoryService).Concat(_virtualChildren);
+            return base.GetNonCachedChildren(directoryService);
         }
 
         /// <summary>

+ 20 - 1
MediaBrowser.Controller/Entities/BaseItem.cs

@@ -639,7 +639,7 @@ namespace MediaBrowser.Controller.Entities
         /// </summary>
         /// <value>The tags.</value>
         public List<string> Tags { get; set; }
-        
+
         /// <summary>
         /// Gets or sets the home page URL.
         /// </summary>
@@ -1898,5 +1898,24 @@ namespace MediaBrowser.Controller.Entities
                 DateLastSaved.Ticks.ToString(CultureInfo.InvariantCulture)
             };
         }
+
+        public virtual IEnumerable<Guid> GetAncestorIds()
+        {
+            return Parents.Select(i => i.Id).Concat(LibraryManager.GetCollectionFolders(this).Select(i => i.Id));
+        }
+
+        [IgnoreDataMember]
+        public virtual bool SupportsAncestors
+        {
+            get
+            {
+                return true;
+            }
+        }
+
+        public virtual IEnumerable<Guid> GetIdsForAncestorQuery()
+        {
+            return new[] { Id };
+        }
     }
 }

+ 31 - 14
MediaBrowser.Controller/Entities/Folder.cs

@@ -149,7 +149,15 @@ namespace MediaBrowser.Controller.Entities
 
             await LibraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false);
 
-            await ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false);
+            if (!EnableNewFolderQuerying())
+            {
+                await ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false);
+            }
+        }
+
+        private static bool EnableNewFolderQuerying()
+        {
+            return ConfigurationManager.Configuration.MigrationVersion >= 1;
         }
 
         protected void AddChildrenInternal(IEnumerable<BaseItem> children)
@@ -222,7 +230,12 @@ namespace MediaBrowser.Controller.Entities
 
             item.SetParent(null);
 
-            return ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken);
+            if (!EnableNewFolderQuerying())
+            {
+                return ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken);
+            }
+
+            return Task.FromResult(true);
         }
 
         /// <summary>
@@ -471,6 +484,7 @@ namespace MediaBrowser.Controller.Entities
                         }
                         else
                         {
+                            child.SetParent(this);
                             newItems.Add(child);
                             validChildren.Add(child);
                         }
@@ -478,6 +492,7 @@ namespace MediaBrowser.Controller.Entities
                     else
                     {
                         // Brand new item - needs to be added
+                        child.SetParent(this);
                         newItems.Add(child);
                         validChildren.Add(child);
                     }
@@ -506,7 +521,6 @@ namespace MediaBrowser.Controller.Entities
                         }
                         else
                         {
-                            await UpdateIsOffline(item, false).ConfigureAwait(false);
                             actualRemovals.Add(item);
                         }
                     }
@@ -517,6 +531,9 @@ namespace MediaBrowser.Controller.Entities
 
                         foreach (var item in actualRemovals)
                         {
+                            item.SetParent(null);
+                            item.IsOffline = false;
+                            await LibraryManager.DeleteItem(item, new DeleteOptions { DeleteFileLocation = false }).ConfigureAwait(false);
                             LibraryManager.ReportItemRemoved(item);
                         }
                     }
@@ -525,7 +542,10 @@ namespace MediaBrowser.Controller.Entities
 
                     AddChildrenInternal(newItems);
 
-                    await ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false);
+                    if (!EnableNewFolderQuerying())
+                    {
+                        await ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false);
+                    }
                 }
             }
 
@@ -755,19 +775,16 @@ namespace MediaBrowser.Controller.Entities
         /// <returns>IEnumerable{BaseItem}.</returns>
         protected IEnumerable<BaseItem> GetCachedChildren()
         {
-            if (ConfigurationManager.Configuration.DisableStartupScan)
+            if (EnableNewFolderQuerying())
             {
-                return ItemRepository.GetChildrenItems(Id).Select(RetrieveChild).Where(i => i != null);
-                //return ItemRepository.GetItems(new InternalItemsQuery
-                //{
-                //    ParentId = Id
+                return ItemRepository.GetItemList(new InternalItemsQuery
+                {
+                    ParentId = Id
 
-                //}).Items.Select(RetrieveChild).Where(i => i != null);
-            }
-            else
-            {
-                return ItemRepository.GetChildrenItems(Id).Select(RetrieveChild).Where(i => i != null);
+                }).Select(RetrieveChild).Where(i => i != null);
             }
+
+            return ItemRepository.GetChildrenItems(Id).Select(RetrieveChild).Where(i => i != null);
         }
 
         private BaseItem RetrieveChild(BaseItem child)

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

@@ -102,7 +102,8 @@ namespace MediaBrowser.Controller.Entities
         public LocationType? LocationType { get; set; }
 
         public Guid? ParentId { get; set; }
-        
+        public string[] AncestorIds { get; set; }
+      
         public InternalItemsQuery()
         {
             Tags = new string[] { };
@@ -121,6 +122,7 @@ namespace MediaBrowser.Controller.Entities
             PersonIds = new string[] { };
             ChannelIds = new string[] { };
             ItemIds = new string[] { };
+            AncestorIds = new string[] { };
         }
 
         public InternalItemsQuery(User user)
@@ -130,6 +132,8 @@ namespace MediaBrowser.Controller.Entities
             {
                 var policy = user.Policy;
                 MaxParentalRating = policy.MaxParentalRating;
+
+                User = user;
             }
         }
     }

+ 9 - 0
MediaBrowser.Controller/Entities/Person.cs

@@ -101,6 +101,15 @@ namespace MediaBrowser.Controller.Entities
                 return false;
             }
         }
+
+        [IgnoreDataMember]
+        public override bool SupportsAncestors
+        {
+            get
+            {
+                return false;
+            }
+        }
     }
 
     /// <summary>

+ 14 - 0
MediaBrowser.Controller/Entities/TV/Episode.cs

@@ -265,6 +265,20 @@ namespace MediaBrowser.Controller.Entities.TV
             }
         }
 
+        public override IEnumerable<Guid> GetAncestorIds()
+        {
+            var list = base.GetAncestorIds().ToList();
+
+            var seasonId = SeasonId;
+
+            if (seasonId.HasValue && !list.Contains(seasonId.Value))
+            {
+                list.Add(seasonId.Value);
+            }
+
+            return list;
+        }
+
         public override IEnumerable<string> GetDeletePaths()
         {
             return new[] { Path };

+ 15 - 0
MediaBrowser.Controller/Entities/UserView.cs

@@ -24,6 +24,21 @@ namespace MediaBrowser.Controller.Entities
         {
             return true;
         }
+
+        public override IEnumerable<Guid> GetIdsForAncestorQuery()
+        {
+            var list = new List<Guid>();
+
+            if (DisplayParentId != Guid.Empty)
+            {
+                list.Add(DisplayParentId);
+            }
+            else if (ParentId != Guid.Empty)
+            {
+                list.Add(ParentId);
+            }
+            return list;
+        }
         
         public override Task<QueryResult<BaseItem>> GetItems(InternalItemsQuery query)
         {

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

@@ -549,7 +549,17 @@ namespace MediaBrowser.Controller.Library
         /// </summary>
         /// <param name="query">The query.</param>
         /// <param name="user">The user.</param>
+        /// <param name="parentIds">The parent ids.</param>
         /// <returns>List&lt;BaseItem&gt;.</returns>
-        IEnumerable<BaseItem> GetItems(InternalItemsQuery query, User user);
+        IEnumerable<BaseItem> GetItems(InternalItemsQuery query, User user, IEnumerable<string> parentIds);
+
+        /// <summary>
+        /// Gets the items result.
+        /// </summary>
+        /// <param name="query">The query.</param>
+        /// <param name="user">The user.</param>
+        /// <param name="parentIds">The parent ids.</param>
+        /// <returns>QueryResult&lt;BaseItem&gt;.</returns>
+        QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query, User user, IEnumerable<string> parentIds);
     }
 }

+ 9 - 0
MediaBrowser.Controller/LiveTv/LiveTvProgram.cs

@@ -217,5 +217,14 @@ namespace MediaBrowser.Controller.LiveTv
                 return base.SupportsPeople;
             }
         }
+
+        [IgnoreDataMember]
+        public override bool SupportsAncestors
+        {
+            get
+            {
+                return false;
+            }
+        }
     }
 }

+ 7 - 0
MediaBrowser.Controller/Persistence/IItemRepository.cs

@@ -176,6 +176,13 @@ namespace MediaBrowser.Controller.Persistence
         /// <param name="query">The query.</param>
         /// <returns>QueryResult&lt;Tuple&lt;Guid, System.String&gt;&gt;.</returns>
         QueryResult<Tuple<Guid, string>> GetItemIdsWithPath(InternalItemsQuery query);
+
+        /// <summary>
+        /// Gets the item list.
+        /// </summary>
+        /// <param name="query">The query.</param>
+        /// <returns>List&lt;BaseItem&gt;.</returns>
+        IEnumerable<BaseItem> GetItemList(InternalItemsQuery query);
     }
 }
 

+ 9 - 15
MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs

@@ -481,23 +481,17 @@ namespace MediaBrowser.Dlna.ContentDirectory
 
         private QueryResult<ServerItem> GetItemsFromPerson(Person person, User user, int? startIndex, int? limit)
         {
-            var itemsWithPerson = _libraryManager.GetItems(new InternalItemsQuery
+            var itemsResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user)
             {
-                Person = person.Name
-
-            }).Items;
-
-            var items = itemsWithPerson
-                .Where(i => i is Movie || i is Series || i is IChannelItem)
-                .Where(i => i.IsVisibleStandalone(user))
-                .ToList();
+                Person = person.Name,
+                IncludeItemTypes = new[] { typeof(Movie).Name, typeof(Series).Name, typeof(ChannelVideoItem).Name },
+                SortBy = new[] { ItemSortBy.SortName },
+                Limit = limit,
+                StartIndex = startIndex
 
-            items = _libraryManager.Sort(items, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending)
-                .Skip(startIndex ?? 0)
-                .Take(limit ?? int.MaxValue)
-                .ToList();
+            }, user, new string[] { });
 
-            var serverItems = items.Select(i => new ServerItem
+            var serverItems = itemsResult.Items.Select(i => new ServerItem
             {
                 Item = i,
                 StubType = null
@@ -506,7 +500,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
 
             return new QueryResult<ServerItem>
             {
-                TotalRecordCount = serverItems.Length,
+                TotalRecordCount = itemsResult.TotalRecordCount,
                 Items = serverItems
             };
         }

+ 6 - 3
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -67,7 +67,7 @@ namespace MediaBrowser.Model.Configuration
         /// </summary>
         /// <value><c>true</c> if [enable high quality image scaling]; otherwise, <c>false</c>.</value>
         public bool EnableHighQualityImageScaling { get; set; }
-        
+
         /// <summary>
         /// Gets or sets the item by name path.
         /// </summary>
@@ -234,12 +234,14 @@ namespace MediaBrowser.Model.Configuration
 
         public string[] Migrations { get; set; }
 
+        public int MigrationVersion { get; set; }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
         /// </summary>
         public ServerConfiguration()
         {
-            Migrations = new string[] {};
+            Migrations = new string[] { };
 
             ImageSavingConvention = ImageSavingConvention.Compatible;
             PublicPort = 8096;
@@ -583,7 +585,8 @@ namespace MediaBrowser.Model.Configuration
                             Limit = 0,
                             Type = ImageType.Thumb
                         }
-                    }
+                    },
+                    DisabledMetadataFetchers = new []{ "TheMovieDb" }
                 }
             };
         }

+ 1 - 0
MediaBrowser.Server.Implementations/Collections/CollectionManager.cs

@@ -40,6 +40,7 @@ namespace MediaBrowser.Server.Implementations.Collections
         public Folder GetCollectionsFolder(string userId)
         {
             return _libraryManager.RootFolder.Children.OfType<ManualCollectionsFolder>()
+                .FirstOrDefault() ?? _libraryManager.GetUserRootFolder().Children.OfType<ManualCollectionsFolder>()
                 .FirstOrDefault();
         }
 

+ 4 - 10
MediaBrowser.Server.Implementations/Dto/DtoService.cs

@@ -163,16 +163,11 @@ namespace MediaBrowser.Server.Implementations.Dto
 
             if (person != null)
             {
-                var items = _libraryManager.GetItems(new InternalItemsQuery
+                var items = _libraryManager.GetItems(new InternalItemsQuery(user)
                 {
                     Person = byName.Name
 
-                }).Items;
-
-                if (user != null)
-                {
-                    return items.Where(i => i.IsVisibleStandalone(user)).ToList();
-                }
+                }, user, new string[] { });
 
                 return items.ToList();
             }
@@ -471,8 +466,7 @@ namespace MediaBrowser.Server.Implementations.Dto
                 dto.ChildCount = GetChildCount(folder, user);
 
                 // These are just far too slow. 
-                // TODO: Disable for CollectionFolder
-                if (!(folder is UserRootFolder) && !(folder is UserView) && !(folder is IChannelItem))
+                if (!(folder is UserRootFolder) && !(folder is UserView) && !(folder is IChannelItem) && !(folder is ICollectionFolder))
                 {
                     SetSpecialCounts(folder, user, dto, fields, syncProgress);
                 }
@@ -1524,7 +1518,7 @@ namespace MediaBrowser.Server.Implementations.Dto
             }
 
             dto.ChannelId = item.ChannelId;
-            
+
             var channelItem = item as IChannelItem;
             if (channelItem != null)
             {

+ 3 - 5
MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs

@@ -83,13 +83,11 @@ namespace MediaBrowser.Server.Implementations.Intros
 
             if (config.EnableIntrosFromMoviesInLibrary)
             {
-                var inputItems = _libraryManager.GetItems(new InternalItemsQuery
+                var inputItems = _libraryManager.GetItems(new InternalItemsQuery(user)
                 {
-                    IncludeItemTypes = new[] { typeof(Movie).Name },
+                    IncludeItemTypes = new[] { typeof(Movie).Name }
 
-                    User = user
-
-                }).Items;
+                }, user, new string[]{});
 
                 var itemsWithTrailers = inputItems
                     .Where(i =>

+ 42 - 16
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -401,12 +401,12 @@ namespace MediaBrowser.Server.Implementations.Library
             {
                 foreach (var path in item.GetDeletePaths().ToList())
                 {
-					if (_fileSystem.DirectoryExists(path))
+                    if (_fileSystem.DirectoryExists(path))
                     {
                         _logger.Debug("Deleting path {0}", path);
                         _fileSystem.DeleteDirectory(path, true);
                     }
-					else if (_fileSystem.FileExists(path))
+                    else if (_fileSystem.FileExists(path))
                     {
                         _logger.Debug("Deleting path {0}", path);
                         _fileSystem.DeleteFile(path);
@@ -697,7 +697,7 @@ namespace MediaBrowser.Server.Implementations.Library
         {
             var rootFolderPath = ConfigurationManager.ApplicationPaths.RootFolderPath;
 
-			_fileSystem.CreateDirectory(rootFolderPath);
+            _fileSystem.CreateDirectory(rootFolderPath);
 
             var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? (AggregateFolder)ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath));
 
@@ -727,6 +727,13 @@ namespace MediaBrowser.Server.Implementations.Library
                         folder = dbItem;
                     }
 
+                    //if (folder.ParentId != rootFolder.Id)
+                    //{
+                    //    folder.ParentId = rootFolder.Id;
+                    //    var task = folder.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None);
+                    //    Task.WaitAll(task);
+                    //}
+
                     rootFolder.AddVirtualChild(folder);
 
                     RegisterItem(folder);
@@ -748,7 +755,7 @@ namespace MediaBrowser.Server.Implementations.Library
                     {
                         var userRootPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
 
-						_fileSystem.CreateDirectory(userRootPath);
+                        _fileSystem.CreateDirectory(userRootPath);
 
                         var tmpItem = GetItemById(GetNewItemId(userRootPath, typeof(UserRootFolder))) as UserRootFolder;
 
@@ -1000,9 +1007,9 @@ namespace MediaBrowser.Server.Implementations.Library
 
         private void SetPropertiesFromSongs(MusicArtist artist, IEnumerable<IHasMetadata> items)
         {
-            
+
         }
-        
+
         /// <summary>
         /// Validate and refresh the People sub-set of the IBN.
         /// The items are stored in the db but not loaded into memory until actually requested by an operation.
@@ -1013,7 +1020,7 @@ namespace MediaBrowser.Server.Implementations.Library
         public Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
         {
             // Ensure the location is available.
-			_fileSystem.CreateDirectory(ConfigurationManager.ApplicationPaths.PeoplePath);
+            _fileSystem.CreateDirectory(ConfigurationManager.ApplicationPaths.PeoplePath);
 
             return new PeopleValidator(this, _logger, ConfigurationManager, _fileSystem).ValidatePeople(cancellationToken, progress);
         }
@@ -1280,9 +1287,29 @@ namespace MediaBrowser.Server.Implementations.Library
             return ItemRepository.GetItemIdsList(query);
         }
 
-        public IEnumerable<BaseItem> GetItems(InternalItemsQuery query, User user)
+        public IEnumerable<BaseItem> GetItems(InternalItemsQuery query, User user, IEnumerable<string> parentIds)
         {
-            return GetItemIds(query).Select(GetItemById).Where(i => i.IsVisibleStandalone(user));
+            var parents = parentIds.Select(i => GetItemById(new Guid(i))).ToList();
+
+            query.AncestorIds = parents.SelectMany(i => i.GetIdsForAncestorQuery()).Select(i => i.ToString("N")).ToArray();
+
+            var items = GetItemIds(query).Select(GetItemById);
+
+            if (user != null)
+            {
+                items = items.Where(i => i.IsVisibleStandalone(user));
+            }
+
+            return items;
+        }
+
+        public QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query, User user, IEnumerable<string> parentIds)
+        {
+            var parents = parentIds.Select(i => GetItemById(new Guid(i))).ToList();
+
+            query.AncestorIds = parents.SelectMany(i => i.GetIdsForAncestorQuery()).Select(i => i.ToString("N")).ToArray();
+
+            return GetItems(query);
         }
 
         /// <summary>
@@ -1700,7 +1727,7 @@ namespace MediaBrowser.Server.Implementations.Library
             if (item == null ||
                 !string.Equals(item.Path, path, StringComparison.OrdinalIgnoreCase))
             {
-				_fileSystem.CreateDirectory(path);
+                _fileSystem.CreateDirectory(path);
 
                 item = new UserView
                 {
@@ -1719,8 +1746,7 @@ namespace MediaBrowser.Server.Implementations.Library
 
             if (!string.Equals(viewType, item.ViewType, StringComparison.OrdinalIgnoreCase))
             {
-                item.ViewType = viewType;
-                await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
+                refresh = true;
             }
 
             if (!refresh)
@@ -1793,7 +1819,7 @@ namespace MediaBrowser.Server.Implementations.Library
 
             if (item == null)
             {
-				_fileSystem.CreateDirectory(path);
+                _fileSystem.CreateDirectory(path);
 
                 item = new UserView
                 {
@@ -1917,7 +1943,7 @@ namespace MediaBrowser.Server.Implementations.Library
 
             return item;
         }
-        
+
         public async Task<UserView> GetNamedView(string name,
             string parentId,
             string viewType,
@@ -1946,7 +1972,7 @@ namespace MediaBrowser.Server.Implementations.Library
 
             if (item == null)
             {
-				_fileSystem.CreateDirectory(path);
+                _fileSystem.CreateDirectory(path);
 
                 item = new UserView
                 {
@@ -2379,7 +2405,7 @@ namespace MediaBrowser.Server.Implementations.Library
             return ItemRepository.UpdatePeople(item.Id, people);
         }
 
-        private readonly SemaphoreSlim _dynamicImageResourcePool = new SemaphoreSlim(1,1);
+        private readonly SemaphoreSlim _dynamicImageResourcePool = new SemaphoreSlim(1, 1);
         public async Task<ItemImageInfo> ConvertImageToLocal(IHasImages item, ItemImageInfo image, int imageIndex)
         {
             _logger.Debug("ConvertImageToLocal item {0}", item.Id);

+ 3 - 5
MediaBrowser.Server.Implementations/Library/MusicManager.cs

@@ -80,15 +80,13 @@ namespace MediaBrowser.Server.Implementations.Library
         {
             var genreList = genres.ToList();
 
-            var inputItems = _libraryManager.GetItems(new InternalItemsQuery
+            var inputItems = _libraryManager.GetItems(new InternalItemsQuery(user)
             {
                 IncludeItemTypes = new[] { typeof(Audio).Name },
 
-                Genres = genreList.ToArray(),
+                Genres = genreList.ToArray()
 
-                User = user
-
-            }).Items;
+            }, user, new string[] { });
 
             var genresDictionary = genreList.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
 

+ 4 - 23
MediaBrowser.Server.Implementations/Library/SearchEngine.cs

@@ -156,18 +156,18 @@ namespace MediaBrowser.Server.Implementations.Library
             }
 
             AddIfMissing(excludeItemTypes, typeof(CollectionFolder).Name);
-            
+
             var mediaItems = _libraryManager.GetItems(new InternalItemsQuery(user)
             {
                 NameContains = searchTerm,
                 ExcludeItemTypes = excludeItemTypes.ToArray(),
                 IncludeItemTypes = includeItemTypes.ToArray(),
-                Limit = (query.Limit.HasValue ? (int?)(query.Limit.Value * 3) : null),
+                Limit = (query.Limit.HasValue ? (int?)(query.Limit.Value * 2) : null),
 
-            }).Items;
+            }, user, new string[] { });
 
             // Add search hints based on item name
-            hints.AddRange(mediaItems.Where(i => IncludeInSearch(i) && IsVisible(i, user)).Select(item =>
+            hints.AddRange(mediaItems.Where(IncludeInSearch).Select(item =>
             {
                 var index = GetIndex(item.Name, searchTerm, terms);
 
@@ -183,25 +183,6 @@ namespace MediaBrowser.Server.Implementations.Library
             return Task.FromResult(returnValue);
         }
 
-        private bool IsVisible(BaseItem item, User user)
-        {
-            if (user == null)
-            {
-                return true;
-            }
-
-            if (item is IItemByName)
-            {
-                var dual = item as IHasDualAccess;
-                if (dual == null || dual.IsAccessedByName)
-                {
-                    return true;
-                }
-            }
-
-            return item.IsVisibleStandalone(user);
-        }
-
         private bool IncludeInSearch(BaseItem item)
         {
             var episode = item as Episode;

+ 13 - 21
MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -1357,7 +1357,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
             await RefreshRecordings(cancellationToken).ConfigureAwait(false);
 
-            var internalQuery = new InternalItemsQuery
+            var internalQuery = new InternalItemsQuery(user)
             {
                 IncludeItemTypes = new[] { typeof(LiveTvVideoRecording).Name, typeof(LiveTvAudioRecording).Name }
             };
@@ -1367,8 +1367,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 internalQuery.ChannelIds = new[] { query.ChannelId };
             }
 
-            var queryResult = _libraryManager.GetItems(internalQuery);
-            IEnumerable<ILiveTvRecording> recordings = queryResult.Items.Cast<ILiveTvRecording>();
+            var queryResult = _libraryManager.GetItems(internalQuery, user, new string[]{});
+            IEnumerable<ILiveTvRecording> recordings = queryResult.Cast<ILiveTvRecording>();
 
             if (!string.IsNullOrEmpty(query.Id))
             {
@@ -1405,12 +1405,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                     .Where(i => _tvDtoService.GetInternalSeriesTimerId(i.ServiceName, i.SeriesTimerId) == guid);
             }
 
-            if (user != null)
-            {
-                var currentUser = user;
-                recordings = recordings.Where(i => i.IsParentalAllowed(currentUser));
-            }
-
             recordings = recordings.OrderByDescending(i => i.StartDate);
 
             var entityList = recordings.ToList();
@@ -1771,19 +1765,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
             var now = DateTime.UtcNow;
 
-            var programs = _libraryManager.GetItems(new InternalItemsQuery
+            var programs = _libraryManager.GetItems(new InternalItemsQuery(user)
             {
                 IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
                 ChannelIds = new[] { id },
                 MaxStartDate = now,
                 MinEndDate = now,
-                Limit = 1
+                Limit = 1,
+                SortBy = new[] { "StartDate"}
 
-            }).Items.Cast<LiveTvProgram>();
+            }, user, new string[]{}).Cast<LiveTvProgram>();
 
-            var currentProgram = programs
-                .OrderBy(i => i.StartDate)
-                .FirstOrDefault();
+            var currentProgram = programs.FirstOrDefault();
 
             var dto = _tvDtoService.GetChannelInfoDto(channel, new DtoOptions(), currentProgram, user);
 
@@ -1796,19 +1789,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
             var now = DateTime.UtcNow;
 
-            var programs = _libraryManager.GetItems(new InternalItemsQuery
+            var programs = _libraryManager.GetItems(new InternalItemsQuery(user)
             {
                 IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
                 ChannelIds = new[] { channel.Id.ToString("N") },
                 MaxStartDate = now,
                 MinEndDate = now,
-                Limit = 1
+                Limit = 1,
+                SortBy = new[] { "StartDate" }
 
-            }).Items.Cast<LiveTvProgram>();
+            }, user, new string []{}).Cast<LiveTvProgram>();
 
-            var currentProgram = programs
-                .OrderBy(i => i.StartDate)
-                .FirstOrDefault();
+            var currentProgram = programs.FirstOrDefault();
 
             if (currentProgram != null)
             {

+ 8 - 0
MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs

@@ -24,6 +24,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
         private readonly IServerConfigurationManager _config;
         private readonly IFileSystem _fileSystem;
 
+        public const int MigrationVersion = 1;
+
         public CleanDatabaseScheduledTask(ILibraryManager libraryManager, IItemRepository itemRepo, ILogger logger, IServerConfigurationManager config, IFileSystem fileSystem)
         {
             _libraryManager = libraryManager;
@@ -121,6 +123,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 _config.SaveConfiguration();
             }
 
+            if (_config.Configuration.MigrationVersion < MigrationVersion)
+            {
+                _config.Configuration.MigrationVersion = MigrationVersion;
+                _config.SaveConfiguration();
+            }
+
             progress.Report(100);
         }
 

+ 144 - 8
MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs

@@ -77,7 +77,10 @@ namespace MediaBrowser.Server.Implementations.Persistence
         private IDbCommand _deleteStreamsCommand;
         private IDbCommand _saveStreamCommand;
 
-        private const int LatestSchemaVersion = 17;
+        private IDbCommand _deleteAncestorsCommand;
+        private IDbCommand _saveAncestorCommand;
+
+        private const int LatestSchemaVersion = 18;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="SqliteItemRepository"/> class.
@@ -126,9 +129,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
 
             string[] queries = {
 
-                                "create table if not exists TypedBaseItems (guid GUID primary key, type TEXT, data BLOB)",
+                                "create table if not exists TypedBaseItems (guid GUID primary key, type TEXT, data BLOB, ParentId GUID)",
                                 "create index if not exists idx_TypedBaseItems on TypedBaseItems(guid)",
+                                "create index if not exists idx_ParentIdTypedBaseItems on TypedBaseItems(ParentId)",
 
+                                "create table if not exists AncestorIds (ItemId GUID, AncestorId GUID, PRIMARY KEY (ItemId, AncestorId))",
+                                "create index if not exists idx_AncestorIds on AncestorIds(ItemId,AncestorId)",
+                                
                                 "create table if not exists ChildrenIds (ParentId GUID, ItemId GUID, PRIMARY KEY (ParentId, ItemId))",
                                 "create index if not exists idx_ChildrenIds on ChildrenIds(ParentId,ItemId)",
 
@@ -205,6 +212,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
             _connection.AddColumn(_logger, "TypedBaseItems", "Studios", "Text");
             _connection.AddColumn(_logger, "TypedBaseItems", "Audio", "Text");
             _connection.AddColumn(_logger, "TypedBaseItems", "ExternalServiceId", "Text");
+            _connection.AddColumn(_logger, "TypedBaseItems", "Tags", "Text");
 
             PrepareStatements();
 
@@ -429,7 +437,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 "LockedFields",
                 "Studios",
                 "Audio",
-                "ExternalServiceId"
+                "ExternalServiceId",
+                "Tags"
             };
             _saveItemCommand = _connection.CreateCommand();
             _saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values (";
@@ -472,6 +481,16 @@ namespace MediaBrowser.Server.Implementations.Persistence
             _savePersonCommand.Parameters.Add(_savePersonCommand, "@PersonType");
             _savePersonCommand.Parameters.Add(_savePersonCommand, "@SortOrder");
             _savePersonCommand.Parameters.Add(_savePersonCommand, "@ListOrder");
+            
+            // Ancestors
+            _deleteAncestorsCommand = _connection.CreateCommand();
+            _deleteAncestorsCommand.CommandText = "delete from AncestorIds where ItemId=@Id";
+            _deleteAncestorsCommand.Parameters.Add(_deleteAncestorsCommand, "@Id");
+
+            _saveAncestorCommand = _connection.CreateCommand();
+            _saveAncestorCommand.CommandText = "insert into AncestorIds (ItemId, AncestorId) values (@ItemId, @AncestorId)";
+            _saveAncestorCommand.Parameters.Add(_saveAncestorCommand, "@ItemId");
+            _saveAncestorCommand.Parameters.Add(_saveAncestorCommand, "@AncestorId");
 
             // Chapters
             _deleteChaptersCommand = _connection.CreateCommand();
@@ -682,9 +701,16 @@ namespace MediaBrowser.Server.Implementations.Persistence
                         _saveItemCommand.GetParameter(index++).Value = null;
                     }
 
+                    _saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Tags.ToArray());
+                    
                     _saveItemCommand.Transaction = transaction;
 
                     _saveItemCommand.ExecuteNonQuery();
+
+                    if (item.SupportsAncestors)
+                    {
+                        UpdateAncestors(item.Id, item.GetAncestorIds().Distinct().ToList(), transaction);
+                    }
                 }
 
                 transaction.Commit();
@@ -765,22 +791,32 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 return null;
             }
 
-            BaseItem item;
+            BaseItem item = null;
 
             using (var stream = reader.GetMemoryStream(1))
             {
                 try
                 {
                     item = _jsonSerializer.DeserializeFromStream(stream, type) as BaseItem;
+                }
+                catch (SerializationException ex)
+                {
+                    _logger.ErrorException("Error deserializing item", ex);
+                }
 
-                    if (item == null)
+                if (item == null)
+                {
+                    try
+                    {
+                        item = Activator.CreateInstance(type) as BaseItem;
+                    }
+                    catch
                     {
-                        return null;
                     }
                 }
-                catch (SerializationException ex)
+
+                if (item == null)
                 {
-                    _logger.ErrorException("Error deserializing item", ex);
                     return null;
                 }
             }
@@ -1328,6 +1364,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
 
                 cmd.Parameters.Add(cmd, "@ParentId", DbType.Guid).Value = parentId;
 
+                //_logger.Debug(cmd.CommandText);
+                
                 using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
                 {
                     while (reader.Read())
@@ -1373,6 +1411,50 @@ namespace MediaBrowser.Server.Implementations.Persistence
             }
         }
 
+        public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query)
+        {
+            if (query == null)
+            {
+                throw new ArgumentNullException("query");
+            }
+
+            CheckDisposed();
+
+            using (var cmd = _connection.CreateCommand())
+            {
+                cmd.CommandText = "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems";
+
+                var whereClauses = GetWhereClauses(query, cmd, true);
+
+                var whereText = whereClauses.Count == 0 ?
+                    string.Empty :
+                    " where " + string.Join(" AND ", whereClauses.ToArray());
+
+                cmd.CommandText += whereText;
+
+                cmd.CommandText += GetOrderByText(query);
+
+                if (query.Limit.HasValue)
+                {
+                    cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture);
+                }
+
+                //_logger.Debug(cmd.CommandText);
+
+                using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
+                {
+                    while (reader.Read())
+                    {
+                        var item = GetItem(reader);
+                        if (item != null)
+                        {
+                            yield return item;
+                        }
+                    }
+                }
+            }
+        }
+
         public QueryResult<BaseItem> GetItems(InternalItemsQuery query)
         {
             if (query == null)
@@ -1453,6 +1535,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
 
         private string MapOrderByField(string name)
         {
+            if (string.Equals(name, "airtime", StringComparison.OrdinalIgnoreCase))
+            {
+                // TODO
+                return "SortName";
+            }
+
             return name;
         }
 
@@ -1813,6 +1901,17 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 }
             }
 
+            if (query.AncestorIds.Length == 1)
+            {
+                whereClauses.Add("Guid in (select itemId from AncestorIds where AncestorId=@AncestorId)");
+                cmd.Parameters.Add(cmd, "@AncestorId", DbType.Guid).Value = new Guid(query.AncestorIds[0]);
+            }
+            if (query.AncestorIds.Length > 1)
+            {
+                var inClause = string.Join(",", query.AncestorIds.Select(i => "'" + i + "'").ToArray());
+                whereClauses.Add(string.Format("Guid in (select itemId from AncestorIds where AncestorId in ({0}))", inClause));
+            }
+
             if (addPaging)
             {
                 if (query.StartIndex.HasValue && query.StartIndex.Value > 0)
@@ -1847,6 +1946,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
             typeof(Movie),
             typeof(BoxSet),
             typeof(Episode),
+            typeof(ChannelVideoItem),
             typeof(Season),
             typeof(Series),
             typeof(Book),
@@ -1933,6 +2033,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 _deleteStreamsCommand.GetParameter(0).Value = id;
                 _deleteStreamsCommand.Transaction = transaction;
                 _deleteStreamsCommand.ExecuteNonQuery();
+                
+                // Delete ancestors
+                _deleteAncestorsCommand.GetParameter(0).Value = id;
+                _deleteAncestorsCommand.Transaction = transaction;
+                _deleteAncestorsCommand.ExecuteNonQuery();
 
                 // Delete the item
                 _deleteItemCommand.GetParameter(0).Value = id;
@@ -2167,6 +2272,37 @@ namespace MediaBrowser.Server.Implementations.Persistence
             return whereClauses;
         }
 
+        private void UpdateAncestors(Guid itemId, List<Guid> ancestorIds, IDbTransaction transaction)
+        {
+            if (itemId == Guid.Empty)
+            {
+                throw new ArgumentNullException("itemId");
+            }
+
+            if (ancestorIds == null)
+            {
+                throw new ArgumentNullException("ancestorIds");
+            }
+
+            CheckDisposed();
+
+            // First delete 
+            _deleteAncestorsCommand.GetParameter(0).Value = itemId;
+            _deleteAncestorsCommand.Transaction = transaction;
+
+            _deleteAncestorsCommand.ExecuteNonQuery();
+
+            foreach (var ancestorId in ancestorIds)
+            {
+                _saveAncestorCommand.GetParameter(0).Value = itemId;
+                _saveAncestorCommand.GetParameter(1).Value = ancestorId;
+
+                _saveAncestorCommand.Transaction = transaction;
+
+                _saveAncestorCommand.ExecuteNonQuery();
+            }
+        }
+
         public async Task UpdatePeople(Guid itemId, List<PersonInfo> people)
         {
             if (itemId == Guid.Empty)

+ 1 - 0
MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs

@@ -264,6 +264,7 @@ namespace MediaBrowser.Server.Implementations.Playlists
         public Folder GetPlaylistsFolder(string userId)
         {
             return _libraryManager.RootFolder.Children.OfType<PlaylistsFolder>()
+                .FirstOrDefault() ?? _libraryManager.GetUserRootFolder().Children.OfType<PlaylistsFolder>()
                 .FirstOrDefault();
         }
     }

+ 10 - 38
MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs

@@ -36,22 +36,12 @@ namespace MediaBrowser.Server.Implementations.TV
                 ? new string[] { }
                 : new[] { request.ParentId };
 
-            IEnumerable<Series> items;
-
-            if (parentIds.Length == 0)
+            var items = _libraryManager.GetItems(new InternalItemsQuery(user)
             {
-                items = _libraryManager.GetItems(new InternalItemsQuery(user)
-               {
-                   IncludeItemTypes = new[] { typeof(Series).Name },
-                   SortOrder = SortOrder.Ascending
+                IncludeItemTypes = new[] { typeof(Series).Name },
+                SortOrder = SortOrder.Ascending
 
-               }, user).Cast<Series>();
-            }
-            else
-            {
-                items = GetAllLibraryItems(user, parentIds, i => i is Series)
-                   .Cast<Series>();
-            }
+            }, user, parentIds).Cast<Series>();
 
             // Avoid implicitly captured closure
             var episodes = GetNextUpEpisodes(request, user, items);
@@ -68,9 +58,12 @@ namespace MediaBrowser.Server.Implementations.TV
                 throw new ArgumentException("User not found");
             }
 
-            var items = parentsFolders
-                .SelectMany(i => i.GetRecursiveChildren(user, s => s is Series))
-                .Cast<Series>();
+            var items = _libraryManager.GetItems(new InternalItemsQuery(user)
+            {
+                IncludeItemTypes = new[] { typeof(Series).Name },
+                SortOrder = SortOrder.Ascending
+
+            }, user, parentsFolders.Select(i => i.Id.ToString("N"))).Cast<Series>();
 
             // Avoid implicitly captured closure
             var episodes = GetNextUpEpisodes(request, user, items);
@@ -78,27 +71,6 @@ namespace MediaBrowser.Server.Implementations.TV
             return GetResult(episodes, null, request);
         }
 
-        private IEnumerable<BaseItem> GetAllLibraryItems(User user, string[] parentIds, Func<BaseItem, bool> filter)
-        {
-            if (parentIds.Length > 0)
-            {
-                return parentIds.SelectMany(i =>
-                {
-                    var folder = (Folder)_libraryManager.GetItemById(new Guid(i));
-
-                    return folder.GetRecursiveChildren(user, filter);
-
-                });
-            }
-
-            if (user == null)
-            {
-                throw new ArgumentException("User not found");
-            }
-
-            return user.RootFolder.GetRecursiveChildren(user, filter);
-        }
-
         public IEnumerable<Episode> GetNextUpEpisodes(NextUpQuery request, User user, IEnumerable<Series> series)
         {
             // Avoid implicitly captured closure

+ 1 - 1
MediaBrowser.Server.Startup.Common/ApplicationHost.cs

@@ -363,7 +363,7 @@ namespace MediaBrowser.Server.Startup.Common
         {
             var migrations = new List<IVersionMigration>
             {
-                new Release5767(ServerConfigurationManager, TaskManager)
+                new DbMigration(ServerConfigurationManager, TaskManager)
             };
 
             foreach (var task in migrations)

+ 1 - 1
MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj

@@ -72,7 +72,7 @@
     <Compile Include="INativeApp.cs" />
     <Compile Include="MbLinkShortcutHandler.cs" />
     <Compile Include="Migrations\IVersionMigration.cs" />
-    <Compile Include="Migrations\Release5767.cs" />
+    <Compile Include="Migrations\DbMigration.cs" />
     <Compile Include="Migrations\RenameXmlOptions.cs" />
     <Compile Include="NativeEnvironment.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />

+ 34 - 0
MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs

@@ -0,0 +1,34 @@
+using System.Threading.Tasks;
+using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Server.Implementations.Persistence;
+
+namespace MediaBrowser.Server.Startup.Common.Migrations
+{
+    public class DbMigration : IVersionMigration
+    {
+        private readonly IServerConfigurationManager _config;
+        private readonly ITaskManager _taskManager;
+
+        public DbMigration(IServerConfigurationManager config, ITaskManager taskManager)
+        {
+            _config = config;
+            _taskManager = taskManager;
+        }
+
+        public void Run()
+        {
+            if (_config.Configuration.MigrationVersion < CleanDatabaseScheduledTask.MigrationVersion)
+            {
+                return;
+            }
+
+            Task.Run(async () =>
+            {
+                await Task.Delay(2000).ConfigureAwait(false);
+
+                _taskManager.QueueScheduledTask<CleanDatabaseScheduledTask>();
+            });
+        }
+    }
+}

+ 0 - 48
MediaBrowser.Server.Startup.Common/Migrations/Release5767.cs

@@ -1,48 +0,0 @@
-using System;
-using System.Linq;
-using System.Threading.Tasks;
-using MediaBrowser.Common.ScheduledTasks;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Server.Implementations.LiveTv;
-using MediaBrowser.Server.Implementations.Persistence;
-using MediaBrowser.Server.Implementations.ScheduledTasks;
-
-namespace MediaBrowser.Server.Startup.Common.Migrations
-{
-    public class Release5767 : IVersionMigration
-    {
-        private readonly IServerConfigurationManager _config;
-        private readonly ITaskManager _taskManager;
-
-        public Release5767(IServerConfigurationManager config, ITaskManager taskManager)
-        {
-            _config = config;
-            _taskManager = taskManager;
-        }
-
-        public async void Run()
-        {
-            var name = "5767.1";
-
-            if (_config.Configuration.Migrations.Contains(name, StringComparer.OrdinalIgnoreCase))
-            {
-                return;
-            }
-
-            Task.Run(async () =>
-            {
-                await Task.Delay(3000).ConfigureAwait(false);
-
-                _taskManager.QueueScheduledTask<CleanDatabaseScheduledTask>();
-            });
-
-            // Wait a few minutes before marking this as done. Make sure the server doesn't get restarted.
-            await Task.Delay(300000).ConfigureAwait(false);
-            
-            var list = _config.Configuration.Migrations.ToList();
-            list.Add(name);
-            _config.Configuration.Migrations = list.ToArray();
-            _config.SaveConfiguration();
-        }
-    }
-}