GenericMovieDbInfo.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. using MediaBrowser.Controller.Entities;
  2. using MediaBrowser.Controller.Entities.Movies;
  3. using MediaBrowser.Controller.Providers;
  4. using MediaBrowser.Model.Entities;
  5. using MediaBrowser.Model.Logging;
  6. using MediaBrowser.Model.Serialization;
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Globalization;
  10. using System.IO;
  11. using System.Linq;
  12. using System.Net;
  13. using System.Threading;
  14. using System.Threading.Tasks;
  15. namespace MediaBrowser.Providers.Movies
  16. {
  17. public class GenericMovieDbInfo<T>
  18. where T : Video, new()
  19. {
  20. private readonly ILogger _logger;
  21. private readonly IJsonSerializer _jsonSerializer;
  22. private readonly CultureInfo _usCulture = new CultureInfo("en-US");
  23. public GenericMovieDbInfo(ILogger logger, IJsonSerializer jsonSerializer)
  24. {
  25. _logger = logger;
  26. _jsonSerializer = jsonSerializer;
  27. }
  28. public async Task<MetadataResult<T>> GetMetadata(ItemLookupInfo itemId, CancellationToken cancellationToken)
  29. {
  30. var result = new MetadataResult<T>();
  31. var tmdbId = itemId.GetProviderId(MetadataProviders.Tmdb);
  32. var imdbId = itemId.GetProviderId(MetadataProviders.Imdb);
  33. // Don't search for music video id's because it is very easy to misidentify.
  34. if (string.IsNullOrEmpty(tmdbId) && string.IsNullOrEmpty(imdbId) && typeof(T) != typeof(MusicVideo))
  35. {
  36. var searchResults = await new MovieDbSearch(_logger, _jsonSerializer).GetMovieSearchResults(itemId, cancellationToken).ConfigureAwait(false);
  37. var searchResult = searchResults.FirstOrDefault();
  38. if (searchResult != null)
  39. {
  40. tmdbId = searchResult.GetProviderId(MetadataProviders.Tmdb);
  41. }
  42. }
  43. if (!string.IsNullOrEmpty(tmdbId) || !string.IsNullOrEmpty(imdbId))
  44. {
  45. cancellationToken.ThrowIfCancellationRequested();
  46. result.Item = await FetchMovieData(tmdbId, imdbId, itemId.MetadataLanguage, itemId.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
  47. result.HasMetadata = result.Item != null;
  48. }
  49. return result;
  50. }
  51. /// <summary>
  52. /// Fetches the movie data.
  53. /// </summary>
  54. /// <param name="tmdbId">The TMDB identifier.</param>
  55. /// <param name="imdbId">The imdb identifier.</param>
  56. /// <param name="language">The language.</param>
  57. /// <param name="preferredCountryCode">The preferred country code.</param>
  58. /// <param name="cancellationToken">The cancellation token.</param>
  59. /// <returns>Task{`0}.</returns>
  60. private async Task<T> FetchMovieData(string tmdbId, string imdbId, string language, string preferredCountryCode, CancellationToken cancellationToken)
  61. {
  62. string dataFilePath = null;
  63. MovieDbProvider.CompleteMovieData movieInfo = null;
  64. // Id could be ImdbId or TmdbId
  65. if (string.IsNullOrEmpty(tmdbId))
  66. {
  67. movieInfo = await MovieDbProvider.Current.FetchMainResult(imdbId, language, cancellationToken).ConfigureAwait(false);
  68. if (movieInfo == null) return null;
  69. tmdbId = movieInfo.id.ToString(_usCulture);
  70. dataFilePath = MovieDbProvider.Current.GetDataFilePath(tmdbId, language);
  71. Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath));
  72. _jsonSerializer.SerializeToFile(movieInfo, dataFilePath);
  73. }
  74. await MovieDbProvider.Current.EnsureMovieInfo(tmdbId, language, cancellationToken).ConfigureAwait(false);
  75. dataFilePath = dataFilePath ?? MovieDbProvider.Current.GetDataFilePath(tmdbId, language);
  76. movieInfo = movieInfo ?? _jsonSerializer.DeserializeFromFile<MovieDbProvider.CompleteMovieData>(dataFilePath);
  77. var item = new T();
  78. ProcessMainInfo(item, preferredCountryCode, movieInfo);
  79. return item;
  80. }
  81. /// <summary>
  82. /// Processes the main info.
  83. /// </summary>
  84. /// <param name="movie">The movie.</param>
  85. /// <param name="preferredCountryCode">The preferred country code.</param>
  86. /// <param name="movieData">The movie data.</param>
  87. private void ProcessMainInfo(T movie, string preferredCountryCode, MovieDbProvider.CompleteMovieData movieData)
  88. {
  89. movie.Name = movieData.title ?? movieData.original_title ?? movieData.name ?? movie.Name;
  90. // Bug in Mono: WebUtility.HtmlDecode should return null if the string is null but in Mono it generate an System.ArgumentNullException.
  91. movie.Overview = movieData.overview != null ? WebUtility.HtmlDecode(movieData.overview) : null;
  92. movie.Overview = movie.Overview != null ? movie.Overview.Replace("\n\n", "\n") : null;
  93. movie.HomePageUrl = movieData.homepage;
  94. var hasBudget = movie as IHasBudget;
  95. if (hasBudget != null)
  96. {
  97. hasBudget.Budget = movieData.budget;
  98. hasBudget.Revenue = movieData.revenue;
  99. }
  100. if (!string.IsNullOrEmpty(movieData.tagline))
  101. {
  102. var hasTagline = movie as IHasTaglines;
  103. if (hasTagline != null)
  104. {
  105. hasTagline.Taglines.Clear();
  106. hasTagline.AddTagline(movieData.tagline);
  107. }
  108. }
  109. movie.SetProviderId(MetadataProviders.Tmdb, movieData.id.ToString(_usCulture));
  110. movie.SetProviderId(MetadataProviders.Imdb, movieData.imdb_id);
  111. if (movieData.belongs_to_collection != null)
  112. {
  113. movie.SetProviderId(MetadataProviders.TmdbCollection,
  114. movieData.belongs_to_collection.id.ToString(CultureInfo.InvariantCulture));
  115. var movieItem = movie as Movie;
  116. if (movieItem != null)
  117. {
  118. movieItem.TmdbCollectionName = movieData.belongs_to_collection.name;
  119. }
  120. }
  121. float rating;
  122. string voteAvg = movieData.vote_average.ToString(CultureInfo.InvariantCulture);
  123. if (float.TryParse(voteAvg, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out rating))
  124. {
  125. movie.CommunityRating = rating;
  126. }
  127. movie.VoteCount = movieData.vote_count;
  128. //release date and certification are retrieved based on configured country and we fall back on US if not there and to minimun release date if still no match
  129. if (movieData.releases != null && movieData.releases.countries != null)
  130. {
  131. var ourRelease = movieData.releases.countries.FirstOrDefault(c => c.iso_3166_1.Equals(preferredCountryCode, StringComparison.OrdinalIgnoreCase)) ?? new MovieDbProvider.Country();
  132. var usRelease = movieData.releases.countries.FirstOrDefault(c => c.iso_3166_1.Equals("US", StringComparison.OrdinalIgnoreCase)) ?? new MovieDbProvider.Country();
  133. var minimunRelease = movieData.releases.countries.OrderBy(c => c.release_date).FirstOrDefault() ?? new MovieDbProvider.Country();
  134. var ratingPrefix = string.Equals(preferredCountryCode, "us", StringComparison.OrdinalIgnoreCase) ? "" : preferredCountryCode + "-";
  135. movie.OfficialRating = !string.IsNullOrEmpty(ourRelease.certification)
  136. ? ratingPrefix + ourRelease.certification
  137. : !string.IsNullOrEmpty(usRelease.certification)
  138. ? usRelease.certification
  139. : !string.IsNullOrEmpty(minimunRelease.certification)
  140. ? minimunRelease.iso_3166_1 + "-" + minimunRelease.certification
  141. : null;
  142. }
  143. if (!string.IsNullOrWhiteSpace(movieData.release_date))
  144. {
  145. DateTime r;
  146. // These dates are always in this exact format
  147. if (DateTime.TryParse(movieData.release_date, _usCulture, DateTimeStyles.None, out r))
  148. {
  149. movie.PremiereDate = r.ToUniversalTime();
  150. movie.ProductionYear = movie.PremiereDate.Value.Year;
  151. }
  152. }
  153. //studios
  154. if (movieData.production_companies != null)
  155. {
  156. movie.Studios.Clear();
  157. foreach (var studio in movieData.production_companies.Select(c => c.name))
  158. {
  159. movie.AddStudio(studio);
  160. }
  161. }
  162. // genres
  163. // Movies get this from imdb
  164. var genres = movieData.genres ?? new List<MovieDbProvider.GenreItem>();
  165. foreach (var genre in genres.Select(g => g.name))
  166. {
  167. movie.AddGenre(genre);
  168. }
  169. //Actors, Directors, Writers - all in People
  170. //actors come from cast
  171. if (movieData.casts != null && movieData.casts.cast != null)
  172. {
  173. foreach (var actor in movieData.casts.cast.OrderBy(a => a.order)) movie.AddPerson(new PersonInfo { Name = actor.name.Trim(), Role = actor.character, Type = PersonType.Actor, SortOrder = actor.order });
  174. }
  175. //and the rest from crew
  176. if (movieData.casts != null && movieData.casts.crew != null)
  177. {
  178. foreach (var person in movieData.casts.crew) movie.AddPerson(new PersonInfo { Name = person.name.Trim(), Role = person.job, Type = person.department });
  179. }
  180. if (movieData.keywords != null && movieData.keywords.keywords != null)
  181. {
  182. var hasTags = movie as IHasKeywords;
  183. if (hasTags != null)
  184. {
  185. hasTags.Keywords = movieData.keywords.keywords.Select(i => i.name).ToList();
  186. }
  187. }
  188. if (movieData.trailers != null && movieData.trailers.youtube != null &&
  189. movieData.trailers.youtube.Count > 0)
  190. {
  191. var hasTrailers = movie as IHasTrailers;
  192. if (hasTrailers != null)
  193. {
  194. hasTrailers.RemoteTrailers = movieData.trailers.youtube.Select(i => new MediaUrl
  195. {
  196. Url = string.Format("http://www.youtube.com/watch?v={0}", i.source),
  197. IsDirectLink = false,
  198. Name = i.name,
  199. VideoSize = string.Equals("hd", i.size, StringComparison.OrdinalIgnoreCase) ? VideoSize.HighDefinition : VideoSize.StandardDefinition
  200. }).ToList();
  201. }
  202. }
  203. }
  204. }
  205. }