Browse Source

beginning manual image providers

Luke Pulverenti 11 years ago
parent
commit
524150331c

+ 29 - 1
MediaBrowser.Api/LibraryService.cs

@@ -5,8 +5,10 @@ using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Providers;
 using MediaBrowser.Model.Querying;
 using ServiceStack.ServiceHost;
 using System;
@@ -32,6 +34,21 @@ namespace MediaBrowser.Api
         public string Id { get; set; }
     }
 
+    [Route("/Items/{Id}/RemoteImages/{Type}", "GET")]
+    [Api(Description = "Gets available remote images for an item")]
+    public class GetRemoteImages : IReturn<List<RemoteImageInfo>>
+    {
+        /// <summary>
+        /// Gets or sets the id.
+        /// </summary>
+        /// <value>The id.</value>
+        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+        public string Id { get; set; }
+
+        [ApiMember(Name = "Type", Description = "The image type", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+        public ImageType Type { get; set; }
+    }
+    
     /// <summary>
     /// Class GetCriticReviews
     /// </summary>
@@ -208,6 +225,7 @@ namespace MediaBrowser.Api
         private readonly ILibraryManager _libraryManager;
         private readonly IUserManager _userManager;
         private readonly IUserDataManager _userDataManager;
+        private readonly IProviderManager _providerManager;
 
         private readonly IDtoService _dtoService;
 
@@ -215,13 +233,14 @@ namespace MediaBrowser.Api
         /// Initializes a new instance of the <see cref="LibraryService" /> class.
         /// </summary>
         public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager,
-                              IDtoService dtoService, IUserDataManager userDataManager)
+                              IDtoService dtoService, IUserDataManager userDataManager, IProviderManager providerManager)
         {
             _itemRepo = itemRepo;
             _libraryManager = libraryManager;
             _userManager = userManager;
             _dtoService = dtoService;
             _userDataManager = userDataManager;
+            _providerManager = providerManager;
         }
 
         public object Get(GetFile request)
@@ -240,6 +259,15 @@ namespace MediaBrowser.Api
             return ToStaticFileResult(item.Path);
         }
 
+        public object Get(GetRemoteImages request)
+        {
+            var item = _dtoService.GetItemByDtoId(request.Id);
+
+            var result = _providerManager.GetAvailableRemoteImages(item, request.Type, CancellationToken.None).Result;
+
+            return ToOptimizedResult(result);
+        }
+
         /// <summary>
         /// Gets the specified request.
         /// </summary>

+ 1 - 0
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -109,6 +109,7 @@
     <Compile Include="Notifications\INotificationsRepository.cs" />
     <Compile Include="Notifications\NotificationUpdateEventArgs.cs" />
     <Compile Include="Providers\IDynamicInfoProvider.cs" />
+    <Compile Include="Providers\IImageProvider.cs" />
     <Compile Include="Session\ISessionManager.cs" />
     <Compile Include="Drawing\ImageExtensions.cs" />
     <Compile Include="Entities\AggregateFolder.cs" />

+ 38 - 0
MediaBrowser.Controller/Providers/IImageProvider.cs

@@ -0,0 +1,38 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Providers;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Providers
+{
+    /// <summary>
+    /// Interface IImageProvider
+    /// </summary>
+    public interface IImageProvider
+    {
+        /// <summary>
+        /// Gets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        string Name { get; }
+
+        /// <summary>
+        /// Supportses the specified item.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="imageType">Type of the image.</param>
+        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
+        bool Supports(BaseItem item, ImageType imageType);
+
+        /// <summary>
+        /// Gets the available images.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="imageType">Type of the image.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task{IEnumerable{RemoteImageInfo}}.</returns>
+        Task<IEnumerable<RemoteImageInfo>> GetAvailableImages(BaseItem item, ImageType imageType, CancellationToken cancellationToken);
+    }
+}

+ 12 - 1
MediaBrowser.Controller/Providers/IProviderManager.cs

@@ -1,6 +1,7 @@
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Providers;
 using System.Collections.Generic;
 using System.IO;
 using System.Threading;
@@ -52,6 +53,16 @@ namespace MediaBrowser.Controller.Providers
         /// Adds the metadata providers.
         /// </summary>
         /// <param name="providers">The providers.</param>
-        void AddParts(IEnumerable<BaseMetadataProvider> providers);
+        /// <param name="imageProviders">The image providers.</param>
+        void AddParts(IEnumerable<BaseMetadataProvider> providers, IEnumerable<IImageProvider> imageProviders);
+
+        /// <summary>
+        /// Gets the available remote images.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="type">The type.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task{IEnumerable{RemoteImageInfo}}.</returns>
+        Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(BaseItem item, ImageType type, CancellationToken cancellationToken);
     }
 }

