From 8a1b12b7d805ce35f4e10acf2294f355f47e75e3 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 28 Jun 2013 16:25:58 -0400 Subject: [PATCH] tightened up image saving to reduce knowledge of file names --- MediaBrowser.Api/Images/ImageService.cs | 132 ++------- .../HttpClientManager/HttpClientManager.cs | 86 ++++++ .../HttpClientManager/HttpResponseInfo.cs | 46 ---- ...MediaBrowser.Common.Implementations.csproj | 1 - .../MediaBrowser.Common.csproj | 1 + MediaBrowser.Common/Net/HttpResponseInfo.cs | 29 ++ MediaBrowser.Common/Net/IHttpClient.cs | 7 + MediaBrowser.Controller/Entities/Folder.cs | 3 + .../Providers/IProviderManager.cs | 58 ++-- .../Movies/FanArtMovieProvider.cs | 20 +- .../Movies/MovieDbImagesProvider.cs | 13 +- .../Movies/MovieDbProvider.cs | 58 ++-- .../Movies/TmdbPersonProvider.cs | 23 +- .../Music/FanArtAlbumProvider.cs | 6 +- .../Music/FanArtArtistProvider.cs | 15 +- .../Savers/SeriesXmlSaver.cs | 15 +- .../TV/FanArtSeasonProvider.cs | 3 +- MediaBrowser.Providers/TV/FanArtTVProvider.cs | 15 +- .../TV/RemoteEpisodeProvider.cs | 5 +- .../TV/RemoteSeasonProvider.cs | 26 +- .../TV/RemoteSeriesProvider.cs | 7 - .../TV/TvdbSeriesImageProvider.cs | 17 +- ...MediaBrowser.Server.Implementations.csproj | 1 + .../Providers/ImageSaver.cs | 255 ++++++++++++++++++ .../Providers/ProviderManager.cs | 136 ++++------ 25 files changed, 576 insertions(+), 402 deletions(-) delete mode 100644 MediaBrowser.Common.Implementations/HttpClientManager/HttpResponseInfo.cs create mode 100644 MediaBrowser.Common/Net/HttpResponseInfo.cs create mode 100644 MediaBrowser.Server.Implementations/Providers/ImageSaver.cs diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 4518ffad00..3074b0d5bc 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -760,145 +760,45 @@ namespace MediaBrowser.Api.Images var bytes = Convert.FromBase64String(text); // Validate first - using (var memoryStream = new MemoryStream(bytes)) + using (var validationStream = new MemoryStream(bytes)) { - using (var image = Image.FromStream(memoryStream)) + using (var image = Image.FromStream(validationStream)) { Logger.Info("New image is {0}x{1}", image.Width, image.Height); } } - string filename; + var memoryStream = new MemoryStream(bytes); - switch (imageType) - { - case ImageType.Art: - filename = "clearart"; - break; - case ImageType.Primary: - filename = entity is Episode ? Path.GetFileNameWithoutExtension(entity.Path) : "folder"; - break; - case ImageType.Backdrop: - filename = GetBackdropFilenameToSave(entity); - break; - case ImageType.Screenshot: - filename = GetScreenshotFilenameToSave(entity); - break; - default: - filename = imageType.ToString().ToLower(); - break; - } + memoryStream.Position = 0; + var imageIndex = 0; - var extension = mimeType.Split(';').First().Split('/').Last(); - - string oldImagePath; - switch (imageType) + if (imageType == ImageType.Screenshot) { - case ImageType.Backdrop: - case ImageType.Screenshot: - oldImagePath = null; - break; - default: - oldImagePath = entity.GetImage(imageType); - break; + imageIndex = entity.ScreenshotImagePaths.Count; } - - // 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; - - if (imageType != ImageType.Primary) + else if (imageType == ImageType.Backdrop) { - if (entity is Episode) - { - saveLocally = false; - } + imageIndex = entity.BackdropImagePaths.Count; } - if (entity.LocationType != LocationType.FileSystem) - { - saveLocally = false; - } + await _providerManager.SaveImage(entity, memoryStream, mimeType, imageType, imageIndex, CancellationToken.None).ConfigureAwait(false); - var imagePath = _providerManager.GetSavePath(entity, filename + "." + extension, saveLocally); + var user = entity as User; - // Save to file system - using (var fs = new FileStream(imagePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true)) + if (user != null) { - await fs.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); - } - - if (imageType == ImageType.Screenshot) - { - entity.ScreenshotImagePaths.Add(imagePath); - } - else if (imageType == ImageType.Backdrop) - { - entity.BackdropImagePaths.Add(imagePath); + await _userManager.UpdateUser(user).ConfigureAwait(false); } else { - // Set the image - entity.SetImage(imageType, imagePath); - } - - // If the new and old paths are different, delete the old one - if (!string.IsNullOrEmpty(oldImagePath) && !oldImagePath.Equals(imagePath, StringComparison.OrdinalIgnoreCase)) - { - File.Delete(oldImagePath); + await _libraryManager.UpdateItem(entity, ItemUpdateType.ImageUpdate, CancellationToken.None) + .ConfigureAwait(false); } - // Directory watchers should repeat this, but do a quick refresh first - await entity.RefreshMetadata(CancellationToken.None, forceSave: true, allowSlowProviders: false).ConfigureAwait(false); + await entity.RefreshMetadata(CancellationToken.None, allowSlowProviders: false).ConfigureAwait(false); } } - - /// - /// Gets the backdrop filename to save. - /// - /// The item. - /// System.String. - private string GetBackdropFilenameToSave(BaseItem item) - { - var paths = item.BackdropImagePaths.ToList(); - - if (!paths.Any(i => string.Equals(Path.GetFileNameWithoutExtension(i), "backdrop", StringComparison.OrdinalIgnoreCase))) - { - return "screenshot"; - } - - var index = 1; - - while (paths.Any(i => string.Equals(Path.GetFileNameWithoutExtension(i), "backdrop" + index, StringComparison.OrdinalIgnoreCase))) - { - index++; - } - - return "backdrop" + index; - } - - /// - /// Gets the screenshot filename to save. - /// - /// The item. - /// System.String. - private string GetScreenshotFilenameToSave(BaseItem item) - { - var paths = item.ScreenshotImagePaths.ToList(); - - if (!paths.Any(i => string.Equals(Path.GetFileNameWithoutExtension(i), "screenshot", StringComparison.OrdinalIgnoreCase))) - { - return "screenshot"; - } - - var index = 1; - - while (paths.Any(i => string.Equals(Path.GetFileNameWithoutExtension(i), "screenshot" + index, StringComparison.OrdinalIgnoreCase))) - { - index++; - } - - return "screenshot" + index; - } } } diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs index f776cf6758..d664d0bba5 100644 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs @@ -104,6 +104,92 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager return client; } + public async Task GetResponse(HttpRequestOptions options) + { + ValidateParams(options.Url, options.CancellationToken); + + options.CancellationToken.ThrowIfCancellationRequested(); + + var client = GetHttpClient(GetHostFromUrl(options.Url), options.EnableHttpCompression); + + if ((DateTime.UtcNow - client.LastTimeout).TotalSeconds < 30) + { + throw new HttpException(string.Format("Cancelling connection to {0} due to a previous timeout.", options.Url)) { IsTimedOut = true }; + } + + using (var message = GetHttpRequestMessage(options)) + { + if (options.ResourcePool != null) + { + await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false); + } + + if ((DateTime.UtcNow - client.LastTimeout).TotalSeconds < 30) + { + if (options.ResourcePool != null) + { + options.ResourcePool.Release(); + } + + throw new HttpException(string.Format("Connection to {0} timed out", options.Url)) { IsTimedOut = true }; + } + + _logger.Info("HttpClientManager.Get url: {0}", options.Url); + + try + { + options.CancellationToken.ThrowIfCancellationRequested(); + + var response = await client.HttpClient.SendAsync(message, HttpCompletionOption.ResponseContentRead, options.CancellationToken).ConfigureAwait(false); + + EnsureSuccessStatusCode(response); + + options.CancellationToken.ThrowIfCancellationRequested(); + + return new HttpResponseInfo + { + Content = await response.Content.ReadAsStreamAsync().ConfigureAwait(false), + + StatusCode = response.StatusCode, + + ContentType = response.Content.Headers.ContentType.MediaType + }; + } + catch (OperationCanceledException ex) + { + var exception = GetCancellationException(options.Url, options.CancellationToken, ex); + + var httpException = exception as HttpException; + + if (httpException != null && httpException.IsTimedOut) + { + client.LastTimeout = DateTime.UtcNow; + } + + throw exception; + } + 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(); + } + } + } + } + /// /// Performs a GET request and returns the resulting stream /// diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpResponseInfo.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpResponseInfo.cs deleted file mode 100644 index 4a4612ffb5..0000000000 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpResponseInfo.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; - -namespace MediaBrowser.Common.Implementations.HttpClientManager -{ - /// - /// Class HttpResponseOutput - /// - public class HttpResponseInfo - { - /// - /// Gets or sets the URL. - /// - /// The URL. - public string Url { get; set; } - - /// - /// Gets or sets the etag. - /// - /// The etag. - public string Etag { get; set; } - - /// - /// Gets or sets the last modified. - /// - /// The last modified. - public DateTime? LastModified { get; set; } - - /// - /// Gets or sets the expires. - /// - /// The expires. - public DateTime? Expires { get; set; } - - /// - /// Gets or sets a value indicating whether [must revalidate]. - /// - /// true if [must revalidate]; otherwise, false. - public bool MustRevalidate { get; set; } - - /// - /// Gets or sets the request date. - /// - /// The request date. - public DateTime RequestDate { get; set; } - } -} diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj index d804f6f1c7..e2a56e9120 100644 --- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj +++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj @@ -66,7 +66,6 @@ - diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 69439c5733..9a81537bff 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -74,6 +74,7 @@ + diff --git a/MediaBrowser.Common/Net/HttpResponseInfo.cs b/MediaBrowser.Common/Net/HttpResponseInfo.cs new file mode 100644 index 0000000000..558218ed16 --- /dev/null +++ b/MediaBrowser.Common/Net/HttpResponseInfo.cs @@ -0,0 +1,29 @@ +using System.IO; +using System.Net; + +namespace MediaBrowser.Common.Net +{ + /// + /// Class HttpResponseInfo + /// + public class HttpResponseInfo + { + /// + /// Gets or sets the type of the content. + /// + /// The type of the content. + public string ContentType { get; set; } + + /// + /// Gets or sets the content. + /// + /// The content. + public Stream Content { get; set; } + + /// + /// Gets or sets the status code. + /// + /// The status code. + public HttpStatusCode StatusCode { get; set; } + } +} diff --git a/MediaBrowser.Common/Net/IHttpClient.cs b/MediaBrowser.Common/Net/IHttpClient.cs index 2998d1af9b..6068d4e8c8 100644 --- a/MediaBrowser.Common/Net/IHttpClient.cs +++ b/MediaBrowser.Common/Net/IHttpClient.cs @@ -11,6 +11,13 @@ namespace MediaBrowser.Common.Net /// public interface IHttpClient : IDisposable { + /// + /// Gets the response. + /// + /// The options. + /// Task{HttpResponseInfo}. + Task GetResponse(HttpRequestOptions options); + /// /// Performs a GET request and returns the resulting stream /// diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index f8ecf003bf..c6d6bf2210 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -798,6 +798,9 @@ namespace MediaBrowser.Controller.Entities }); await ((Folder)child).ValidateChildren(innerProgress, cancellationToken, recursive, forceRefreshMetadata).ConfigureAwait(false); + + // Some folder providers are unable to refresh until children have been refreshed. + await child.RefreshMetadata(cancellationToken, resetResolveArgs: false).ConfigureAwait(false); } else { diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs index 643dbe1c2c..6b8083b20e 100644 --- a/MediaBrowser.Controller/Providers/IProviderManager.cs +++ b/MediaBrowser.Controller/Providers/IProviderManager.cs @@ -1,5 +1,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Entities; using System.Collections.Generic; using System.IO; using System.Threading; @@ -12,64 +13,47 @@ namespace MediaBrowser.Controller.Providers /// public interface IProviderManager { - /// - /// Downloads the and save image. - /// - /// The item. - /// The source. - /// Name of the target. - /// if set to true [save locally]. - /// The resource pool. - /// The cancellation token. - /// Task{System.String}. - /// item - Task DownloadAndSaveImage(BaseItem item, string source, string targetName, bool saveLocally, SemaphoreSlim resourcePool, CancellationToken cancellationToken); + Task DownloadAndSaveImage(BaseItem item, string source, string targetName, bool saveLocally, + SemaphoreSlim resourcePool, CancellationToken cancellationToken); /// - /// Saves the image. + /// Executes the metadata providers. /// /// The item. - /// The source. - /// Name of the target. - /// if set to true [save locally]. /// The cancellation token. - /// Task{System.String}. - Task SaveImage(BaseItem item, Stream source, string targetName, bool saveLocally, CancellationToken cancellationToken); + /// if set to true [force]. + /// if set to true [allow slow providers]. + /// Task{System.Boolean}. + Task ExecuteMetadataProviders(BaseItem item, CancellationToken cancellationToken, bool force = false, bool allowSlowProviders = true); /// - /// Saves to library filesystem. + /// Saves the image. /// /// The item. - /// The path. - /// The data to save. + /// The URL. + /// The resource pool. + /// The type. + /// Index of the image. /// The cancellation token. /// Task. - /// - Task SaveToLibraryFilesystem(BaseItem item, string path, Stream dataToSave, CancellationToken cancellationToken); + Task SaveImage(BaseItem item, string url, SemaphoreSlim resourcePool, ImageType type, int? imageIndex, CancellationToken cancellationToken); /// - /// Executes the metadata providers. + /// Saves the image. /// /// The item. + /// The source. + /// Type of the MIME. + /// The type. + /// Index of the image. /// The cancellation token. - /// if set to true [force]. - /// if set to true [allow slow providers]. - /// Task{System.Boolean}. - Task ExecuteMetadataProviders(BaseItem item, CancellationToken cancellationToken, bool force = false, bool allowSlowProviders = true); + /// Task. + Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken); /// /// Adds the metadata providers. /// /// The providers. void AddParts(IEnumerable providers); - - /// - /// Gets the save path. - /// - /// The item. - /// Name of the target file. - /// if set to true [save locally]. - /// System.String. - string GetSavePath(BaseItem item, string targetFileName, bool saveLocally); } } \ No newline at end of file diff --git a/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs b/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs index 1a1c34928e..f0e696a06d 100644 --- a/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs +++ b/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs @@ -303,9 +303,6 @@ namespace MediaBrowser.Providers.Movies cancellationToken.ThrowIfCancellationRequested(); - var saveLocal = ConfigurationManager.Configuration.SaveLocalMeta && - item.LocationType == LocationType.FileSystem; - string path; var hd = ConfigurationManager.Configuration.DownloadHDFanArt ? "hd" : ""; @@ -322,7 +319,7 @@ namespace MediaBrowser.Providers.Movies path = node != null ? node.Value : null; if (!string.IsNullOrEmpty(path)) { - item.SetImage(ImageType.Logo, await _providerManager.DownloadAndSaveImage(item, path, LogoFile, saveLocal, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Logo, null, cancellationToken).ConfigureAwait(false); } } cancellationToken.ThrowIfCancellationRequested(); @@ -337,7 +334,8 @@ namespace MediaBrowser.Providers.Movies path = node != null ? node.Value : null; if (!string.IsNullOrEmpty(path)) { - item.SetImage(ImageType.Art, await _providerManager.DownloadAndSaveImage(item, path, ArtFile, saveLocal, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Art, null, cancellationToken) + .ConfigureAwait(false); } } cancellationToken.ThrowIfCancellationRequested(); @@ -349,7 +347,8 @@ namespace MediaBrowser.Providers.Movies path = node != null ? node.Value : null; if (!string.IsNullOrEmpty(path)) { - item.SetImage(ImageType.Disc, await _providerManager.DownloadAndSaveImage(item, path, DiscFile, saveLocal, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Disc, null, cancellationToken) + .ConfigureAwait(false); } } @@ -362,7 +361,8 @@ namespace MediaBrowser.Providers.Movies path = node != null ? node.Value : null; if (!string.IsNullOrEmpty(path)) { - item.SetImage(ImageType.Banner, await _providerManager.DownloadAndSaveImage(item, path, BannerFile, saveLocal, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Banner, null, cancellationToken) + .ConfigureAwait(false); } } @@ -375,7 +375,8 @@ namespace MediaBrowser.Providers.Movies path = node != null ? node.Value : null; if (!string.IsNullOrEmpty(path)) { - item.SetImage(ImageType.Thumb, await _providerManager.DownloadAndSaveImage(item, path, ThumbFile, saveLocal, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Thumb, null, cancellationToken) + .ConfigureAwait(false); } } @@ -393,7 +394,8 @@ namespace MediaBrowser.Providers.Movies if (!string.IsNullOrEmpty(path)) { - item.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(item, path, ("backdrop" + (numBackdrops > 0 ? numBackdrops.ToString(UsCulture) : "") + ".jpg"), saveLocal, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Backdrop, numBackdrops, cancellationToken) + .ConfigureAwait(false); numBackdrops++; diff --git a/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs b/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs index 2c9fbcec8a..feb14c3a01 100644 --- a/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs @@ -93,7 +93,7 @@ namespace MediaBrowser.Providers.Movies return ItemUpdateType.ImageUpdate; } } - + /// /// Gets a value indicating whether [requires internet]. /// @@ -148,7 +148,7 @@ namespace MediaBrowser.Providers.Movies { return false; } - + return base.NeedsRefreshInternal(item, providerInfo); } @@ -168,7 +168,7 @@ namespace MediaBrowser.Providers.Movies data = new BaseProviderInfo(); item.ProviderData[Id] = data; } - + var images = await FetchImages(item, item.GetProviderId(MetadataProviders.Tmdb), cancellationToken).ConfigureAwait(false); var status = await ProcessImages(item, images, cancellationToken).ConfigureAwait(false); @@ -246,7 +246,9 @@ namespace MediaBrowser.Providers.Movies }).ConfigureAwait(false); - item.PrimaryImagePath = await _providerManager.SaveImage(item, img, "folder" + Path.GetExtension(poster.file_path), ConfigurationManager.Configuration.SaveLocalMeta && item.LocationType == LocationType.FileSystem, cancellationToken).ConfigureAwait(false); + await _providerManager.SaveImage(item, img, MimeTypes.GetMimeType(poster.file_path), ImageType.Primary, null, cancellationToken) + .ConfigureAwait(false); + } } @@ -274,7 +276,8 @@ namespace MediaBrowser.Providers.Movies }).ConfigureAwait(false); - item.BackdropImagePaths.Add(await _providerManager.SaveImage(item, img, bdName + Path.GetExtension(images.backdrops[i].file_path), ConfigurationManager.Configuration.SaveLocalMeta && item.LocationType == LocationType.FileSystem, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, img, MimeTypes.GetMimeType(images.backdrops[i].file_path), ImageType.Backdrop, item.BackdropImagePaths.Count, cancellationToken) + .ConfigureAwait(false); } if (item.BackdropImagePaths.Count >= ConfigurationManager.Configuration.MaxBackdrops) diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs index 5f56ab690d..64259c4242 100644 --- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs @@ -32,7 +32,7 @@ namespace MediaBrowser.Providers.Movies /// /// The movie db /// - private readonly SemaphoreSlim _movieDbResourcePool = new SemaphoreSlim(1,1); + private readonly SemaphoreSlim _movieDbResourcePool = new SemaphoreSlim(1, 1); internal static MovieDbProvider Current { get; private set; } @@ -158,7 +158,7 @@ namespace MediaBrowser.Providers.Movies _tmdbSettingsSemaphore.Release(); return _tmdbSettings; } - + try { using (var json = await GetMovieDbResponse(new HttpRequestOptions @@ -199,7 +199,13 @@ namespace MediaBrowser.Providers.Movies protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo) { if (HasAltMeta(item)) - return false; + return false; + + // Boxsets require two passes because we need the children to be refreshed + if (item is BoxSet && string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.TmdbCollection))) + { + return true; + } return base.NeedsRefreshInternal(item, providerInfo); } @@ -291,19 +297,6 @@ namespace MediaBrowser.Providers.Movies /// Task{System.String}. public async Task FindId(BaseItem item, int? productionYear, CancellationToken cancellationToken) { - string id = null; - - if (item.LocationType == LocationType.FileSystem) - { - string justName = item.Path != null ? item.Path.Substring(item.Path.LastIndexOf(Path.DirectorySeparatorChar)) : string.Empty; - id = justName.GetAttributeValue("tmdbid"); - if (id != null) - { - Logger.Debug("Using tmdb id specified in path."); - return id; - } - } - int? year; string name = item.Name; ParseName(name, out name, out year); @@ -320,25 +313,14 @@ namespace MediaBrowser.Providers.Movies var boxset = item as BoxSet; if (boxset != null) { - var firstChild = boxset.Children.FirstOrDefault(); - - if (firstChild != null) - { - Logger.Debug("MovieDbProvider - Attempting to find boxset ID from: " + firstChild.Name); - string childName; - int? childYear; - ParseName(firstChild.Name, out childName, out childYear); - id = await GetBoxsetIdFromMovie(childName, childYear, language, cancellationToken).ConfigureAwait(false); - if (id != null) - { - Logger.Info("MovieDbProvider - Found Boxset ID: " + id); - } - } - - return id; + // See if any movies have a collection id already + return boxset.Children.OfType