Browse Source

fixes #97 and creates a library dictionary cache to avoid FindById recursion

Luke Pulverenti 12 years ago
parent
commit
9f06eb781f

+ 3 - 2
MediaBrowser.Api/Images/ImageService.cs

@@ -160,11 +160,12 @@ namespace MediaBrowser.Api.Images
         /// The _library manager
         /// The _library manager
         /// </summary>
         /// </summary>
         private readonly ILibraryManager _libraryManager;
         private readonly ILibraryManager _libraryManager;
-        
+
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="ImageService" /> class.
         /// Initializes a new instance of the <see cref="ImageService" /> class.
         /// </summary>
         /// </summary>
         /// <param name="userManager">The user manager.</param>
         /// <param name="userManager">The user manager.</param>
+        /// <param name="libraryManager">The library manager.</param>
         public ImageService(IUserManager userManager, ILibraryManager libraryManager)
         public ImageService(IUserManager userManager, ILibraryManager libraryManager)
         {
         {
             _userManager = userManager;
             _userManager = userManager;
@@ -178,7 +179,7 @@ namespace MediaBrowser.Api.Images
         /// <returns>System.Object.</returns>
         /// <returns>System.Object.</returns>
         public object Get(GetItemImage request)
         public object Get(GetItemImage request)
         {
         {
-            var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager);
+            var item = string.IsNullOrEmpty(request.Id) ? _libraryManager.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager);
 
 
             return GetImage(request, item);
             return GetImage(request, item);
         }
         }

+ 1 - 1
MediaBrowser.Api/UserLibrary/GenresService.cs

@@ -13,7 +13,7 @@ namespace MediaBrowser.Api.UserLibrary
     /// </summary>
     /// </summary>
     [Route("/Users/{UserId}/Items/{ParentId}/Genres", "GET")]
     [Route("/Users/{UserId}/Items/{ParentId}/Genres", "GET")]
     [Route("/Users/{UserId}/Items/Root/Genres", "GET")]
     [Route("/Users/{UserId}/Items/Root/Genres", "GET")]
-    [ServiceStack.ServiceHost.Api(Description = "Gets all genres from a given item, folder, or the entire library")]
+    [Api(Description = "Gets all genres from a given item, folder, or the entire library")]
     public class GetGenres : GetItemsByName
     public class GetGenres : GetItemsByName
     {
     {
     }
     }

+ 1 - 1
MediaBrowser.Api/UserLibrary/ItemsService.cs

@@ -55,7 +55,7 @@ namespace MediaBrowser.Api.UserLibrary
         /// Filters to apply to the results
         /// Filters to apply to the results
         /// </summary>
         /// </summary>
         /// <value>The filters.</value>
         /// <value>The filters.</value>
