AudioFileProber.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. #nullable disable
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. using MediaBrowser.Controller.Entities;
  8. using MediaBrowser.Controller.Entities.Audio;
  9. using MediaBrowser.Controller.Library;
  10. using MediaBrowser.Controller.MediaEncoding;
  11. using MediaBrowser.Controller.Persistence;
  12. using MediaBrowser.Controller.Providers;
  13. using MediaBrowser.Model.Dlna;
  14. using MediaBrowser.Model.Dto;
  15. using MediaBrowser.Model.Entities;
  16. using MediaBrowser.Model.MediaInfo;
  17. using TagLib;
  18. namespace MediaBrowser.Providers.MediaInfo
  19. {
  20. /// <summary>
  21. /// Probes audio files for metadata.
  22. /// </summary>
  23. public class AudioFileProber
  24. {
  25. private readonly IMediaEncoder _mediaEncoder;
  26. private readonly IItemRepository _itemRepo;
  27. private readonly ILibraryManager _libraryManager;
  28. private readonly IMediaSourceManager _mediaSourceManager;
  29. /// <summary>
  30. /// Initializes a new instance of the <see cref="AudioFileProber"/> class.
  31. /// </summary>
  32. /// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param>
  33. /// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param>
  34. /// <param name="itemRepo">Instance of the <see cref="IItemRepository"/> interface.</param>
  35. /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
  36. public AudioFileProber(
  37. IMediaSourceManager mediaSourceManager,
  38. IMediaEncoder mediaEncoder,
  39. IItemRepository itemRepo,
  40. ILibraryManager libraryManager)
  41. {
  42. _mediaEncoder = mediaEncoder;
  43. _itemRepo = itemRepo;
  44. _libraryManager = libraryManager;
  45. _mediaSourceManager = mediaSourceManager;
  46. }
  47. /// <summary>
  48. /// Probes the specified item for metadata.
  49. /// </summary>
  50. /// <param name="item">The item to probe.</param>
  51. /// <param name="options">The <see cref="MetadataRefreshOptions"/>.</param>
  52. /// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
  53. /// <typeparam name="T">The type of item to resolve.</typeparam>
  54. /// <returns>A <see cref="Task"/> probing the item for metadata.</returns>
  55. public async Task<ItemUpdateType> Probe<T>(
  56. T item,
  57. MetadataRefreshOptions options,
  58. CancellationToken cancellationToken)
  59. where T : Audio
  60. {
  61. var path = item.Path;
  62. var protocol = item.PathProtocol ?? MediaProtocol.File;
  63. if (!item.IsShortcut || options.EnableRemoteContentProbe)
  64. {
  65. if (item.IsShortcut)
  66. {
  67. path = item.ShortcutPath;
  68. protocol = _mediaSourceManager.GetPathProtocol(path);
  69. }
  70. var result = await _mediaEncoder.GetMediaInfo(
  71. new MediaInfoRequest
  72. {
  73. MediaType = DlnaProfileType.Audio,
  74. MediaSource = new MediaSourceInfo
  75. {
  76. Path = path,
  77. Protocol = protocol
  78. }
  79. },
  80. cancellationToken).ConfigureAwait(false);
  81. cancellationToken.ThrowIfCancellationRequested();
  82. Fetch(item, result, cancellationToken);
  83. }
  84. return ItemUpdateType.MetadataImport;
  85. }
  86. /// <summary>
  87. /// Fetches the specified audio.
  88. /// </summary>
  89. /// <param name="audio">The <see cref="Audio"/>.</param>
  90. /// <param name="mediaInfo">The <see cref="Model.MediaInfo.MediaInfo"/>.</param>
  91. /// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
  92. protected void Fetch(Audio audio, Model.MediaInfo.MediaInfo mediaInfo, CancellationToken cancellationToken)
  93. {
  94. audio.Container = mediaInfo.Container;
  95. audio.TotalBitrate = mediaInfo.Bitrate;
  96. audio.RunTimeTicks = mediaInfo.RunTimeTicks;
  97. audio.Size = mediaInfo.Size;
  98. FetchDataFromTags(audio);
  99. _itemRepo.SaveMediaStreams(audio.Id, mediaInfo.MediaStreams, cancellationToken);
  100. }
  101. /// <summary>
  102. /// Fetches data from the tags.
  103. /// </summary>
  104. /// <param name="audio">The <see cref="Audio"/>.</param>
  105. private void FetchDataFromTags(Audio audio)
  106. {
  107. var file = TagLib.File.Create(audio.Path);
  108. var tagTypes = file.TagTypesOnDisk;
  109. Tag tags = null;
  110. if (tagTypes.HasFlag(TagTypes.Id3v2))
  111. {
  112. tags = file.GetTag(TagTypes.Id3v2);
  113. }
  114. else if (tagTypes.HasFlag(TagTypes.Ape))
  115. {
  116. tags = file.GetTag(TagTypes.Ape);
  117. }
  118. else if (tagTypes.HasFlag(TagTypes.FlacMetadata))
  119. {
  120. tags = file.GetTag(TagTypes.FlacMetadata);
  121. }
  122. else if (tagTypes.HasFlag(TagTypes.Apple))
  123. {
  124. tags = file.GetTag(TagTypes.Apple);
  125. }
  126. else if (tagTypes.HasFlag(TagTypes.AudibleMetadata))
  127. {
  128. tags = file.GetTag(TagTypes.AudibleMetadata);
  129. }
  130. else if (tagTypes.HasFlag(TagTypes.Id3v1))
  131. {
  132. tags = file.GetTag(TagTypes.Id3v1);
  133. }
  134. if (tags != null)
  135. {
  136. if (audio.SupportsPeople && !audio.LockedFields.Contains(MetadataField.Cast))
  137. {
  138. var people = new List<PersonInfo>();
  139. var albumArtists = tags.AlbumArtists;
  140. foreach (var albumArtist in albumArtists)
  141. {
  142. PeopleHelper.AddPerson(people, new PersonInfo
  143. {
  144. Name = albumArtist,
  145. Type = "AlbumArtist"
  146. });
  147. }
  148. var performers = tags.Performers;
  149. foreach (var performer in performers)
  150. {
  151. PeopleHelper.AddPerson(people, new PersonInfo
  152. {
  153. Name = performer,
  154. Type = "Artist"
  155. });
  156. }
  157. foreach (var composer in tags.Composers)
  158. {
  159. PeopleHelper.AddPerson(people, new PersonInfo
  160. {
  161. Name = composer,
  162. Type = "Composer"
  163. });
  164. }
  165. _libraryManager.UpdatePeople(audio, people);
  166. audio.Artists = performers;
  167. audio.AlbumArtists = albumArtists;
  168. }
  169. audio.Name = tags.Title;
  170. audio.Album = tags.Album;
  171. audio.IndexNumber = Convert.ToInt32(tags.Track);
  172. audio.ParentIndexNumber = Convert.ToInt32(tags.Disc);
  173. if (tags.Year != 0)
  174. {
  175. var year = Convert.ToInt32(tags.Year);
  176. audio.ProductionYear = year;
  177. audio.PremiereDate = new DateTime(year, 01, 01);
  178. }
  179. if (!audio.LockedFields.Contains(MetadataField.Genres))
  180. {
  181. audio.Genres = tags.Genres.Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
  182. }
  183. audio.SetProviderId(MetadataProvider.MusicBrainzArtist, tags.MusicBrainzArtistId);
  184. audio.SetProviderId(MetadataProvider.MusicBrainzAlbumArtist, tags.MusicBrainzReleaseArtistId);
  185. audio.SetProviderId(MetadataProvider.MusicBrainzAlbum, tags.MusicBrainzReleaseId);
  186. audio.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, tags.MusicBrainzReleaseGroupId);
  187. audio.SetProviderId(MetadataProvider.MusicBrainzTrack, tags.MusicBrainzTrackId);
  188. }
  189. }
  190. }
  191. }