Browse Source

improved performance of item counts

Luke Pulverenti 12 năm trước cách đây
mục cha
commit
803e8b4a2e
49 tập tin đã thay đổi với 494 bổ sung378 xóa
  1. 78 28
      MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs
  2. 9 3
      MediaBrowser.Api/DefaultTheme/MoviesView.cs
  3. 3 3
      MediaBrowser.Api/DefaultTheme/TvView.cs
  4. 5 3
      MediaBrowser.Api/ItemUpdateService.cs
  5. 0 1
      MediaBrowser.Api/SimilarItemsHelper.cs
  6. 45 4
      MediaBrowser.Api/UserLibrary/ItemsService.cs
  7. 2 2
      MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
  8. 1 1
      MediaBrowser.Common.Implementations/packages.config
  9. 0 4
      MediaBrowser.Controller/Entities/Audio/Artist.cs
  10. 3 2
      MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
  11. 0 4
      MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
  12. 38 85
      MediaBrowser.Controller/Entities/BaseItem.cs
  13. 51 0
      MediaBrowser.Controller/Entities/Extensions.cs
  14. 2 2
      MediaBrowser.Controller/Entities/Folder.cs
  15. 0 4
      MediaBrowser.Controller/Entities/GameGenre.cs
  16. 0 4
      MediaBrowser.Controller/Entities/Genre.cs
  17. 1 3
      MediaBrowser.Controller/Entities/IItemByName.cs
  18. 0 4
      MediaBrowser.Controller/Entities/Person.cs
  19. 0 4
      MediaBrowser.Controller/Entities/Studio.cs
  20. 9 2
      MediaBrowser.Controller/Entities/Trailer.cs
  21. 0 4
      MediaBrowser.Controller/Entities/Year.cs
  22. 2 0
      MediaBrowser.Controller/Library/ILibraryManager.cs
  23. 1 1
      MediaBrowser.Controller/Library/ItemResolveArgs.cs
  24. 1 0
      MediaBrowser.Controller/MediaBrowser.Controller.csproj
  25. 37 13
      MediaBrowser.Model/ApiClient/IApiClient.cs
  26. 1 1
      MediaBrowser.Model/Dto/BaseItemDto.cs
  27. 4 0
      MediaBrowser.Model/Querying/ItemQuery.cs
  28. 1 1
      MediaBrowser.Providers/Movies/MovieDbProvider.cs
  29. 13 27
      MediaBrowser.Providers/Movies/OpenMovieDatabaseProvider.cs
  30. 1 1
      MediaBrowser.Providers/Music/MusicAlbumDynamicInfoProvider.cs
  31. 5 3
      MediaBrowser.Server.Implementations/Dto/DtoService.cs
  32. 48 17
      MediaBrowser.Server.Implementations/Library/LibraryManager.cs
  33. 1 4
      MediaBrowser.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
  34. 1 5
      MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
  35. 1 5
      MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs
  36. 44 30
      MediaBrowser.Server.Implementations/Library/Validators/CountHelpers.cs
  37. 9 16
      MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs
  38. 9 16
      MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs
  39. 9 16
      MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs
  40. 24 28
      MediaBrowser.Server.Implementations/Library/Validators/PeoplePostScanTask.cs
  41. 9 16
      MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs
  42. 6 1
      MediaBrowser.Server.Implementations/Sorting/BudgetComparer.cs
  43. 6 1
      MediaBrowser.Server.Implementations/Sorting/CriticRatingComparer.cs
  44. 6 1
      MediaBrowser.Server.Implementations/Sorting/RevenueComparer.cs
  45. 2 2
      MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
  46. 1 1
      MediaBrowser.ServerApplication/packages.config
  47. 2 2
      Nuget/MediaBrowser.Common.Internal.nuspec
  48. 1 1
      Nuget/MediaBrowser.Common.nuspec
  49. 2 2
      Nuget/MediaBrowser.Server.Core.nuspec

+ 78 - 28
MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs

@@ -4,8 +4,10 @@ using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Localization;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Querying;
 using ServiceStack.ServiceHost;
 using System;
 using System.Collections.Generic;