-        [ApiMember(Name = "Filters", Description = "Optional. Specify additional filters to apply. This allows multiple, comma delimeted. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsRecentlyAdded, IsResumable", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+        [ApiMember(Name = "Filters", Description = "Optional. Specify additional filters to apply. This allows multiple, comma delimeted. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsRecentlyAdded, IsResumable, Likes, Dislikes", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
         public string Filters { get; set; }
         public string Filters { get; set; }
 
 
         /// <summary>
         /// <summary>

+ 11 - 10
MediaBrowser.Api/UserLibrary/UserLibraryService.cs

@@ -378,7 +378,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
         {
             var user = _userManager.GetUserById(request.UserId);
             var user = _userManager.GetUserById(request.UserId);
 
 
-            var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
+            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
 
 
             // Get everything
             // Get everything
             var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
             var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
@@ -401,7 +401,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
         {
             var user = _userManager.GetUserById(request.UserId);
             var user = _userManager.GetUserById(request.UserId);
 
 
-            var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
+            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
 
 
             // Get everything
             // Get everything
             var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
             var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
@@ -422,7 +422,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
         {
             var user = _userManager.GetUserById(request.UserId);
             var user = _userManager.GetUserById(request.UserId);
 
 
-            var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
+            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
 
 
             // Get everything
             // Get everything
             var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
             var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
@@ -459,7 +459,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
         {
             var user = _userManager.GetUserById(request.UserId);
             var user = _userManager.GetUserById(request.UserId);
 
 
-            var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
+            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
 
 
             var result = _libraryManager.GetIntros(item, user);
             var result = _libraryManager.GetIntros(item, user);
 
 
@@ -480,12 +480,13 @@ namespace MediaBrowser.Api.UserLibrary
 
 
             var user = _userManager.GetUserById(userId);
             var user = _userManager.GetUserById(userId);
 
 
-            var item = (Folder)DtoBuilder.GetItemByClientId(itemId, _userManager, _libraryManager, user.Id);
+            var item = string.IsNullOrEmpty(itemId) ? user.RootFolder : DtoBuilder.GetItemByClientId(itemId, _userManager, _libraryManager, user.Id);
+            var folder = (Folder)item;
 
 
             // Serialize to json and then back so that the core doesn't see the request dto type
             // Serialize to json and then back so that the core doesn't see the request dto type
             var displayPreferences = _jsonSerializer.DeserializeFromString<DisplayPreferences>(_jsonSerializer.SerializeToString(request));
             var displayPreferences = _jsonSerializer.DeserializeFromString<DisplayPreferences>(_jsonSerializer.SerializeToString(request));
 
 
-            var task = _libraryManager.SaveDisplayPreferencesForFolder(user, item, displayPreferences);
+            var task = _libraryManager.SaveDisplayPreferencesForFolder(user, folder, displayPreferences);
 
 
             Task.WaitAll(task);
             Task.WaitAll(task);
         }
         }
@@ -498,7 +499,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
         {
             var user = _userManager.GetUserById(request.UserId);
             var user = _userManager.GetUserById(request.UserId);
 
 
-            var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
+            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
 
 
             // Get the user data for this item
             // Get the user data for this item
             var data = item.GetUserData(user, true);
             var data = item.GetUserData(user, true);
@@ -519,7 +520,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
         {
             var user = _userManager.GetUserById(request.UserId);
             var user = _userManager.GetUserById(request.UserId);
 
 
-            var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
+            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
 
 
             // Get the user data for this item
             // Get the user data for this item
             var data = item.GetUserData(user, true);
             var data = item.GetUserData(user, true);
@@ -540,7 +541,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
         {
             var user = _userManager.GetUserById(request.UserId);
             var user = _userManager.GetUserById(request.UserId);
 
 
-            var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
+            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
 
 
             // Get the user data for this item
             // Get the user data for this item
             var data = item.GetUserData(user, true);
             var data = item.GetUserData(user, true);
@@ -560,7 +561,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
         {
             var user = _userManager.GetUserById(request.UserId);
             var user = _userManager.GetUserById(request.UserId);
 
 
-            var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
+            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
 
 
             // Get the user data for this item
             // Get the user data for this item
             var data = item.GetUserData(user, true);
             var data = item.GetUserData(user, true);

+ 5 - 2
MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs

@@ -1,4 +1,5 @@
-using System.Net.Http.Headers;
+using System.Globalization;
+using System.Net.Http.Headers;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
@@ -216,6 +217,8 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
             return GetTempFile(options, tempFile, 0);
             return GetTempFile(options, tempFile, 0);
         }
         }
 
 
+        protected static readonly CultureInfo UsCulture = new CultureInfo("en-US");
+        
         /// <summary>
         /// <summary>
         /// Gets the temp file.
         /// Gets the temp file.
         /// </summary>
         /// </summary>
@@ -278,7 +281,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
                     }
                     }
                     else
                     else
                     {
                     {
-                        var length = long.Parse(string.Join(string.Empty, lengthValues.ToArray()));
+                        var length = long.Parse(string.Join(string.Empty, lengthValues.ToArray()), UsCulture);
 
 
                         using (var stream = ProgressStream.CreateReadProgressStream(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), options.Progress.Report, length))
                         using (var stream = ProgressStream.CreateReadProgressStream(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), options.Progress.Report, length))
                         {
                         {

+ 4 - 1
MediaBrowser.Common.Implementations/NetworkManagement/NetworkManager.cs

@@ -1,4 +1,5 @@
-using System.Management;
+using System.Globalization;
+using System.Management;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Net;
 using System;
 using System;
@@ -343,6 +344,8 @@ namespace MediaBrowser.Common.Implementations.NetworkManagement
             return new IPEndPoint(ipaddy, port);
             return new IPEndPoint(ipaddy, port);
         }
         }
 
 
+        protected static readonly CultureInfo UsCulture = new CultureInfo("en-US");
+        
         /// <summary>
         /// <summary>
         /// Gets the port.
         /// Gets the port.
         /// </summary>
         /// </summary>

+ 6 - 3
MediaBrowser.Common/Net/BasePeriodicWebSocketListener.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Model.Logging;
+using System.Globalization;
+using MediaBrowser.Model.Logging;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
@@ -80,6 +81,8 @@ namespace MediaBrowser.Common.Net
             return NullTaskResult;
             return NullTaskResult;
         }
         }
 
 
+        protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
+        
         /// <summary>
         /// <summary>
         /// Starts sending messages over a web socket
         /// Starts sending messages over a web socket
         /// </summary>
         /// </summary>
@@ -88,8 +91,8 @@ namespace MediaBrowser.Common.Net
         {
         {
             var vals = message.Data.Split(',');
             var vals = message.Data.Split(',');
 
 
-            var dueTimeMs = long.Parse(vals[0]);
-            var periodMs = long.Parse(vals[1]);
+            var dueTimeMs = long.Parse(vals[0], UsCulture);
+            var periodMs = long.Parse(vals[1], UsCulture);
 
 
             var cancellationTokenSource = new CancellationTokenSource();
             var cancellationTokenSource = new CancellationTokenSource();
 
 

+ 0 - 27
MediaBrowser.Controller/Entities/BaseItem.cs

@@ -950,33 +950,6 @@ namespace MediaBrowser.Controller.Entities
             return IsParentalAllowed(user);
             return IsParentalAllowed(user);
         }
         }
 
 
-        /// <summary>
-        /// Finds an item by ID, recursively
-        /// </summary>
-        /// <param name="id">The id.</param>
-        /// <param name="user">The user.</param>
-        /// <returns>BaseItem.</returns>
-        /// <exception cref="System.ArgumentNullException">id</exception>
-        public virtual BaseItem FindItemById(Guid id, User user)
-        {
-            if (id == Guid.Empty)
-            {
-                throw new ArgumentNullException("id");
-            }
-
-            if (Id == id)
-            {
-                return this;
-            }
-
-            if (LocalTrailers != null)
-            {
-                return LocalTrailers.FirstOrDefault(i => i.Id == id);
-            }
-
-            return null;
-        }
-
         /// <summary>
         /// <summary>
         /// Finds the particular item by searching through our parents and, if not found there, loading from repo
         /// Finds the particular item by searching through our parents and, if not found there, loading from repo
         /// </summary>
         /// </summary>

+ 3 - 33
MediaBrowser.Controller/Entities/Folder.cs

@@ -673,7 +673,7 @@ namespace MediaBrowser.Controller.Entities
 
 
                 foreach (var item in changedArgs.ItemsRemoved)
                 foreach (var item in changedArgs.ItemsRemoved)
                 {
                 {
-                    Logger.Info("** " + item.Name + " Removed from library.");
+                    Logger.Debug("** " + item.Name + " Removed from library.");
                 }
                 }
 
 
                 var childrenReplaced = false;
                 var childrenReplaced = false;
@@ -688,7 +688,7 @@ namespace MediaBrowser.Controller.Entities
 
 
                 foreach (var item in changedArgs.ItemsAdded)
                 foreach (var item in changedArgs.ItemsAdded)
                 {
                 {
-                    Logger.Info("** " + item.Name + " Added to library.");
+                    Logger.Debug("** " + item.Name + " Added to library.");
 
 
                     if (!childrenReplaced)
                     if (!childrenReplaced)
                     {
                     {
@@ -701,7 +701,7 @@ namespace MediaBrowser.Controller.Entities
                 await Task.WhenAll(saveTasks).ConfigureAwait(false);
                 await Task.WhenAll(saveTasks).ConfigureAwait(false);
 
 
                 //and save children in repo...
                 //and save children in repo...
-                Logger.Info("*** Saving " + newChildren.Count + " children for " + Name);
+                Logger.Debug("*** Saving " + newChildren.Count + " children for " + Name);
                 await Kernel.Instance.ItemRepository.SaveChildren(Id, newChildren, CancellationToken.None).ConfigureAwait(false);
                 await Kernel.Instance.ItemRepository.SaveChildren(Id, newChildren, CancellationToken.None).ConfigureAwait(false);
             }
             }
 
 
@@ -913,36 +913,6 @@ namespace MediaBrowser.Controller.Entities
             await Task.WhenAll(tasks).ConfigureAwait(false);
             await Task.WhenAll(tasks).ConfigureAwait(false);
         }
         }
 
 
-        /// <summary>
-        /// Finds an item by ID, recursively
-        /// </summary>
-        /// <param name="id">The id.</param>
-        /// <param name="user">The user.</param>
-        /// <returns>BaseItem.</returns>
-        public override BaseItem FindItemById(Guid id, User user)
-        {
-            var result = base.FindItemById(id, user);
-
-            if (result != null)
-            {
-                return result;
-            }
-
-            var children = user == null ? ActualChildren : GetChildren(user);
-
-            foreach (var child in children)
-            {
-                result = child.FindItemById(id, user);
-
-                if (result != null)
-                {
-                    return result;
-                }
-            }
-
-            return null;
-        }
-
         /// <summary>
         /// <summary>
         /// Finds an item by path, recursively
         /// Finds an item by path, recursively
         /// </summary>
         /// </summary>

+ 1 - 24
MediaBrowser.Controller/Entities/Movies/Movie.cs

@@ -118,30 +118,7 @@ namespace MediaBrowser.Controller.Entities.Movies
             cancellationToken.ThrowIfCancellationRequested();
             cancellationToken.ThrowIfCancellationRequested();
 
 
             return result;
             return result;
-        }
-
-        /// <summary>
-        /// Finds an item by ID, recursively
-        /// </summary>
-        /// <param name="id">The id.</param>
-        /// <param name="user">The user.</param>
-        /// <returns>BaseItem.</returns>
-        public override BaseItem FindItemById(Guid id, User user)
-        {
-            var item = base.FindItemById(id, user);
-
-            if (item != null)
-            {
-                return item;
-            }
-
-            if (SpecialFeatures != null)
-            {
-                return SpecialFeatures.FirstOrDefault(i => i.Id == id);
-            }
-
-            return null;
-        }        
+        }      
         
         
         /// <summary>
         /// <summary>
         /// Loads special features from the file system
         /// Loads special features from the file system

+ 0 - 1
MediaBrowser.Controller/Extensions/XmlExtensions.cs

@@ -191,7 +191,6 @@ namespace MediaBrowser.Controller.Extensions
 
 
             if (!string.IsNullOrWhiteSpace(valueString))
             if (!string.IsNullOrWhiteSpace(valueString))
             {
             {
-
                 int.TryParse(valueString, out value);
                 int.TryParse(valueString, out value);
             }
             }
 
 

+ 10 - 6
MediaBrowser.Controller/Library/DtoBuilder.cs

@@ -809,15 +809,19 @@ namespace MediaBrowser.Controller.Library
         /// Gets a BaseItem based upon it's client-side item id
         /// Gets a BaseItem based upon it's client-side item id
         /// </summary>
         /// </summary>
         /// <param name="id">The id.</param>
         /// <param name="id">The id.</param>
+        /// <param name="userManager">The user manager.</param>
+        /// <param name="libraryManager">The library manager.</param>
         /// <param name="userId">The user id.</param>
         /// <param name="userId">The user id.</param>
         /// <returns>BaseItem.</returns>
         /// <returns>BaseItem.</returns>
         public static BaseItem GetItemByClientId(string id, IUserManager userManager, ILibraryManager libraryManager, Guid? userId = null)
         public static BaseItem GetItemByClientId(string id, IUserManager userManager, ILibraryManager libraryManager, Guid? userId = null)
         {
         {
-            var isIdEmpty = string.IsNullOrEmpty(id);
+            if (string.IsNullOrEmpty(id))
+            {
+                throw new ArgumentNullException("id");
+            }
 
 
             // If the item is an indexed folder we have to do a special routine to get it
             // If the item is an indexed folder we have to do a special routine to get it
-            var isIndexFolder = !isIdEmpty &&
-                                id.IndexOf(IndexFolderDelimeter, StringComparison.OrdinalIgnoreCase) != -1;
+            var isIndexFolder = id.IndexOf(IndexFolderDelimeter, StringComparison.OrdinalIgnoreCase) != -1;
 
 
             if (isIndexFolder)
             if (isIndexFolder)
             {
             {
@@ -831,9 +835,7 @@ namespace MediaBrowser.Controller.Library
 
 
             if (userId.HasValue)
             if (userId.HasValue)
             {
             {
-                item = isIdEmpty
-                           ? userManager.GetUserById(userId.Value).RootFolder
-                           : libraryManager.GetItemById(new Guid(id), userId.Value);
+                item = libraryManager.GetItemById(new Guid(id));
             }
             }
             else if (!isIndexFolder)
             else if (!isIndexFolder)
             {
             {
@@ -862,6 +864,8 @@ namespace MediaBrowser.Controller.Library
         /// </summary>
         /// </summary>
         /// <param name="id">The id.</param>
         /// <param name="id">The id.</param>
         /// <param name="userId">The user id.</param>
         /// <param name="userId">The user id.</param>
+        /// <param name="userManager">The user manager.</param>
+        /// <param name="libraryManager">The library manager.</param>
         /// <returns>BaseItem.</returns>
         /// <returns>BaseItem.</returns>
         private static BaseItem GetIndexFolder(string id, Guid userId, IUserManager userManager, ILibraryManager libraryManager)
         private static BaseItem GetIndexFolder(string id, Guid userId, IUserManager userManager, ILibraryManager libraryManager)
         {
         {

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

@@ -136,14 +136,6 @@ namespace MediaBrowser.Controller.Library
         /// <returns>BaseItem.</returns>
         /// <returns>BaseItem.</returns>
         BaseItem GetItemById(Guid id);
         BaseItem GetItemById(Guid id);
 
 
-        /// <summary>
-        /// Gets the item by id.
-        /// </summary>
-        /// <param name="id">The id.</param>
-        /// <param name="userId">The user id.</param>
-        /// <returns>BaseItem.</returns>
-        BaseItem GetItemById(Guid id, Guid userId);
-
         /// <summary>
         /// <summary>
         /// Gets the intros.
         /// Gets the intros.
         /// </summary>
         /// </summary>

+ 9 - 6
MediaBrowser.Controller/Providers/MediaInfo/BaseFFProbeProvider.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Common.IO;
+using System.Globalization;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.MediaInfo;
 using MediaBrowser.Controller.MediaInfo;
@@ -61,6 +62,8 @@ namespace MediaBrowser.Controller.Providers.MediaInfo
             get { return MetadataProviderPriority.Second; }
             get { return MetadataProviderPriority.Second; }
         }
         }
 
 
+        protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
+        
         /// <summary>
         /// <summary>
         /// Fetches metadata and returns true or false indicating if any work that requires persistence was done
         /// Fetches metadata and returns true or false indicating if any work that requires persistence was done
         /// </summary>
         /// </summary>
@@ -203,7 +206,7 @@ namespace MediaBrowser.Controller.Providers.MediaInfo
 
 
                 if (!string.IsNullOrEmpty(streamInfo.sample_rate))
                 if (!string.IsNullOrEmpty(streamInfo.sample_rate))
                 {
                 {
-                    stream.SampleRate = int.Parse(streamInfo.sample_rate);
+                    stream.SampleRate = int.Parse(streamInfo.sample_rate, UsCulture);
                 }
                 }
             }
             }
             else if (streamInfo.codec_type.Equals("subtitle", StringComparison.OrdinalIgnoreCase))
             else if (streamInfo.codec_type.Equals("subtitle", StringComparison.OrdinalIgnoreCase))
@@ -227,12 +230,12 @@ namespace MediaBrowser.Controller.Providers.MediaInfo
             {
             {
                 if (!string.IsNullOrEmpty(streamInfo.bit_rate))
                 if (!string.IsNullOrEmpty(streamInfo.bit_rate))
                 {
                 {
-                    stream.BitRate = int.Parse(streamInfo.bit_rate);
+                    stream.BitRate = int.Parse(streamInfo.bit_rate, UsCulture);
                 }
                 }
                 else if (formatInfo != null && !string.IsNullOrEmpty(formatInfo.bit_rate))
                 else if (formatInfo != null && !string.IsNullOrEmpty(formatInfo.bit_rate))
                 {
                 {
                     // If the stream info doesn't have a bitrate get the value from the media format info
                     // If the stream info doesn't have a bitrate get the value from the media format info
-                    stream.BitRate = int.Parse(formatInfo.bit_rate);
+                    stream.BitRate = int.Parse(formatInfo.bit_rate, UsCulture);
                 }
                 }
             }
             }
 
 
@@ -265,11 +268,11 @@ namespace MediaBrowser.Controller.Providers.MediaInfo
 
 
                 if (parts.Length == 2)
                 if (parts.Length == 2)
                 {
                 {
-                    result = float.Parse(parts[0])/float.Parse(parts[1]);
+                    result = float.Parse(parts[0], UsCulture) / float.Parse(parts[1], UsCulture);
                 }
                 }
                 else
                 else
                 {
                 {
-                    result = float.Parse(parts[0]);
+                    result = float.Parse(parts[0], UsCulture);
                 }
                 }
 
 
                 return float.IsNaN(result) ? (float?)null : result;
                 return float.IsNaN(result) ? (float?)null : result;

+ 1 - 1
MediaBrowser.Controller/Providers/MediaInfo/FFProbeAudioInfoProvider.cs

@@ -69,7 +69,7 @@ namespace MediaBrowser.Controller.Providers.MediaInfo
                 // If we got something, parse it
                 // If we got something, parse it
                 if (!string.IsNullOrEmpty(duration))
                 if (!string.IsNullOrEmpty(duration))
                 {
                 {
-                    audio.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(duration)).Ticks;
+                    audio.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(duration, UsCulture)).Ticks;
                 }
                 }
 
 
                 if (data.format.tags != null)
                 if (data.format.tags != null)

+ 1 - 1
MediaBrowser.Controller/Providers/MediaInfo/FFProbeVideoInfoProvider.cs

@@ -198,7 +198,7 @@ namespace MediaBrowser.Controller.Providers.MediaInfo
 
 
                     if (needToSetRuntime && !string.IsNullOrEmpty(data.format.duration))
                     if (needToSetRuntime && !string.IsNullOrEmpty(data.format.duration))
                     {
                     {
-                        video.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.format.duration)).Ticks;
+                        video.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.format.duration, UsCulture)).Ticks;
                     }
                     }
                 }
                 }
 
 

