diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index ba436a746a..dc01ba6e5d 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -62,6 +62,8 @@ + + @@ -72,7 +74,7 @@ - + diff --git a/MediaBrowser.Providers/Movies/ManualMovieDbImageProvider.cs b/MediaBrowser.Providers/Movies/ManualMovieDbImageProvider.cs index 7c6ede0c23..e5bd3bf472 100644 --- a/MediaBrowser.Providers/Movies/ManualMovieDbImageProvider.cs +++ b/MediaBrowser.Providers/Movies/ManualMovieDbImageProvider.cs @@ -86,8 +86,33 @@ namespace MediaBrowser.Providers.Movies Type = ImageType.Backdrop, RatingType = RatingType.Score })); - - return list; + + var language = _config.Configuration.PreferredMetadataLanguage; + + var isLanguageEn = string.Equals(language, "en", StringComparison.OrdinalIgnoreCase); + + return list.OrderByDescending(i => + { + if (string.Equals(language, i.Language, StringComparison.OrdinalIgnoreCase)) + { + return 3; + } + if (!isLanguageEn) + { + if (string.Equals("en", i.Language, StringComparison.OrdinalIgnoreCase)) + { + return 2; + } + } + if (string.IsNullOrEmpty(i.Language)) + { + return isLanguageEn ? 3 : 2; + } + return 0; + }) + .ThenByDescending(i => i.CommunityRating ?? 0) + .ThenByDescending(i => i.VoteCount ?? 0) + .ToList(); } /// @@ -100,35 +125,7 @@ namespace MediaBrowser.Providers.Movies { var language = _config.Configuration.PreferredMetadataLanguage; - var isLanguageEn = string.Equals(language, "en", StringComparison.OrdinalIgnoreCase); - - var eligiblePosters = images.posters == null ? - new List() : - images.posters - .ToList(); - - return eligiblePosters.OrderByDescending(i => - { - if (string.Equals(language, i.iso_639_1, StringComparison.OrdinalIgnoreCase)) - { - return 3; - } - if (!isLanguageEn) - { - if (string.Equals("en", i.iso_639_1, StringComparison.OrdinalIgnoreCase)) - { - return 2; - } - } - if (string.IsNullOrEmpty(i.iso_639_1)) - { - return isLanguageEn ? 3 : 2; - } - return 0; - }) - .ThenByDescending(i => i.vote_average) - .ThenByDescending(i => i.vote_count) - .ToList(); + return images.posters ?? new List(); } /// diff --git a/MediaBrowser.Providers/Movies/ManualMovieDbPersonImageProvider.cs b/MediaBrowser.Providers/Movies/ManualMovieDbPersonImageProvider.cs new file mode 100644 index 0000000000..ecfae9d5c0 --- /dev/null +++ b/MediaBrowser.Providers/Movies/ManualMovieDbPersonImageProvider.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.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Providers.Movies +{ + public class ManualMovieDbPersonImageProvider : IImageProvider + { + private readonly IServerConfigurationManager _config; + private readonly IJsonSerializer _jsonSerializer; + + public ManualMovieDbPersonImageProvider(IServerConfigurationManager config, IJsonSerializer jsonSerializer) + { + _config = config; + _jsonSerializer = jsonSerializer; + } + + public string Name + { + get { return ProviderName; } + } + + public static string ProviderName + { + get { return "TheMovieDb"; } + } + + public bool Supports(BaseItem item) + { + return item is Person; + } + + public async Task> GetImages(BaseItem item, ImageType imageType, CancellationToken cancellationToken) + { + var images = await GetAllImages(item, cancellationToken).ConfigureAwait(false); + + return images.Where(i => i.Type == imageType); + } + + public async Task> GetAllImages(BaseItem item, CancellationToken cancellationToken) + { + var id = item.GetProviderId(MetadataProviders.Tmdb); + + if (!string.IsNullOrEmpty(id)) + { + var dataFilePath = MovieDbPersonProvider.GetPersonDataFilePath(_config.ApplicationPaths, id); + + try + { + var result = _jsonSerializer.DeserializeFromFile(dataFilePath); + + var images = result.images ?? new MovieDbPersonProvider.Images(); + + var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false); + + var tmdbImageUrl = tmdbSettings.images.base_url + "original"; + + return GetImages(images, tmdbImageUrl); + } + catch (FileNotFoundException) + { + + } + } + + return new List(); + } + + private IEnumerable GetImages(MovieDbPersonProvider.Images images, string baseImageUrl) + { + var list = new List(); + + if (images.profiles != null) + { + list.AddRange(images.profiles.Select(i => new RemoteImageInfo + { + ProviderName = Name, + Type = ImageType.Primary, + Width = i.width, + Height = i.height, + Language = GetLanguage(i), + Url = baseImageUrl + i.file_path + })); + } + + var language = _config.Configuration.PreferredMetadataLanguage; + + var isLanguageEn = string.Equals(language, "en", StringComparison.OrdinalIgnoreCase); + + return list.OrderByDescending(i => + { + if (string.Equals(language, i.Language, StringComparison.OrdinalIgnoreCase)) + { + return 3; + } + if (!isLanguageEn) + { + if (string.Equals("en", i.Language, StringComparison.OrdinalIgnoreCase)) + { + return 2; + } + } + if (string.IsNullOrEmpty(i.Language)) + { + return isLanguageEn ? 3 : 2; + } + return 0; + }) + .ThenByDescending(i => i.CommunityRating ?? 0) + .ThenByDescending(i => i.VoteCount ?? 0) + .ToList(); + } + + private string GetLanguage(MovieDbPersonProvider.Profile profile) + { + return profile.iso_639_1 == null ? null : profile.iso_639_1.ToString(); + } + + public int Priority + { + get { return 0; } + } + } +} diff --git a/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs b/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs index d3645fdc8b..ab6dbf6d4d 100644 --- a/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs @@ -166,14 +166,9 @@ namespace MediaBrowser.Providers.Movies /// Task{System.Boolean}. public override async Task FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken) { - var id = item.GetProviderId(MetadataProviders.Tmdb); + var images = await _providerManager.GetAvailableRemoteImages(item, cancellationToken, ManualMovieDbImageProvider.ProviderName).ConfigureAwait(false); - if (!string.IsNullOrEmpty(id)) - { - var images = await _providerManager.GetAvailableRemoteImages(item, cancellationToken, ManualMovieDbImageProvider.ProviderName).ConfigureAwait(false); - - await ProcessImages(item, images.ToList(), cancellationToken).ConfigureAwait(false); - } + await ProcessImages(item, images.ToList(), cancellationToken).ConfigureAwait(false); SetLastRefreshed(item, DateTime.UtcNow); return true; diff --git a/MediaBrowser.Providers/Movies/MovieDbPersonImageProvider.cs b/MediaBrowser.Providers/Movies/MovieDbPersonImageProvider.cs new file mode 100644 index 0000000000..9074663f05 --- /dev/null +++ b/MediaBrowser.Providers/Movies/MovieDbPersonImageProvider.cs @@ -0,0 +1,209 @@ +using MediaBrowser.Common.IO; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Providers; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Providers.Movies +{ + /// + /// Class MovieDbPersonImageProvider. + /// + public class MovieDbPersonImageProvider : BaseMetadataProvider + { + /// + /// The _provider manager + /// + private readonly IProviderManager _providerManager; + + private readonly IFileSystem _fileSystem; + + /// + /// Initializes a new instance of the class. + /// + /// The log manager. + /// The configuration manager. + /// The provider manager. + public MovieDbPersonImageProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem) + : base(logManager, configurationManager) + { + _providerManager = providerManager; + _fileSystem = fileSystem; + } + + /// + /// Gets the priority. + /// + /// The priority. + public override MetadataProviderPriority Priority + { + get { return MetadataProviderPriority.Third; } + } + + /// + /// Supports the specified item. + /// + /// The item. + /// true if XXXX, false otherwise + public override bool Supports(BaseItem item) + { + return item is Person; + } + + public override ItemUpdateType ItemUpdateType + { + get + { + return ItemUpdateType.ImageUpdate; + } + } + + /// + /// Gets a value indicating whether [requires internet]. + /// + /// true if [requires internet]; otherwise, false. + public override bool RequiresInternet + { + get + { + return true; + } + } + + /// + /// Gets a value indicating whether [refresh on version change]. + /// + /// true if [refresh on version change]; otherwise, false. + protected override bool RefreshOnVersionChange + { + get + { + return true; + } + } + + /// + /// Gets the provider version. + /// + /// The provider version. + protected override string ProviderVersion + { + get + { + return "3"; + } + } + + /// + /// Needses the refresh internal. + /// + /// The item. + /// The provider info. + /// true if XXXX, false otherwise + protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo) + { + if (string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Tmdb))) + { + return false; + } + + // Don't refresh if we already have both poster and backdrop and we're not refreshing images + if (item.HasImage(ImageType.Primary)) + { + return false; + } + + return base.NeedsRefreshInternal(item, providerInfo); + } + + /// + /// Needses the refresh based on compare date. + /// + /// The item. + /// The provider info. + /// true if XXXX, false otherwise + protected override bool NeedsRefreshBasedOnCompareDate(BaseItem item, BaseProviderInfo providerInfo) + { + var provderId = item.GetProviderId(MetadataProviders.Tmdb); + + if (!string.IsNullOrEmpty(provderId)) + { + // Process images + var path = MovieDbPersonProvider.GetPersonDataFilePath(ConfigurationManager.ApplicationPaths, provderId); + + var fileInfo = new FileInfo(path); + + if (fileInfo.Exists) + { + return _fileSystem.GetLastWriteTimeUtc(fileInfo) > providerInfo.LastRefreshed; + } + + return false; + } + + return false; + } + + /// + /// 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) + { + var images = await _providerManager.GetAvailableRemoteImages(item, cancellationToken, ManualMovieDbPersonImageProvider.ProviderName).ConfigureAwait(false); + + await ProcessImages(item, images.ToList(), cancellationToken).ConfigureAwait(false); + + SetLastRefreshed(item, DateTime.UtcNow); + return true; + } + + /// + /// Processes the images. + /// + /// The item. + /// The images. + /// The cancellation token + /// Task. + private async Task ProcessImages(BaseItem item, List images, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + var eligiblePosters = images + .Where(i => i.Type == ImageType.Primary) + .ToList(); + + // poster + if (eligiblePosters.Count > 0 && !item.HasImage(ImageType.Primary)) + { + var poster = eligiblePosters[0]; + + var url = poster.Url; + + var img = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions + { + Url = url, + CancellationToken = cancellationToken + + }).ConfigureAwait(false); + + await _providerManager.SaveImage(item, img, MimeTypes.GetMimeType(url), ImageType.Primary, null, url, cancellationToken) + .ConfigureAwait(false); + } + } + } +} diff --git a/MediaBrowser.Providers/Movies/TmdbPersonProvider.cs b/MediaBrowser.Providers/Movies/MovieDbPersonProvider.cs similarity index 94% rename from MediaBrowser.Providers/Movies/TmdbPersonProvider.cs rename to MediaBrowser.Providers/Movies/MovieDbPersonProvider.cs index 7c38eb97b8..fe2b301d1f 100644 --- a/MediaBrowser.Providers/Movies/TmdbPersonProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbPersonProvider.cs @@ -23,16 +23,16 @@ namespace MediaBrowser.Providers.Movies /// /// Class TmdbPersonProvider /// - public class TmdbPersonProvider : BaseMetadataProvider + public class MovieDbPersonProvider : BaseMetadataProvider { protected readonly IProviderManager ProviderManager; - internal static TmdbPersonProvider Current { get; private set; } + internal static MovieDbPersonProvider Current { get; private set; } const string DataFileName = "info.json"; private readonly IFileSystem _fileSystem; - public TmdbPersonProvider(IJsonSerializer jsonSerializer, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem) + public MovieDbPersonProvider(IJsonSerializer jsonSerializer, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem) : base(logManager, configurationManager) { if (jsonSerializer == null) @@ -125,6 +125,15 @@ namespace MediaBrowser.Providers.Movies return seriesDataPath; } + internal static string GetPersonDataFilePath(IApplicationPaths appPaths, string tmdbId) + { + var letter = tmdbId.GetMD5().ToString().Substring(0, 1); + + var seriesDataPath = Path.Combine(GetPersonsDataPath(appPaths), letter, tmdbId); + + return Path.Combine(seriesDataPath, DataFileName); + } + internal static string GetPersonsDataPath(IApplicationPaths appPaths) { var dataPath = Path.Combine(appPaths.DataPath, "tmdb-people"); @@ -231,20 +240,18 @@ namespace MediaBrowser.Providers.Movies /// Task. private async Task FetchInfo(Person person, string id, bool isForcedRefresh, CancellationToken cancellationToken) { - var personDataPath = GetPersonDataPath(ConfigurationManager.ApplicationPaths, id); - - var file = Path.Combine(personDataPath, DataFileName); + var dataFilePath = GetPersonDataFilePath(ConfigurationManager.ApplicationPaths, id); // Only download if not already there // The prescan task will take care of updates so we don't need to re-download here - if (!File.Exists(file)) + if (!File.Exists(dataFilePath)) { await DownloadPersonInfo(id, cancellationToken).ConfigureAwait(false); } if (isForcedRefresh || ConfigurationManager.Configuration.EnableTmdbUpdates || !HasAltMeta(person)) { - var info = JsonSerializer.DeserializeFromFile(Path.Combine(personDataPath, DataFileName)); + var info = JsonSerializer.DeserializeFromFile(dataFilePath); cancellationToken.ThrowIfCancellationRequested(); @@ -398,7 +405,7 @@ namespace MediaBrowser.Providers.Movies /// /// Class PersonSearchResult /// - protected class PersonSearchResult + public class PersonSearchResult { /// /// Gets or sets a value indicating whether this is adult. @@ -425,7 +432,7 @@ namespace MediaBrowser.Providers.Movies /// /// Class PersonSearchResults /// - protected class PersonSearchResults + public class PersonSearchResults { /// /// Gets or sets the page. @@ -449,7 +456,7 @@ namespace MediaBrowser.Providers.Movies public int Total_Results { get; set; } } - protected class Cast + public class Cast { public int id { get; set; } public string title { get; set; } @@ -460,7 +467,7 @@ namespace MediaBrowser.Providers.Movies public bool adult { get; set; } } - protected class Crew + public class Crew { public int id { get; set; } public string title { get; set; } @@ -472,13 +479,13 @@ namespace MediaBrowser.Providers.Movies public bool adult { get; set; } } - protected class Credits + public class Credits { public List cast { get; set; } public List crew { get; set; } } - protected class Profile + public class Profile { public string file_path { get; set; } public int width { get; set; } @@ -487,12 +494,12 @@ namespace MediaBrowser.Providers.Movies public double aspect_ratio { get; set; } } - protected class Images + public class Images { public List profiles { get; set; } } - protected class PersonResult + public class PersonResult { public bool adult { get; set; } public List also_known_as { get; set; } diff --git a/MediaBrowser.Providers/Movies/PersonUpdatesPreScanTask.cs b/MediaBrowser.Providers/Movies/PersonUpdatesPreScanTask.cs index 8a5e6bd9dc..2264ccd3fb 100644 --- a/MediaBrowser.Providers/Movies/PersonUpdatesPreScanTask.cs +++ b/MediaBrowser.Providers/Movies/PersonUpdatesPreScanTask.cs @@ -68,7 +68,7 @@ namespace MediaBrowser.Providers.Movies return; } - var path = TmdbPersonProvider.GetPersonsDataPath(_config.CommonApplicationPaths); + var path = MovieDbPersonProvider.GetPersonsDataPath(_config.CommonApplicationPaths); Directory.CreateDirectory(path); @@ -211,7 +211,7 @@ namespace MediaBrowser.Providers.Movies { _logger.Info("Updating person from tmdb " + id); - return TmdbPersonProvider.Current.DownloadPersonInfo(id, cancellationToken); + return MovieDbPersonProvider.Current.DownloadPersonInfo(id, cancellationToken); } class Result diff --git a/MediaBrowser.Providers/TV/ManualTvdbPersonImageProvider.cs b/MediaBrowser.Providers/TV/ManualTvdbPersonImageProvider.cs index 757e16d3d6..adeca12f26 100644 --- a/MediaBrowser.Providers/TV/ManualTvdbPersonImageProvider.cs +++ b/MediaBrowser.Providers/TV/ManualTvdbPersonImageProvider.cs @@ -186,7 +186,7 @@ namespace MediaBrowser.Providers.TV public int Priority { - get { return 1; } + get { return 0; } } } } diff --git a/MediaBrowser.Providers/TV/TvdbPersonImageProvider.cs b/MediaBrowser.Providers/TV/TvdbPersonImageProvider.cs index 8c2e201aab..53f1c7bdb8 100644 --- a/MediaBrowser.Providers/TV/TvdbPersonImageProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbPersonImageProvider.cs @@ -91,7 +91,7 @@ namespace MediaBrowser.Providers.TV public override MetadataProviderPriority Priority { - get { return MetadataProviderPriority.Third; } + get { return MetadataProviderPriority.Fourth; } } } }