ChapterManager.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. using MediaBrowser.Common.Extensions;
  2. using MediaBrowser.Controller.Chapters;
  3. using MediaBrowser.Controller.Configuration;
  4. using MediaBrowser.Controller.Entities;
  5. using MediaBrowser.Controller.Entities.Movies;
  6. using MediaBrowser.Controller.Entities.TV;
  7. using MediaBrowser.Controller.Library;
  8. using MediaBrowser.Controller.Providers;
  9. using MediaBrowser.Model.Chapters;
  10. using MediaBrowser.Model.Logging;
  11. using System;
  12. using System.Collections.Generic;
  13. using System.Linq;
  14. using System.Threading;
  15. using System.Threading.Tasks;
  16. namespace MediaBrowser.Providers.Chapters
  17. {
  18. public class ChapterManager : IChapterManager
  19. {
  20. private IChapterProvider[] _providers;
  21. private readonly ILibraryManager _libraryManager;
  22. private readonly ILogger _logger;
  23. private readonly IServerConfigurationManager _config;
  24. public ChapterManager(ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config)
  25. {
  26. _libraryManager = libraryManager;
  27. _logger = logger;
  28. _config = config;
  29. }
  30. public void AddParts(IEnumerable<IChapterProvider> chapterProviders)
  31. {
  32. _providers = chapterProviders.ToArray();
  33. }
  34. public Task<IEnumerable<RemoteChapterResult>> Search(Video video, CancellationToken cancellationToken)
  35. {
  36. VideoContentType mediaType;
  37. if (video is Episode)
  38. {
  39. mediaType = VideoContentType.Episode;
  40. }
  41. else if (video is Movie)
  42. {
  43. mediaType = VideoContentType.Movie;
  44. }
  45. else
  46. {
  47. // These are the only supported types
  48. return Task.FromResult<IEnumerable<RemoteChapterResult>>(new List<RemoteChapterResult>());
  49. }
  50. var request = new ChapterSearchRequest
  51. {
  52. ContentType = mediaType,
  53. IndexNumber = video.IndexNumber,
  54. //Language = language,
  55. MediaPath = video.Path,
  56. Name = video.Name,
  57. ParentIndexNumber = video.ParentIndexNumber,
  58. ProductionYear = video.ProductionYear,
  59. ProviderIds = video.ProviderIds,
  60. RuntimeTicks = video.RunTimeTicks
  61. };
  62. var episode = video as Episode;
  63. if (episode != null)
  64. {
  65. request.IndexNumberEnd = episode.IndexNumberEnd;
  66. request.SeriesName = episode.SeriesName;
  67. }
  68. return Search(request, cancellationToken);
  69. }
  70. public async Task<IEnumerable<RemoteChapterResult>> Search(ChapterSearchRequest request, CancellationToken cancellationToken)
  71. {
  72. var contentType = request.ContentType;
  73. var providers = GetInternalProviders(false)
  74. .Where(i => i.SupportedMediaTypes.Contains(contentType))
  75. .ToList();
  76. // If not searching all, search one at a time until something is found
  77. if (!request.SearchAllProviders)
  78. {
  79. foreach (var provider in providers)
  80. {
  81. try
  82. {
  83. return await Search(request, provider, cancellationToken).ConfigureAwait(false);
  84. }
  85. catch (Exception ex)
  86. {
  87. _logger.ErrorException("Error downloading subtitles from {0}", ex, provider.Name);
  88. }
  89. }
  90. return new List<RemoteChapterResult>();
  91. }
  92. var tasks = providers.Select(async i =>
  93. {
  94. try
  95. {
  96. return await Search(request, i, cancellationToken).ConfigureAwait(false);
  97. }
  98. catch (Exception ex)
  99. {
  100. _logger.ErrorException("Error downloading subtitles from {0}", ex, i.Name);
  101. return new List<RemoteChapterResult>();
  102. }
  103. });
  104. var results = await Task.WhenAll(tasks).ConfigureAwait(false);
  105. return results.SelectMany(i => i);
  106. }
  107. private async Task<IEnumerable<RemoteChapterResult>> Search(ChapterSearchRequest request,
  108. IChapterProvider provider,
  109. CancellationToken cancellationToken)
  110. {
  111. var searchResults = await provider.Search(request, cancellationToken).ConfigureAwait(false);
  112. foreach (var result in searchResults)
  113. {
  114. result.Id = GetProviderId(provider.Name) + "_" + result.Id;
  115. result.ProviderName = provider.Name;
  116. }
  117. return searchResults;
  118. }
  119. public Task<ChapterResponse> GetChapters(string id, CancellationToken cancellationToken)
  120. {
  121. var parts = id.Split(new[] { '_' }, 2);
  122. var provider = GetProvider(parts.First());
  123. id = parts.Last();
  124. return provider.GetChapters(id, cancellationToken);
  125. }
  126. public IEnumerable<ChapterProviderInfo> GetProviders(string itemId)
  127. {
  128. var video = _libraryManager.GetItemById(itemId) as Video;
  129. VideoContentType mediaType;
  130. if (video is Episode)
  131. {
  132. mediaType = VideoContentType.Episode;
  133. }
  134. else if (video is Movie)
  135. {
  136. mediaType = VideoContentType.Movie;
  137. }
  138. else
  139. {
  140. // These are the only supported types
  141. return new List<ChapterProviderInfo>();
  142. }
  143. var providers = GetInternalProviders(false)
  144. .Where(i => i.SupportedMediaTypes.Contains(mediaType));
  145. return GetInfos(providers);
  146. }
  147. public IEnumerable<ChapterProviderInfo> GetProviders()
  148. {
  149. return GetInfos(GetInternalProviders(true));
  150. }
  151. private IEnumerable<IChapterProvider> GetInternalProviders(bool includeDisabledProviders)
  152. {
  153. var providers = _providers;
  154. if (!includeDisabledProviders)
  155. {
  156. providers = providers
  157. .Where(i => _config.Configuration.ChapterOptions.DisabledFetchers.Contains(i.Name))
  158. .ToArray();
  159. }
  160. return providers
  161. .OrderBy(GetConfiguredOrder)
  162. .ThenBy(GetDefaultOrder)
  163. .ToArray();
  164. }
  165. private IEnumerable<ChapterProviderInfo> GetInfos(IEnumerable<IChapterProvider> providers)
  166. {
  167. return providers.Select(i => new ChapterProviderInfo
  168. {
  169. Name = i.Name,
  170. Id = GetProviderId(i.Name)
  171. });
  172. }
  173. private string GetProviderId(string name)
  174. {
  175. return name.ToLower().GetMD5().ToString("N");
  176. }
  177. private IChapterProvider GetProvider(string id)
  178. {
  179. return _providers.First(i => string.Equals(id, GetProviderId(i.Name)));
  180. }
  181. private int GetConfiguredOrder(IChapterProvider provider)
  182. {
  183. // See if there's a user-defined order
  184. var index = Array.IndexOf(_config.Configuration.ChapterOptions.FetcherOrder, provider.Name);
  185. if (index != -1)
  186. {
  187. return index;
  188. }
  189. // Not configured. Just return some high number to put it at the end.
  190. return 100;
  191. }
  192. private int GetDefaultOrder(IChapterProvider provider)
  193. {
  194. var hasOrder = provider as IHasOrder;
  195. if (hasOrder != null)
  196. {
  197. return hasOrder.Order;
  198. }
  199. return 0;
  200. }
  201. }
  202. }