+ 3 - 1
MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs

@@ -127,6 +127,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer
             EndpointHostConfig.Instance.MetadataRedirectPath = "metadata";
             EndpointHostConfig.Instance.MetadataRedirectPath = "metadata";
         }
         }
 
 
+        protected static readonly CultureInfo UsCulture = new CultureInfo("en-US");
+        
         /// <summary>
         /// <summary>
         /// Configures the specified container.
         /// Configures the specified container.
         /// </summary>
         /// </summary>
@@ -184,7 +186,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
 
 
                         if (hasOptions.Options.TryGetValue("Content-Length", out contentLength) && !string.IsNullOrEmpty(contentLength))
                         if (hasOptions.Options.TryGetValue("Content-Length", out contentLength) && !string.IsNullOrEmpty(contentLength))
                         {
                         {
-                            var length = long.Parse(contentLength);
+                            var length = long.Parse(contentLength, UsCulture);
 
 
                             if (length > 0)
                             if (length > 0)
                             {
                             {

+ 2 - 2
MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs

@@ -139,11 +139,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer
 
 
                         if (!string.IsNullOrEmpty(vals[0]))
                         if (!string.IsNullOrEmpty(vals[0]))
                         {
                         {
-                            start = long.Parse(vals[0]);
+                            start = long.Parse(vals[0], UsCulture);
                         }
                         }
                         if (!string.IsNullOrEmpty(vals[1]))
                         if (!string.IsNullOrEmpty(vals[1]))
                         {
                         {
-                            end = long.Parse(vals[1]);
+                            end = long.Parse(vals[1], UsCulture);
                         }
                         }
 
 
                         _requestedRanges.Add(new KeyValuePair<long, long?>(start, end));
                         _requestedRanges.Add(new KeyValuePair<long, long?>(start, end));

+ 102 - 34
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -4,6 +4,7 @@ using MediaBrowser.Common.ScheduledTasks;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Resolvers;
 using MediaBrowser.Controller.Resolvers;
@@ -73,6 +74,8 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <param name="args">The <see cref="ChildrenChangedEventArgs" /> instance containing the event data.</param>
         /// <param name="args">The <see cref="ChildrenChangedEventArgs" /> instance containing the event data.</param>
         public void ReportLibraryChanged(ChildrenChangedEventArgs args)
         public void ReportLibraryChanged(ChildrenChangedEventArgs args)
         {
         {
+            UpdateLibraryCache(args);
+
             EventHelper.QueueEventIfNotNull(LibraryChanged, this, args, _logger);
             EventHelper.QueueEventIfNotNull(LibraryChanged, this, args, _logger);
         }
         }
         #endregion
         #endregion
@@ -109,7 +112,28 @@ namespace MediaBrowser.Server.Implementations.Library
         /// (typically, multiple user roots).  We store them here and be sure they all reference a
         /// (typically, multiple user roots).  We store them here and be sure they all reference a
         /// single instance.
         /// single instance.
         /// </summary>
         /// </summary>
-        private ConcurrentDictionary<Guid, BaseItem> ByReferenceItems { get; set; } 
+        private ConcurrentDictionary<Guid, BaseItem> ByReferenceItems { get; set; }
+
+        private ConcurrentDictionary<Guid, BaseItem> _libraryItemsCache;
+        private object _libraryItemsCacheSyncLock = new object();
+        private bool _libraryItemsCacheInitialized;
+        private ConcurrentDictionary<Guid, BaseItem> LibraryItemsCache
+        {
+            get
+            {
+                LazyInitializer.EnsureInitialized(ref _libraryItemsCache, ref _libraryItemsCacheInitialized, ref _libraryItemsCacheSyncLock, CreateLibraryItemsCache);
+                return _libraryItemsCache;
+            }
+            set
+            {
+                _libraryItemsCache = value;
+
+                if (value == null)
+                {
+                    _libraryItemsCacheInitialized = false;
+                }
+            }
+        }
 
 
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="LibraryManager" /> class.
         /// Initializes a new instance of the <see cref="LibraryManager" /> class.
@@ -219,7 +243,7 @@ namespace MediaBrowser.Server.Implementations.Library
             {
             {
                 // Any number of configuration settings could change the way the library is refreshed, so do that now
                 // Any number of configuration settings could change the way the library is refreshed, so do that now
                 _taskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>();
                 _taskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>();
-
+                
                 if (refreshPeopleAfterUpdate)
                 if (refreshPeopleAfterUpdate)
                 {
                 {
                     _taskManager.CancelIfRunningAndQueue<PeopleValidationTask>();
                     _taskManager.CancelIfRunningAndQueue<PeopleValidationTask>();
@@ -227,6 +251,77 @@ namespace MediaBrowser.Server.Implementations.Library
             });
             });
         }
         }
 
 
+        /// <summary>
+        /// Creates the library items cache.
+        /// </summary>
+        /// <returns>ConcurrentDictionary{GuidBaseItem}.</returns>
+        private ConcurrentDictionary<Guid, BaseItem> CreateLibraryItemsCache()
+        {
+            var items = RootFolder.RecursiveChildren.ToList();
+
+            items.Add(RootFolder);
+
+            var specialFeatures = items.OfType<Movie>().SelectMany(i => i.SpecialFeatures).ToList();
+            var localTrailers = items.SelectMany(i => i.LocalTrailers).ToList();
+
+            items.AddRange(specialFeatures);
+            items.AddRange(localTrailers);
+
+            // Can't add these right now because there could be separate instances with the same id.
+            //items.AddRange(_userManager.Users.Select(i => i.RootFolder).Distinct().ToList());
+
+            items.AddRange(_userManager.Users.SelectMany(i => i.RootFolder.Children).Where(i => !(i is BasePluginFolder)).Distinct().ToList());
+
+            return new ConcurrentDictionary<Guid,BaseItem>(items.ToDictionary(i => i.Id));
+        }
+
+        /// <summary>
+        /// Updates the library cache.
+        /// </summary>
+        /// <param name="args">The <see cref="ChildrenChangedEventArgs"/> instance containing the event data.</param>
+        private void UpdateLibraryCache(ChildrenChangedEventArgs args)
+        {
+            UpdateItemInLibraryCache(args.Folder);
+
+            foreach (var item in args.ItemsAdded)
+            {
+                UpdateItemInLibraryCache(item);
+            }
+
+            foreach (var item in args.ItemsUpdated)
+            {
+                UpdateItemInLibraryCache(item);
+            }
+        }
+
+        /// <summary>
+        /// Updates the item in library cache.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        private void UpdateItemInLibraryCache(BaseItem item)
+        {
+            LibraryItemsCache.AddOrUpdate(item.Id, item, delegate { return item; });
+
+            foreach (var trailer in item.LocalTrailers)
+            {
+                // Prevent access to foreach variable in closure
+                var trailer1 = trailer;
+                LibraryItemsCache.AddOrUpdate(trailer.Id, trailer, delegate { return trailer1; });
+            }
+
+            var movie = item as Movie;
+
+            if (movie != null)
+            {
+                foreach (var special in movie.SpecialFeatures)
+                {
+                    // Prevent access to foreach variable in closure
+                    Video special1 = special;
+                    LibraryItemsCache.AddOrUpdate(special.Id, special, delegate { return special1; });
+                }
+            }
+        }
+
         /// <summary>
         /// <summary>
         /// Resolves the item.
         /// Resolves the item.
         /// </summary>
         /// </summary>
@@ -647,11 +742,6 @@ namespace MediaBrowser.Server.Implementations.Library
 
 
             // Now validate the entire media library
             // Now validate the entire media library
             await RootFolder.ValidateChildren(progress, cancellationToken, recursive: true).ConfigureAwait(false);
             await RootFolder.ValidateChildren(progress, cancellationToken, recursive: true).ConfigureAwait(false);
-
-            //foreach (var user in _userManager.Users)
-            //{
-            //    await user.ValidateMediaLibrary(new Progress<double> { }, cancellationToken).ConfigureAwait(false);
-            //}
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -708,32 +798,6 @@ namespace MediaBrowser.Server.Implementations.Library
                 });
                 });
         }
         }
 
 
