diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
index fd50cf25a0..345cf581e7 100644
--- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj
+++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
@@ -103,6 +103,7 @@
+
diff --git a/MediaBrowser.Providers/TV/TvdbPersonImageProvider.cs b/MediaBrowser.Providers/TV/TvdbPersonImageProvider.cs
new file mode 100644
index 0000000000..bcdd03fc10
--- /dev/null
+++ b/MediaBrowser.Providers/TV/TvdbPersonImageProvider.cs
@@ -0,0 +1,127 @@
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Providers.Extensions;
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Xml;
+
+namespace MediaBrowser.Providers.TV
+{
+ public class TvdbPersonImageProvider : BaseMetadataProvider
+ {
+ private readonly ILibraryManager _library;
+ private readonly IProviderManager _providerManager;
+
+ public TvdbPersonImageProvider(ILogManager logManager, IServerConfigurationManager configurationManager, ILibraryManager library, IProviderManager providerManager)
+ : base(logManager, configurationManager)
+ {
+ _library = library;
+ _providerManager = providerManager;
+ }
+
+ public override bool Supports(BaseItem item)
+ {
+ return item is Person;
+ }
+
+ ///
+ /// Fetches metadata and returns true or false indicating if any work that requires persistence was done
+ ///
+ /// The item.
+ /// if set to true [force].
+ /// The cancellation token.
+ /// Task{System.Boolean}.
+ public override async Task FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
+ {
+ if (string.IsNullOrEmpty(item.PrimaryImagePath))
+ {
+ var seriesWithPerson = _library.RootFolder
+ .RecursiveChildren
+ .OfType()
+ .Where(i => !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tvdb)) && i.People.Any(p => string.Equals(p.Name, item.Name, StringComparison.OrdinalIgnoreCase)))
+ .ToList();
+
+ foreach (var series in seriesWithPerson)
+ {
+ try
+ {
+ await DownloadImageFromSeries(item, series, cancellationToken).ConfigureAwait(false);
+ }
+ catch (FileNotFoundException)
+ {
+ // No biggie
+ continue;
+ }
+
+ // break once we have an image
+ if (!string.IsNullOrEmpty(item.PrimaryImagePath))
+ {
+ break;
+ }
+ }
+
+ }
+
+ SetLastRefreshed(item, DateTime.UtcNow);
+ return true;
+ }
+
+ ///
+ /// Downloads the image from series.
+ ///
+ /// The item.
+ /// The series.
+ /// The cancellation token.
+ /// Task.
+ private async Task DownloadImageFromSeries(BaseItem item, Series series, CancellationToken cancellationToken)
+ {
+ var tvdbPath = RemoteSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, series.GetProviderId(MetadataProviders.Tvdb));
+
+ var actorXmlPath = Path.Combine(tvdbPath, "actors.xml");
+
+ var xmlDoc = new XmlDocument();
+
+ xmlDoc.Load(actorXmlPath);
+
+ var actorNodes = xmlDoc.SelectNodes("//Actor");
+
+ if (actorNodes == null)
+ {
+ return;
+ }
+
+ foreach (var actorNode in actorNodes.OfType())
+ {
+ var name = actorNode.SafeGetString("Name");
+
+ if (string.Equals(item.Name, name, StringComparison.OrdinalIgnoreCase))
+ {
+ var image = actorNode.SafeGetString("Image");
+
+ if (!string.IsNullOrEmpty(image))
+ {
+ var url = TVUtils.BannerUrl + image;
+
+ await _providerManager.SaveImage(item, url, RemoteSeriesProvider.Current.TvDbResourcePool,
+ ImageType.Primary, null, cancellationToken).ConfigureAwait(false);
+ }
+
+ break;
+ }
+ }
+ }
+
+ public override MetadataProviderPriority Priority
+ {
+ get { return MetadataProviderPriority.Third; }
+ }
+ }
+}
diff --git a/MediaBrowser.sln b/MediaBrowser.sln
index 744debbcd2..0c5360b494 100644
--- a/MediaBrowser.sln
+++ b/MediaBrowser.sln
@@ -237,4 +237,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(Performance) = preSolution
+ HasPerformanceSessions = true
+ EndGlobalSection
EndGlobal