From e2d6a5c05df874cb812cbc0b85e7deda22ce567a Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 17 May 2013 14:05:49 -0400 Subject: [PATCH 1/8] support static trailer streaming --- MediaBrowser.Api/MediaBrowser.Api.csproj | 3 + .../Playback/BaseStreamingService.cs | 19 ++++- .../BaseProgressiveStreamingService.cs | 64 +++++++++++++++- .../Playback/StaticRemoteStreamWriter.cs | 75 +++++++++++++++++++ .../UserLibrary/BaseItemsByNameService.cs | 2 +- MediaBrowser.Api/UserLibrary/ItemsService.cs | 2 +- .../HttpClientManager/HttpClientManager.cs | 2 +- .../Providers/TV/SeriesXmlParser.cs | 11 ++- .../Session/ISessionManager.cs | 2 +- .../Session/SessionManager.cs | 37 +++++---- 10 files changed, 195 insertions(+), 22 deletions(-) create mode 100644 MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index 2819a649aa..fb06e35ea3 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -56,6 +56,8 @@ + + @@ -82,6 +84,7 @@ + diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 04b6a656d5..19b339cd74 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -621,10 +621,27 @@ namespace MediaBrowser.Api.Playback /// The item. /// System.String. protected string GetUserAgentParam(BaseItem item) + { + var useragent = GetUserAgent(item); + + if (!string.IsNullOrEmpty(useragent)) + { + return "-user-agent \"" + useragent + "\""; + } + + return string.Empty; + } + + /// + /// Gets the user agent. + /// + /// The item. + /// System.String. + protected string GetUserAgent(BaseItem item) { if (item.Path.IndexOf("apple.com", StringComparison.OrdinalIgnoreCase) != -1) { - return "-user-agent \"QuickTime/7.6.2\""; + return "QuickTime/7.6.2"; } return string.Empty; diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index 9bcce87c89..50a0c9accd 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -1,4 +1,7 @@ -using MediaBrowser.Api.Images; +using System.Net; +using System.Net.Cache; +using System.Net.Http; +using MediaBrowser.Api.Images; using MediaBrowser.Common.IO; using MediaBrowser.Common.MediaInfo; using MediaBrowser.Common.Net; @@ -188,6 +191,11 @@ namespace MediaBrowser.Api.Playback.Progressive var responseHeaders = new Dictionary(); + if (request.Static && state.Item.LocationType == LocationType.Remote) + { + return GetStaticRemoteStreamResult(state.Item, responseHeaders, isHeadRequest).Result; + } + var outputPath = GetOutputFilePath(state); var outputPathExists = File.Exists(outputPath); @@ -209,6 +217,60 @@ namespace MediaBrowser.Api.Playback.Progressive return GetStreamResult(state, responseHeaders, isHeadRequest).Result; } + /// + /// Gets the static remote stream result. + /// + /// The item. + /// The response headers. + /// if set to true [is head request]. + /// Task{System.Object}. + private async Task GetStaticRemoteStreamResult(BaseItem item, Dictionary responseHeaders, bool isHeadRequest) + { + responseHeaders["Accept-Ranges"] = "none"; + + var httpClient = new HttpClient(new WebRequestHandler + { + CachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache), + AutomaticDecompression = DecompressionMethods.None + }); + + using (var message = new HttpRequestMessage(HttpMethod.Get, item.Path)) + { + var useragent = GetUserAgent(item); + + if (!string.IsNullOrEmpty(useragent)) + { + message.Headers.Add("User-Agent", useragent); + } + + var response = await httpClient.SendAsync(message, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false); + + response.EnsureSuccessStatusCode(); + + var contentType = response.Content.Headers.ContentType.MediaType; + + // Headers only + if (isHeadRequest) + { + response.Dispose(); + + return ResultFactory.GetResult(null, contentType, responseHeaders); + } + + var result = new StaticRemoteStreamWriter(response, httpClient); + + result.Options["Content-Type"] = contentType; + + // Add the response headers to the result object + foreach (var header in responseHeaders) + { + result.Options[header.Key] = header.Value; + } + + return result; + } + } + /// /// Gets the album art response. /// diff --git a/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs b/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs new file mode 100644 index 0000000000..89e13acb38 --- /dev/null +++ b/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs @@ -0,0 +1,75 @@ +using ServiceStack.Service; +using ServiceStack.ServiceHost; +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using System.Threading.Tasks; + +namespace MediaBrowser.Api.Playback +{ + /// + /// Class StaticRemoteStreamWriter + /// + public class StaticRemoteStreamWriter : IStreamWriter, IHasOptions + { + /// + /// The _input stream + /// + private readonly HttpResponseMessage _msg; + + private readonly HttpClient _client; + + /// + /// The _options + /// + private readonly IDictionary _options = new Dictionary(); + + /// + /// Initializes a new instance of the class. + /// + public StaticRemoteStreamWriter(HttpResponseMessage msg, HttpClient client) + { + _msg = msg; + _client = client; + } + + /// + /// Gets the options. + /// + /// The options. + public IDictionary Options + { + get { return _options; } + } + + /// + /// Writes to. + /// + /// The response stream. + public void WriteTo(Stream responseStream) + { + var task = WriteToAsync(responseStream); + + Task.WaitAll(task); + } + + /// + /// Writes to async. + /// + /// The response stream. + /// Task. + public async Task WriteToAsync(Stream responseStream) + { + using (_client) + { + using (_msg) + { + using (var input = await _msg.Content.ReadAsStreamAsync().ConfigureAwait(false)) + { + await input.CopyToAsync(responseStream).ConfigureAwait(false); + } + } + } + } + } +} diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs index 22098a368e..26b0aa1921 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs @@ -135,7 +135,7 @@ namespace MediaBrowser.Api.UserLibrary { if (!string.IsNullOrEmpty(request.NameStartsWithOrGreater)) { - items = items.Where(i => string.Compare(request.NameStartsWithOrGreater, i.Name, StringComparison.OrdinalIgnoreCase) < 1); + items = items.Where(i => string.Compare(request.NameStartsWithOrGreater, i.Name, StringComparison.CurrentCultureIgnoreCase) < 1); } var filters = request.GetFilters().ToList(); diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index c57778fd65..fbf41eb38a 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -456,7 +456,7 @@ namespace MediaBrowser.Api.UserLibrary if (!string.IsNullOrEmpty(request.NameStartsWithOrGreater)) { - items = items.Where(i => string.Compare(request.NameStartsWithOrGreater, i.SortName, StringComparison.OrdinalIgnoreCase) < 1); + items = items.Where(i => string.Compare(request.NameStartsWithOrGreater, i.SortName, StringComparison.CurrentCultureIgnoreCase) < 1); } // Filter by Series Status diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs index 4c51d1299a..82a91fa46a 100644 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs @@ -97,7 +97,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager }; client = new HttpClient(handler); - client.Timeout = TimeSpan.FromSeconds(30); + client.Timeout = TimeSpan.FromSeconds(15); _httpClients.TryAdd(host, client); } diff --git a/MediaBrowser.Controller/Providers/TV/SeriesXmlParser.cs b/MediaBrowser.Controller/Providers/TV/SeriesXmlParser.cs index f63a47627e..c03e2a7f5e 100644 --- a/MediaBrowser.Controller/Providers/TV/SeriesXmlParser.cs +++ b/MediaBrowser.Controller/Providers/TV/SeriesXmlParser.cs @@ -63,8 +63,15 @@ namespace MediaBrowser.Controller.Providers.TV } case "Airs_Time": - item.AirTime = reader.ReadElementContentAsString(); - break; + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + item.AirTime = val; + } + break; + } case "SeriesName": item.Name = reader.ReadElementContentAsString(); diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index 8227170d41..f28721f5ff 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -52,7 +52,7 @@ namespace MediaBrowser.Controller.Session /// The device id. /// Name of the device. /// - void OnPlaybackStart(User user, BaseItem item, string clientType, string deviceId, string deviceName); + Task OnPlaybackStart(User user, BaseItem item, string clientType, string deviceId, string deviceName); /// /// Used to report playback progress for an item diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index 2f9c7e3895..d3dbbc62b8 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -200,7 +200,7 @@ namespace MediaBrowser.Server.Implementations.Session /// Name of the device. /// /// - public void OnPlaybackStart(User user, BaseItem item, string clientType, string deviceId, string deviceName) + public async Task OnPlaybackStart(User user, BaseItem item, string clientType, string deviceId, string deviceName) { if (user == null) { @@ -213,6 +213,15 @@ namespace MediaBrowser.Server.Implementations.Session UpdateNowPlayingItemId(user, clientType, deviceId, deviceName, item, false); + var key = item.GetUserDataKey(); + + var data = await _userDataRepository.GetUserData(user.Id, key).ConfigureAwait(false); + + data.PlayCount++; + data.LastPlayedDate = DateTime.UtcNow; + + await _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None).ConfigureAwait(false); + // Nothing to save here // Fire events to inform plugins EventHelper.QueueEventIfNotNull(PlaybackStart, this, new PlaybackProgressEventArgs @@ -254,7 +263,7 @@ namespace MediaBrowser.Server.Implementations.Session { var data = await _userDataRepository.GetUserData(user.Id, key).ConfigureAwait(false); - UpdatePlayState(item, data, positionTicks.Value, false); + UpdatePlayState(item, data, positionTicks.Value); await _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None).ConfigureAwait(false); } @@ -297,7 +306,7 @@ namespace MediaBrowser.Server.Implementations.Session if (positionTicks.HasValue) { - UpdatePlayState(item, data, positionTicks.Value, true); + UpdatePlayState(item, data, positionTicks.Value); } else { @@ -322,11 +331,12 @@ namespace MediaBrowser.Server.Implementations.Session /// The item /// User data for the item /// The current playback position - /// Whether or not to increment playcount - private void UpdatePlayState(BaseItem item, UserItemData data, long positionTicks, bool incrementPlayCount) + private void UpdatePlayState(BaseItem item, UserItemData data, long positionTicks) { + var hasRuntime = item.RunTimeTicks.HasValue && item.RunTimeTicks > 0; + // If a position has been reported, and if we know the duration - if (positionTicks > 0 && item.RunTimeTicks.HasValue && item.RunTimeTicks > 0) + if (positionTicks > 0 && hasRuntime) { var pctIn = Decimal.Divide(positionTicks, item.RunTimeTicks.Value) * 100; @@ -334,7 +344,6 @@ namespace MediaBrowser.Server.Implementations.Session if (pctIn < _configurationManager.Configuration.MinResumePct) { positionTicks = 0; - incrementPlayCount = false; } // If we're at the end, assume completed @@ -356,19 +365,19 @@ namespace MediaBrowser.Server.Implementations.Session } } } + else if (!hasRuntime) + { + // If we don't know the runtime we'll just have to assume it was fully played + data.Played = true; + positionTicks = 0; + } if (item is Audio) { - data.PlaybackPositionTicks = 0; + positionTicks = 0; } data.PlaybackPositionTicks = positionTicks; - - if (incrementPlayCount) - { - data.PlayCount++; - data.LastPlayedDate = DateTime.UtcNow; - } } } } From 032bf6b8c6541a54632eb741609619879b11c9c7 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 17 May 2013 15:18:54 -0400 Subject: [PATCH 2/8] record original runtime --- .../Playback/Progressive/BaseProgressiveStreamingService.cs | 1 + MediaBrowser.Controller/Entities/BaseItem.cs | 5 +++++ MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs | 4 ++-- Nuget/MediaBrowser.Common.Internal.nuspec | 4 ++-- Nuget/MediaBrowser.Common.nuspec | 2 +- Nuget/MediaBrowser.Server.Core.nuspec | 4 ++-- 6 files changed, 13 insertions(+), 7 deletions(-) diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index 50a0c9accd..ab1fb4f903 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -253,6 +253,7 @@ namespace MediaBrowser.Api.Playback.Progressive if (isHeadRequest) { response.Dispose(); + httpClient.Dispose(); return ResultFactory.GetResult(null, contentType, responseHeaders); } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index a0dba1aab4..ca3ef7fac5 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -646,6 +646,11 @@ namespace MediaBrowser.Controller.Entities /// The run time ticks. public long? RunTimeTicks { get; set; } + /// + /// Gets or sets the original run time ticks. + /// + /// The original run time ticks. + public long? OriginalRunTimeTicks { get; set; } /// /// Gets or sets the aspect ratio. /// diff --git a/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs index 307db023fa..38d80883a8 100644 --- a/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs +++ b/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs @@ -973,8 +973,8 @@ namespace MediaBrowser.Controller.Providers.Movies boxset.OfficialRating = firstChild != null ? firstChild.OfficialRating : null; } - //if (movie.RunTimeTicks == null && movieData.runtime > 0) - // movie.RunTimeTicks = TimeSpan.FromMinutes(movieData.runtime).Ticks; + if (movieData.runtime > 0) + movie.OriginalRunTimeTicks = TimeSpan.FromMinutes(movieData.runtime).Ticks; //studios if (movieData.production_companies != null) diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index cbe918ddf0..13b1bae99b 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.103 + 3.0.104 MediaBrowser.Common.Internal Luke ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains common components shared by Media Browser Theatre and Media Browser Server. Not intended for plugin developer consumption. Copyright © Media Browser 2013 - + diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index 00ba0028f9..a8530230c3 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.103 + 3.0.104 MediaBrowser.Common Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index a2dee313d7..8236cd6333 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.103 + 3.0.104 Media Browser.Server.Core Media Browser Team ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains core components required to build plugins for Media Browser Server. Copyright © Media Browser 2013 - + From 4cd7030248ae26e48f43a7557cab5893f50c3d74 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 18 May 2013 13:07:20 -0400 Subject: [PATCH 3/8] fixed image uploading for virtual items --- MediaBrowser.Api/Images/ImageService.cs | 11 ++++++++--- .../Providers/BaseItemXmlParser.cs | 8 ++++---- MediaBrowser.Controller/Resolvers/ResolverPriority.cs | 3 ++- .../Providers/ProviderManager.cs | 2 +- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 3f5b9da2a1..51608a899e 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -361,7 +361,7 @@ namespace MediaBrowser.Api.Images index++; } - + index = 0; foreach (var image in item.ScreenshotImagePaths) @@ -422,7 +422,7 @@ namespace MediaBrowser.Api.Images return list; } - + /// /// Gets the specified request. /// @@ -765,7 +765,7 @@ namespace MediaBrowser.Api.Images } // Don't save locally if there's no parent (special feature, trailer, etc) - var saveLocally = (!(entity is Audio) && entity.Parent != null && !string.IsNullOrEmpty(entity.MetaLocation)) || entity is User; + var saveLocally = !(entity is Audio) && entity.Parent != null && !string.IsNullOrEmpty(entity.MetaLocation) || entity is User; if (imageType != ImageType.Primary) { @@ -775,6 +775,11 @@ namespace MediaBrowser.Api.Images } } + if (entity.LocationType != LocationType.FileSystem) + { + saveLocally = false; + } + var imagePath = _providerManager.GetSavePath(entity, filename + "." + extension, saveLocally); // Save to file system diff --git a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs index 65ec6899fc..60a2c19a79 100644 --- a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs +++ b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs @@ -325,7 +325,7 @@ namespace MediaBrowser.Controller.Providers if (!string.IsNullOrWhiteSpace(val)) { - item.AddTrailerUrl(val); + //item.AddTrailerUrl(val); } break; } @@ -336,10 +336,10 @@ namespace MediaBrowser.Controller.Providers if (!string.IsNullOrWhiteSpace(val)) { - int ProductionYear; - if (int.TryParse(val, out ProductionYear) && ProductionYear > 1850) + int productionYear; + if (int.TryParse(val, out productionYear) && productionYear > 1850) { - item.ProductionYear = ProductionYear; + item.ProductionYear = productionYear; } } diff --git a/MediaBrowser.Controller/Resolvers/ResolverPriority.cs b/MediaBrowser.Controller/Resolvers/ResolverPriority.cs index 63a107fda6..df5edeb05f 100644 --- a/MediaBrowser.Controller/Resolvers/ResolverPriority.cs +++ b/MediaBrowser.Controller/Resolvers/ResolverPriority.cs @@ -18,9 +18,10 @@ namespace MediaBrowser.Controller.Resolvers /// The third /// Third = 3, + Fourth = 4, /// /// The last /// - Last = 4 + Last = 5 } } diff --git a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs index b0a0f8760d..cc586ccbf9 100644 --- a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs +++ b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs @@ -408,7 +408,7 @@ namespace MediaBrowser.Server.Implementations.Providers { return (saveLocally && item.MetaLocation != null) ? Path.Combine(item.MetaLocation, targetFileName) : - _remoteImageCache.GetResourcePath(item.GetType().FullName + item.Path.ToLower(), targetFileName); + _remoteImageCache.GetResourcePath(item.GetType().FullName + item.Id.ToString(), targetFileName); } /// From 4c971ed1615c2a1f5a88e4f160672718fe24f1b4 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 18 May 2013 14:16:07 -0400 Subject: [PATCH 4/8] fixes #281 - Metadata images incomplete --- .../ImageFromMediaLocationProvider.cs | 7 +- .../Providers/TV/RemoteEpisodeProvider.cs | 58 +++---- .../Providers/TV/RemoteSeriesProvider.cs | 157 ++++++------------ 3 files changed, 75 insertions(+), 147 deletions(-) diff --git a/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs b/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs index 3e8501dfaf..6e14682ddc 100644 --- a/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs +++ b/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs @@ -91,12 +91,13 @@ namespace MediaBrowser.Controller.Providers } // 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 = item.Images.Keys.Where(image => + var deletedKeys = item.Images.ToList().Where(image => { - var path = item.Images[image]; + var path = image.Value; return IsInMetaLocation(item, path) && item.ResolveArgs.GetMetaFileByPath(path) == null; - }).ToList(); + + }).Select(i => i.Key).ToList(); // Now remove them from the dictionary foreach (var key in deletedKeys) diff --git a/MediaBrowser.Controller/Providers/TV/RemoteEpisodeProvider.cs b/MediaBrowser.Controller/Providers/TV/RemoteEpisodeProvider.cs index 2b4173ed90..b6852e9ba1 100644 --- a/MediaBrowser.Controller/Providers/TV/RemoteEpisodeProvider.cs +++ b/MediaBrowser.Controller/Providers/TV/RemoteEpisodeProvider.cs @@ -46,11 +46,11 @@ namespace MediaBrowser.Controller.Providers.TV /// /// The episode query /// - private const string episodeQuery = "http://www.thetvdb.com/api/{0}/series/{1}/default/{2}/{3}/{4}.xml"; + private const string EpisodeQuery = "http://www.thetvdb.com/api/{0}/series/{1}/default/{2}/{3}/{4}.xml"; /// /// The abs episode query /// - private const string absEpisodeQuery = "http://www.thetvdb.com/api/{0}/series/{1}/absolute/{2}/{3}.xml"; + private const string AbsEpisodeQuery = "http://www.thetvdb.com/api/{0}/series/{1}/absolute/{2}/{3}.xml"; /// /// Supportses the specified item. @@ -179,11 +179,28 @@ namespace MediaBrowser.Controller.Providers.TV seasonNumber = "0"; // Specials } - var url = string.Format(episodeQuery, TVUtils.TvdbApiKey, seriesId, seasonNumber, episodeNumber, ConfigurationManager.Configuration.PreferredMetadataLanguage); + var url = string.Format(EpisodeQuery, TVUtils.TvdbApiKey, seriesId, seasonNumber, episodeNumber, ConfigurationManager.Configuration.PreferredMetadataLanguage); var doc = new XmlDocument(); - try + using (var result = await HttpClient.Get(new HttpRequestOptions { + Url = url, + ResourcePool = RemoteSeriesProvider.Current.TvDbResourcePool, + CancellationToken = cancellationToken, + EnableResponseCache = true + + }).ConfigureAwait(false)) + { + doc.Load(result); + } + + //episode does not exist under this season, try absolute numbering. + //still assuming it's numbered as 1x01 + //this is basicly just for anime. + if (!doc.HasChildNodes && Int32.Parse(seasonNumber) == 1) + { + url = string.Format(AbsEpisodeQuery, TVUtils.TvdbApiKey, seriesId, episodeNumber, ConfigurationManager.Configuration.PreferredMetadataLanguage); + using (var result = await HttpClient.Get(new HttpRequestOptions { Url = url, @@ -193,37 +210,8 @@ namespace MediaBrowser.Controller.Providers.TV }).ConfigureAwait(false)) { - doc.Load(result); - } - } - catch (HttpException) - { - } - - //episode does not exist under this season, try absolute numbering. - //still assuming it's numbered as 1x01 - //this is basicly just for anime. - if (!doc.HasChildNodes && Int32.Parse(seasonNumber) == 1) - { - url = string.Format(absEpisodeQuery, TVUtils.TvdbApiKey, seriesId, episodeNumber, ConfigurationManager.Configuration.PreferredMetadataLanguage); - - try - { - using (var result = await HttpClient.Get(new HttpRequestOptions - { - Url = url, - ResourcePool = RemoteSeriesProvider.Current.TvDbResourcePool, - CancellationToken = cancellationToken, - EnableResponseCache = true - - }).ConfigureAwait(false)) - { - if (result != null) doc.Load(result); - usingAbsoluteData = true; - } - } - catch (HttpException) - { + if (result != null) doc.Load(result); + usingAbsoluteData = true; } } diff --git a/MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs b/MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs index eb689ed2f7..39fe4f2c67 100644 --- a/MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs +++ b/MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs @@ -1,5 +1,4 @@ -using System.Globalization; -using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; @@ -11,6 +10,7 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Model.Net; using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Net; using System.Text; @@ -142,8 +142,7 @@ namespace MediaBrowser.Controller.Providers.TV if (item.DontFetchMeta) return false; - return !HasLocalMeta(item) && (ConfigurationManager.Configuration.MetadataRefreshDays != -1 && - DateTime.UtcNow.Subtract(downloadDate).TotalDays > ConfigurationManager.Configuration.MetadataRefreshDays); + return !HasLocalMeta(item) && base.NeedsRefreshInternal(item, providerInfo); } /// @@ -164,16 +163,17 @@ namespace MediaBrowser.Controller.Providers.TV var seriesId = Path.GetFileName(path).GetAttributeValue("tvdbid") ?? await GetSeriesId(series, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); - + + var status = ProviderRefreshStatus.Success; + if (!string.IsNullOrEmpty(seriesId)) { series.SetProviderId(MetadataProviders.Tvdb, seriesId); - if (!HasCompleteMetadata(series)) - { - await FetchSeriesData(series, seriesId, cancellationToken).ConfigureAwait(false); - } + + status = await FetchSeriesData(series, seriesId, cancellationToken).ConfigureAwait(false); } - SetLastRefreshed(item, DateTime.UtcNow); + + SetLastRefreshed(item, DateTime.UtcNow, status); return true; } Logger.Info("Series provider not fetching because local meta exists or requested to ignore: " + item.Name); @@ -188,11 +188,9 @@ namespace MediaBrowser.Controller.Providers.TV /// The series id. /// The cancellation token. /// Task{System.Boolean}. - private async Task FetchSeriesData(Series series, string seriesId, CancellationToken cancellationToken) + private async Task FetchSeriesData(Series series, string seriesId, CancellationToken cancellationToken) { - var success = false; - - var name = series.Name; + var status = ProviderRefreshStatus.Success; if (!string.IsNullOrEmpty(seriesId)) { @@ -200,22 +198,16 @@ namespace MediaBrowser.Controller.Providers.TV string url = string.Format(seriesGet, TVUtils.TvdbApiKey, seriesId, ConfigurationManager.Configuration.PreferredMetadataLanguage); var doc = new XmlDocument(); - try + using (var xml = await HttpClient.Get(new HttpRequestOptions { - using (var xml = await HttpClient.Get(new HttpRequestOptions - { - Url = url, - ResourcePool = TvDbResourcePool, - CancellationToken = cancellationToken, - EnableResponseCache = true + Url = url, + ResourcePool = TvDbResourcePool, + CancellationToken = cancellationToken, + EnableResponseCache = true - }).ConfigureAwait(false)) - { - doc.Load(xml); - } - } - catch (HttpException) + }).ConfigureAwait(false)) { + doc.Load(xml); } if (doc.HasChildNodes) @@ -224,8 +216,6 @@ namespace MediaBrowser.Controller.Providers.TV var actorTask = FetchActors(series, seriesId, doc, cancellationToken); var imageTask = FetchImages(series, seriesId, cancellationToken); - success = true; - series.Name = doc.SafeGetString("//SeriesName"); series.Overview = doc.SafeGetString("//Overview"); series.CommunityRating = doc.SafeGetSingle("//Rating", 0, 10); @@ -268,8 +258,15 @@ namespace MediaBrowser.Controller.Providers.TV } } - //wait for other tasks - await Task.WhenAll(actorTask, imageTask).ConfigureAwait(false); + try + { + //wait for other tasks + await Task.WhenAll(actorTask, imageTask).ConfigureAwait(false); + } + catch (HttpException) + { + status = ProviderRefreshStatus.CompletedWithErrors; + } if (ConfigurationManager.Configuration.SaveLocalMeta) { @@ -281,9 +278,7 @@ namespace MediaBrowser.Controller.Providers.TV } } - - - return success; + return status; } /// @@ -299,22 +294,16 @@ namespace MediaBrowser.Controller.Providers.TV string urlActors = string.Format(getActors, TVUtils.TvdbApiKey, seriesId); var docActors = new XmlDocument(); - try + using (var actors = await HttpClient.Get(new HttpRequestOptions { - using (var actors = await HttpClient.Get(new HttpRequestOptions - { - Url = urlActors, - ResourcePool = TvDbResourcePool, - CancellationToken = cancellationToken, - EnableResponseCache = true + Url = urlActors, + ResourcePool = TvDbResourcePool, + CancellationToken = cancellationToken, + EnableResponseCache = true - }).ConfigureAwait(false)) - { - docActors.Load(actors); - } - } - catch (HttpException) + }).ConfigureAwait(false)) { + docActors.Load(actors); } if (docActors.HasChildNodes) @@ -380,22 +369,16 @@ namespace MediaBrowser.Controller.Providers.TV string url = string.Format("http://www.thetvdb.com/api/" + TVUtils.TvdbApiKey + "/series/{0}/banners.xml", seriesId); var images = new XmlDocument(); - try + using (var imgs = await HttpClient.Get(new HttpRequestOptions { - using (var imgs = await HttpClient.Get(new HttpRequestOptions - { - Url = url, - ResourcePool = TvDbResourcePool, - CancellationToken = cancellationToken, - EnableResponseCache = true + Url = url, + ResourcePool = TvDbResourcePool, + CancellationToken = cancellationToken, + EnableResponseCache = true - }).ConfigureAwait(false)) - { - images.Load(imgs); - } - } - catch (HttpException) + }).ConfigureAwait(false)) { + images.Load(imgs); } if (images.HasChildNodes) @@ -408,17 +391,7 @@ namespace MediaBrowser.Controller.Providers.TV n = n.SelectSingleNode("./BannerPath"); if (n != null) { - try - { - series.PrimaryImagePath = await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n.InnerText, "folder" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, TvDbResourcePool, cancellationToken).ConfigureAwait(false); - } - catch (HttpException) - { - } - catch (IOException) - { - - } + series.PrimaryImagePath = await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n.InnerText, "folder" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, TvDbResourcePool, cancellationToken).ConfigureAwait(false); } } } @@ -431,19 +404,9 @@ namespace MediaBrowser.Controller.Providers.TV n = n.SelectSingleNode("./BannerPath"); if (n != null) { - try - { - var bannerImagePath = await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n.InnerText, "banner" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, TvDbResourcePool, cancellationToken); + var bannerImagePath = await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n.InnerText, "banner" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, TvDbResourcePool, cancellationToken); - series.SetImage(ImageType.Banner, bannerImagePath); - } - catch (HttpException) - { - } - catch (IOException) - { - - } + series.SetImage(ImageType.Banner, bannerImagePath); } } } @@ -460,17 +423,7 @@ namespace MediaBrowser.Controller.Providers.TV var bdName = "backdrop" + (bdNo > 0 ? bdNo.ToString(UsCulture) : ""); if (ConfigurationManager.Configuration.RefreshItemImages || !series.HasLocalImage(bdName)) { - try - { - series.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + p.InnerText, bdName + Path.GetExtension(p.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, TvDbResourcePool, cancellationToken).ConfigureAwait(false)); - } - catch (HttpException) - { - } - catch (IOException) - { - - } + series.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + p.InnerText, bdName + Path.GetExtension(p.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, TvDbResourcePool, cancellationToken).ConfigureAwait(false)); } bdNo++; if (bdNo >= ConfigurationManager.Configuration.MaxBackdrops) break; @@ -480,18 +433,6 @@ namespace MediaBrowser.Controller.Providers.TV } } - /// - /// Determines whether [has complete metadata] [the specified series]. - /// - /// The series. - /// true if [has complete metadata] [the specified series]; otherwise, false. - private bool HasCompleteMetadata(Series series) - { - return (series.HasImage(ImageType.Banner)) && (series.CommunityRating != null) - && (series.Overview != null) && (series.Name != null) && (series.People != null) - && (series.Genres != null) && (series.OfficialRating != null); - } - /// /// Determines whether [has local meta] [the specified item]. /// @@ -499,9 +440,7 @@ namespace MediaBrowser.Controller.Providers.TV /// true if [has local meta] [the specified item]; otherwise, false. private bool HasLocalMeta(BaseItem item) { - //need at least the xml and folder.jpg/png - return item.ResolveArgs.ContainsMetaFileByName(LOCAL_META_FILE_NAME) && (item.ResolveArgs.ContainsMetaFileByName("folder.jpg") || - item.ResolveArgs.ContainsMetaFileByName("folder.png")); + return item.ResolveArgs.ContainsMetaFileByName(LOCAL_META_FILE_NAME); } /// From 5ecc276cb7c4188b149283722331ad776eeab906 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 18 May 2013 14:58:16 -0400 Subject: [PATCH 5/8] Dispose httprequestmessage --- .../HttpClientManager/HttpClientManager.cs | 198 +++++++++--------- 1 file changed, 101 insertions(+), 97 deletions(-) diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs index 82a91fa46a..7ea2d0adf9 100644 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs @@ -136,8 +136,8 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager { var now = DateTime.UtcNow; - var isCacheValid = (!cachedInfo.MustRevalidate && !string.IsNullOrEmpty(cachedInfo.Etag) && (now - cachedInfo.RequestDate).TotalDays < 7) - || (cachedInfo.Expires.HasValue && cachedInfo.Expires.Value > now); + var isCacheValid = cachedInfo.Expires.HasValue ? cachedInfo.Expires.Value > now : + !cachedInfo.MustRevalidate && !string.IsNullOrEmpty(cachedInfo.Etag) && (now - cachedInfo.RequestDate).TotalDays < 5; if (isCacheValid) { @@ -157,89 +157,90 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager options.CancellationToken.ThrowIfCancellationRequested(); - var message = GetHttpRequestMessage(options); - - if (options.EnableResponseCache && cachedInfo != null) + using (var message = GetHttpRequestMessage(options)) { - if (!string.IsNullOrEmpty(cachedInfo.Etag)) + if (options.EnableResponseCache && cachedInfo != null) { - message.Headers.Add("If-None-Match", cachedInfo.Etag); - } - else if (cachedInfo.LastModified.HasValue) - { - message.Headers.IfModifiedSince = new DateTimeOffset(cachedInfo.LastModified.Value); - } - } - - if (options.ResourcePool != null) - { - await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false); - } - - _logger.Info("HttpClientManager.Get url: {0}", options.Url); - - try - { - options.CancellationToken.ThrowIfCancellationRequested(); - - var response = await GetHttpClient(GetHostFromUrl(options.Url)).SendAsync(message, HttpCompletionOption.ResponseHeadersRead, options.CancellationToken).ConfigureAwait(false); - - if (options.EnableResponseCache) - { - if (response.StatusCode != HttpStatusCode.NotModified) + if (!string.IsNullOrEmpty(cachedInfo.Etag)) { - EnsureSuccessStatusCode(response); + message.Headers.Add("If-None-Match", cachedInfo.Etag); } - - options.CancellationToken.ThrowIfCancellationRequested(); - - cachedInfo = UpdateInfoCache(cachedInfo, options.Url, cachedInfoPath, response); - - if (response.StatusCode == HttpStatusCode.NotModified) + else if (cachedInfo.LastModified.HasValue) { - _logger.Debug("Server indicates not modified for {0}. Returning cached result.", options.Url); - - return GetCachedResponse(cachedReponsePath); - } - - if (!string.IsNullOrEmpty(cachedInfo.Etag) || cachedInfo.LastModified.HasValue || - (cachedInfo.Expires.HasValue && cachedInfo.Expires.Value > DateTime.UtcNow)) - { - await UpdateResponseCache(response, cachedReponsePath).ConfigureAwait(false); - - return GetCachedResponse(cachedReponsePath); + message.Headers.IfModifiedSince = new DateTimeOffset(cachedInfo.LastModified.Value); } } - else - { - EnsureSuccessStatusCode(response); - options.CancellationToken.ThrowIfCancellationRequested(); - } - - return await response.Content.ReadAsStreamAsync().ConfigureAwait(false); - } - catch (OperationCanceledException ex) - { - throw GetCancellationException(options.Url, options.CancellationToken, ex); - } - catch (HttpRequestException ex) - { - _logger.ErrorException("Error getting response from " + options.Url, ex); - - throw new HttpException(ex.Message, ex); - } - catch (Exception ex) - { - _logger.ErrorException("Error getting response from " + options.Url, ex); - - throw; - } - finally - { if (options.ResourcePool != null) { - options.ResourcePool.Release(); + await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false); + } + + _logger.Info("HttpClientManager.Get url: {0}", options.Url); + + try + { + options.CancellationToken.ThrowIfCancellationRequested(); + + var response = await GetHttpClient(GetHostFromUrl(options.Url)).SendAsync(message, HttpCompletionOption.ResponseHeadersRead, options.CancellationToken).ConfigureAwait(false); + + if (options.EnableResponseCache) + { + if (response.StatusCode != HttpStatusCode.NotModified) + { + EnsureSuccessStatusCode(response); + } + + options.CancellationToken.ThrowIfCancellationRequested(); + + cachedInfo = UpdateInfoCache(cachedInfo, options.Url, cachedInfoPath, response); + + if (response.StatusCode == HttpStatusCode.NotModified) + { + _logger.Debug("Server indicates not modified for {0}. Returning cached result.", options.Url); + + return GetCachedResponse(cachedReponsePath); + } + + if (!string.IsNullOrEmpty(cachedInfo.Etag) || cachedInfo.LastModified.HasValue || + (cachedInfo.Expires.HasValue && cachedInfo.Expires.Value > DateTime.UtcNow)) + { + await UpdateResponseCache(response, cachedReponsePath).ConfigureAwait(false); + + return GetCachedResponse(cachedReponsePath); + } + } + else + { + EnsureSuccessStatusCode(response); + + options.CancellationToken.ThrowIfCancellationRequested(); + } + + return await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + } + catch (OperationCanceledException ex) + { + throw GetCancellationException(options.Url, options.CancellationToken, ex); + } + catch (HttpRequestException ex) + { + _logger.ErrorException("Error getting response from " + options.Url, ex); + + throw new HttpException(ex.Message, ex); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting response from " + options.Url, ex); + + throw; + } + finally + { + if (options.ResourcePool != null) + { + options.ResourcePool.Release(); + } } } } @@ -469,39 +470,42 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager { options.CancellationToken.ThrowIfCancellationRequested(); - using (var response = await GetHttpClient(GetHostFromUrl(options.Url)).SendAsync(GetHttpRequestMessage(options), HttpCompletionOption.ResponseHeadersRead, options.CancellationToken).ConfigureAwait(false)) + using (var message = GetHttpRequestMessage(options)) { - EnsureSuccessStatusCode(response); - - options.CancellationToken.ThrowIfCancellationRequested(); - - var contentLength = GetContentLength(response); - - if (!contentLength.HasValue) + using (var response = await GetHttpClient(GetHostFromUrl(options.Url)).SendAsync(message, HttpCompletionOption.ResponseHeadersRead, options.CancellationToken).ConfigureAwait(false)) { - // We're not able to track progress - using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) + EnsureSuccessStatusCode(response); + + options.CancellationToken.ThrowIfCancellationRequested(); + + var contentLength = GetContentLength(response); + + if (!contentLength.HasValue) { - using (var fs = new FileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous)) + // We're not able to track progress + using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) { - await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false); + using (var fs = new FileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous)) + { + await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false); + } } } - } - else - { - using (var stream = ProgressStream.CreateReadProgressStream(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), options.Progress.Report, contentLength.Value)) + else { - using (var fs = new FileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous)) + using (var stream = ProgressStream.CreateReadProgressStream(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), options.Progress.Report, contentLength.Value)) { - await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false); + using (var fs = new FileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous)) + { + await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false); + } } } + + options.Progress.Report(100); + + options.CancellationToken.ThrowIfCancellationRequested(); } - - options.Progress.Report(100); - - options.CancellationToken.ThrowIfCancellationRequested(); } } catch (Exception ex) From 99959f5d10899167fea23d15ed9f858403053a2e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 18 May 2013 17:47:00 -0400 Subject: [PATCH 6/8] fixed image providers from running everytime against collection folders --- MediaBrowser.Controller/Entities/BaseItem.cs | 3 +-- MediaBrowser.Controller/Entities/CollectionFolder.cs | 2 +- MediaBrowser.Controller/Entities/Folder.cs | 2 +- MediaBrowser.Controller/Providers/ImagesByNameProvider.cs | 3 ++- .../Library/LibraryManager.cs | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index ca3ef7fac5..1bc6b523e7 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -905,7 +905,6 @@ namespace MediaBrowser.Controller.Entities if (changed || forceSave || themeSongsChanged || themeVideosChanged || localTrailersChanged) { cancellationToken.ThrowIfCancellationRequested(); - await LibraryManager.UpdateItem(this, cancellationToken).ConfigureAwait(false); } @@ -1506,7 +1505,7 @@ namespace MediaBrowser.Controller.Entities } // Refresh metadata - return RefreshMetadata(CancellationToken.None); + return RefreshMetadata(CancellationToken.None, forceSave: true); } } } diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index 67692273d7..70f3548f38 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Entities /// Specialized Folder class that points to a subset of the physical folders in the system. /// It is created from the user-specific folders within the system root /// - public class CollectionFolder : Folder, ICollectionFolder, IByReferenceItem + public class CollectionFolder : Folder, ICollectionFolder { /// /// Gets a value indicating whether this instance is virtual folder. diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 472cc115ec..66a4ca215f 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -760,7 +760,7 @@ namespace MediaBrowser.Controller.Entities var child = currentTuple.Item1; //refresh it - await child.RefreshMetadata(cancellationToken, resetResolveArgs: child.IsFolder).ConfigureAwait(false); + await child.RefreshMetadata(cancellationToken, resetResolveArgs: child.IsFolder, forceSave: currentTuple.Item2).ConfigureAwait(false); // Refresh children if a folder and the item changed or recursive is set to true var refreshChildren = child.IsFolder && (currentTuple.Item2 || (recursive.HasValue && recursive.Value)); diff --git a/MediaBrowser.Controller/Providers/ImagesByNameProvider.cs b/MediaBrowser.Controller/Providers/ImagesByNameProvider.cs index 64a9883780..3611607c9f 100644 --- a/MediaBrowser.Controller/Providers/ImagesByNameProvider.cs +++ b/MediaBrowser.Controller/Providers/ImagesByNameProvider.cs @@ -126,7 +126,8 @@ namespace MediaBrowser.Controller.Providers } data.Data = ConfigurationManager.ApplicationPaths.ItemsByNamePath.GetMD5(); - + SetLastRefreshed(item, DateTime.UtcNow); + return result; } diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 65905b0824..b692e97f30 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -269,16 +269,16 @@ namespace MediaBrowser.Server.Implementations.Library // Need to use DistinctBy Id because there could be multiple instances with the same id // due to sharing the default library var userRootFolders = _userManager.Users.Select(i => i.RootFolder) - .DistinctBy(i => i.Id) + .Distinct() .ToList(); items.AddRange(userRootFolders); // Get all user collection folders + // Skip BasePluginFolders because we already got them from RootFolder.RecursiveChildren var userFolders = - _userManager.Users.SelectMany(i => i.RootFolder.Children) + userRootFolders.SelectMany(i => i.Children) .Where(i => !(i is BasePluginFolder)) - .DistinctBy(i => i.Id) .ToList(); items.AddRange(userFolders); From 3fc0b768d1ddc1e72cbeaaa83a0cc9f16930ed35 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 18 May 2013 17:47:50 -0400 Subject: [PATCH 7/8] shorten image task delay --- .../ScheduledTasks/AudioImagesTask.cs | 12 ++++++------ .../ScheduledTasks/ChapterImagesTask.cs | 4 ++-- .../ScheduledTasks/RefreshMediaLibraryTask.cs | 2 +- .../ScheduledTasks/VideoImagesTask.cs | 7 ++++--- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/AudioImagesTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/AudioImagesTask.cs index d3ed270b85..c56a2b54a6 100644 --- a/MediaBrowser.Server.Implementations/ScheduledTasks/AudioImagesTask.cs +++ b/MediaBrowser.Server.Implementations/ScheduledTasks/AudioImagesTask.cs @@ -46,14 +46,14 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks private readonly List