-        /// <summary>
-        /// Finds a library item by Id and UserId.
-        /// </summary>
-        /// <param name="id">The id.</param>
-        /// <param name="userId">The user id.</param>
-        /// <param name="userManager">The user manager.</param>
-        /// <returns>BaseItem.</returns>
-        /// <exception cref="System.ArgumentNullException">id</exception>
-        public BaseItem GetItemById(Guid id, Guid userId)
-        {
-            if (id == Guid.Empty)
-            {
-                throw new ArgumentNullException("id");
-            }
-
-            if (userId == Guid.Empty)
-            {
-                throw new ArgumentNullException("userId");
-            }
-
-            var user = _userManager.GetUserById(userId);
-            var userRoot = user.RootFolder;
-
-            return userRoot.FindItemById(id, user);
-        }
-
         /// <summary>
         /// <summary>
         /// Gets the item by id.
         /// Gets the item by id.
         /// </summary>
         /// </summary>
@@ -747,7 +811,11 @@ namespace MediaBrowser.Server.Implementations.Library
                 throw new ArgumentNullException("id");
                 throw new ArgumentNullException("id");
             }
             }
 
 
-            return RootFolder.FindItemById(id, null);
+            BaseItem item;
+
+            LibraryItemsCache.TryGetValue(id, out item);
+
+            return item;
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 2 - 4
MediaBrowser.Server.Implementations/Providers/ProviderManager.cs

