FFProbeProvider.cs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. #pragma warning disable CS1591
  2. using System;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. using MediaBrowser.Controller.Chapters;
  8. using MediaBrowser.Controller.Configuration;
  9. using MediaBrowser.Controller.Entities;
  10. using MediaBrowser.Controller.Entities.Audio;
  11. using MediaBrowser.Controller.Entities.Movies;
  12. using MediaBrowser.Controller.Entities.TV;
  13. using MediaBrowser.Controller.Library;
  14. using MediaBrowser.Controller.MediaEncoding;
  15. using MediaBrowser.Controller.Persistence;
  16. using MediaBrowser.Controller.Providers;
  17. using MediaBrowser.Controller.Subtitles;
  18. using MediaBrowser.Model.Entities;
  19. using MediaBrowser.Model.Globalization;
  20. using MediaBrowser.Model.MediaInfo;
  21. using Microsoft.Extensions.Logging;
  22. namespace MediaBrowser.Providers.MediaInfo
  23. {
  24. public class FFProbeProvider : ICustomMetadataProvider<Episode>,
  25. ICustomMetadataProvider<MusicVideo>,
  26. ICustomMetadataProvider<Movie>,
  27. ICustomMetadataProvider<Trailer>,
  28. ICustomMetadataProvider<Video>,
  29. ICustomMetadataProvider<Audio>,
  30. ICustomMetadataProvider<AudioBook>,
  31. IHasOrder,
  32. IForcedProvider,
  33. IPreRefreshProvider,
  34. IHasItemChangeMonitor
  35. {
  36. private readonly ILogger<FFProbeProvider> _logger;
  37. private readonly IMediaEncoder _mediaEncoder;
  38. private readonly IItemRepository _itemRepo;
  39. private readonly IBlurayExaminer _blurayExaminer;
  40. private readonly ILocalizationManager _localization;
  41. private readonly IEncodingManager _encodingManager;
  42. private readonly IServerConfigurationManager _config;
  43. private readonly ISubtitleManager _subtitleManager;
  44. private readonly IChapterManager _chapterManager;
  45. private readonly ILibraryManager _libraryManager;
  46. private readonly IMediaSourceManager _mediaSourceManager;
  47. private readonly SubtitleResolver _subtitleResolver;
  48. private readonly Task<ItemUpdateType> _cachedTask = Task.FromResult(ItemUpdateType.None);
  49. public FFProbeProvider(
  50. ILogger<FFProbeProvider> logger,
  51. IMediaSourceManager mediaSourceManager,
  52. IMediaEncoder mediaEncoder,
  53. IItemRepository itemRepo,
  54. IBlurayExaminer blurayExaminer,
  55. ILocalizationManager localization,
  56. IEncodingManager encodingManager,
  57. IServerConfigurationManager config,
  58. ISubtitleManager subtitleManager,
  59. IChapterManager chapterManager,
  60. ILibraryManager libraryManager)
  61. {
  62. _logger = logger;
  63. _mediaEncoder = mediaEncoder;
  64. _itemRepo = itemRepo;
  65. _blurayExaminer = blurayExaminer;
  66. _localization = localization;
  67. _encodingManager = encodingManager;
  68. _config = config;
  69. _subtitleManager = subtitleManager;
  70. _chapterManager = chapterManager;
  71. _libraryManager = libraryManager;
  72. _mediaSourceManager = mediaSourceManager;
  73. _subtitleResolver = new SubtitleResolver(BaseItem.LocalizationManager);
  74. }
  75. public string Name => "ffprobe";
  76. // Run last
  77. public int Order => 100;
  78. public bool HasChanged(BaseItem item, IDirectoryService directoryService)
  79. {
  80. var video = item as Video;
  81. if (video == null || video.VideoType == VideoType.VideoFile || video.VideoType == VideoType.Iso)
  82. {
  83. var path = item.Path;
  84. if (!string.IsNullOrWhiteSpace(path) && item.IsFileProtocol)
  85. {
  86. var file = directoryService.GetFile(path);
  87. if (file != null && file.LastWriteTimeUtc != item.DateModified)
  88. {
  89. _logger.LogDebug("Refreshing {0} due to date modified timestamp change.", path);
  90. return true;
  91. }
  92. }
  93. }
  94. if (item.SupportsLocalMetadata && video != null && !video.IsPlaceHolder
  95. && !video.SubtitleFiles.SequenceEqual(
  96. _subtitleResolver.GetExternalSubtitleFiles(video, directoryService, false), StringComparer.Ordinal))
  97. {
  98. _logger.LogDebug("Refreshing {0} due to external subtitles change.", item.Path);
  99. return true;
  100. }
  101. return false;
  102. }
  103. public Task<ItemUpdateType> FetchAsync(Episode item, MetadataRefreshOptions options, CancellationToken cancellationToken)
  104. {
  105. return FetchVideoInfo(item, options, cancellationToken);
  106. }
  107. public Task<ItemUpdateType> FetchAsync(MusicVideo item, MetadataRefreshOptions options, CancellationToken cancellationToken)
  108. {
  109. return FetchVideoInfo(item, options, cancellationToken);
  110. }
  111. public Task<ItemUpdateType> FetchAsync(Movie item, MetadataRefreshOptions options, CancellationToken cancellationToken)
  112. {
  113. return FetchVideoInfo(item, options, cancellationToken);
  114. }
  115. public Task<ItemUpdateType> FetchAsync(Trailer item, MetadataRefreshOptions options, CancellationToken cancellationToken)
  116. {
  117. return FetchVideoInfo(item, options, cancellationToken);
  118. }
  119. public Task<ItemUpdateType> FetchAsync(Video item, MetadataRefreshOptions options, CancellationToken cancellationToken)
  120. {
  121. return FetchVideoInfo(item, options, cancellationToken);
  122. }
  123. public Task<ItemUpdateType> FetchAsync(Audio item, MetadataRefreshOptions options, CancellationToken cancellationToken)
  124. {
  125. return FetchAudioInfo(item, options, cancellationToken);
  126. }
  127. public Task<ItemUpdateType> FetchAsync(AudioBook item, MetadataRefreshOptions options, CancellationToken cancellationToken)
  128. {
  129. return FetchAudioInfo(item, options, cancellationToken);
  130. }
  131. public Task<ItemUpdateType> FetchVideoInfo<T>(T item, MetadataRefreshOptions options, CancellationToken cancellationToken)
  132. where T : Video
  133. {
  134. if (item.VideoType == VideoType.Iso)
  135. {
  136. return _cachedTask;
  137. }
  138. if (item.IsPlaceHolder)
  139. {
  140. return _cachedTask;
  141. }
  142. if (!item.IsCompleteMedia)
  143. {
  144. return _cachedTask;
  145. }
  146. if (item.IsVirtualItem)
  147. {
  148. return _cachedTask;
  149. }
  150. if (!options.EnableRemoteContentProbe && !item.IsFileProtocol)
  151. {
  152. return _cachedTask;
  153. }
  154. if (item.IsShortcut)
  155. {
  156. FetchShortcutInfo(item);
  157. }
  158. var prober = new FFProbeVideoInfo(
  159. _logger,
  160. _mediaSourceManager,
  161. _mediaEncoder,
  162. _itemRepo,
  163. _blurayExaminer,
  164. _localization,
  165. _encodingManager,
  166. _config,
  167. _subtitleManager,
  168. _chapterManager,
  169. _libraryManager);
  170. return prober.ProbeVideo(item, options, cancellationToken);
  171. }
  172. private string NormalizeStrmLine(string line)
  173. {
  174. return line.Replace("\t", string.Empty, StringComparison.Ordinal)
  175. .Replace("\r", string.Empty, StringComparison.Ordinal)
  176. .Replace("\n", string.Empty, StringComparison.Ordinal)
  177. .Trim();
  178. }
  179. private void FetchShortcutInfo(BaseItem item)
  180. {
  181. item.ShortcutPath = File.ReadAllLines(item.Path)
  182. .Select(NormalizeStrmLine)
  183. .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i) && !i.StartsWith("#", StringComparison.OrdinalIgnoreCase));
  184. }
  185. public Task<ItemUpdateType> FetchAudioInfo<T>(T item, MetadataRefreshOptions options, CancellationToken cancellationToken)
  186. where T : Audio
  187. {
  188. if (item.IsVirtualItem)
  189. {
  190. return _cachedTask;
  191. }
  192. if (!options.EnableRemoteContentProbe && !item.IsFileProtocol)
  193. {
  194. return _cachedTask;
  195. }
  196. if (item.IsShortcut)
  197. {
  198. FetchShortcutInfo(item);
  199. }
  200. var prober = new FFProbeAudioInfo(_mediaSourceManager, _mediaEncoder, _itemRepo, _libraryManager);
  201. return prober.Probe(item, options, cancellationToken);
  202. }
  203. }
  204. }