+ 3 - 0
MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj

@@ -287,6 +287,9 @@
     <Compile Include="..\MediaBrowser.Model\Plugins\PluginInfo.cs">
       <Link>Plugins\PluginInfo.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Providers\RemoteImageInfo.cs">
+      <Link>Providers\RemoteImageInfo.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Querying\ArtistsQuery.cs">
       <Link>Querying\ArtistsQuery.cs</Link>
     </Compile>

+ 3 - 0
MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj

@@ -274,6 +274,9 @@
     <Compile Include="..\MediaBrowser.Model\Plugins\PluginInfo.cs">
       <Link>Plugins\PluginInfo.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Providers\RemoteImageInfo.cs">
+      <Link>Providers\RemoteImageInfo.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Querying\ArtistsQuery.cs">
       <Link>Querying\ArtistsQuery.cs</Link>
     </Compile>

+ 1 - 0
MediaBrowser.Model/MediaBrowser.Model.csproj

@@ -59,6 +59,7 @@
     <Compile Include="Dto\ItemByNameCounts.cs" />
     <Compile Include="Dto\ItemCounts.cs" />
     <Compile Include="Dto\ItemIndex.cs" />
+    <Compile Include="Providers\RemoteImageInfo.cs" />
     <Compile Include="Dto\StudioDto.cs" />
     <Compile Include="Entities\CollectionType.cs" />
     <Compile Include="Entities\ItemReview.cs" />

+ 51 - 0
MediaBrowser.Model/Providers/RemoteImageInfo.cs

@@ -0,0 +1,51 @@
+
+namespace MediaBrowser.Model.Providers
+{
+    /// <summary>
+    /// Class RemoteImageInfo
+    /// </summary>
+    public class RemoteImageInfo
+    {
+        /// <summary>
+        /// Gets or sets the name of the provider.
+        /// </summary>
+        /// <value>The name of the provider.</value>
+        public string ProviderName { get; set; }
+
+        /// <summary>
+        /// Gets or sets the URL.
+        /// </summary>
+        /// <value>The URL.</value>
+        public string Url { get; set; }
+
+        /// <summary>
+        /// Gets or sets the height.
+        /// </summary>
+        /// <value>The height.</value>
+        public int? Height { get; set; }
+
+        /// <summary>
+        /// Gets or sets the width.
+        /// </summary>
+        /// <value>The width.</value>
+        public int? Width { get; set; }
+
+        /// <summary>
+        /// Gets or sets the community rating.
+        /// </summary>
+        /// <value>The community rating.</value>
+        public double? CommunityRating { get; set; }
+
+        /// <summary>
+        /// Gets or sets the vote count.
+        /// </summary>
+        /// <value>The vote count.</value>
+        public int? VoteCount { get; set; }
+
+        /// <summary>
+        /// Gets or sets the language.
+        /// </summary>
+        /// <value>The language.</value>
+        public string Language { get; set; }
+    }
+}

+ 1 - 0
MediaBrowser.Providers/MediaBrowser.Providers.csproj

@@ -60,6 +60,7 @@
     <Compile Include="MediaInfo\FFProbeVideoInfoProvider.cs" />
     <Compile Include="MediaInfo\VideoImageProvider.cs" />
     <Compile Include="Movies\BoxSetProviderFromXml.cs" />
+    <Compile Include="Movies\ManualMovieDbImageProvider.cs" />
     <Compile Include="Movies\MovieUpdatesPrescanTask.cs" />
     <Compile Include="Movies\MovieXmlParser.cs" />
     <Compile Include="Movies\FanArtMovieProvider.cs" />

+ 133 - 0
MediaBrowser.Providers/Movies/ManualMovieDbImageProvider.cs

