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;
+}