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