@@ -0,0 +1,133 @@
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Providers;
+using MediaBrowser.Model.Serialization;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Providers.Movies
+{
+    class ManualMovieDbImageProvider : IImageProvider
+    {
+        private readonly IJsonSerializer _jsonSerializer;
+        private readonly IServerConfigurationManager _config;
+
+        public ManualMovieDbImageProvider(IJsonSerializer jsonSerializer, IServerConfigurationManager config)
+        {
+            _jsonSerializer = jsonSerializer;
+            _config = config;
+        }
+
+        public string Name
+        {
+            get { return "TheMovieDB"; }
+        }
+
+        public bool Supports(BaseItem item, ImageType imageType)
+        {
+            if (MovieDbImagesProvider.SupportsItem(item))
+            {
+                return imageType == ImageType.Primary || imageType == ImageType.Backdrop;
+            }
+
+            return false;
+        }
+
+        public async Task<IEnumerable<RemoteImageInfo>> GetAvailableImages(BaseItem item, ImageType imageType, CancellationToken cancellationToken)
+        {
+            var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
+
+            var results = MovieDbImagesProvider.FetchImages(item, _jsonSerializer);
+
+            var tmdbImageUrl = tmdbSettings.images.base_url + "original";
+
+            if (imageType == ImageType.Primary)
+            {
+                var sources = GetPosters(results, item);
+
+                return sources.Select(i => new RemoteImageInfo
+                {
+                    Url = tmdbImageUrl + i.file_path,
+                    CommunityRating = i.vote_average,
+                    VoteCount = i.vote_count,
+                    Width = i.width,
+                    Height = i.height,
+                    Language = i.iso_639_1,
+                    ProviderName = Name
+                });
+            }
+
+            if (imageType == ImageType.Backdrop)
+            {
+                var sources = GetBackdrops(results, item);
+
+                return sources.Select(i => new RemoteImageInfo
+                {
+                    Url = tmdbImageUrl + i.file_path,
+                    CommunityRating = i.vote_average,
+                    VoteCount = i.vote_count,
+                    Width = i.width,
+                    Height = i.height,
+                    ProviderName = Name
+                });
+            }
+
+            throw new ArgumentException("Unrecognized ImageType: " + imageType);
+        }
+        
+        /// <summary>
+        /// Gets the posters.
+        /// </summary>
+        /// <param name="images">The images.</param>
+        /// <param name="item">The item.</param>
+        /// <returns>IEnumerable{MovieDbProvider.Poster}.</returns>
+        public IEnumerable<MovieDbProvider.Poster> GetPosters(MovieDbProvider.Images images, BaseItem item)
+        {
+            var language = _config.Configuration.PreferredMetadataLanguage;
+
+            var eligiblePosters = images.posters == null ?
+                new List<MovieDbProvider.Poster>() :
+                images.posters.Where(i => i.width >= _config.Configuration.MinMoviePosterWidth)
+                .ToList();
+
+            return eligiblePosters.OrderByDescending(i => i.vote_average)
+                .ThenByDescending(i =>
+                {
+                    if (string.Equals(language, i.iso_639_1, StringComparison.OrdinalIgnoreCase))
+                    {
+                        return 3;
+                    }
+                    if (string.Equals("en", i.iso_639_1, StringComparison.OrdinalIgnoreCase))
+                    {
+                        return 2;
+                    }
+                    if (string.IsNullOrEmpty(i.iso_639_1))
+                    {
+                        return 1;
+                    }
+                    return 0;
+                })
+                .ToList();
+        }
+
+        /// <summary>
+        /// Gets the backdrops.
+        /// </summary>
+        /// <param name="images">The images.</param>
+        /// <param name="item">The item.</param>
+        /// <returns>IEnumerable{MovieDbProvider.Backdrop}.</returns>
+        public IEnumerable<MovieDbProvider.Backdrop> GetBackdrops(MovieDbProvider.Images images, BaseItem item)
+        {
+            var eligibleBackdrops = images.backdrops == null ? new List<MovieDbProvider.Backdrop>() :
+                images.backdrops.Where(i => i.width >= _config.Configuration.MinMovieBackdropWidth)
+                .ToList();
+
+            return eligibleBackdrops.OrderByDescending(i => i.vote_average);
+        }
+    }
+}

+ 19 - 41
MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs

@@ -65,6 +65,11 @@ namespace MediaBrowser.Providers.Movies
         /// <param name="item">The item.</param>
         /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
         public override bool Supports(BaseItem item)
