Procházet zdrojové kódy

improved performance of item counts

Luke Pulverenti před 11 roky
rodič
revize
803e8b4a2e
49 změnil soubory, kde provedl 494 přidání a 378 odebrání
  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>