AudioFileProber.cs 8.3 KB

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