@@ -236,7 +236,7 @@ namespace MediaBrowser.Server.Implementations.Providers
 
 
             cancellationToken.ThrowIfCancellationRequested();
             cancellationToken.ThrowIfCancellationRequested();
 
 
-            _logger.Info("Running {0} for {1}", provider.GetType().Name, item.Path ?? item.Name ?? "--Unknown--");
+            _logger.Debug("Running {0} for {1}", provider.GetType().Name, item.Path ?? item.Name ?? "--Unknown--");
 
 
             // This provides the ability to cancel just this one provider
             // This provides the ability to cancel just this one provider
             var innerCancellationTokenSource = new CancellationTokenSource();
             var innerCancellationTokenSource = new CancellationTokenSource();
@@ -249,7 +249,7 @@ namespace MediaBrowser.Server.Implementations.Providers
             }
             }
             catch (OperationCanceledException ex)
             catch (OperationCanceledException ex)
             {
             {
-                _logger.Info("{0} cancelled for {1}", provider.GetType().Name, item.Name);
+                _logger.Debug("{0} cancelled for {1}", provider.GetType().Name, item.Name);
 
 
                 // If the outer cancellation token is the one that caused the cancellation, throw it
                 // If the outer cancellation token is the one that caused the cancellation, throw it
                 if (cancellationToken.IsCancellationRequested && ex.CancellationToken == cancellationToken)
                 if (cancellationToken.IsCancellationRequested && ex.CancellationToken == cancellationToken)
@@ -325,8 +325,6 @@ namespace MediaBrowser.Server.Implementations.Providers
         /// </summary>
         /// </summary>
         private void ValidateCurrentlyRunningProviders()
         private void ValidateCurrentlyRunningProviders()
         {
         {
-            _logger.Info("Validing currently running providers");
-
             var enableInternetProviders = ConfigurationManager.Configuration.EnableInternetProviders;
             var enableInternetProviders = ConfigurationManager.Configuration.EnableInternetProviders;
             var internetProviderExcludeTypes = ConfigurationManager.Configuration.InternetProviderExcludeTypes;
             var internetProviderExcludeTypes = ConfigurationManager.Configuration.InternetProviderExcludeTypes;
 
 

+ 14 - 9
MediaBrowser.Server.Implementations/WorldWeatherOnline/WeatherProvider.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Net;
+using System.Globalization;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Weather;
 using MediaBrowser.Controller.Weather;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Serialization;
@@ -181,6 +182,8 @@ namespace MediaBrowser.Server.Implementations.WorldWeatherOnline
         /// <value>The weather code.</value>
         /// <value>The weather code.</value>
         public string weatherCode { get; set; }
         public string weatherCode { get; set; }
 
 
+        protected static readonly CultureInfo UsCulture = new CultureInfo("en-US");
+        
         /// <summary>
         /// <summary>
         /// To the weather status.
         /// To the weather status.
         /// </summary>
         /// </summary>
@@ -189,9 +192,9 @@ namespace MediaBrowser.Server.Implementations.WorldWeatherOnline
         {
         {
             return new WeatherStatus
             return new WeatherStatus
             {
             {
-                TemperatureCelsius = int.Parse(temp_C),
-                TemperatureFahrenheit = int.Parse(temp_F),
-                Humidity = int.Parse(humidity),
+                TemperatureCelsius = int.Parse(temp_C, UsCulture),
+                TemperatureFahrenheit = int.Parse(temp_F, UsCulture),
+                Humidity = int.Parse(humidity, UsCulture),
                 Condition = DailyWeatherInfo.GetCondition(weatherCode)
                 Condition = DailyWeatherInfo.GetCondition(weatherCode)
             };
             };
         }
         }
@@ -263,6 +266,8 @@ namespace MediaBrowser.Server.Implementations.WorldWeatherOnline
         /// <value>The windspeed miles.</value>
         /// <value>The windspeed miles.</value>
         public string windspeedMiles { get; set; }
         public string windspeedMiles { get; set; }
 
 
+        protected static readonly CultureInfo UsCulture = new CultureInfo("en-US");
+        
         /// <summary>
         /// <summary>
         /// To the weather forecast.
         /// To the weather forecast.
         /// </summary>
         /// </summary>
@@ -271,11 +276,11 @@ namespace MediaBrowser.Server.Implementations.WorldWeatherOnline
         {
         {
             return new WeatherForecast
             return new WeatherForecast
             {
             {
-                Date = DateTime.Parse(date),
-                HighTemperatureCelsius = int.Parse(tempMaxC),
-                HighTemperatureFahrenheit = int.Parse(tempMaxF),
-                LowTemperatureCelsius = int.Parse(tempMinC),
-                LowTemperatureFahrenheit = int.Parse(tempMinF),
+                Date = DateTime.Parse(date, UsCulture),
+                HighTemperatureCelsius = int.Parse(tempMaxC, UsCulture),
+                HighTemperatureFahrenheit = int.Parse(tempMaxF, UsCulture),
+                LowTemperatureCelsius = int.Parse(tempMinC, UsCulture),
+                LowTemperatureFahrenheit = int.Parse(tempMinF, UsCulture),
                 Condition = GetCondition(weatherCode)
                 Condition = GetCondition(weatherCode)
             };
             };
         }
         }

+ 3 - 0
MediaBrowser.sln

@@ -205,4 +205,7 @@ Global
 	GlobalSection(SolutionProperties) = preSolution
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 		HideSolutionNode = FALSE
 	EndGlobalSection
 	EndGlobalSection
+	GlobalSection(Performance) = preSolution
+		HasPerformanceSessions = true
+	EndGlobalSection
 EndGlobal
 EndGlobal