+        {
+            return SupportsItem(item);
+        }
+
+        public static bool SupportsItem(BaseItem item)
         {
             var trailer = item as Trailer;
 
@@ -180,7 +185,7 @@ namespace MediaBrowser.Providers.Movies
 
             if (!string.IsNullOrEmpty(id))
             {
-                var images = FetchImages(item);
+                var images = FetchImages(item, _jsonSerializer);
 
                 if (images != null)
                 {
@@ -196,8 +201,9 @@ namespace MediaBrowser.Providers.Movies
         /// Fetches the images.
         /// </summary>
         /// <param name="item">The item.</param>
+        /// <param name="jsonSerializer">The json serializer.</param>
         /// <returns>Task{MovieImages}.</returns>
-        private MovieDbProvider.Images FetchImages(BaseItem item)
+        internal static MovieDbProvider.Images FetchImages(BaseItem item, IJsonSerializer jsonSerializer)
         {
             var path = MovieDbProvider.Current.GetDataFilePath(item, "default");
 
@@ -207,7 +213,7 @@ namespace MediaBrowser.Providers.Movies
 
                 if (fileInfo.Exists)
                 {
-                    return _jsonSerializer.DeserializeFromFile<MovieDbProvider.CompleteMovieData>(path).images;
+                    return jsonSerializer.DeserializeFromFile<MovieDbProvider.CompleteMovieData>(path).images;
                 }
             }
 
@@ -227,13 +233,9 @@ namespace MediaBrowser.Providers.Movies
 
             var status = ProviderRefreshStatus.Success;
 
-            var eligiblePosters = images.posters == null ?
-                new List<MovieDbProvider.Poster>() :
-                images.posters.Where(i => i.width >= ConfigurationManager.Configuration.MinMoviePosterWidth)
+            var eligiblePosters = new ManualMovieDbImageProvider(_jsonSerializer, ConfigurationManager).GetPosters(images, item)
                 .ToList();
 
-            eligiblePosters = eligiblePosters.OrderByDescending(i => i.vote_average).ToList();
-
             //        poster
             if (eligiblePosters.Count > 0 && !item.HasImage(ImageType.Primary))
             {
@@ -242,48 +244,24 @@ namespace MediaBrowser.Providers.Movies
                 var tmdbImageUrl = tmdbSettings.images.base_url + "original";
                 // get highest rated poster for our language
 
-                var poster = eligiblePosters.FirstOrDefault(p => string.Equals(p.iso_639_1, ConfigurationManager.Configuration.PreferredMetadataLanguage, StringComparison.OrdinalIgnoreCase));
-
-                if (poster == null)
-                {
-                    // couldn't find our specific language, find english
-                    poster = eligiblePosters.FirstOrDefault(p => string.Equals(p.iso_639_1, "en", StringComparison.OrdinalIgnoreCase));
-                }
-
-                if (poster == null)
-                {
-                    //still couldn't find it - try highest rated null one
-                    poster = eligiblePosters.FirstOrDefault(p => p.iso_639_1 == null);
-                }
+                var poster = eligiblePosters[0];
 
-                if (poster == null)
-                {
-                    //finally - just get the highest rated one
-                    poster = eligiblePosters.FirstOrDefault();
-                }
+                var url = tmdbImageUrl + poster.file_path;
 
-                if (poster != null)
+                var img = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions
                 {
-                    var url = tmdbImageUrl + poster.file_path;
+                    Url = url,
+                    CancellationToken = cancellationToken
 
-                    var img = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions
-                    {
-                        Url = url,
-                        CancellationToken = cancellationToken
+                }).ConfigureAwait(false);
 
-                    }).ConfigureAwait(false);
-
-                    await _providerManager.SaveImage(item, img, MimeTypes.GetMimeType(poster.file_path), ImageType.Primary, null, url, cancellationToken)
-                                        .ConfigureAwait(false);
-
-                }
+                await _providerManager.SaveImage(item, img, MimeTypes.GetMimeType(poster.file_path), ImageType.Primary, null, url, cancellationToken)
+                                    .ConfigureAwait(false);
             }
 
             cancellationToken.ThrowIfCancellationRequested();
 
-            var eligibleBackdrops = images.backdrops == null ? new List<MovieDbProvider.Backdrop>() :
-                images.backdrops.Where(i => i.width >= ConfigurationManager.Configuration.MinMovieBackdropWidth)
-                .ToList();
+            var eligibleBackdrops = new ManualMovieDbImageProvider(_jsonSerializer, ConfigurationManager).GetBackdrops(images, item).ToList();
 
             var backdropLimit = ConfigurationManager.Configuration.MaxBackdrops;
 

+ 61 - 3
MediaBrowser.Server.Implementations/Providers/ProviderManager.cs

@@ -13,6 +13,7 @@ using System.IO;
 using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