@@ -26,8 +28,11 @@ namespace MediaBrowser.Api.DefaultTheme
     {
         [ApiMember(Name = "UserId", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
         public Guid UserId { get; set; }
+
+        [ApiMember(Name = "FamilyRating", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public string FamilyRating { get; set; }
     }
-    
+
     public class DefaultThemeService : BaseApiService
     {
         private readonly IUserManager _userManager;
@@ -35,12 +40,15 @@ namespace MediaBrowser.Api.DefaultTheme
         private readonly ILogger _logger;
         private readonly ILibraryManager _libraryManager;
 
-        public DefaultThemeService(IUserManager userManager, IDtoService dtoService, ILogger logger, ILibraryManager libraryManager)
+        private readonly ILocalizationManager _localization;
+        
+        public DefaultThemeService(IUserManager userManager, IDtoService dtoService, ILogger logger, ILibraryManager libraryManager, ILocalizationManager localization)
         {
             _userManager = userManager;
             _dtoService = dtoService;
             _logger = logger;
             _libraryManager = libraryManager;
+            _localization = localization;
         }
 
         public object Get(GetTvView request)
@@ -62,19 +70,16 @@ namespace MediaBrowser.Api.DefaultTheme
 
             var view = new TvView();
 
-            view.BackdropItems = seriesWithBackdrops
+            var fields = Enum.GetNames(typeof(ItemFields))
+              .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
+              .ToList();
+
+            var spotlightItemTasks = seriesWithBackdrops
                 .OrderBy(i => Guid.NewGuid())
-                .Select(i => GetItemStub(i, ImageType.Backdrop))
-                .Where(i => i != null)
                 .Take(30)
-                .ToArray();
+                .Select(i => _dtoService.GetBaseItemDto(i, fields, user));
 
-            view.SpotlightItems = seriesWithBackdrops
-               .OrderBy(i => Guid.NewGuid())
-               .Select(i => GetItemStub(i, ImageType.Backdrop))
-               .Where(i => i != null)
-               .Take(30)
-               .ToArray();
+            view.SpotlightItems = await Task.WhenAll(spotlightItemTasks).ConfigureAwait(false);
 
             view.ShowsItems = series
                .Where(i => !string.IsNullOrEmpty(i.PrimaryImagePath))
@@ -104,31 +109,43 @@ namespace MediaBrowser.Api.DefaultTheme
                 .Where(i => i is Movie || i is Trailer || i is BoxSet)
                 .ToList();
 
+            var actorsTask = GetActors(items);
+
             // Exclude trailers from backdrops because they're not always 1080p
             var itemsWithBackdrops = items.Where(i => i.BackdropImagePaths.Count > 0 && !(i is Trailer))
                 .ToList();
 
-            var movies = items.OfType<Movie>().ToList();
+            var baselineRating = _localization.GetRatingLevel(request.FamilyRating ?? "PG");
+
+            var view = new MoviesView();
+
+            var movies = items.OfType<Movie>()
+                .ToList();
+
+            var hdMovies = movies.Where(i => i.IsHd).ToList();
+
+            var familyMovies = movies.Where(i => IsFamilyMovie(i, baselineRating)).ToList();
+
+            view.HDMoviePercentage = 100 * hdMovies.Count;
+            view.HDMoviePercentage /= movies.Count;
 
+            view.FamilyMoviePercentage = 100 * familyMovies.Count;
+            view.FamilyMoviePercentage /= movies.Count;
+            
             var moviesWithImages = movies
                 .Where(i => !string.IsNullOrEmpty(i.PrimaryImagePath))
                 .ToList();
 
-            var view = new MoviesView();
+            var fields = Enum.GetNames(typeof(ItemFields))
+             .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
+             .ToList();
 
-            view.BackdropItems = itemsWithBackdrops
+            var spotlightItemTasks = itemsWithBackdrops
                 .OrderBy(i => Guid.NewGuid())
-                .Select(i => GetItemStub(i, ImageType.Backdrop))
-                .Where(i => i != null)
                 .Take(30)
-                .ToArray();
+                .Select(i => _dtoService.GetBaseItemDto(i, fields, user));
 
-            view.SpotlightItems = itemsWithBackdrops
-               .OrderBy(i => Guid.NewGuid())
-               .Select(i => GetItemStub(i, ImageType.Backdrop))
-               .Where(i => i != null)
-               .Take(30)
-               .ToArray();
+            view.SpotlightItems = await Task.WhenAll(spotlightItemTasks).ConfigureAwait(false);
 
             view.MovieItems = moviesWithImages
                .OrderBy(i => Guid.NewGuid())
@@ -155,8 +172,6 @@ namespace MediaBrowser.Api.DefaultTheme
              .Take(3)
              .ToArray();
 
-            view.PeopleItems = await GetActors(items).ConfigureAwait(false);
-
             view.ThreeDItems = moviesWithImages
              .Where(i => i.Is3D)
              .OrderBy(i => Guid.NewGuid())
@@ -165,17 +180,51 @@ namespace MediaBrowser.Api.DefaultTheme
              .Take(3)
              .ToArray();
 
-            view.HDItems = moviesWithImages
-             .Where(i => i.IsHd)
+            view.HDItems = hdMovies
+             .Where(i => !string.IsNullOrEmpty(i.PrimaryImagePath))
              .OrderBy(i => Guid.NewGuid())
              .Select(i => GetItemStub(i, ImageType.Primary))
              .Where(i => i != null)
              .Take(3)
              .ToArray();
 
+            view.FamilyMovies = familyMovies
+             .Where(i => !string.IsNullOrEmpty(i.PrimaryImagePath))
+             .OrderBy(i => Guid.NewGuid())
+             .Select(i => GetItemStub(i, ImageType.Primary))
+             .Where(i => i != null)
+             .Take(3)
+             .ToArray();
+
+            view.PeopleItems = await actorsTask.ConfigureAwait(false);
+
             return view;
         }
 
+        private bool IsFamilyMovie(BaseItem item, int? baselineRating)
+        {
+            var ratingString = item.CustomRating;
+
+            if (string.IsNullOrEmpty(ratingString))
+            {
+                ratingString = item.OfficialRating;
+            }
+
+            if (string.IsNullOrEmpty(ratingString))
+            {
+                return false;
+            }
+
+            var rating = _localization.GetRatingLevel(ratingString);
+
+            if (!baselineRating.HasValue || !rating.HasValue)
+            {
+                return false;
+            }
+
+            return rating.Value <= baselineRating.Value;
+        }
+
         private async Task<ItemStub[]> GetActors(IEnumerable<BaseItem> mediaItems)
         {
             var actorStubs = new List<ItemStub>();
@@ -183,6 +232,7 @@ namespace MediaBrowser.Api.DefaultTheme
             var actors = mediaItems.SelectMany(i => i.People)
                 .Select(i => i.Name)
                 .Distinct(StringComparer.OrdinalIgnoreCase)
+                .OrderBy(i => Guid.NewGuid())
                 .ToList();
 
             foreach (var actor in actors)

+ 9 - 3
MediaBrowser.Api/DefaultTheme/MoviesView.cs

@@ -1,10 +1,10 @@
-
+using MediaBrowser.Model.Dto;
+
 namespace MediaBrowser.Api.DefaultTheme
 {
     public class MoviesView
     {
-        public ItemStub[] SpotlightItems { get; set; }
-        public ItemStub[] BackdropItems { get; set; }
+        public BaseItemDto[] SpotlightItems { get; set; }
         public ItemStub[] MovieItems { get; set; }
         public ItemStub[] PeopleItems { get; set; }
 
@@ -12,5 +12,11 @@ namespace MediaBrowser.Api.DefaultTheme
         public ItemStub[] TrailerItems { get; set; }
         public ItemStub[] HDItems { get; set; }
         public ItemStub[] ThreeDItems { get; set; }
+
+        public ItemStub[] FamilyMovies { get; set; }
+
+        public double FamilyMoviePercentage { get; set; }
+
+        public double HDMoviePercentage { get; set; }
     }
 }

+ 3 - 3
MediaBrowser.Api/DefaultTheme/TvView.cs

@@ -1,10 +1,10 @@
-
+using MediaBrowser.Model.Dto;
+
 namespace MediaBrowser.Api.DefaultTheme
 {
     public class TvView
     {
-        public ItemStub[] SpotlightItems { get; set; }
-        public ItemStub[] BackdropItems { get; set; }
+        public BaseItemDto[] SpotlightItems { get; set; }
         public ItemStub[] ShowsItems { get; set; }
         public ItemStub[] ActorItems { get; set; }
     }

+ 5 - 3
MediaBrowser.Api/ItemUpdateService.cs

@@ -207,13 +207,15 @@ namespace MediaBrowser.Api
                 item.ForcedSortName = request.SortName;
             }
 
-            item.DisplayMediaType = request.DisplayMediaType;
-            item.CommunityRating = request.CommunityRating;
-            item.HomePageUrl = request.HomePageUrl;
             item.Budget = request.Budget;
             item.Revenue = request.Revenue;
+
             item.CriticRating = request.CriticRating;
             item.CriticRatingSummary = request.CriticRatingSummary;
+            
+            item.DisplayMediaType = request.DisplayMediaType;
+            item.CommunityRating = request.CommunityRating;
+            item.HomePageUrl = request.HomePageUrl;
             item.IndexNumber = request.IndexNumber;
             item.ParentIndexNumber = request.ParentIndexNumber;
             item.Overview = request.Overview;

+ 0 - 1
MediaBrowser.Api/SimilarItemsHelper.cs

@@ -139,7 +139,6 @@ namespace MediaBrowser.Api
                 .Select(i => new Tuple<BaseItem, int>(i, getSimilarityScore(item, i)))
                 .Where(i => i.Item2 > 2)
                 .OrderByDescending(i => i.Item2)
-                .ThenByDescending(i => i.Item1.CriticRating ?? 0)
                 .Select(i => i.Item1);
         }
 

+ 45 - 4
MediaBrowser.Api/UserLibrary/ItemsService.cs

@@ -121,7 +121,7 @@ namespace MediaBrowser.Api.UserLibrary
 
         [ApiMember(Name = "AlbumArtistStartsWithOrGreater", Description = "Optional filter by items whose album artist is sorted equally or greater than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         public string AlbumArtistStartsWithOrGreater { get; set; }
-        
+
         /// <summary>
         /// Gets or sets the air days.
         /// </summary>
@@ -161,8 +161,14 @@ namespace MediaBrowser.Api.UserLibrary
         [ApiMember(Name = "AdjacentTo", Description = "Optional. Return items that are siblings of a supplied item.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         public string AdjacentTo { get; set; }
 
-        [ApiMember(Name = "MinIndexNumber", Description = "Optional filter index number.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+        [ApiMember(Name = "MinIndexNumber", Description = "Optional filter by minimum index number.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
         public int? MinIndexNumber { get; set; }
+
+        [ApiMember(Name = "HasParentalRating", Description = "Optional filter by items that have or do not have a parental rating", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
+        public bool? HasParentalRating { get; set; }
+
+        [ApiMember(Name = "IsHD", Description = "Optional filter by items that are HD or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
+        public bool? IsHD { get; set; }
     }
 
     /// <summary>
@@ -481,7 +487,12 @@ namespace MediaBrowser.Api.UserLibrary
                 {
                     items = items.Where(i =>
                     {
-                        var rating = i.CustomRating ?? i.OfficialRating;
+                        var rating = i.CustomRating;
+
+                        if (string.IsNullOrEmpty(rating))
+                        {
+                            rating = i.OfficialRating;
+                        }
 
                         if (string.IsNullOrEmpty(rating))
                         {
@@ -504,7 +515,12 @@ namespace MediaBrowser.Api.UserLibrary
                 {
                     items = items.Where(i =>
                     {
-                        var rating = i.CustomRating ?? i.OfficialRating;
+                        var rating = i.CustomRating;
+
+                        if (string.IsNullOrEmpty(rating))
+                        {
+                            rating = i.OfficialRating;
+                        }
 
                         if (string.IsNullOrEmpty(rating))
                         {
@@ -669,6 +685,31 @@ namespace MediaBrowser.Api.UserLibrary
                 });
             }
 
+            if (request.HasParentalRating.HasValue)
+            {
+                items = items.Where(i =>
+                {
+                    var rating = i.CustomRating;
+
+                    if (string.IsNullOrEmpty(rating))
+                    {
+                        rating = i.OfficialRating;
+                    }
+
+                    if (request.HasParentalRating.Value)
+                    {
+                        return !string.IsNullOrEmpty(rating);
+                    }
+
+                    return string.IsNullOrEmpty(rating);
+                });
+            }
+
+            if (request.IsHD.HasValue)
+            {
+                items = items.OfType<Video>().Where(i => i.IsHd == request.IsHD.Value);
+            }
+
             return items;
         }
 

+ 2 - 2
MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj

@@ -43,9 +43,9 @@
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\packages\ServiceStack.Text.3.9.58\lib\net35\ServiceStack.Text.dll</HintPath>
     </Reference>
-    <Reference Include="SimpleInjector, Version=2.3.2.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
+    <Reference Include="SimpleInjector, Version=2.3.5.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\SimpleInjector.2.3.2\lib\net40-client\SimpleInjector.dll</HintPath>
+      <HintPath>..\packages\SimpleInjector.2.3.5\lib\net40-client\SimpleInjector.dll</HintPath>
     </Reference>
     <Reference Include="System" />
     <Reference Include="System.Configuration" />

+ 1 - 1
MediaBrowser.Common.Implementations/packages.config

@@ -2,5 +2,5 @@
 <packages>
   <package id="NLog" version="2.0.1.2" targetFramework="net45" />
   <package id="ServiceStack.Text" version="3.9.58" targetFramework="net45" />
-  <package id="SimpleInjector" version="2.3.2" targetFramework="net45" />
+  <package id="SimpleInjector" version="2.3.5" targetFramework="net45" />
 </packages>

+ 0 - 4
MediaBrowser.Controller/Entities/Audio/Artist.cs

@@ -12,7 +12,6 @@ namespace MediaBrowser.Controller.Entities.Audio
     {
         public Artist()
         {
-            ItemCounts = new ItemByNameCounts();
             UserItemCounts = new Dictionary<Guid, ItemByNameCounts>();
         }
 
@@ -27,9 +26,6 @@ namespace MediaBrowser.Controller.Entities.Audio
             return "Artist-" + Name;
         }
 
-        [IgnoreDataMember]
-        public ItemByNameCounts ItemCounts { get; set; }
-
         [IgnoreDataMember]
         public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
     }

+ 3 - 2
MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Generic;
 using System.Linq;
 using System.Runtime.Serialization;
 
@@ -11,7 +12,7 @@ namespace MediaBrowser.Controller.Entities.Audio
     {
         public MusicAlbum()
         {
-            Artists = new string[] { };
+            Artists = new List<string>();
         }
 
         public string LastFmImageUrl { get; set; }
@@ -72,7 +73,7 @@ namespace MediaBrowser.Controller.Entities.Audio
 
         public string AlbumArtist { get; set; }
 
-        public string[] Artists { get; set; }
+        public List<string> Artists { get; set; }
     }
 
     public class MusicAlbumDisc : Folder

+ 0 - 4
MediaBrowser.Controller/Entities/Audio/MusicGenre.cs

@@ -12,7 +12,6 @@ namespace MediaBrowser.Controller.Entities.Audio
     {
         public MusicGenre()
         {
-            ItemCounts = new ItemByNameCounts();
             UserItemCounts = new Dictionary<Guid, ItemByNameCounts>();
         }
 
@@ -25,9 +24,6 @@ namespace MediaBrowser.Controller.Entities.Audio
             return "MusicGenre-" + Name;
         }
 
-        [IgnoreDataMember]
-        public ItemByNameCounts ItemCounts { get; set; }
-
         [IgnoreDataMember]
         public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
     }

+ 38 - 85
MediaBrowser.Controller/Entities/BaseItem.cs

@@ -31,10 +31,8 @@ namespace MediaBrowser.Controller.Entities
         protected BaseItem()
         {
             Genres = new List<string>();
-            RemoteTrailers = new List<MediaUrl>();
             Studios = new List<string>();
             People = new List<PersonInfo>();
-            Taglines = new List<string>();
             ScreenshotImagePaths = new List<string>();
             BackdropImagePaths = new List<string>();
             ProductionLocations = new List<string>();
@@ -46,6 +44,8 @@ namespace MediaBrowser.Controller.Entities
             SoundtrackIds = new List<Guid>();
             LocalTrailerIds = new List<Guid>();
             LockedFields = new List<MetadataFields>();
+            Taglines = new List<string>();
+            RemoteTrailers = new List<MediaUrl>();
         }
 
         /// <summary>
@@ -90,6 +90,42 @@ namespace MediaBrowser.Controller.Entities
         /// <value>The id.</value>
         public Guid Id { get; set; }
 
+        /// <summary>
+        /// Gets or sets the budget.
+        /// </summary>
+        /// <value>The budget.</value>
+        public double? Budget { get; set; }
+
+        /// <summary>
+        /// Gets or sets the taglines.
+        /// </summary>
+        /// <value>The taglines.</value>
+        public List<string> Taglines { get; set; }
+
+        /// <summary>
+        /// Gets or sets the revenue.
+        /// </summary>
+        /// <value>The revenue.</value>
+        public double? Revenue { get; set; }
+
+        /// <summary>
+        /// Gets or sets the critic rating.
+        /// </summary>
+        /// <value>The critic rating.</value>
+        public float? CriticRating { get; set; }
+
+        /// <summary>
+        /// Gets or sets the critic rating summary.
+        /// </summary>
+        /// <value>The critic rating summary.</value>
+        public string CriticRatingSummary { get; set; }
+
+        /// <summary>
+        /// Gets or sets the trailer URL.
+        /// </summary>
+        /// <value>The trailer URL.</value>
+        public List<MediaUrl> RemoteTrailers { get; set; }
+        
         /// <summary>
         /// Return the id that should be used to key display prefs for this item.
         /// Default is based on the type for everything except actual generic folders.
@@ -522,11 +558,6 @@ namespace MediaBrowser.Controller.Entities
         /// </summary>
         /// <value>The overview.</value>
         public string Overview { get; set; }
-        /// <summary>
-        /// Gets or sets the taglines.
-        /// </summary>
-        /// <value>The taglines.</value>
-        public List<string> Taglines { get; set; }
 
         /// <summary>
         /// Gets or sets the people.
@@ -580,36 +611,12 @@ namespace MediaBrowser.Controller.Entities
         /// <value>The home page URL.</value>
         public string HomePageUrl { get; set; }
 
-        /// <summary>
-        /// Gets or sets the budget.
-        /// </summary>
-        /// <value>The budget.</value>
-        public double? Budget { get; set; }
-
-        /// <summary>
-        /// Gets or sets the revenue.
-        /// </summary>
-        /// <value>The revenue.</value>
-        public double? Revenue { get; set; }
-
         /// <summary>
         /// Gets or sets the production locations.
         /// </summary>
         /// <value>The production locations.</value>
         public List<string> ProductionLocations { get; set; }
 
-        /// <summary>
-        /// Gets or sets the critic rating.
-        /// </summary>
-        /// <value>The critic rating.</value>
-        public float? CriticRating { get; set; }
-
-        /// <summary>
-        /// Gets or sets the critic rating summary.
-        /// </summary>
-        /// <value>The critic rating summary.</value>
-        public string CriticRatingSummary { get; set; }
-
         /// <summary>
         /// Gets or sets the community rating.
         /// </summary>
@@ -973,12 +980,6 @@ namespace MediaBrowser.Controller.Entities
             return themeSongsChanged || results.Contains(true);
         }
 
-        /// <summary>
-        /// Gets or sets the trailer URL.
-        /// </summary>
-        /// <value>The trailer URL.</value>
-        public List<MediaUrl> RemoteTrailers { get; set; }
-
         /// <summary>
         /// Gets or sets the provider ids.
         /// </summary>
@@ -1255,53 +1256,6 @@ namespace MediaBrowser.Controller.Entities
             }
         }
 
-        /// <summary>
-        /// Adds a tagline to the item
-        /// </summary>
-        /// <param name="name">The name.</param>
-        /// <exception cref="System.ArgumentNullException"></exception>
-        public void AddTagline(string name)
-        {
-            if (string.IsNullOrWhiteSpace(name))
-            {
-                throw new ArgumentNullException("name");
-            }
-
-            if (!Taglines.Contains(name, StringComparer.OrdinalIgnoreCase))
-            {
-                Taglines.Add(name);
-            }
-        }
-
-        /// <summary>
-        /// Adds a TrailerUrl to the item
-        /// </summary>
-        /// <param name="url">The URL.</param>
-        /// <param name="isDirectLink">if set to <c>true</c> [is direct link].</param>
-        /// <exception cref="System.ArgumentNullException">url</exception>
-        public void AddTrailerUrl(string url, bool isDirectLink)
-        {
-            if (string.IsNullOrWhiteSpace(url))
-            {
-                throw new ArgumentNullException("url");
-            }
-
-            var current = RemoteTrailers.FirstOrDefault(i => string.Equals(i.Url, url, StringComparison.OrdinalIgnoreCase));
-
-            if (current != null)
-            {
-                current.IsDirectLink = isDirectLink;
-            }
-            else
-            {
-                RemoteTrailers.Add(new MediaUrl
-                {
-                    Url = url,
-                    IsDirectLink = isDirectLink
-                });
-            }
-        }
-
         /// <summary>
         /// Adds a genre to the item
         /// </summary>
@@ -1545,7 +1499,6 @@ namespace MediaBrowser.Controller.Entities
         {
             // Only validate paths from the same directory - need to copy to a list because we are going to potentially modify the collection below
             var deletedKeys = Images
-                .ToList()
                 .Where(image => !File.Exists(image.Value))
                 .Select(i => i.Key)
                 .ToList();

+ 51 - 0
MediaBrowser.Controller/Entities/Extensions.cs

@@ -0,0 +1,51 @@
+using MediaBrowser.Model.Entities;
+using System;
+using System.Linq;
+
+namespace MediaBrowser.Controller.Entities
+{
+    public static class Extensions
+    {
+        /// <summary>
+        /// Adds the tagline.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="tagline">The tagline.</param>
+        /// <exception cref="System.ArgumentNullException">tagline</exception>
+        public static void AddTagline(this BaseItem item, string tagline)
+        {
+            if (string.IsNullOrWhiteSpace(tagline))
+            {
+                throw new ArgumentNullException("tagline");
+            }
+
+            if (!item.Taglines.Contains(tagline, StringComparer.OrdinalIgnoreCase))
+            {
+                item.Taglines.Add(tagline);
+            }
+        }
+
+        public static void AddTrailerUrl(this BaseItem item, string url, bool isDirectLink)
+        {
+            if (string.IsNullOrWhiteSpace(url))
+            {
+                throw new ArgumentNullException("url");
+            }
+
+            var current = item.RemoteTrailers.FirstOrDefault(i => string.Equals(i.Url, url, StringComparison.OrdinalIgnoreCase));
+
+            if (current != null)
+            {
+                current.IsDirectLink = isDirectLink;
+            }
+            else
+            {
+                item.RemoteTrailers.Add(new MediaUrl
+                {
+                    Url = url,
+                    IsDirectLink = isDirectLink
+                });
+            }
+        }
+    }
+}

+ 2 - 2
MediaBrowser.Controller/Entities/Folder.cs

@@ -499,7 +499,7 @@ namespace MediaBrowser.Controller.Entities
         {
             get
             {
-                return ActualChildren.Values.ToList();
+                return ActualChildren.Values.ToArray();
             }
         }
 
@@ -757,7 +757,7 @@ namespace MediaBrowser.Controller.Entities
         {
             var list = children.ToList();
 
-            var percentages = new Dictionary<Guid, double>();
+            var percentages = new Dictionary<Guid, double>(list.Count);
 
             var tasks = new List<Task>();
 

+ 0 - 4
MediaBrowser.Controller/Entities/GameGenre.cs

@@ -9,7 +9,6 @@ namespace MediaBrowser.Controller.Entities
     {
         public GameGenre()
         {
-            ItemCounts = new ItemByNameCounts();
             UserItemCounts = new Dictionary<Guid, ItemByNameCounts>();
         }
 
@@ -22,9 +21,6 @@ namespace MediaBrowser.Controller.Entities
             return "GameGenre-" + Name;
         }
 
-        [IgnoreDataMember]
-        public ItemByNameCounts ItemCounts { get; set; }
-
         [IgnoreDataMember]
         public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
     }

+ 0 - 4
MediaBrowser.Controller/Entities/Genre.cs

@@ -12,7 +12,6 @@ namespace MediaBrowser.Controller.Entities
     {
         public Genre()
         {
-            ItemCounts = new ItemByNameCounts();
             UserItemCounts = new Dictionary<Guid, ItemByNameCounts>();
         }
 
@@ -25,9 +24,6 @@ namespace MediaBrowser.Controller.Entities
             return "Genre-" + Name;
         }
 
-        [IgnoreDataMember]
-        public ItemByNameCounts ItemCounts { get; set; }
-
         [IgnoreDataMember]
         public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
     }

+ 1 - 3
MediaBrowser.Controller/Entities/IItemByName.cs

@@ -9,8 +9,6 @@ namespace MediaBrowser.Controller.Entities
     /// </summary>
     public interface IItemByName
     {
-        ItemByNameCounts ItemCounts { get; set; }
-
         Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
     }
 
@@ -20,7 +18,7 @@ namespace MediaBrowser.Controller.Entities
         {
             if (user == null)
             {
-                return item.ItemCounts;
+                throw new ArgumentNullException("user");
             }
 
             ItemByNameCounts counts;

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

@@ -12,13 +12,9 @@ namespace MediaBrowser.Controller.Entities
     {
         public Person()
         {
-            ItemCounts = new ItemByNameCounts();
             UserItemCounts = new Dictionary<Guid, ItemByNameCounts>();
         }
 
-        [IgnoreDataMember]
-        public ItemByNameCounts ItemCounts { get; set; }
-
         [IgnoreDataMember]
         public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
         

+ 0 - 4
MediaBrowser.Controller/Entities/Studio.cs

@@ -12,7 +12,6 @@ namespace MediaBrowser.Controller.Entities
     {
         public Studio()
         {
-            ItemCounts = new ItemByNameCounts();
             UserItemCounts = new Dictionary<Guid, ItemByNameCounts>();
         }
 
@@ -25,9 +24,6 @@ namespace MediaBrowser.Controller.Entities
             return "Studio-" + Name;
         }
 
-        [IgnoreDataMember]
-        public ItemByNameCounts ItemCounts { get; set; }
-
         [IgnoreDataMember]
         public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
     }

+ 9 - 2
MediaBrowser.Controller/Entities/Trailer.cs

@@ -1,5 +1,6 @@
-using System.Runtime.Serialization;
-using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Entities;
+using System.Collections.Generic;
+using System.Runtime.Serialization;
 
 namespace MediaBrowser.Controller.Entities
 {
@@ -8,6 +9,12 @@ namespace MediaBrowser.Controller.Entities
     /// </summary>
     public class Trailer : Video
     {
+        public Trailer()
+        {
+            RemoteTrailers = new List<MediaUrl>();
+            Taglines = new List<string>();
+        }
+
         /// <summary>
         /// Gets a value indicating whether this instance is local trailer.
         /// </summary>

+ 0 - 4
MediaBrowser.Controller/Entities/Year.cs

@@ -12,13 +12,9 @@ namespace MediaBrowser.Controller.Entities
     {
         public Year()
         {
-            ItemCounts = new ItemByNameCounts();
             UserItemCounts = new Dictionary<Guid, ItemByNameCounts>();
         }
 
-        [IgnoreDataMember]
-        public ItemByNameCounts ItemCounts { get; set; }
-
         [IgnoreDataMember]
         public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
 

+ 2 - 0
MediaBrowser.Controller/Library/ILibraryManager.cs

@@ -48,6 +48,8 @@ namespace MediaBrowser.Controller.Library
         /// <value>The root folder.</value>
         AggregateFolder RootFolder { get; }
 
+        Person GetPersonSync(string name);
+
         /// <summary>
         /// Gets a Person
         /// </summary>

+ 1 - 1
MediaBrowser.Controller/Library/ItemResolveArgs.cs

@@ -245,7 +245,7 @@ namespace MediaBrowser.Controller.Library
             {
                 throw new ArgumentNullException();
             }
-            
+
             if (MetadataFileDictionary == null)
             {
                 MetadataFileDictionary = new Dictionary<string, FileSystemInfo>(StringComparer.OrdinalIgnoreCase);

+ 1 - 0
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -78,6 +78,7 @@
     <Compile Include="Entities\Book.cs" />
     <Compile Include="Configuration\IServerConfigurationManager.cs" />
     <Compile Include="Entities\Audio\MusicGenre.cs" />
+    <Compile Include="Entities\Extensions.cs" />
     <Compile Include="Entities\Game.cs" />
     <Compile Include="Entities\GameGenre.cs" />
     <Compile Include="Entities\IByReferenceItem.cs" />

+ 37 - 13
MediaBrowser.Model/ApiClient/IApiClient.cs

@@ -19,8 +19,14 @@ using System.Threading.Tasks;
 
 namespace MediaBrowser.Model.ApiClient
 {
+    /// <summary>
+    /// Interface IApiClient
+    /// </summary>
     public interface IApiClient : IDisposable
     {
+        /// <summary>
+        /// Occurs when [server location changed].
+        /// </summary>
         event EventHandler ServerLocationChanged;
 
         /// <summary>
@@ -28,12 +34,23 @@ namespace MediaBrowser.Model.ApiClient
         /// </summary>
         event EventHandler<HttpResponseEventArgs> HttpResponseReceived;
 
-        Task<T> GetAsync<T>(string url, CancellationToken cancellationToken);
+        string GetApiUrl(string handler);
+
+        /// <summary>
+        /// Gets the async.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="url">The URL.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task{``0}.</returns>
+        Task<T> GetAsync<T>(string url, CancellationToken cancellationToken)
+            where T : class;
 
         /// <summary>
         /// Gets the critic reviews.
         /// </summary>
         /// <param name="itemId">The item id.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="startIndex">The start index.</param>
         /// <param name="limit">The limit.</param>
         /// <returns>Task{ItemReviewsResult}.</returns>
@@ -45,6 +62,7 @@ namespace MediaBrowser.Model.ApiClient
         /// <param name="userId">The user id.</param>
         /// <param name="itemId">The item id.</param>
         /// <param name="inheritFromParents">if set to <c>true</c> [inherit from parents].</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task{ThemeMediaResult}.</returns>
         Task<ThemeMediaResult> GetThemeSongsAsync(string userId, string itemId, bool inheritFromParents, CancellationToken cancellationToken);
 
@@ -65,6 +83,7 @@ namespace MediaBrowser.Model.ApiClient
         /// <param name="userId">The user id.</param>
         /// <param name="itemId">The item id.</param>
         /// <param name="inheritFromParents">if set to <c>true</c> [inherit from parents].</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task{ThemeMediaResult}.</returns>
         Task<ThemeMediaResult> GetThemeVideosAsync(string userId, string itemId, bool inheritFromParents, CancellationToken cancellationToken);
 
@@ -74,6 +93,7 @@ namespace MediaBrowser.Model.ApiClient
         /// <param name="userId">The user id.</param>
         /// <param name="itemId">The item id.</param>
         /// <param name="inheritFromParents">if set to <c>true</c> [inherit from parents].</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task{AllThemeMediaResult}.</returns>
         Task<AllThemeMediaResult> GetAllThemeMediaAsync(string userId, string itemId, bool inheritFromParents, CancellationToken cancellationToken);
 
@@ -152,12 +172,14 @@ namespace MediaBrowser.Model.ApiClient
         /// <summary>
         /// Gets the users async.
         /// </summary>
+        /// <param name="query">The query.</param>
         /// <returns>Task{UserDto[]}.</returns>
         Task<UserDto[]> GetUsersAsync(UserQuery query);
 
         /// <summary>
         /// Gets the public users async.
         /// </summary>
+        /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task{UserDto[]}.</returns>
         Task<UserDto[]> GetPublicUsersAsync(CancellationToken cancellationToken);
 
@@ -469,6 +491,7 @@ namespace MediaBrowser.Model.ApiClient
         /// <param name="userId">The user id.</param>
         /// <param name="positionTicks">The position ticks.</param>
         /// <param name="isPaused">if set to <c>true</c> [is paused].</param>
+        /// <param name="isMuted">if set to <c>true</c> [is muted].</param>
         /// <returns>Task{UserItemDataDto}.</returns>
         /// <exception cref="ArgumentNullException">itemId</exception>
         Task ReportPlaybackProgressAsync(string itemId, string userId, long? positionTicks, bool isPaused, bool isMuted);
@@ -508,29 +531,27 @@ namespace MediaBrowser.Model.ApiClient
         /// <param name="sessionId">The session id.</param>
         /// <param name="request">The request.</param>
         /// <returns>Task.</returns>
-        /// <exception cref="ArgumentNullException">
-        /// sessionId
+        /// <exception cref="ArgumentNullException">sessionId
         /// or
-        /// request
-        /// </exception>
+        /// request</exception>
         Task SendPlayCommandAsync(string sessionId, PlayRequest request);
 
         /// <summary>
         /// Sends a system command to the client
         /// </summary>
-        /// <param name="sessionId"></param>
-        /// <param name="command"></param>
-        /// <returns></returns>
+        /// <param name="sessionId">The session id.</param>
+        /// <param name="command">The command.</param>
+        /// <returns>Task.</returns>
         Task SendSystemCommandAsync(string sessionId, SystemCommand command);
 
         /// <summary>
         /// Instructs the client to display a message to the user
         /// </summary>
-        /// <param name="sessionId"></param>
-        /// <param name="command"></param>
-        /// <returns></returns>
+        /// <param name="sessionId">The session id.</param>
+        /// <param name="command">The command.</param>
+        /// <returns>Task.</returns>
         Task SendMessageCommandAsync(string sessionId, MessageCommand command);
-        
+
         /// <summary>
         /// Clears a user's rating for an item
         /// </summary>
@@ -582,14 +603,17 @@ namespace MediaBrowser.Model.ApiClient
         /// <param name="id">The id.</param>
         /// <param name="userId">The user id.</param>
         /// <param name="client">The client.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task{BaseItemDto}.</returns>
         Task<DisplayPreferences> GetDisplayPreferencesAsync(string id, string userId, string client, CancellationToken cancellationToken);
 
         /// <summary>
         /// Updates display preferences for a user
         /// </summary>
-        /// <param name="id">The id.</param>
         /// <param name="displayPreferences">The display preferences.</param>
+        /// <param name="userId">The user id.</param>
+        /// <param name="client">The client.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task{DisplayPreferences}.</returns>
         /// <exception cref="System.ArgumentNullException">userId</exception>
         Task UpdateDisplayPreferencesAsync(DisplayPreferences displayPreferences, string userId, string client, CancellationToken cancellationToken);

+ 1 - 1
MediaBrowser.Model/Dto/BaseItemDto.cs

@@ -348,7 +348,7 @@ namespace MediaBrowser.Model.Dto
         /// Gets or sets the artists.
         /// </summary>
         /// <value>The artists.</value>
-        public string[] Artists { get; set; }
+        public List<string> Artists { get; set; }
 
         /// <summary>
         /// Gets or sets the album.

+ 4 - 0
MediaBrowser.Model/Querying/ItemQuery.cs

@@ -177,6 +177,10 @@ namespace MediaBrowser.Model.Querying
         public string MaxOfficialRating { get; set; }
 
         public int? MinIndexNumber { get; set; }
+
+        public bool? HasParentalRating { get; set; }
+
+        public bool? IsHD { get; set; }
         
         /// <summary>
         /// Initializes a new instance of the <see cref="ItemQuery"/> class.

+ 1 - 1
MediaBrowser.Providers/Movies/MovieDbProvider.cs

@@ -12,7 +12,6 @@ using System.Globalization;
 using System.IO;
 using System.Linq;
 using System.Net;
-using System.Text;
 using System.Text.RegularExpressions;
 using System.Threading;
 using System.Threading.Tasks;
@@ -550,6 +549,7 @@ namespace MediaBrowser.Providers.Movies
                     movie.Overview = movie.Overview != null ? movie.Overview.Replace("\n\n", "\n") : null;
                 }
                 movie.HomePageUrl = movieData.homepage;
+
                 movie.Budget = movieData.budget;
                 movie.Revenue = movieData.revenue;
 

+ 13 - 27
MediaBrowser.Providers/Movies/OpenMovieDatabaseProvider.cs

@@ -73,17 +73,6 @@ namespace MediaBrowser.Providers.Movies
             }
         }
 
-        protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
-        {
-            // These values are now saved in movie.xml, so don't refresh if they're present
-            if (MovieDbProvider.HasAltMeta(item) && item.CriticRating.HasValue && !string.IsNullOrEmpty(item.CriticRatingSummary))
-            {
-                return false;
-            }
-
-            return base.NeedsRefreshInternal(item, providerInfo);
-        }
-
         /// <summary>
         /// Supports the specified item.
         /// </summary>
@@ -151,23 +140,20 @@ namespace MediaBrowser.Providers.Movies
 
                 // Seeing some bogus RT data on omdb for series, so filter it out here
                 // RT doesn't even have tv series
-                if (!(item is Series))
+                int tomatoMeter;
+
+                if (!string.IsNullOrEmpty(result.tomatoMeter)
+                    && int.TryParse(result.tomatoMeter, NumberStyles.Integer, UsCulture, out tomatoMeter)
+                    && tomatoMeter >= 0)
+                {
+                    item.CriticRating = tomatoMeter;
+                }
+
+                if (!string.IsNullOrEmpty(result.tomatoConsensus)
+                    && !string.Equals(result.tomatoConsensus, "n/a", StringComparison.OrdinalIgnoreCase)
+                    && !string.Equals(result.tomatoConsensus, "No consensus yet.", StringComparison.OrdinalIgnoreCase))
                 {
-                    int tomatoMeter;
-
-                    if (!string.IsNullOrEmpty(result.tomatoMeter)
-                        && int.TryParse(result.tomatoMeter, NumberStyles.Integer, UsCulture, out tomatoMeter)
-                        && tomatoMeter >= 0)
-                    {
-                        item.CriticRating = tomatoMeter;
-                    }
-
-                    if (!string.IsNullOrEmpty(result.tomatoConsensus)
-                        && !string.Equals(result.tomatoConsensus, "n/a", StringComparison.OrdinalIgnoreCase)
-                        && !string.Equals(result.tomatoConsensus, "No consensus yet.", StringComparison.OrdinalIgnoreCase))
-                    {
-                        item.CriticRatingSummary = result.tomatoConsensus;
-                    }
+                    item.CriticRatingSummary = result.tomatoConsensus;
                 }
 
                 int voteCount;

+ 1 - 1
MediaBrowser.Providers/Music/MusicAlbumDynamicInfoProvider.cs

@@ -67,7 +67,7 @@ namespace MediaBrowser.Providers.Music
 
             album.Artists = songs.SelectMany(i => i.Artists)
                 .Distinct(StringComparer.OrdinalIgnoreCase)
-                .ToArray();
+                .ToList();
 
             // Don't save to the db
             return FalseTaskResult;

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

@@ -137,7 +137,8 @@ namespace MediaBrowser.Server.Implementations.Dto
 
             if (user == null)
             {
-                counts = item.ItemCounts;
+                //counts = item.ItemCounts;
+                return;
             }
             else
             {
@@ -376,7 +377,7 @@ namespace MediaBrowser.Server.Implementations.Dto
             }
 
             dto.Album = item.Album;
-            dto.Artists = string.IsNullOrEmpty(item.Artist) ? new string[] { } : new[] { item.Artist };
+            dto.Artists = string.IsNullOrEmpty(item.Artist) ? new List<string>() : new List<string> { item.Artist };
         }
 
         private void SetGameProperties(BaseItemDto dto, Game item)
@@ -804,6 +805,7 @@ namespace MediaBrowser.Server.Implementations.Dto
             dto.Language = item.Language;
             dto.MediaType = item.MediaType;
             dto.LocationType = item.LocationType;
+
             dto.CriticRating = item.CriticRating;
 
             if (fields.Contains(ItemFields.CriticRatingSummary))
@@ -938,7 +940,7 @@ namespace MediaBrowser.Server.Implementations.Dto
             if (audio != null)
             {
                 dto.Album = audio.Album;
-                dto.Artists = audio.Artists.ToArray();
+                dto.Artists = audio.Artists;
 
                 var albumParent = audio.FindParent<MusicAlbum>();
 

+ 48 - 17
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -581,6 +581,11 @@ namespace MediaBrowser.Server.Implementations.Library
                 (UserRootFolder)ResolvePath(new DirectoryInfo(userRootPath)));
         }
 
+        public Person GetPersonSync(string name)
+        {
+            return GetItemByName<Person>(ConfigurationManager.ApplicationPaths.PeoplePath, name);
+        }
+
         /// <summary>
         /// Gets a Person
         /// </summary>
@@ -752,6 +757,37 @@ namespace MediaBrowser.Server.Implementations.Library
         /// </summary>
         private readonly ConcurrentDictionary<string, BaseItem> _itemsByName = new ConcurrentDictionary<string, BaseItem>(StringComparer.OrdinalIgnoreCase);
 
+        private T GetItemByName<T>(string path, string name)
+            where T : BaseItem, new()
+        {
+            if (string.IsNullOrEmpty(path))
+            {
+                throw new ArgumentNullException();
+            }
+
+            if (string.IsNullOrEmpty(name))
+            {
+                throw new ArgumentNullException();
+            }
+
+            var validFilename = FileSystem.GetValidFilename(name);
+
+            var key = Path.Combine(path, validFilename);
+
+            BaseItem obj;
+
+            if (!_itemsByName.TryGetValue(key, out obj))
+            {
+                var tuple = CreateItemByName<T>(key, name);
+
+                obj = tuple.Item2;
+
+                _itemsByName.AddOrUpdate(key, obj, (keyName, oldValue) => obj);
+            }
+
+            return obj as T;
+        }
+
         /// <summary>
         /// Generically retrieves an IBN item
         /// </summary>
@@ -777,13 +813,15 @@ namespace MediaBrowser.Server.Implementations.Library
                 throw new ArgumentNullException();
             }
 
-            var key = Path.Combine(path, FileSystem.GetValidFilename(name));
+            var validFilename = FileSystem.GetValidFilename(name);
+
+            var key = Path.Combine(path, validFilename);
 
             BaseItem obj;
 
             if (!_itemsByName.TryGetValue(key, out obj))
             {
-                var tuple = CreateItemByName<T>(path, name, cancellationToken);
+                var tuple = CreateItemByName<T>(key, name);
 
                 obj = tuple.Item2;
 
@@ -815,16 +853,11 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <typeparam name="T"></typeparam>
         /// <param name="path">The path.</param>
         /// <param name="name">The name.</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task{``0}.</returns>
         /// <exception cref="System.IO.IOException">Path not created:  + path</exception>
-        private Tuple<bool, T> CreateItemByName<T>(string path, string name, CancellationToken cancellationToken)
+        private Tuple<bool, T> CreateItemByName<T>(string path, string name)
             where T : BaseItem, new()
         {
-            cancellationToken.ThrowIfCancellationRequested();
-
-            path = Path.Combine(path, FileSystem.GetValidFilename(name));
-
             var fileInfo = new DirectoryInfo(path);
 
             var isNew = false;
@@ -842,8 +875,6 @@ namespace MediaBrowser.Server.Implementations.Library
                 isNew = true;
             }
 
-            cancellationToken.ThrowIfCancellationRequested();
-
             var type = typeof(T);
 
             var id = path.GetMBId(type);
@@ -866,7 +897,7 @@ namespace MediaBrowser.Server.Implementations.Library
             // Set this now so we don't cause additional file system access during provider executions
             item.ResetResolveArgs(fileInfo);
 
-            return new Tuple<bool,T>(isNew, item);
+            return new Tuple<bool, T>(isNew, item);
         }
 
         /// <summary>
@@ -878,16 +909,12 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <returns>Task.</returns>
         public async Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
         {
-            const int maxTasks = 10;
+            const int maxTasks = 5;
 
             var tasks = new List<Task>();
 
-            var includedPersonTypes = new[] { PersonType.Actor, PersonType.Director, PersonType.GuestStar, PersonType.Writer, PersonType.Producer }
-                .ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
-
             var people = RootFolder.RecursiveChildren
-                .Where(c => c.People != null)
-                .SelectMany(c => c.People.Where(p => includedPersonTypes.ContainsKey(p.Type ?? string.Empty) || includedPersonTypes.ContainsKey(p.Role ?? string.Empty)))
+                .SelectMany(c => c.People)
                 .DistinctBy(p => p.Name, StringComparer.OrdinalIgnoreCase)
                 .ToList();
 
@@ -1050,6 +1077,10 @@ namespace MediaBrowser.Server.Implementations.Library
             await RunPostScanTasks(progress, cancellationToken).ConfigureAwait(false);
 
             progress.Report(100);
+
+            // Bad practice, i know. But we keep a lot in memory, unfortunately.
+            GC.Collect(2, GCCollectionMode.Forced, true);
+            GC.Collect(2, GCCollectionMode.Forced, true);
         }
 
         /// <summary>

+ 1 - 4
MediaBrowser.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs

@@ -30,10 +30,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
             {
                 if (EntityResolutionHelper.IsAudioFile(args.Path))
                 {
-                    return new Controller.Entities.Audio.Audio
-                    {
-                        DisplayMediaType = "Song"
-                    };
+                    return new Controller.Entities.Audio.Audio();
                 }
             }
 

+ 1 - 5
MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs

@@ -46,11 +46,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
                 return null;
             }
             
-            return IsMusicAlbum(args) ? new MusicAlbum
-            {
-                DisplayMediaType = "Album"
-
-            } : null;
+            return IsMusicAlbum(args) ? new MusicAlbum() : null;
         }
 
 

+ 1 - 5
MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs

@@ -108,7 +108,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
                 }
 
                 // Populate counts of items
-                SetItemCounts(artist, null, allItems.OfType<IHasArtist>());
+                //SetItemCounts(artist, null, allItems.OfType<IHasArtist>());
 
                 foreach (var lib in userLibraries)
                 {
@@ -155,10 +155,6 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
             {
                 artist.UserItemCounts[userId.Value] = counts;
             }
-            else
-            {
-                artist.ItemCounts = counts;
-            }
         }
 
         /// <summary>

+ 44 - 30
MediaBrowser.Server.Implementations/Library/Validators/CountHelpers.cs

@@ -18,46 +18,46 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
         /// </summary>
         /// <param name="item">The item.</param>
         /// <param name="counts">The counts.</param>
-        internal static void AddToDictionary(BaseItem item, Dictionary<string, int> counts)
+        internal static void AddToDictionary(BaseItem item, Dictionary<CountType, int> counts)
         {
             if (item is Movie)
             {
-                IncrementCount(counts, "Movie");
+                IncrementCount(counts, CountType.Movie);
             }
             else if (item is Trailer)
             {
-                IncrementCount(counts, "Trailer");
+                IncrementCount(counts, CountType.Trailer);
             }
             else if (item is Series)
             {
-                IncrementCount(counts, "Series");
+                IncrementCount(counts, CountType.Series);
             }
             else if (item is Game)
             {
-                IncrementCount(counts, "Game");
+                IncrementCount(counts, CountType.Game);
             }
             else if (item is Audio)
             {
-                IncrementCount(counts, "Audio");
+                IncrementCount(counts, CountType.Song);
             }
             else if (item is MusicAlbum)
             {
-                IncrementCount(counts, "MusicAlbum");
+                IncrementCount(counts, CountType.MusicAlbum);
             }
             else if (item is Episode)
             {
-                IncrementCount(counts, "Episode");
+                IncrementCount(counts, CountType.Episode);
             }
             else if (item is MusicVideo)
             {
-                IncrementCount(counts, "MusicVideo");
+                IncrementCount(counts, CountType.MusicVideo);
             }
             else if (item is AdultVideo)
             {
-                IncrementCount(counts, "AdultVideo");
+                IncrementCount(counts, CountType.AdultVideo);
             }
 
-            IncrementCount(counts, "Total");
+            IncrementCount(counts, CountType.Total);
         }
 
         /// <summary>
@@ -65,7 +65,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
         /// </summary>
         /// <param name="counts">The counts.</param>
         /// <param name="key">The key.</param>
-        internal static void IncrementCount(Dictionary<string, int> counts, string key)
+        internal static void IncrementCount(Dictionary<CountType, int> counts, CountType key)
         {
             int count;
 
@@ -85,20 +85,20 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
         /// </summary>
         /// <param name="counts">The counts.</param>
         /// <returns>ItemByNameCounts.</returns>
-        internal static ItemByNameCounts GetCounts(Dictionary<string, int> counts)
+        internal static ItemByNameCounts GetCounts(Dictionary<CountType, int> counts)
         {
             return new ItemByNameCounts
             {
-                AdultVideoCount = GetCount(counts, "AdultVideo"),
-                AlbumCount = GetCount(counts, "MusicAlbum"),
-                EpisodeCount = GetCount(counts, "Episode"),
-                GameCount = GetCount(counts, "Game"),
-                MovieCount = GetCount(counts, "Movie"),
-                MusicVideoCount = GetCount(counts, "MusicVideo"),
-                SeriesCount = GetCount(counts, "Series"),
-                SongCount = GetCount(counts, "Audio"),
-                TrailerCount = GetCount(counts, "Trailer"),
-                TotalCount = GetCount(counts, "Total")
+                AdultVideoCount = GetCount(counts, CountType.AdultVideo),
+                AlbumCount = GetCount(counts, CountType.MusicAlbum),
+                EpisodeCount = GetCount(counts, CountType.Episode),
+                GameCount = GetCount(counts, CountType.Game),
+                MovieCount = GetCount(counts, CountType.Movie),
+                MusicVideoCount = GetCount(counts, CountType.MusicVideo),
+                SeriesCount = GetCount(counts, CountType.Series),
+                SongCount = GetCount(counts, CountType.Song),
+                TrailerCount = GetCount(counts, CountType.Trailer),
+                TotalCount = GetCount(counts, CountType.Total)
             };
         }
 
@@ -108,7 +108,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
         /// <param name="counts">The counts.</param>
         /// <param name="key">The key.</param>
         /// <returns>System.Int32.</returns>
-        internal static int GetCount(Dictionary<string, int> counts, string key)
+        internal static int GetCount(Dictionary<CountType, int> counts, CountType key)
         {
             int count;
 
@@ -127,24 +127,24 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
         /// <param name="media">The media.</param>
         /// <param name="names">The names.</param>
         /// <param name="masterDictionary">The master dictionary.</param>
-        internal static void SetItemCounts(Guid? userId, BaseItem media, List<string> names, Dictionary<string, Dictionary<Guid, Dictionary<string, int>>> masterDictionary)
+        internal static void SetItemCounts(Guid userId, BaseItem media, List<string> names, Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>> masterDictionary)
         {
             foreach (var name in names)
             {
-                Dictionary<Guid, Dictionary<string, int>> libraryCounts;
+                Dictionary<Guid, Dictionary<CountType, int>> libraryCounts;
 
                 if (!masterDictionary.TryGetValue(name, out libraryCounts))
                 {
-                    libraryCounts = new Dictionary<Guid, Dictionary<string, int>>();
+                    libraryCounts = new Dictionary<Guid, Dictionary<CountType, int>>();
                     masterDictionary.Add(name, libraryCounts);
                 }
 
-                var userLibId = userId ?? Guid.Empty;
-                Dictionary<string, int> userDictionary;
+                var userLibId = userId/* ?? Guid.Empty*/;
+                Dictionary<CountType, int> userDictionary;
 
                 if (!libraryCounts.TryGetValue(userLibId, out userDictionary))
                 {
-                    userDictionary = new Dictionary<string, int>();
+                    userDictionary = new Dictionary<CountType, int>();
                     libraryCounts.Add(userLibId, userDictionary);
                 }
 
@@ -152,4 +152,18 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
             }
         }
     }
+
+    internal enum CountType
+    {
+        AdultVideo,
+        MusicAlbum,
+        Episode,
+        Game,
+        Movie,
+        MusicVideo,
+        Series,
+        Song,
+        Trailer,
+        Total
+    }
 }

+ 9 - 16
MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs

@@ -49,10 +49,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
 
             var allLibraryItems = allItems;
 
-            var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<string, int>>>(StringComparer.OrdinalIgnoreCase);
+            var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>>(StringComparer.OrdinalIgnoreCase);
 
             // Populate counts of items
-            SetItemCounts(null, allLibraryItems, masterDictionary);
+            //SetItemCounts(null, allLibraryItems, masterDictionary);
 
             progress.Report(2);
 
@@ -72,10 +72,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
 
             progress.Report(10);
 
-            var names = masterDictionary.Keys.ToList();
+            var count = masterDictionary.Count;
             numComplete = 0;
 
-            foreach (var name in names)
+            foreach (var name in masterDictionary.Keys)
             {
                 try
                 {
@@ -88,7 +88,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
 
                 numComplete++;
                 double percent = numComplete;
-                percent /= names.Count;
+                percent /= count;
                 percent *= 90;
 
                 progress.Report(percent + 10);
@@ -97,26 +97,19 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
             progress.Report(100);
         }
 
-        private async Task UpdateItemByNameCounts(string name, CancellationToken cancellationToken, Dictionary<Guid, Dictionary<string, int>> counts)
+        private async Task UpdateItemByNameCounts(string name, CancellationToken cancellationToken, Dictionary<Guid, Dictionary<CountType, int>> counts)
         {
             var itemByName = await _libraryManager.GetGameGenre(name, cancellationToken, true, true).ConfigureAwait(false);
 
-            foreach (var libraryId in counts.Keys.ToList())
+            foreach (var libraryId in counts.Keys)
             {
                 var itemCounts = CountHelpers.GetCounts(counts[libraryId]);
 
-                if (libraryId == Guid.Empty)
-                {
-                    itemByName.ItemCounts = itemCounts;
-                }
-                else
-                {
-                    itemByName.UserItemCounts[libraryId] = itemCounts;
-                }
+                itemByName.UserItemCounts[libraryId] = itemCounts;
             }
         }
 
-        private void SetItemCounts(Guid? userId, IEnumerable<BaseItem> allItems, Dictionary<string, Dictionary<Guid, Dictionary<string, int>>> masterDictionary)
+        private void SetItemCounts(Guid userId, IEnumerable<BaseItem> allItems, Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>> masterDictionary)
         {
             foreach (var media in allItems)
             {

+ 9 - 16
MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs

@@ -52,10 +52,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
 
             var allLibraryItems = allItems;
 
-            var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<string, int>>>(StringComparer.OrdinalIgnoreCase);
+            var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>>(StringComparer.OrdinalIgnoreCase);
 
             // Populate counts of items
-            SetItemCounts(null, allLibraryItems, masterDictionary);
+            //SetItemCounts(null, allLibraryItems, masterDictionary);
 
             progress.Report(2);
 
@@ -75,10 +75,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
 
             progress.Report(10);
 
-            var names = masterDictionary.Keys.ToList();
+            var count = masterDictionary.Count;
             numComplete = 0;
 
-            foreach (var name in names)
+            foreach (var name in masterDictionary.Keys)
             {
                 try
                 {
@@ -91,7 +91,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
 
                 numComplete++;
                 double percent = numComplete;
-                percent /= names.Count;
+                percent /= count;
                 percent *= 90;
 
                 progress.Report(percent + 10);
@@ -100,26 +100,19 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
             progress.Report(100);
         }
 
-        private async Task UpdateItemByNameCounts(string name, CancellationToken cancellationToken, Dictionary<Guid, Dictionary<string, int>> counts)
+        private async Task UpdateItemByNameCounts(string name, CancellationToken cancellationToken, Dictionary<Guid, Dictionary<CountType, int>> counts)
         {
             var itemByName = await _libraryManager.GetGenre(name, cancellationToken, true, true).ConfigureAwait(false);
 
-            foreach (var libraryId in counts.Keys.ToList())
+            foreach (var libraryId in counts.Keys)
             {
                 var itemCounts = CountHelpers.GetCounts(counts[libraryId]);
 
-                if (libraryId == Guid.Empty)
-                {
-                    itemByName.ItemCounts = itemCounts;
-                }
-                else
-                {
-                    itemByName.UserItemCounts[libraryId] = itemCounts;
-                }
+                itemByName.UserItemCounts[libraryId] = itemCounts;
             }
         }
 
-        private void SetItemCounts(Guid? userId, IEnumerable<BaseItem> allItems, Dictionary<string, Dictionary<Guid, Dictionary<string, int>>> masterDictionary)
+        private void SetItemCounts(Guid userId, IEnumerable<BaseItem> allItems, Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>> masterDictionary)
         {
             foreach (var media in allItems)
             {

+ 9 - 16
MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs

@@ -52,10 +52,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
 
             var allLibraryItems = allItems;
 
-            var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<string, int>>>(StringComparer.OrdinalIgnoreCase);
+            var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>>(StringComparer.OrdinalIgnoreCase);
 
             // Populate counts of items
-            SetItemCounts(null, allLibraryItems, masterDictionary);
+            //SetItemCounts(null, allLibraryItems, masterDictionary);
 
             progress.Report(2);
 
@@ -75,10 +75,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
 
             progress.Report(10);
 
-            var names = masterDictionary.Keys.ToList();
+            var count = masterDictionary.Count;
             numComplete = 0;
 
-            foreach (var name in names)
+            foreach (var name in masterDictionary.Keys)
             {
                 try
                 {
@@ -91,7 +91,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
 
                 numComplete++;
                 double percent = numComplete;
-                percent /= names.Count;
+                percent /= count;
                 percent *= 90;
 
                 progress.Report(percent + 10);
@@ -100,26 +100,19 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
             progress.Report(100);
         }
 
-        private async Task UpdateItemByNameCounts(string name, CancellationToken cancellationToken, Dictionary<Guid, Dictionary<string, int>> counts)
+        private async Task UpdateItemByNameCounts(string name, CancellationToken cancellationToken, Dictionary<Guid, Dictionary<CountType, int>> counts)
         {
             var itemByName = await _libraryManager.GetMusicGenre(name, cancellationToken, true, true).ConfigureAwait(false);
 
-            foreach (var libraryId in counts.Keys.ToList())
+            foreach (var libraryId in counts.Keys)
             {
                 var itemCounts = CountHelpers.GetCounts(counts[libraryId]);
 
-                if (libraryId == Guid.Empty)
-                {
-                    itemByName.ItemCounts = itemCounts;
-                }
-                else
-                {
-                    itemByName.UserItemCounts[libraryId] = itemCounts;
-                }
+                itemByName.UserItemCounts[libraryId] = itemCounts;
             }
         }
 
-        private void SetItemCounts(Guid? userId, IEnumerable<BaseItem> allItems, Dictionary<string, Dictionary<Guid, Dictionary<string, int>>> masterDictionary)
+        private void SetItemCounts(Guid userId, IEnumerable<BaseItem> allItems, Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>> masterDictionary)
         {
             foreach (var media in allItems)
             {

+ 24 - 28
MediaBrowser.Server.Implementations/Library/Validators/PeoplePostScanTask.cs

@@ -39,7 +39,13 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
         /// <param name="progress">The progress.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
-        public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
+        public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
+        {
+            return RunInternal(progress, cancellationToken);
+            //return Task.Run(() => RunInternal(progress, cancellationToken));
+        }
+
+        private async Task RunInternal(IProgress<double> progress, CancellationToken cancellationToken)
         {
             var allItems = _libraryManager.RootFolder.RecursiveChildren.ToList();
 
@@ -49,10 +55,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
 
             var allLibraryItems = allItems;
 
-            var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<string, int>>>(StringComparer.OrdinalIgnoreCase);
+            var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>>(StringComparer.OrdinalIgnoreCase);
 
             // Populate counts of items
-            SetItemCounts(null, allLibraryItems, masterDictionary);
+            //SetItemCounts(null, allLibraryItems, masterDictionary);
 
             progress.Report(2);
 
@@ -74,16 +80,25 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
 
             progress.Report(10);
 
-            var names = masterDictionary.Keys.ToList();
+            var count = masterDictionary.Count;
             numComplete = 0;
 
-            foreach (var name in names)
+            foreach (var name in masterDictionary.Keys)
             {
                 cancellationToken.ThrowIfCancellationRequested();
-                
+
                 try
                 {
-                    await UpdateItemByNameCounts(name, masterDictionary[name]).ConfigureAwait(false);
+                    var counts = masterDictionary[name];
+
+                    var itemByName = await _libraryManager.GetPerson(name).ConfigureAwait(false);
+
+                    foreach (var libraryId in counts.Keys)
+                    {
+                        var itemCounts = CountHelpers.GetCounts(counts[libraryId]);
+
+                        itemByName.UserItemCounts[libraryId] = itemCounts;
+                    }
                 }
                 catch (Exception ex)
                 {
@@ -92,7 +107,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
 
                 numComplete++;
                 double percent = numComplete;
-                percent /= names.Count;
+                percent /= count;
                 percent *= 90;
 
                 progress.Report(percent + 10);
@@ -101,26 +116,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
             progress.Report(100);
         }
 
-        private async Task UpdateItemByNameCounts(string name, Dictionary<Guid, Dictionary<string, int>> counts)
-        {
-            var itemByName = await _libraryManager.GetPerson(name).ConfigureAwait(false);
-
-            foreach (var libraryId in counts.Keys.ToList())
-            {
-                var itemCounts = CountHelpers.GetCounts(counts[libraryId]);
-
-                if (libraryId == Guid.Empty)
-                {
-                    itemByName.ItemCounts = itemCounts;
-                }
-                else
-                {
-                    itemByName.UserItemCounts[libraryId] = itemCounts;
-                }
-            }
-        }
-
-        private void SetItemCounts(Guid? userId, IEnumerable<BaseItem> allItems, Dictionary<string, Dictionary<Guid, Dictionary<string, int>>> masterDictionary)
+        private void SetItemCounts(Guid userId, IEnumerable<BaseItem> allItems, Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>> masterDictionary)
         {
             foreach (var media in allItems)
             {

+ 9 - 16
MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs

@@ -49,10 +49,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
 
             var allLibraryItems = allItems;
 
-            var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<string, int>>>(StringComparer.OrdinalIgnoreCase);
+            var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>>(StringComparer.OrdinalIgnoreCase);
 
             // Populate counts of items
-            SetItemCounts(null, allLibraryItems, masterDictionary);
+            //SetItemCounts(null, allLibraryItems, masterDictionary);
 
             progress.Report(2);
 
@@ -72,10 +72,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
 
             progress.Report(10);
 
-            var names = masterDictionary.Keys.ToList();
+            var count = masterDictionary.Count;
             numComplete = 0;
 
-            foreach (var name in names)
+            foreach (var name in masterDictionary.Keys)
             {
                 try
                 {
@@ -88,7 +88,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
 
                 numComplete++;
                 double percent = numComplete;
-                percent /= names.Count;
+                percent /= count;
                 percent *= 90;
 
                 progress.Report(percent + 10);
@@ -97,26 +97,19 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
             progress.Report(100);
         }
 
-        private async Task UpdateItemByNameCounts(string name, CancellationToken cancellationToken, Dictionary<Guid, Dictionary<string, int>> counts)
+        private async Task UpdateItemByNameCounts(string name, CancellationToken cancellationToken, Dictionary<Guid, Dictionary<CountType, int>> counts)
         {
             var itemByName = await _libraryManager.GetStudio(name, cancellationToken, true, true).ConfigureAwait(false);
 
-            foreach (var libraryId in counts.Keys.ToList())
+            foreach (var libraryId in counts.Keys)
             {
                 var itemCounts = CountHelpers.GetCounts(counts[libraryId]);
 
-                if (libraryId == Guid.Empty)
-                {
-                    itemByName.ItemCounts = itemCounts;
-                }
-                else
-                {
-                    itemByName.UserItemCounts[libraryId] = itemCounts;
-                }
+                itemByName.UserItemCounts[libraryId] = itemCounts;
             }
         }
 
-        private void SetItemCounts(Guid? userId, IEnumerable<BaseItem> allItems, Dictionary<string, Dictionary<Guid, Dictionary<string, int>>> masterDictionary)
+        private void SetItemCounts(Guid userId, IEnumerable<BaseItem> allItems, Dictionary<string, Dictionary<Guid, Dictionary<CountType, int>>> masterDictionary)
         {
             foreach (var media in allItems)
             {

+ 6 - 1
MediaBrowser.Server.Implementations/Sorting/BudgetComparer.cs

@@ -14,7 +14,12 @@ namespace MediaBrowser.Server.Implementations.Sorting
         /// <returns>System.Int32.</returns>
         public int Compare(BaseItem x, BaseItem y)
         {
-            return (x.Budget ?? 0).CompareTo(y.Budget ?? 0);
+            return GetValue(x).CompareTo(GetValue(y));
+        }
+
+        private double GetValue(BaseItem x)
+        {
+            return x.Budget ?? 0;
         }
 
         /// <summary>

+ 6 - 1
MediaBrowser.Server.Implementations/Sorting/CriticRatingComparer.cs

@@ -17,7 +17,12 @@ namespace MediaBrowser.Server.Implementations.Sorting
         /// <returns>System.Int32.</returns>
         public int Compare(BaseItem x, BaseItem y)
         {
-            return (x.CriticRating ?? 0).CompareTo(y.CriticRating ?? 0);
+            return GetValue(x).CompareTo(GetValue(y));
+        }
+
+        private float GetValue(BaseItem x)
+        {
+            return x.CriticRating ?? 0;
         }
 
         /// <summary>

+ 6 - 1
MediaBrowser.Server.Implementations/Sorting/RevenueComparer.cs

@@ -14,7 +14,12 @@ namespace MediaBrowser.Server.Implementations.Sorting
         /// <returns>System.Int32.</returns>
         public int Compare(BaseItem x, BaseItem y)
         {
-            return (x.Revenue ?? 0).CompareTo(y.Revenue ?? 0);
+            return GetValue(x).CompareTo(GetValue(y));
+        }
+
+        private double GetValue(BaseItem x)
+        {
+            return x.Revenue ?? 0;
         }
 
         /// <summary>

+ 2 - 2
MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj

@@ -168,9 +168,9 @@
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\packages\ServiceStack.Text.3.9.58\lib\net35\ServiceStack.Text.dll</HintPath>
     </Reference>
-    <Reference Include="SimpleInjector, Version=2.3.2.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
+    <Reference Include="SimpleInjector, Version=2.3.5.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\SimpleInjector.2.3.2\lib\net40-client\SimpleInjector.dll</HintPath>
+      <HintPath>..\packages\SimpleInjector.2.3.5\lib\net40-client\SimpleInjector.dll</HintPath>
     </Reference>
     <Reference Include="System" />
     <Reference Include="System.Data" />

+ 1 - 1
MediaBrowser.ServerApplication/packages.config

@@ -11,6 +11,6 @@
   <package id="ServiceStack.OrmLite.SqlServer" version="3.9.44" targetFramework="net45" />
   <package id="ServiceStack.Redis" version="3.9.44" targetFramework="net45" />
   <package id="ServiceStack.Text" version="3.9.58" targetFramework="net45" />
-  <package id="SimpleInjector" version="2.3.2" targetFramework="net45" />
+  <package id="SimpleInjector" version="2.3.5" targetFramework="net45" />
   <package id="System.Data.SQLite.x86" version="1.0.88.0" targetFramework="net45" />
 </packages>

+ 2 - 2
Nuget/MediaBrowser.Common.Internal.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Common.Internal</id>
-        <version>3.0.192</version>
+        <version>3.0.198</version>
         <title>MediaBrowser.Common.Internal</title>
         <authors>Luke</authors>
         <owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
         <description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
         <copyright>Copyright © Media Browser 2013</copyright>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.192" />
+            <dependency id="MediaBrowser.Common" version="3.0.198" />
             <dependency id="NLog" version="2.0.1.2" />
             <dependency id="ServiceStack.Text" version="3.9.58" />
             <dependency id="SimpleInjector" version="2.3.2" />

+ 1 - 1
Nuget/MediaBrowser.Common.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Common</id>
-        <version>3.0.192</version>
+        <version>3.0.198</version>
         <title>MediaBrowser.Common</title>
         <authors>Media Browser Team</authors>
         <owners>ebr,Luke,scottisafool</owners>

+ 2 - 2
Nuget/MediaBrowser.Server.Core.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Server.Core</id>
-        <version>3.0.192</version>
+        <version>3.0.198</version>
         <title>Media Browser.Server.Core</title>
         <authors>Media Browser Team</authors>
         <owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
         <description>Contains core components required to build plugins for Media Browser Server.</description>
         <copyright>Copyright © Media Browser 2013</copyright>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.192" />
+            <dependency id="MediaBrowser.Common" version="3.0.198" />
         </dependencies>
     </metadata>
     <files>