diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 457a0b3abd..949b333d4a 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -1293,33 +1293,41 @@ namespace MediaBrowser.Controller.Entities public IList GetRecursiveChildren(Func filter) { - var list = new List(); + var result = new Dictionary(); - AddChildrenToList(list, true, filter); + AddChildrenToList(result, true, true, filter); - return list; + return result.Values.ToList(); } /// /// Adds the children to list. /// - /// The list. - /// if set to true [recursive]. - /// The filter. - private void AddChildrenToList(List list, bool recursive, Func filter) + private void AddChildrenToList(Dictionary result, bool includeLinkedChildren, bool recursive, Func filter) { foreach (var child in Children) { if (filter == null || filter(child)) { - list.Add(child); + result[child.Id] = child; } if (recursive && child.IsFolder) { var folder = (Folder)child; - folder.AddChildrenToList(list, true, filter); + folder.AddChildrenToList(result, includeLinkedChildren, true, filter); + } + } + + if (includeLinkedChildren) + { + foreach (var child in GetLinkedChildren()) + { + if (filter == null || filter(child)) + { + result[child.Id] = child; + } } } } diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 218127ab9e..a0c6bd889a 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -421,7 +421,8 @@ namespace MediaBrowser.Providers.Manager var folder = item as Folder; if (folder != null && folder.SupportsCumulativeRunTimeTicks) { - var ticks = folder.GetRecursiveChildren(i => !i.IsFolder).Select(i => i.RunTimeTicks ?? 0).Sum(); + var items = folder.GetRecursiveChildren(i => !i.IsFolder).ToList(); + var ticks = items.Select(i => i.RunTimeTicks ?? 0).Sum(); if (!folder.RunTimeTicks.HasValue || folder.RunTimeTicks.Value != ticks) { @@ -443,9 +444,10 @@ namespace MediaBrowser.Providers.Manager var folder = item as Folder; if (folder != null && folder.SupportsDateLastMediaAdded) { - var date = folder.GetRecursiveChildren(i => !i.IsFolder).Select(i => i.DateCreated).Max(); + var items = folder.GetRecursiveChildren(i => !i.IsFolder).Select(i => i.DateCreated).ToList(); + var date = items.Count == 0 ? (DateTime?)null : items.Max(); - if (!folder.DateLastMediaAdded.HasValue || folder.DateLastMediaAdded.Value != date) + if ((!folder.DateLastMediaAdded.HasValue && date.HasValue) || folder.DateLastMediaAdded != date) { folder.DateLastMediaAdded = date; updateType = ItemUpdateType.MetadataEdit; diff --git a/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs b/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs index f7f0fd6cc5..70c155ad5d 100644 --- a/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs +++ b/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs @@ -176,9 +176,13 @@ namespace MediaBrowser.Providers.Movies var numComplete = 0; // Gather all movies into a lookup by tmdb id - var allMovies = _libraryManager.RootFolder - .GetRecursiveChildren(i => i is Movie && !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tmdb))) - .ToLookup(i => i.GetProviderId(MetadataProviders.Tmdb)); + var allMovies = _libraryManager.GetItemList(new Controller.Entities.InternalItemsQuery + { + IncludeItemTypes = new[] {typeof (Movie).Name}, + Recursive = true + + }).Where(i => !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tmdb))) + .ToLookup(i => i.GetProviderId(MetadataProviders.Tmdb)); foreach (var id in list) { diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs index 270f01b2b4..f402a0a33b 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs @@ -116,7 +116,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization premiereDate, options, overwriteExisting, - false, + false, result, cancellationToken).ConfigureAwait(false); } @@ -202,7 +202,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization null, options, true, - request.RememberCorrection, + request.RememberCorrection, result, cancellationToken).ConfigureAwait(false); @@ -219,7 +219,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization DateTime? premiereDate, AutoOrganizeOptions options, bool overwriteExisting, - bool rememberCorrection, + bool rememberCorrection, FileOrganizationResult result, CancellationToken cancellationToken) { @@ -242,7 +242,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization premiereDate, options, overwriteExisting, - rememberCorrection, + rememberCorrection, result, cancellationToken); } @@ -255,7 +255,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization DateTime? premiereDate, AutoOrganizeOptions options, bool overwriteExisting, - bool rememberCorrection, + bool rememberCorrection, FileOrganizationResult result, CancellationToken cancellationToken) { @@ -536,7 +536,11 @@ namespace MediaBrowser.Server.Implementations.FileOrganization result.ExtractedName = nameWithoutYear; result.ExtractedYear = yearInName; - var series = _libraryManager.RootFolder.GetRecursiveChildren(i => i is Series) + var series = _libraryManager.GetItemList(new Controller.Entities.InternalItemsQuery + { + IncludeItemTypes = new[] { typeof(Series).Name }, + Recursive = true + }) .Cast() .Select(i => NameUtils.GetMatchScore(nameWithoutYear, yearInName, i)) .Where(i => i.Item2 > 0) @@ -550,10 +554,12 @@ namespace MediaBrowser.Server.Implementations.FileOrganization if (info != null) { - series = _libraryManager.RootFolder - .GetRecursiveChildren(i => i is Series) - .Cast() - .FirstOrDefault(i => string.Equals(i.Name, info.ItemName, StringComparison.OrdinalIgnoreCase)); + series = _libraryManager.GetItemList(new Controller.Entities.InternalItemsQuery + { + IncludeItemTypes = new[] { typeof(Series).Name }, + Recursive = true + }).Cast() + .FirstOrDefault(i => string.Equals(i.Name, info.ItemName, StringComparison.OrdinalIgnoreCase)); } } diff --git a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs index d3aad20f5f..0fabbf54aa 100644 --- a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Server.Implementations.Library { public event EventHandler UserDataSaved; - private readonly ConcurrentDictionary _userData = new ConcurrentDictionary(); + private readonly Dictionary _userData = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly ILogger _logger; private readonly IServerConfigurationManager _config; @@ -66,8 +66,10 @@ namespace MediaBrowser.Server.Implementations.Library var newValue = userData; - // Once it succeeds, put it into the dictionary to make it available to everyone else - _userData.AddOrUpdate(GetCacheKey(userId, key), newValue, delegate { return newValue; }); + lock (_userData) + { + _userData[GetCacheKey(userId, key)] = newValue; + } } catch (Exception ex) { @@ -154,13 +156,33 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentNullException("key"); } - return _userData.GetOrAdd(GetCacheKey(userId, key), keyName => GetUserDataFromRepository(userId, key)); + lock (_userData) + { + var cacheKey = GetCacheKey(userId, key); + UserItemData value; + if (_userData.TryGetValue(cacheKey, out value)) + { + return value; + } + + value = GetUserDataFromRepository(userId, key); + _userData[cacheKey] = value; + return value; + } } private UserItemData GetUserDataFromRepository(Guid userId, string key) { var data = Repository.GetUserData(userId, key); + if (data == null) + { + data = new UserItemData + { + UserId = userId, + Key = key + }; + } return data; } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 180bd35479..20cc7f82a9 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -2056,6 +2056,10 @@ namespace MediaBrowser.Server.Implementations.Persistence { var whereClauses = new List(); + if (EnableJoinUserData(query)) + { + whereClauses.Add("UserId=@UserId"); + } if (query.IsCurrentSchema.HasValue) { if (query.IsCurrentSchema.Value) diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs index 8c521d88a6..7f3b32e062 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs @@ -296,11 +296,7 @@ namespace MediaBrowser.Server.Implementations.Persistence } } - return new UserItemData - { - UserId = userId, - Key = key - }; + return null; } } diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs index e50de7baca..607a043a64 100644 --- a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs +++ b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs @@ -12,6 +12,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Model.Entities; namespace MediaBrowser.Server.Implementations.ScheduledTasks { @@ -85,8 +86,13 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks /// Task. public async Task Execute(CancellationToken cancellationToken, IProgress progress) { - var videos = _libraryManager.RootFolder.GetRecursiveChildren(i => i is Video) - .Cast