TmdbEpisodeProvider.cs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. #nullable disable
  2. #pragma warning disable CS1591
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Globalization;
  6. using System.Linq;
  7. using System.Net.Http;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. using MediaBrowser.Common.Net;
  11. using MediaBrowser.Controller.Entities;
  12. using MediaBrowser.Controller.Entities.TV;
  13. using MediaBrowser.Controller.Providers;
  14. using MediaBrowser.Model.Entities;
  15. using MediaBrowser.Model.Providers;
  16. namespace MediaBrowser.Providers.Plugins.Tmdb.TV
  17. {
  18. public class TmdbEpisodeProvider : IRemoteMetadataProvider<Episode, EpisodeInfo>, IHasOrder
  19. {
  20. private readonly IHttpClientFactory _httpClientFactory;
  21. private readonly TmdbClientManager _tmdbClientManager;
  22. public TmdbEpisodeProvider(IHttpClientFactory httpClientFactory, TmdbClientManager tmdbClientManager)
  23. {
  24. _httpClientFactory = httpClientFactory;
  25. _tmdbClientManager = tmdbClientManager;
  26. }
  27. // After TheTvDb
  28. public int Order => 1;
  29. public string Name => TmdbUtils.ProviderName;
  30. public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken)
  31. {
  32. // The search query must either provide an episode number or date
  33. if (!searchInfo.IndexNumber.HasValue || !searchInfo.ParentIndexNumber.HasValue)
  34. {
  35. return Enumerable.Empty<RemoteSearchResult>();
  36. }
  37. var metadataResult = await GetMetadata(searchInfo, cancellationToken).ConfigureAwait(false);
  38. if (!metadataResult.HasMetadata)
  39. {
  40. return Enumerable.Empty<RemoteSearchResult>();
  41. }
  42. var item = metadataResult.Item;
  43. return new[]
  44. {
  45. new RemoteSearchResult
  46. {
  47. IndexNumber = item.IndexNumber,
  48. Name = item.Name,
  49. ParentIndexNumber = item.ParentIndexNumber,
  50. PremiereDate = item.PremiereDate,
  51. ProductionYear = item.ProductionYear,
  52. ProviderIds = item.ProviderIds,
  53. SearchProviderName = Name,
  54. IndexNumberEnd = item.IndexNumberEnd
  55. }
  56. };
  57. }
  58. public async Task<MetadataResult<Episode>> GetMetadata(EpisodeInfo info, CancellationToken cancellationToken)
  59. {
  60. var metadataResult = new MetadataResult<Episode>();
  61. // Allowing this will dramatically increase scan times
  62. if (info.IsMissingEpisode)
  63. {
  64. return metadataResult;
  65. }
  66. info.SeriesProviderIds.TryGetValue(MetadataProvider.Tmdb.ToString(), out string tmdbId);
  67. var seriesTmdbId = Convert.ToInt32(tmdbId, CultureInfo.InvariantCulture);
  68. if (seriesTmdbId <= 0)
  69. {
  70. return metadataResult;
  71. }
  72. var seasonNumber = info.ParentIndexNumber;
  73. var episodeNumber = info.IndexNumber;
  74. if (!seasonNumber.HasValue || !episodeNumber.HasValue)
  75. {
  76. return metadataResult;
  77. }
  78. var episodeResult = await _tmdbClientManager
  79. .GetEpisodeAsync(seriesTmdbId, seasonNumber.Value, episodeNumber.Value, info.SeriesDisplayOrder, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken)
  80. .ConfigureAwait(false);
  81. if (episodeResult == null)
  82. {
  83. return metadataResult;
  84. }
  85. metadataResult.HasMetadata = true;
  86. metadataResult.QueriedById = true;
  87. if (!string.IsNullOrEmpty(episodeResult.Overview))
  88. {
  89. // if overview is non-empty, we can assume that localized data was returned
  90. metadataResult.ResultLanguage = info.MetadataLanguage;
  91. }
  92. var item = new Episode
  93. {
  94. IndexNumber = info.IndexNumber,
  95. ParentIndexNumber = info.ParentIndexNumber,
  96. IndexNumberEnd = info.IndexNumberEnd,
  97. Name = episodeResult.Name,
  98. PremiereDate = episodeResult.AirDate,
  99. ProductionYear = episodeResult.AirDate?.Year,
  100. Overview = episodeResult.Overview,
  101. CommunityRating = Convert.ToSingle(episodeResult.VoteAverage)
  102. };
  103. var externalIds = episodeResult.ExternalIds;
  104. if (!string.IsNullOrEmpty(externalIds?.TvdbId))
  105. {
  106. item.SetProviderId(MetadataProvider.Tvdb, externalIds.TvdbId);
  107. }
  108. if (!string.IsNullOrEmpty(externalIds?.ImdbId))
  109. {
  110. item.SetProviderId(MetadataProvider.Imdb, externalIds.ImdbId);
  111. }
  112. if (!string.IsNullOrEmpty(externalIds?.TvrageId))
  113. {
  114. item.SetProviderId(MetadataProvider.TvRage, externalIds.TvrageId);
  115. }
  116. if (episodeResult.Videos?.Results != null)
  117. {
  118. foreach (var video in episodeResult.Videos.Results)
  119. {
  120. if (TmdbUtils.IsTrailerType(video))
  121. {
  122. item.AddTrailerUrl("https://www.youtube.com/watch?v=" + video.Key);
  123. }
  124. }
  125. }
  126. var credits = episodeResult.Credits;
  127. if (credits?.Cast != null)
  128. {
  129. foreach (var actor in credits.Cast.OrderBy(a => a.Order).Take(Plugin.Instance.Configuration.MaxCastMembers))
  130. {
  131. metadataResult.AddPerson(new PersonInfo
  132. {
  133. Name = actor.Name.Trim(),
  134. Role = actor.Character,
  135. Type = PersonType.Actor,
  136. SortOrder = actor.Order
  137. });
  138. }
  139. }
  140. if (credits?.GuestStars != null)
  141. {
  142. foreach (var guest in credits.GuestStars.OrderBy(a => a.Order).Take(Plugin.Instance.Configuration.MaxCastMembers))
  143. {
  144. metadataResult.AddPerson(new PersonInfo
  145. {
  146. Name = guest.Name.Trim(),
  147. Role = guest.Character,
  148. Type = PersonType.GuestStar,
  149. SortOrder = guest.Order
  150. });
  151. }
  152. }
  153. // and the rest from crew
  154. if (credits?.Crew != null)
  155. {
  156. foreach (var person in credits.Crew)
  157. {
  158. // Normalize this
  159. var type = TmdbUtils.MapCrewToPersonType(person);
  160. if (!TmdbUtils.WantedCrewTypes.Contains(type, StringComparer.OrdinalIgnoreCase)
  161. && !TmdbUtils.WantedCrewTypes.Contains(person.Job ?? string.Empty, StringComparer.OrdinalIgnoreCase))
  162. {
  163. continue;
  164. }
  165. metadataResult.AddPerson(new PersonInfo
  166. {
  167. Name = person.Name.Trim(),
  168. Role = person.Job,
  169. Type = type
  170. });
  171. }
  172. }
  173. metadataResult.Item = item;
  174. return metadataResult;
  175. }
  176. public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
  177. {
  178. return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken);
  179. }
  180. }
  181. }