AlbumMetadataService.cs 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Jellyfin.Data.Enums;
  5. using MediaBrowser.Controller.Configuration;
  6. using MediaBrowser.Controller.Entities;
  7. using MediaBrowser.Controller.Entities.Audio;
  8. using MediaBrowser.Controller.IO;
  9. using MediaBrowser.Controller.Library;
  10. using MediaBrowser.Controller.Providers;
  11. using MediaBrowser.Model.Entities;
  12. using MediaBrowser.Model.IO;
  13. using MediaBrowser.Providers.Manager;
  14. using Microsoft.Extensions.Logging;
  15. namespace MediaBrowser.Providers.Music;
  16. /// <summary>
  17. /// The album metadata service.
  18. /// </summary>
  19. public class AlbumMetadataService : MetadataService<MusicAlbum, AlbumInfo>
  20. {
  21. /// <summary>
  22. /// Initializes a new instance of the <see cref="AlbumMetadataService"/> class.
  23. /// </summary>
  24. /// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/>.</param>
  25. /// <param name="logger">Instance of the <see cref="ILogger"/> interface.</param>
  26. /// <param name="providerManager">Instance of the <see cref="IProviderManager"/> interface.</param>
  27. /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
  28. /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
  29. /// <param name="externalDataManager">Instance of the <see cref="IExternalDataManager"/> interface.</param>
  30. public AlbumMetadataService(
  31. IServerConfigurationManager serverConfigurationManager,
  32. ILogger<AlbumMetadataService> logger,
  33. IProviderManager providerManager,
  34. IFileSystem fileSystem,
  35. ILibraryManager libraryManager,
  36. IExternalDataManager externalDataManager)
  37. : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager, externalDataManager)
  38. {
  39. }
  40. /// <inheritdoc />
  41. protected override bool EnableUpdatingPremiereDateFromChildren => true;
  42. /// <inheritdoc />
  43. protected override bool EnableUpdatingGenresFromChildren => true;
  44. /// <inheritdoc />
  45. protected override bool EnableUpdatingStudiosFromChildren => true;
  46. /// <inheritdoc />
  47. protected override IReadOnlyList<BaseItem> GetChildrenForMetadataUpdates(MusicAlbum item)
  48. => item.GetRecursiveChildren(i => i is Audio);
  49. /// <inheritdoc />
  50. protected override ItemUpdateType UpdateMetadataFromChildren(MusicAlbum item, IReadOnlyList<BaseItem> children, bool isFullRefresh, ItemUpdateType currentUpdateType)
  51. {
  52. var updateType = base.UpdateMetadataFromChildren(item, children, isFullRefresh, currentUpdateType);
  53. // don't update user-changeable metadata for locked items
  54. if (item.IsLocked)
  55. {
  56. return updateType;
  57. }
  58. if (isFullRefresh || currentUpdateType > ItemUpdateType.None)
  59. {
  60. if (!item.LockedFields.Contains(MetadataField.Name))
  61. {
  62. var name = children.Select(i => i.Album).FirstOrDefault(i => !string.IsNullOrEmpty(i));
  63. if (!string.IsNullOrEmpty(name)
  64. && !string.Equals(item.Name, name, StringComparison.Ordinal))
  65. {
  66. item.Name = name;
  67. updateType |= ItemUpdateType.MetadataEdit;
  68. }
  69. }
  70. var songs = children.Cast<Audio>().ToArray();
  71. updateType |= SetArtistsFromSongs(item, songs);
  72. updateType |= SetAlbumArtistFromSongs(item, songs);
  73. updateType |= SetAlbumFromSongs(item, songs);
  74. updateType |= SetPeople(item);
  75. }
  76. return updateType;
  77. }
  78. private ItemUpdateType SetAlbumArtistFromSongs(MusicAlbum item, IReadOnlyList<Audio> songs)
  79. {
  80. var updateType = ItemUpdateType.None;
  81. var albumArtists = songs
  82. .SelectMany(i => i.AlbumArtists)
  83. .GroupBy(i => i)
  84. .OrderByDescending(g => g.Count())
  85. .Select(g => g.Key)
  86. .ToArray();
  87. updateType |= SetProviderIdFromSongs(item, songs, MetadataProvider.MusicBrainzAlbumArtist);
  88. if (!item.AlbumArtists.SequenceEqual(albumArtists, StringComparer.OrdinalIgnoreCase))
  89. {
  90. item.AlbumArtists = albumArtists;
  91. updateType |= ItemUpdateType.MetadataEdit;
  92. }
  93. return updateType;
  94. }
  95. private ItemUpdateType SetArtistsFromSongs(MusicAlbum item, IReadOnlyList<Audio> songs)
  96. {
  97. var updateType = ItemUpdateType.None;
  98. var artists = songs
  99. .SelectMany(i => i.Artists)
  100. .GroupBy(i => i)
  101. .OrderByDescending(g => g.Count())
  102. .Select(g => g.Key)
  103. .ToArray();
  104. if (!item.Artists.SequenceEqual(artists, StringComparer.OrdinalIgnoreCase))
  105. {
  106. item.Artists = artists;
  107. updateType |= ItemUpdateType.MetadataEdit;
  108. }
  109. return updateType;
  110. }
  111. private ItemUpdateType SetAlbumFromSongs(MusicAlbum item, IReadOnlyList<Audio> songs)
  112. {
  113. var updateType = ItemUpdateType.None;
  114. updateType |= SetProviderIdFromSongs(item, songs, MetadataProvider.MusicBrainzAlbum);
  115. updateType |= SetProviderIdFromSongs(item, songs, MetadataProvider.MusicBrainzReleaseGroup);
  116. return updateType;
  117. }
  118. private ItemUpdateType SetProviderIdFromSongs(BaseItem item, IReadOnlyList<Audio> songs, MetadataProvider provider)
  119. {
  120. var ids = songs
  121. .Select(i => i.GetProviderId(provider))
  122. .GroupBy(i => i)
  123. .OrderByDescending(g => g.Count())
  124. .Select(g => g.Key)
  125. .ToArray();
  126. var id = item.GetProviderId(provider);
  127. if (ids.Length != 0)
  128. {
  129. var firstId = ids[0];
  130. if (!string.IsNullOrEmpty(firstId)
  131. && (string.IsNullOrEmpty(id)
  132. || !id.Equals(firstId, StringComparison.OrdinalIgnoreCase)))
  133. {
  134. item.SetProviderId(provider, firstId);
  135. return ItemUpdateType.MetadataEdit;
  136. }
  137. }
  138. return ItemUpdateType.None;
  139. }
  140. private void SetProviderId(MusicAlbum sourceItem, MusicAlbum targetItem, MetadataProvider provider)
  141. {
  142. var source = sourceItem.GetProviderId(provider);
  143. var target = targetItem.GetProviderId(provider);
  144. if (!string.IsNullOrEmpty(source)
  145. && (string.IsNullOrEmpty(target)
  146. || !target.Equals(source, StringComparison.Ordinal)))
  147. {
  148. targetItem.SetProviderId(provider, source);
  149. }
  150. }
  151. private ItemUpdateType SetPeople(MusicAlbum item)
  152. {
  153. var updateType = ItemUpdateType.None;
  154. if (item.AlbumArtists.Any() || item.Artists.Any())
  155. {
  156. var people = new List<PersonInfo>();
  157. foreach (var albumArtist in item.AlbumArtists)
  158. {
  159. PeopleHelper.AddPerson(people, new PersonInfo
  160. {
  161. Name = albumArtist.Trim(),
  162. Type = PersonKind.AlbumArtist
  163. });
  164. }
  165. foreach (var artist in item.Artists)
  166. {
  167. PeopleHelper.AddPerson(people, new PersonInfo
  168. {
  169. Name = artist.Trim(),
  170. Type = PersonKind.Artist
  171. });
  172. }
  173. LibraryManager.UpdatePeople(item, people);
  174. updateType |= ItemUpdateType.MetadataEdit;
  175. }
  176. return updateType;
  177. }
  178. /// <inheritdoc />
  179. protected override void MergeData(
  180. MetadataResult<MusicAlbum> source,
  181. MetadataResult<MusicAlbum> target,
  182. MetadataField[] lockedFields,
  183. bool replaceData,
  184. bool mergeMetadataSettings)
  185. {
  186. base.MergeData(source, target, lockedFields, replaceData, mergeMetadataSettings);
  187. var sourceItem = source.Item;
  188. var targetItem = target.Item;
  189. if (replaceData || targetItem.Artists.Count == 0)
  190. {
  191. targetItem.Artists = sourceItem.Artists;
  192. }
  193. else
  194. {
  195. targetItem.Artists = targetItem.Artists.Concat(sourceItem.Artists).Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
  196. }
  197. if (replaceData || string.IsNullOrEmpty(targetItem.GetProviderId(MetadataProvider.MusicBrainzAlbumArtist)))
  198. {
  199. SetProviderId(sourceItem, targetItem, MetadataProvider.MusicBrainzAlbumArtist);
  200. }
  201. if (replaceData || string.IsNullOrEmpty(targetItem.GetProviderId(MetadataProvider.MusicBrainzAlbum)))
  202. {
  203. SetProviderId(sourceItem, targetItem, MetadataProvider.MusicBrainzAlbum);
  204. }
  205. if (replaceData || string.IsNullOrEmpty(targetItem.GetProviderId(MetadataProvider.MusicBrainzReleaseGroup)))
  206. {
  207. SetProviderId(sourceItem, targetItem, MetadataProvider.MusicBrainzReleaseGroup);
  208. }
  209. }
  210. }