+using MediaBrowser.Model.Providers;
 
 namespace MediaBrowser.Server.Implementations.Providers
 {
@@ -48,6 +49,8 @@ namespace MediaBrowser.Server.Implementations.Providers
         /// <value>The metadata providers enumerable.</value>
         private BaseMetadataProvider[] MetadataProviders { get; set; }
 
+        private IImageProvider[] ImageProviders { get; set; }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="ProviderManager" /> class.
         /// </summary>
@@ -55,8 +58,7 @@ namespace MediaBrowser.Server.Implementations.Providers
         /// <param name="configurationManager">The configuration manager.</param>
         /// <param name="directoryWatchers">The directory watchers.</param>
         /// <param name="logManager">The log manager.</param>
-        /// <param name="libraryManager">The library manager.</param>
-        public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, IDirectoryWatchers directoryWatchers, ILogManager logManager, ILibraryManager libraryManager)
+        public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, IDirectoryWatchers directoryWatchers, ILogManager logManager)
         {
             _logger = logManager.GetLogger("ProviderManager");
             _httpClient = httpClient;
@@ -68,9 +70,12 @@ namespace MediaBrowser.Server.Implementations.Providers
         /// Adds the metadata providers.
         /// </summary>
         /// <param name="providers">The providers.</param>
-        public void AddParts(IEnumerable<BaseMetadataProvider> providers)
+        /// <param name="imageProviders">The image providers.</param>
+        public void AddParts(IEnumerable<BaseMetadataProvider> providers, IEnumerable<IImageProvider> imageProviders)
         {
             MetadataProviders = providers.OrderBy(e => e.Priority).ToArray();
+
+            ImageProviders = imageProviders.ToArray();
         }
 
         /// <summary>
@@ -344,5 +349,58 @@ namespace MediaBrowser.Server.Implementations.Providers
         {
             return new ImageSaver(ConfigurationManager, _directoryWatchers).SaveImage(item, source, mimeType, type, imageIndex, sourceUrl, cancellationToken);
         }
+
+        /// <summary>
+        /// Gets the available remote images.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="type">The type.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task{IEnumerable{RemoteImageInfo}}.</returns>
+        public async Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(BaseItem item, ImageType type, CancellationToken cancellationToken)
+        {
+            var providers = GetSupportedImageProviders(item, type);
+
+            var tasks = providers.Select(i => Task.Run(async () =>
+            {
+                try
+                {
+                    var result = await i.GetAvailableImages(item, type, cancellationToken).ConfigureAwait(false);
+                    return result.ToList();
+                }
+                catch (Exception ex)
+                {
+                    _logger.ErrorException("{0} failed in GetAvailableImages for type {1}", ex, i.GetType().Name, item.GetType().Name);
+                    return new List<RemoteImageInfo>();
+                }
+            }));
+
+            var results = await Task.WhenAll(tasks).ConfigureAwait(false);
+
+            return results.SelectMany(i => i);
+        }
+
+        /// <summary>
+        /// Gets the supported image providers.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="type">The type.</param>
+        /// <returns>IEnumerable{IImageProvider}.</returns>
+        private IEnumerable<IImageProvider> GetSupportedImageProviders(BaseItem item, ImageType type)
+        {
+            return ImageProviders.Where(i =>
+            {
+                try
+                {
+                    return i.Supports(item, type);
+                }
+                catch (Exception ex)
+                {
+                    _logger.ErrorException("{0} failed in Supports for type {1}", ex, i.GetType().Name, item.GetType().Name);
+                    return false;
+                }
+
+            });
+        }
     }
 }

+ 2 - 2
MediaBrowser.ServerApplication/ApplicationHost.cs

@@ -275,7 +275,7 @@ namespace MediaBrowser.ServerApplication
             DirectoryWatchers = new DirectoryWatchers(LogManager, TaskManager, LibraryManager, ServerConfigurationManager, FileSystemManager);
             RegisterSingleInstance(DirectoryWatchers);
 
-            ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, DirectoryWatchers, LogManager, LibraryManager);
+            ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, DirectoryWatchers, LogManager);
             RegisterSingleInstance(ProviderManager);
 
             RegisterSingleInstance<ILibrarySearchEngine>(() => new LuceneSearchEngine(ApplicationPaths, LogManager, LibraryManager));
@@ -449,7 +449,7 @@ namespace MediaBrowser.ServerApplication
                                     GetExports<IPeoplePrescanTask>(),
                                     GetExports<IMetadataSaver>());
 
-            ProviderManager.AddParts(GetExports<BaseMetadataProvider>());
+            ProviderManager.AddParts(GetExports<BaseMetadataProvider>(), GetExports<IImageProvider>());
 
             ImageProcessor.AddParts(GetExports<IImageEnhancer>());