diff --git a/MediaBrowser.Model/Entities/MetadataProvider.cs b/MediaBrowser.Model/Entities/MetadataProvider.cs index dcc4ae88c5..65337b60fd 100644 --- a/MediaBrowser.Model/Entities/MetadataProvider.cs +++ b/MediaBrowser.Model/Entities/MetadataProvider.cs @@ -84,6 +84,11 @@ namespace MediaBrowser.Model.Entities /// /// The TvMaze provider. /// - TvMaze = 19 + TvMaze = 19, + + /// + /// The MusicBrainz recording provider. + /// + MusicBrainzRecording = 20, } } diff --git a/MediaBrowser.Model/Providers/ExternalIdMediaType.cs b/MediaBrowser.Model/Providers/ExternalIdMediaType.cs index ef518369cc..71a131bb80 100644 --- a/MediaBrowser.Model/Providers/ExternalIdMediaType.cs +++ b/MediaBrowser.Model/Providers/ExternalIdMediaType.cs @@ -71,6 +71,11 @@ namespace MediaBrowser.Model.Providers /// /// A book. /// - Book = 13 + Book = 13, + + /// + /// A music recording. + /// + Recording = 14 } } diff --git a/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs b/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs index a0481a6426..963b611515 100644 --- a/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs +++ b/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs @@ -19,6 +19,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Extensions; using MediaBrowser.Model.MediaInfo; using Microsoft.Extensions.Logging; +using static Jellyfin.Extensions.StringExtensions; namespace MediaBrowser.Providers.MediaInfo { @@ -400,6 +401,24 @@ namespace MediaBrowser.Providers.MediaInfo } } + if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzRecording, out _)) + { + if ((track.AdditionalFields.TryGetValue("MUSICBRAINZ_TRACKID", out var recordingMbId) + || track.AdditionalFields.TryGetValue("MusicBrainz Track Id", out recordingMbId)) + && !string.IsNullOrEmpty(recordingMbId)) + { + audio.TrySetProviderId(MetadataProvider.MusicBrainzRecording, recordingMbId); + } + else if (track.AdditionalFields.TryGetValue("UFID", out var ufIdValue) && !string.IsNullOrEmpty(ufIdValue)) + { + // If tagged with MB Picard, the format is 'http://musicbrainz.org\0' + if (ufIdValue.Contains("musicbrainz.org", StringComparison.OrdinalIgnoreCase)) + { + audio.TrySetProviderId(MetadataProvider.MusicBrainzRecording, ufIdValue.AsSpan().RightPart('\0').ToString()); + } + } + } + // Save extracted lyrics if they exist, // and if the audio doesn't yet have lyrics. var lyrics = track.Lyrics.SynchronizedLyrics.Count > 0 ? track.Lyrics.FormatSynchToLRC() : track.Lyrics.UnsynchronizedLyrics; diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzRecordingId.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzRecordingId.cs new file mode 100644 index 0000000000..d2af628067 --- /dev/null +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzRecordingId.cs @@ -0,0 +1,27 @@ +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; + +namespace MediaBrowser.Providers.Plugins.MusicBrainz; + +/// +/// MusicBrainz recording id. +/// +public class MusicBrainzRecordingId : IExternalId +{ + /// + public string ProviderName => "MusicBrainz"; + + /// + public string Key => MetadataProvider.MusicBrainzRecording.ToString(); + + /// + public ExternalIdMediaType? Type => ExternalIdMediaType.Recording; + + /// + public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/recording/{0}"; + + /// + public bool Supports(IHasProviderIds item) => item is Audio; +}