AudioFileProber.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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. FetchDataFromTags(audio);
  98. _itemRepo.SaveMediaStreams(audio.Id, mediaInfo.MediaStreams, cancellationToken);
  99. }
  100. /// <summary>
  101. /// Fetches data from the tags.
  102. /// </summary>
  103. /// <param name="audio">The <see cref="Audio"/>.</param>
  104. private void FetchDataFromTags(Audio audio)
  105. {
  106. var file = TagLib.File.Create(audio.Path);
  107. var tagTypes = file.TagTypesOnDisk;
  108. Tag? tags = null;
  109. if (tagTypes.HasFlag(TagTypes.Id3v2))
  110. {
  111. tags = file.GetTag(TagTypes.Id3v2);
  112. }
  113. else if (tagTypes.HasFlag(TagTypes.Ape))
  114. {
  115. tags = file.GetTag(TagTypes.Ape);
  116. }
  117. else if (tagTypes.HasFlag(TagTypes.FlacMetadata))
  118. {
  119. tags = file.GetTag(TagTypes.FlacMetadata);
  120. }
  121. else if (tagTypes.HasFlag(TagTypes.Apple))
  122. {
  123. tags = file.GetTag(TagTypes.Apple);
  124. }
  125. else if (tagTypes.HasFlag(TagTypes.Xiph))
  126. {
  127. tags = file.GetTag(TagTypes.Xiph);
  128. }
  129. else if (tagTypes.HasFlag(TagTypes.AudibleMetadata))
  130. {
  131. tags = file.GetTag(TagTypes.AudibleMetadata);
  132. }
  133. else if (tagTypes.HasFlag(TagTypes.Id3v1))
  134. {
  135. tags = file.GetTag(TagTypes.Id3v1);
  136. }
  137. if (tags is not null)
  138. {
  139. if (audio.SupportsPeople && !audio.LockedFields.Contains(MetadataField.Cast))
  140. {
  141. var people = new List<PersonInfo>();
  142. var albumArtists = tags.AlbumArtists;
  143. foreach (var albumArtist in albumArtists)
  144. {
  145. PeopleHelper.AddPerson(people, new PersonInfo
  146. {
  147. Name = albumArtist,
  148. Type = "AlbumArtist"
  149. });
  150. }
  151. var performers = tags.Performers;
  152. foreach (var performer in performers)
  153. {
  154. PeopleHelper.AddPerson(people, new PersonInfo
  155. {
  156. Name = performer,
  157. Type = "Artist"
  158. });
  159. }
  160. foreach (var composer in tags.Composers)
  161. {
  162. PeopleHelper.AddPerson(people, new PersonInfo
  163. {
  164. Name = composer,
  165. Type = "Composer"
  166. });
  167. }
  168. _libraryManager.UpdatePeople(audio, people);
  169. audio.Artists = performers;
  170. audio.AlbumArtists = albumArtists;
  171. }
  172. audio.Name = tags.Title;
  173. audio.Album = tags.Album;
  174. audio.IndexNumber = Convert.ToInt32(tags.Track);
  175. audio.ParentIndexNumber = Convert.ToInt32(tags.Disc);
  176. if (tags.Year != 0)
  177. {
  178. var year = Convert.ToInt32(tags.Year);
  179. audio.ProductionYear = year;
  180. audio.PremiereDate = new DateTime(year, 01, 01);
  181. }
  182. if (!audio.LockedFields.Contains(MetadataField.Genres))
  183. {
  184. audio.Genres = tags.Genres.Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
  185. }
  186. audio.SetProviderId(MetadataProvider.MusicBrainzArtist, tags.MusicBrainzArtistId);
  187. audio.SetProviderId(MetadataProvider.MusicBrainzAlbumArtist, tags.MusicBrainzReleaseArtistId);
  188. audio.SetProviderId(MetadataProvider.MusicBrainzAlbum, tags.MusicBrainzReleaseId);
  189. audio.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, tags.MusicBrainzReleaseGroupId);
  190. audio.SetProviderId(MetadataProvider.MusicBrainzTrack, tags.MusicBrainzTrackId);
  191. }
  192. }
  193. }
  194. }