From 9f06eb781f5992496a7b1a59fb55b0aa6520261f Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 31 Mar 2013 13:39:28 -0400 Subject: [PATCH] fixes #97 and creates a library dictionary cache to avoid FindById recursion --- MediaBrowser.Api/Images/ImageService.cs | 5 +- MediaBrowser.Api/UserLibrary/GenresService.cs | 2 +- MediaBrowser.Api/UserLibrary/ItemsService.cs | 2 +- .../UserLibrary/UserLibraryService.cs | 21 +-- .../HttpClientManager/HttpClientManager.cs | 7 +- .../NetworkManagement/NetworkManager.cs | 5 +- .../Net/BasePeriodicWebSocketListener.cs | 9 +- MediaBrowser.Controller/Entities/BaseItem.cs | 27 ---- MediaBrowser.Controller/Entities/Folder.cs | 36 +---- .../Entities/Movies/Movie.cs | 25 +--- .../Extensions/XmlExtensions.cs | 1 - MediaBrowser.Controller/Library/DtoBuilder.cs | 16 ++- .../Library/ILibraryManager.cs | 8 -- .../MediaInfo/BaseFFProbeProvider.cs | 15 +- .../MediaInfo/FFProbeAudioInfoProvider.cs | 2 +- .../MediaInfo/FFProbeVideoInfoProvider.cs | 2 +- .../HttpServer/HttpServer.cs | 4 +- .../HttpServer/RangeRequestWriter.cs | 4 +- .../Library/LibraryManager.cs | 136 +++++++++++++----- .../Providers/ProviderManager.cs | 6 +- .../WorldWeatherOnline/WeatherProvider.cs | 23 +-- MediaBrowser.sln | 3 + 22 files changed, 182 insertions(+), 177 deletions(-) diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 8498292da6..cb26688e39 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -160,11 +160,12 @@ namespace MediaBrowser.Api.Images /// The _library manager /// private readonly ILibraryManager _libraryManager; - + /// /// Initializes a new instance of the class. /// /// The user manager. + /// The library manager. public ImageService(IUserManager userManager, ILibraryManager libraryManager) { _userManager = userManager; @@ -178,7 +179,7 @@ namespace MediaBrowser.Api.Images /// System.Object. 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); } diff --git a/MediaBrowser.Api/UserLibrary/GenresService.cs b/MediaBrowser.Api/UserLibrary/GenresService.cs index 1962dff5c9..5957c7ce69 100644 --- a/MediaBrowser.Api/UserLibrary/GenresService.cs +++ b/MediaBrowser.Api/UserLibrary/GenresService.cs @@ -13,7 +13,7 @@ namespace MediaBrowser.Api.UserLibrary /// [Route("/Users/{UserId}/Items/{ParentId}/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 { } diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index a8a9109c1b..77b991a546 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -55,7 +55,7 @@ namespace MediaBrowser.Api.UserLibrary /// Filters to apply to the results /// /// The filters. - [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; } /// diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs index 3e0f249991..5c9c8e1f39 100644 --- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs +++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs @@ -378,7 +378,7 @@ namespace MediaBrowser.Api.UserLibrary { 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 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 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 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 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 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 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); @@ -480,12 +480,13 @@ namespace MediaBrowser.Api.UserLibrary 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 var displayPreferences = _jsonSerializer.DeserializeFromString(_jsonSerializer.SerializeToString(request)); - var task = _libraryManager.SaveDisplayPreferencesForFolder(user, item, displayPreferences); + var task = _libraryManager.SaveDisplayPreferencesForFolder(user, folder, displayPreferences); Task.WaitAll(task); } @@ -498,7 +499,7 @@ namespace MediaBrowser.Api.UserLibrary { 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 var data = item.GetUserData(user, true); @@ -519,7 +520,7 @@ namespace MediaBrowser.Api.UserLibrary { 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 var data = item.GetUserData(user, true); @@ -540,7 +541,7 @@ namespace MediaBrowser.Api.UserLibrary { 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 var data = item.GetUserData(user, true); @@ -560,7 +561,7 @@ namespace MediaBrowser.Api.UserLibrary { 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 var data = item.GetUserData(user, true); diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs index 0e96966480..8508fcdf50 100644 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/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.IO; using MediaBrowser.Common.Net; @@ -216,6 +217,8 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager return GetTempFile(options, tempFile, 0); } + protected static readonly CultureInfo UsCulture = new CultureInfo("en-US"); + /// /// Gets the temp file. /// @@ -278,7 +281,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager } 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)) { diff --git a/MediaBrowser.Common.Implementations/NetworkManagement/NetworkManager.cs b/MediaBrowser.Common.Implementations/NetworkManagement/NetworkManager.cs index 513339eef5..d88b57be56 100644 --- a/MediaBrowser.Common.Implementations/NetworkManagement/NetworkManager.cs +++ b/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.Model.Net; using System; @@ -343,6 +344,8 @@ namespace MediaBrowser.Common.Implementations.NetworkManagement return new IPEndPoint(ipaddy, port); } + protected static readonly CultureInfo UsCulture = new CultureInfo("en-US"); + /// /// Gets the port. /// diff --git a/MediaBrowser.Common/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Common/Net/BasePeriodicWebSocketListener.cs index a8e8d7a8cd..4ff34cfa12 100644 --- a/MediaBrowser.Common/Net/BasePeriodicWebSocketListener.cs +++ b/MediaBrowser.Common/Net/BasePeriodicWebSocketListener.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Model.Logging; +using System.Globalization; +using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; using System.Linq; @@ -80,6 +81,8 @@ namespace MediaBrowser.Common.Net return NullTaskResult; } + protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); + /// /// Starts sending messages over a web socket /// @@ -88,8 +91,8 @@ namespace MediaBrowser.Common.Net { 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(); diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 474d14ee1d..d30f11f7d9 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -950,33 +950,6 @@ namespace MediaBrowser.Controller.Entities return IsParentalAllowed(user); } - /// - /// Finds an item by ID, recursively - /// - /// The id. - /// The user. - /// BaseItem. - /// id - 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; - } - /// /// Finds the particular item by searching through our parents and, if not found there, loading from repo /// diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 83f29e58b4..5a61844c2b 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -673,7 +673,7 @@ namespace MediaBrowser.Controller.Entities foreach (var item in changedArgs.ItemsRemoved) { - Logger.Info("** " + item.Name + " Removed from library."); + Logger.Debug("** " + item.Name + " Removed from library."); } var childrenReplaced = false; @@ -688,7 +688,7 @@ namespace MediaBrowser.Controller.Entities foreach (var item in changedArgs.ItemsAdded) { - Logger.Info("** " + item.Name + " Added to library."); + Logger.Debug("** " + item.Name + " Added to library."); if (!childrenReplaced) { @@ -701,7 +701,7 @@ namespace MediaBrowser.Controller.Entities await Task.WhenAll(saveTasks).ConfigureAwait(false); //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); } @@ -913,36 +913,6 @@ namespace MediaBrowser.Controller.Entities await Task.WhenAll(tasks).ConfigureAwait(false); } - /// - /// Finds an item by ID, recursively - /// - /// The id. - /// The user. - /// BaseItem. - 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; - } - /// /// Finds an item by path, recursively /// diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index 5d8ada21f7..a9dfde7f9e 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -118,30 +118,7 @@ namespace MediaBrowser.Controller.Entities.Movies cancellationToken.ThrowIfCancellationRequested(); return result; - } - - /// - /// Finds an item by ID, recursively - /// - /// The id. - /// The user. - /// BaseItem. - 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; - } + } /// /// Loads special features from the file system diff --git a/MediaBrowser.Controller/Extensions/XmlExtensions.cs b/MediaBrowser.Controller/Extensions/XmlExtensions.cs index 00bee7d1d5..8698730d46 100644 --- a/MediaBrowser.Controller/Extensions/XmlExtensions.cs +++ b/MediaBrowser.Controller/Extensions/XmlExtensions.cs @@ -191,7 +191,6 @@ namespace MediaBrowser.Controller.Extensions if (!string.IsNullOrWhiteSpace(valueString)) { - int.TryParse(valueString, out value); } diff --git a/MediaBrowser.Controller/Library/DtoBuilder.cs b/MediaBrowser.Controller/Library/DtoBuilder.cs index c3102ab64c..36c7eba1fb 100644 --- a/MediaBrowser.Controller/Library/DtoBuilder.cs +++ b/MediaBrowser.Controller/Library/DtoBuilder.cs @@ -809,15 +809,19 @@ namespace MediaBrowser.Controller.Library /// Gets a BaseItem based upon it's client-side item id /// /// The id. + /// The user manager. + /// The library manager. /// The user id. /// BaseItem. 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 - var isIndexFolder = !isIdEmpty && - id.IndexOf(IndexFolderDelimeter, StringComparison.OrdinalIgnoreCase) != -1; + var isIndexFolder = id.IndexOf(IndexFolderDelimeter, StringComparison.OrdinalIgnoreCase) != -1; if (isIndexFolder) { @@ -831,9 +835,7 @@ namespace MediaBrowser.Controller.Library 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) { @@ -862,6 +864,8 @@ namespace MediaBrowser.Controller.Library /// /// The id. /// The user id. + /// The user manager. + /// The library manager. /// BaseItem. private static BaseItem GetIndexFolder(string id, Guid userId, IUserManager userManager, ILibraryManager libraryManager) { diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 84a39db691..1b9d2f4b2a 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -136,14 +136,6 @@ namespace MediaBrowser.Controller.Library /// BaseItem. BaseItem GetItemById(Guid id); - /// - /// Gets the item by id. - /// - /// The id. - /// The user id. - /// BaseItem. - BaseItem GetItemById(Guid id, Guid userId); - /// /// Gets the intros. /// diff --git a/MediaBrowser.Controller/Providers/MediaInfo/BaseFFProbeProvider.cs b/MediaBrowser.Controller/Providers/MediaInfo/BaseFFProbeProvider.cs index e616118288..a465adeb6c 100644 --- a/MediaBrowser.Controller/Providers/MediaInfo/BaseFFProbeProvider.cs +++ b/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.Entities; using MediaBrowser.Controller.MediaInfo; @@ -61,6 +62,8 @@ namespace MediaBrowser.Controller.Providers.MediaInfo get { return MetadataProviderPriority.Second; } } + protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); + /// /// Fetches metadata and returns true or false indicating if any work that requires persistence was done /// @@ -203,7 +206,7 @@ namespace MediaBrowser.Controller.Providers.MediaInfo 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)) @@ -227,12 +230,12 @@ namespace MediaBrowser.Controller.Providers.MediaInfo { 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)) { // 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) { - result = float.Parse(parts[0])/float.Parse(parts[1]); + result = float.Parse(parts[0], UsCulture) / float.Parse(parts[1], UsCulture); } else { - result = float.Parse(parts[0]); + result = float.Parse(parts[0], UsCulture); } return float.IsNaN(result) ? (float?)null : result; diff --git a/MediaBrowser.Controller/Providers/MediaInfo/FFProbeAudioInfoProvider.cs b/MediaBrowser.Controller/Providers/MediaInfo/FFProbeAudioInfoProvider.cs index 603b7dcaae..a7cc4985b0 100644 --- a/MediaBrowser.Controller/Providers/MediaInfo/FFProbeAudioInfoProvider.cs +++ b/MediaBrowser.Controller/Providers/MediaInfo/FFProbeAudioInfoProvider.cs @@ -69,7 +69,7 @@ namespace MediaBrowser.Controller.Providers.MediaInfo // If we got something, parse it 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) diff --git a/MediaBrowser.Controller/Providers/MediaInfo/FFProbeVideoInfoProvider.cs b/MediaBrowser.Controller/Providers/MediaInfo/FFProbeVideoInfoProvider.cs index 06692b2bc1..957000ae29 100644 --- a/MediaBrowser.Controller/Providers/MediaInfo/FFProbeVideoInfoProvider.cs +++ b/MediaBrowser.Controller/Providers/MediaInfo/FFProbeVideoInfoProvider.cs @@ -198,7 +198,7 @@ namespace MediaBrowser.Controller.Providers.MediaInfo 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; } } diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs index 681b08825d..edb227c799 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs @@ -127,6 +127,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer EndpointHostConfig.Instance.MetadataRedirectPath = "metadata"; } + protected static readonly CultureInfo UsCulture = new CultureInfo("en-US"); + /// /// Configures the specified container. /// @@ -184,7 +186,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer 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) { diff --git a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs index a355a2db52..24292f0a14 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs @@ -139,11 +139,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer if (!string.IsNullOrEmpty(vals[0])) { - start = long.Parse(vals[0]); + start = long.Parse(vals[0], UsCulture); } if (!string.IsNullOrEmpty(vals[1])) { - end = long.Parse(vals[1]); + end = long.Parse(vals[1], UsCulture); } _requestedRanges.Add(new KeyValuePair(start, end)); diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index cf12d6ad57..303580a496 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -4,6 +4,7 @@ using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Resolvers; @@ -73,6 +74,8 @@ namespace MediaBrowser.Server.Implementations.Library /// The instance containing the event data. public void ReportLibraryChanged(ChildrenChangedEventArgs args) { + UpdateLibraryCache(args); + EventHelper.QueueEventIfNotNull(LibraryChanged, this, args, _logger); } #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 /// single instance. /// - private ConcurrentDictionary ByReferenceItems { get; set; } + private ConcurrentDictionary ByReferenceItems { get; set; } + + private ConcurrentDictionary _libraryItemsCache; + private object _libraryItemsCacheSyncLock = new object(); + private bool _libraryItemsCacheInitialized; + private ConcurrentDictionary LibraryItemsCache + { + get + { + LazyInitializer.EnsureInitialized(ref _libraryItemsCache, ref _libraryItemsCacheInitialized, ref _libraryItemsCacheSyncLock, CreateLibraryItemsCache); + return _libraryItemsCache; + } + set + { + _libraryItemsCache = value; + + if (value == null) + { + _libraryItemsCacheInitialized = false; + } + } + } /// /// Initializes a new instance of the 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 _taskManager.CancelIfRunningAndQueue(); - + if (refreshPeopleAfterUpdate) { _taskManager.CancelIfRunningAndQueue(); @@ -227,6 +251,77 @@ namespace MediaBrowser.Server.Implementations.Library }); } + /// + /// Creates the library items cache. + /// + /// ConcurrentDictionary{GuidBaseItem}. + private ConcurrentDictionary CreateLibraryItemsCache() + { + var items = RootFolder.RecursiveChildren.ToList(); + + items.Add(RootFolder); + + var specialFeatures = items.OfType().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(items.ToDictionary(i => i.Id)); + } + + /// + /// Updates the library cache. + /// + /// The instance containing the event data. + private void UpdateLibraryCache(ChildrenChangedEventArgs args) + { + UpdateItemInLibraryCache(args.Folder); + + foreach (var item in args.ItemsAdded) + { + UpdateItemInLibraryCache(item); + } + + foreach (var item in args.ItemsUpdated) + { + UpdateItemInLibraryCache(item); + } + } + + /// + /// Updates the item in library cache. + /// + /// The item. + 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; }); + } + } + } + /// /// Resolves the item. /// @@ -647,11 +742,6 @@ namespace MediaBrowser.Server.Implementations.Library // Now validate the entire media library await RootFolder.ValidateChildren(progress, cancellationToken, recursive: true).ConfigureAwait(false); - - //foreach (var user in _userManager.Users) - //{ - // await user.ValidateMediaLibrary(new Progress { }, cancellationToken).ConfigureAwait(false); - //} } /// @@ -708,32 +798,6 @@ namespace MediaBrowser.Server.Implementations.Library }); } - /// - /// Finds a library item by Id and UserId. - /// - /// The id. - /// The user id. - /// The user manager. - /// BaseItem. - /// id - 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); - } - /// /// Gets the item by id. /// @@ -747,7 +811,11 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentNullException("id"); } - return RootFolder.FindItemById(id, null); + BaseItem item; + + LibraryItemsCache.TryGetValue(id, out item); + + return item; } /// diff --git a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs index a8239deb41..df6e061742 100644 --- a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs +++ b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs @@ -236,7 +236,7 @@ namespace MediaBrowser.Server.Implementations.Providers 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 var innerCancellationTokenSource = new CancellationTokenSource(); @@ -249,7 +249,7 @@ namespace MediaBrowser.Server.Implementations.Providers } 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 (cancellationToken.IsCancellationRequested && ex.CancellationToken == cancellationToken) @@ -325,8 +325,6 @@ namespace MediaBrowser.Server.Implementations.Providers /// private void ValidateCurrentlyRunningProviders() { - _logger.Info("Validing currently running providers"); - var enableInternetProviders = ConfigurationManager.Configuration.EnableInternetProviders; var internetProviderExcludeTypes = ConfigurationManager.Configuration.InternetProviderExcludeTypes; diff --git a/MediaBrowser.Server.Implementations/WorldWeatherOnline/WeatherProvider.cs b/MediaBrowser.Server.Implementations/WorldWeatherOnline/WeatherProvider.cs index ae8b1ff974..195bfeee3b 100644 --- a/MediaBrowser.Server.Implementations/WorldWeatherOnline/WeatherProvider.cs +++ b/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.Model.Logging; using MediaBrowser.Model.Serialization; @@ -181,6 +182,8 @@ namespace MediaBrowser.Server.Implementations.WorldWeatherOnline /// The weather code. public string weatherCode { get; set; } + protected static readonly CultureInfo UsCulture = new CultureInfo("en-US"); + /// /// To the weather status. /// @@ -189,9 +192,9 @@ namespace MediaBrowser.Server.Implementations.WorldWeatherOnline { 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) }; } @@ -263,6 +266,8 @@ namespace MediaBrowser.Server.Implementations.WorldWeatherOnline /// The windspeed miles. public string windspeedMiles { get; set; } + protected static readonly CultureInfo UsCulture = new CultureInfo("en-US"); + /// /// To the weather forecast. /// @@ -271,11 +276,11 @@ namespace MediaBrowser.Server.Implementations.WorldWeatherOnline { 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) }; } diff --git a/MediaBrowser.sln b/MediaBrowser.sln index e5ccebc7bd..c3a809c3fc 100644 --- a/MediaBrowser.sln +++ b/MediaBrowser.sln @@ -205,4 +205,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection EndGlobal