GenericTmdbMovieInfo.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. #pragma warning disable CS1591
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Globalization;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Net;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. using MediaBrowser.Controller.Entities;
  11. using MediaBrowser.Controller.Entities.Movies;
  12. using MediaBrowser.Controller.Library;
  13. using MediaBrowser.Controller.Providers;
  14. using MediaBrowser.Model.Entities;
  15. using MediaBrowser.Model.IO;
  16. using MediaBrowser.Model.Serialization;
  17. using MediaBrowser.Providers.Plugins.Tmdb.Models.Movies;
  18. using Microsoft.Extensions.Logging;
  19. namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
  20. {
  21. public class GenericTmdbMovieInfo<T>
  22. where T : BaseItem, new()
  23. {
  24. private readonly ILogger _logger;
  25. private readonly IJsonSerializer _jsonSerializer;
  26. private readonly ILibraryManager _libraryManager;
  27. private readonly IFileSystem _fileSystem;
  28. private readonly CultureInfo _usCulture = new CultureInfo("en-US");
  29. public GenericTmdbMovieInfo(ILogger logger, IJsonSerializer jsonSerializer, ILibraryManager libraryManager, IFileSystem fileSystem)
  30. {
  31. _logger = logger;
  32. _jsonSerializer = jsonSerializer;
  33. _libraryManager = libraryManager;
  34. _fileSystem = fileSystem;
  35. }
  36. public async Task<MetadataResult<T>> GetMetadata(ItemLookupInfo itemId, CancellationToken cancellationToken)
  37. {
  38. var tmdbId = itemId.GetProviderId(MetadataProvider.Tmdb);
  39. var imdbId = itemId.GetProviderId(MetadataProvider.Imdb);
  40. // Don't search for music video id's because it is very easy to misidentify.
  41. if (string.IsNullOrEmpty(tmdbId) && string.IsNullOrEmpty(imdbId) && typeof(T) != typeof(MusicVideo))
  42. {
  43. var searchResults = await new TmdbSearch(_logger, _jsonSerializer, _libraryManager).GetMovieSearchResults(itemId, cancellationToken).ConfigureAwait(false);
  44. var searchResult = searchResults.FirstOrDefault();
  45. if (searchResult != null)
  46. {
  47. tmdbId = searchResult.GetProviderId(MetadataProvider.Tmdb);
  48. }
  49. }
  50. if (!string.IsNullOrEmpty(tmdbId) || !string.IsNullOrEmpty(imdbId))
  51. {
  52. cancellationToken.ThrowIfCancellationRequested();
  53. return await FetchMovieData(tmdbId, imdbId, itemId.MetadataLanguage, itemId.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
  54. }
  55. return new MetadataResult<T>();
  56. }
  57. /// <summary>
  58. /// Fetches the movie data.
  59. /// </summary>
  60. /// <param name="tmdbId">The TMDB identifier.</param>
  61. /// <param name="imdbId">The imdb identifier.</param>
  62. /// <param name="language">The language.</param>
  63. /// <param name="preferredCountryCode">The preferred country code.</param>
  64. /// <param name="cancellationToken">The cancellation token.</param>
  65. /// <returns>Task{`0}.</returns>
  66. private async Task<MetadataResult<T>> FetchMovieData(string tmdbId, string imdbId, string language, string preferredCountryCode, CancellationToken cancellationToken)
  67. {
  68. var item = new MetadataResult<T>
  69. {
  70. Item = new T()
  71. };
  72. string dataFilePath = null;
  73. MovieResult movieInfo = null;
  74. // Id could be ImdbId or TmdbId
  75. if (string.IsNullOrEmpty(tmdbId))
  76. {
  77. movieInfo = await TmdbMovieProvider.Current.FetchMainResult(imdbId, false, language, cancellationToken).ConfigureAwait(false);
  78. if (movieInfo != null)
  79. {
  80. tmdbId = movieInfo.Id.ToString(_usCulture);
  81. dataFilePath = TmdbMovieProvider.Current.GetDataFilePath(tmdbId, language);
  82. Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath));
  83. _jsonSerializer.SerializeToFile(movieInfo, dataFilePath);
  84. }
  85. }
  86. if (!string.IsNullOrWhiteSpace(tmdbId))
  87. {
  88. await TmdbMovieProvider.Current.EnsureMovieInfo(tmdbId, language, cancellationToken).ConfigureAwait(false);
  89. dataFilePath = dataFilePath ?? TmdbMovieProvider.Current.GetDataFilePath(tmdbId, language);
  90. movieInfo = movieInfo ?? _jsonSerializer.DeserializeFromFile<MovieResult>(dataFilePath);
  91. var settings = await TmdbMovieProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
  92. ProcessMainInfo(item, settings, preferredCountryCode, movieInfo);
  93. item.HasMetadata = true;
  94. }
  95. return item;
  96. }
  97. /// <summary>
  98. /// Processes the main info.
  99. /// </summary>
  100. /// <param name="resultItem">The result item.</param>
  101. /// <param name="settings">The settings.</param>
  102. /// <param name="preferredCountryCode">The preferred country code.</param>
  103. /// <param name="movieData">The movie data.</param>
  104. private void ProcessMainInfo(MetadataResult<T> resultItem, TmdbSettingsResult settings, string preferredCountryCode, MovieResult movieData)
  105. {
  106. var movie = resultItem.Item;
  107. movie.Name = movieData.GetTitle() ?? movie.Name;
  108. movie.OriginalTitle = movieData.GetOriginalTitle();
  109. movie.Overview = string.IsNullOrWhiteSpace(movieData.Overview) ? null : WebUtility.HtmlDecode(movieData.Overview);
  110. movie.Overview = movie.Overview != null ? movie.Overview.Replace("\n\n", "\n") : null;
  111. // movie.HomePageUrl = movieData.homepage;
  112. if (!string.IsNullOrEmpty(movieData.Tagline))
  113. {
  114. movie.Tagline = movieData.Tagline;
  115. }
  116. if (movieData.Production_Countries != null)
  117. {
  118. movie.ProductionLocations = movieData
  119. .Production_Countries
  120. .Select(i => i.Name)
  121. .ToArray();
  122. }
  123. movie.SetProviderId(MetadataProvider.Tmdb, movieData.Id.ToString(_usCulture));
  124. movie.SetProviderId(MetadataProvider.Imdb, movieData.Imdb_Id);
  125. if (movieData.Belongs_To_Collection != null)
  126. {
  127. movie.SetProviderId(MetadataProvider.TmdbCollection,
  128. movieData.Belongs_To_Collection.Id.ToString(CultureInfo.InvariantCulture));
  129. if (movie is Movie movieItem)
  130. {
  131. movieItem.CollectionName = movieData.Belongs_To_Collection.Name;
  132. }
  133. }
  134. string voteAvg = movieData.Vote_Average.ToString(CultureInfo.InvariantCulture);
  135. if (float.TryParse(voteAvg, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var rating))
  136. {
  137. movie.CommunityRating = rating;
  138. }
  139. // movie.VoteCount = movieData.vote_count;
  140. if (movieData.Releases != null && movieData.Releases.Countries != null)
  141. {
  142. var releases = movieData.Releases.Countries.Where(i => !string.IsNullOrWhiteSpace(i.Certification)).ToList();
  143. var ourRelease = releases.FirstOrDefault(c => string.Equals(c.Iso_3166_1, preferredCountryCode, StringComparison.OrdinalIgnoreCase));
  144. var usRelease = releases.FirstOrDefault(c => string.Equals(c.Iso_3166_1, "US", StringComparison.OrdinalIgnoreCase));
  145. if (ourRelease != null)
  146. {
  147. var ratingPrefix = string.Equals(preferredCountryCode, "us", StringComparison.OrdinalIgnoreCase) ? "" : preferredCountryCode + "-";
  148. var newRating = ratingPrefix + ourRelease.Certification;
  149. newRating = newRating.Replace("de-", "FSK-", StringComparison.OrdinalIgnoreCase);
  150. movie.OfficialRating = newRating;
  151. }
  152. else if (usRelease != null)
  153. {
  154. movie.OfficialRating = usRelease.Certification;
  155. }
  156. }
  157. if (!string.IsNullOrWhiteSpace(movieData.Release_Date))
  158. {
  159. // These dates are always in this exact format
  160. if (DateTime.TryParse(movieData.Release_Date, _usCulture, DateTimeStyles.None, out var r))
  161. {
  162. movie.PremiereDate = r.ToUniversalTime();
  163. movie.ProductionYear = movie.PremiereDate.Value.Year;
  164. }
  165. }
  166. // studios
  167. if (movieData.Production_Companies != null)
  168. {
  169. movie.SetStudios(movieData.Production_Companies.Select(c => c.Name));
  170. }
  171. // genres
  172. // Movies get this from imdb
  173. var genres = movieData.Genres ?? new List<Tmdb.Models.General.Genre>();
  174. foreach (var genre in genres.Select(g => g.Name))
  175. {
  176. movie.AddGenre(genre);
  177. }
  178. resultItem.ResetPeople();
  179. var tmdbImageUrl = settings.images.GetImageUrl("original");
  180. // Actors, Directors, Writers - all in People
  181. // actors come from cast
  182. if (movieData.Casts != null && movieData.Casts.Cast != null)
  183. {
  184. foreach (var actor in movieData.Casts.Cast.OrderBy(a => a.Order))
  185. {
  186. var personInfo = new PersonInfo
  187. {
  188. Name = actor.Name.Trim(),
  189. Role = actor.Character,
  190. Type = PersonType.Actor,
  191. SortOrder = actor.Order
  192. };
  193. if (!string.IsNullOrWhiteSpace(actor.Profile_Path))
  194. {
  195. personInfo.ImageUrl = tmdbImageUrl + actor.Profile_Path;
  196. }
  197. if (actor.Id > 0)
  198. {
  199. personInfo.SetProviderId(MetadataProvider.Tmdb, actor.Id.ToString(CultureInfo.InvariantCulture));
  200. }
  201. resultItem.AddPerson(personInfo);
  202. }
  203. }
  204. // and the rest from crew
  205. if (movieData.Casts?.Crew != null)
  206. {
  207. var keepTypes = new[]
  208. {
  209. PersonType.Director,
  210. PersonType.Writer,
  211. PersonType.Producer
  212. };
  213. foreach (var person in movieData.Casts.Crew)
  214. {
  215. // Normalize this
  216. var type = TmdbUtils.MapCrewToPersonType(person);
  217. if (!keepTypes.Contains(type, StringComparer.OrdinalIgnoreCase) &&
  218. !keepTypes.Contains(person.Job ?? string.Empty, StringComparer.OrdinalIgnoreCase))
  219. {
  220. continue;
  221. }
  222. var personInfo = new PersonInfo
  223. {
  224. Name = person.Name.Trim(),
  225. Role = person.Job,
  226. Type = type
  227. };
  228. if (!string.IsNullOrWhiteSpace(person.Profile_Path))
  229. {
  230. personInfo.ImageUrl = tmdbImageUrl + person.Profile_Path;
  231. }
  232. if (person.Id > 0)
  233. {
  234. personInfo.SetProviderId(MetadataProvider.Tmdb, person.Id.ToString(CultureInfo.InvariantCulture));
  235. }
  236. resultItem.AddPerson(personInfo);
  237. }
  238. }
  239. // if (movieData.keywords != null && movieData.keywords.keywords != null)
  240. //{
  241. // movie.Keywords = movieData.keywords.keywords.Select(i => i.name).ToList();
  242. //}
  243. if (movieData.Trailers != null && movieData.Trailers.Youtube != null)
  244. {
  245. movie.RemoteTrailers = movieData.Trailers.Youtube.Select(i => new MediaUrl
  246. {
  247. Url = string.Format(CultureInfo.InvariantCulture, "https://www.youtube.com/watch?v={0}", i.Source),
  248. Name = i.Name
  249. }).ToArray();
  250. }
  251. }
  252. }
  253. }