FFProbeProvider.cs 7.4 KB

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