瀏覽代碼

Merge pull request #13175 from Shadowghost/external-url-providers

Migrate to IExternalUrlProvider
Joshua M. Boniface 2 月之前
父節點
當前提交
79437f85c5
共有 42 個文件被更改,包括 385 次插入171 次删除
  1. 2 4
      MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
  2. 0 6
      MediaBrowser.Controller/Providers/IExternalId.cs
  3. 1 13
      MediaBrowser.Model/Providers/ExternalIdInfo.cs
  4. 2 30
      MediaBrowser.Providers/Manager/ProviderManager.cs
  5. 0 3
      MediaBrowser.Providers/Movies/ImdbExternalId.cs
  6. 25 0
      MediaBrowser.Providers/Movies/ImdbExternalUrlProvider.cs
  7. 0 3
      MediaBrowser.Providers/Movies/ImdbPersonExternalId.cs
  8. 0 3
      MediaBrowser.Providers/Music/ImvdbId.cs
  9. 0 3
      MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumExternalId.cs
  10. 31 0
      MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumExternalUrlProvider.cs
  11. 2 5
      MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumImageProvider.cs
  12. 0 3
      MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalId.cs
  13. 32 0
      MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalUrlProvider.cs
  14. 5 8
      MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistImageProvider.cs
  15. 0 3
      MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherAlbumExternalId.cs
  16. 0 3
      MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherArtistExternalId.cs
  17. 0 3
      MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumArtistExternalId.cs
  18. 28 0
      MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumArtistExternalUrlProvider.cs
  19. 0 3
      MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumExternalId.cs
  20. 28 0
      MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumExternalUrlProvider.cs
  21. 0 3
      MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalId.cs
  22. 32 0
      MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalUrlProvider.cs
  23. 0 3
      MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzOtherArtistExternalId.cs
  24. 0 3
      MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzReleaseGroupExternalId.cs
  25. 28 0
      MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzReleaseGroupExternalUrlProvider.cs
  26. 28 0
      MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzTrackExternalUrlProvider.cs
  27. 0 3
      MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzTrackId.cs
  28. 0 3
      MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetExternalId.cs
  29. 0 3
      MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieExternalId.cs
  30. 0 3
      MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonExternalId.cs
  31. 0 3
      MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesExternalId.cs
  32. 95 0
      MediaBrowser.Providers/Plugins/Tmdb/TmdbExternalUrlProvider.cs
  33. 0 3
      MediaBrowser.Providers/TV/Zap2ItExternalId.cs
  34. 24 0
      MediaBrowser.Providers/TV/Zap2ItExternalUrlProvider.cs
  35. 12 32
      MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
  36. 1 3
      MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs
  37. 1 3
      MediaBrowser.XbmcMetadata/Savers/SeriesNfoSaver.cs
  38. 4 9
      src/Jellyfin.LiveTv/Recordings/RecordingsMetadataManager.cs
  39. 1 1
      tests/Jellyfin.XbmcMetadata.Tests/Parsers/EpisodeNfoProviderTests.cs
  40. 1 1
      tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs
  41. 1 1
      tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicAlbumNfoProviderTests.cs
  42. 1 1
      tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicArtistNfoParserTests.cs

+ 2 - 4
MediaBrowser.Controller/Entities/Audio/MusicArtist.cs

@@ -138,11 +138,9 @@ namespace MediaBrowser.Controller.Entities.Audio
         private static List<string> GetUserDataKeys(MusicArtist item)
         {
             var list = new List<string>();
-            var id = item.GetProviderId(MetadataProvider.MusicBrainzArtist);
-
-            if (!string.IsNullOrEmpty(id))
+            if (item.TryGetProviderId(MetadataProvider.MusicBrainzArtist, out var externalId))
             {
-                list.Add("Artist-Musicbrainz-" + id);
+                list.Add("Artist-Musicbrainz-" + externalId);
             }
 
             list.Add("Artist-" + (item.Name ?? string.Empty).RemoveDiacritics());

+ 0 - 6
MediaBrowser.Controller/Providers/IExternalId.cs

@@ -31,12 +31,6 @@ namespace MediaBrowser.Controller.Providers
         /// </remarks>
         ExternalIdMediaType? Type { get; }
 
-        /// <summary>
-        /// Gets the URL format string for this id.
-        /// </summary>
-        [Obsolete("Obsolete in 10.10, to be removed in 10.11")]
-        string? UrlFormatString { get; }
-
         /// <summary>
         /// Determines whether this id supports a given item type.
         /// </summary>

+ 1 - 13
MediaBrowser.Model/Providers/ExternalIdInfo.cs

@@ -1,5 +1,3 @@
-using System;
-
 namespace MediaBrowser.Model.Providers
 {
     /// <summary>
@@ -13,15 +11,11 @@ namespace MediaBrowser.Model.Providers
         /// <param name="name">Name of the external id provider (IE: IMDB, MusicBrainz, etc).</param>
         /// <param name="key">Key for this id. This key should be unique across all providers.</param>
         /// <param name="type">Specific media type for this id.</param>
-        /// <param name="urlFormatString">URL format string.</param>
-        public ExternalIdInfo(string name, string key, ExternalIdMediaType? type, string? urlFormatString)
+        public ExternalIdInfo(string name, string key, ExternalIdMediaType? type)
         {
             Name = name;
             Key = key;
             Type = type;
-#pragma warning disable CS0618 // Type or member is obsolete - Remove 10.11
-            UrlFormatString = urlFormatString;
-#pragma warning restore CS0618 // Type or member is obsolete
         }
 
         /// <summary>
@@ -46,11 +40,5 @@ namespace MediaBrowser.Model.Providers
         /// This can be used along with the <see cref="Name"/> to localize the external id on the client.
         /// </remarks>
         public ExternalIdMediaType? Type { get; set; }
-
-        /// <summary>
-        /// Gets or sets the URL format string.
-        /// </summary>
-        [Obsolete("Obsolete in 10.10, to be removed in 10.11")]
-        public string? UrlFormatString { get; set; }
     }
 }

+ 2 - 30
MediaBrowser.Providers/Manager/ProviderManager.cs

@@ -899,35 +899,10 @@ namespace MediaBrowser.Providers.Manager
         /// <inheritdoc/>
         public IEnumerable<ExternalUrl> GetExternalUrls(BaseItem item)
         {
-#pragma warning disable CS0618 // Type or member is obsolete - Remove 10.11
-            var legacyExternalIdUrls = GetExternalIds(item)
-                .Select(i =>
-                {
-                    var urlFormatString = i.UrlFormatString;
-                    if (string.IsNullOrEmpty(urlFormatString)
-                        || !item.TryGetProviderId(i.Key, out var providerId))
-                    {
-                        return null;
-                    }
-
-                    return new ExternalUrl
-                    {
-                        Name = i.ProviderName,
-                        Url = string.Format(
-                            CultureInfo.InvariantCulture,
-                            urlFormatString,
-                            providerId)
-                    };
-                })
-                .OfType<ExternalUrl>();
-#pragma warning restore CS0618 // Type or member is obsolete
-
-            var externalUrls = _externalUrlProviders
+            return _externalUrlProviders
                 .SelectMany(p => p
                     .GetExternalUrls(item)
                     .Select(externalUrl => new ExternalUrl { Name = p.Name, Url = externalUrl }));
-
-            return legacyExternalIdUrls.Concat(externalUrls).OrderBy(u => u.Name);
         }
 
         /// <inheritdoc/>
@@ -937,10 +912,7 @@ namespace MediaBrowser.Providers.Manager
                 .Select(i => new ExternalIdInfo(
                     name: i.ProviderName,
                     key: i.Key,
-                    type: i.Type,
-#pragma warning disable CS0618 // Type or member is obsolete - Remove 10.11
-                    urlFormatString: i.UrlFormatString));
-#pragma warning restore CS0618 // Type or member is obsolete
+                    type: i.Type));
         }
 
         /// <inheritdoc/>

+ 0 - 3
MediaBrowser.Providers/Movies/ImdbExternalId.cs

@@ -21,9 +21,6 @@ namespace MediaBrowser.Providers.Movies
         /// <inheritdoc />
         public ExternalIdMediaType? Type => null;
 
-        /// <inheritdoc />
-        public string UrlFormatString => "https://www.imdb.com/title/{0}";
-
         /// <inheritdoc />
         public bool Supports(IHasProviderIds item)
         {

+ 25 - 0
MediaBrowser.Providers/Movies/ImdbExternalUrlProvider.cs

@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Providers.Movies;
+
+/// <summary>
+/// External URLs for IMDb.
+/// </summary>
+public class ImdbExternalUrlProvider : IExternalUrlProvider
+{
+    /// <inheritdoc/>
+    public string Name => "IMDb";
+
+    /// <inheritdoc/>
+    public IEnumerable<string> GetExternalUrls(BaseItem item)
+    {
+        var baseUrl = "https://www.imdb.com/";
+        if (item.TryGetProviderId(MetadataProvider.Imdb, out var externalId))
+        {
+            yield return baseUrl + $"title/{externalId}";
+        }
+    }
+}

+ 0 - 3
MediaBrowser.Providers/Movies/ImdbPersonExternalId.cs

@@ -18,9 +18,6 @@ namespace MediaBrowser.Providers.Movies
         /// <inheritdoc />
         public ExternalIdMediaType? Type => ExternalIdMediaType.Person;
 
-        /// <inheritdoc />
-        public string UrlFormatString => "https://www.imdb.com/name/{0}";
-
         /// <inheritdoc />
         public bool Supports(IHasProviderIds item) => item is Person;
     }

+ 0 - 3
MediaBrowser.Providers/Music/ImvdbId.cs

@@ -18,9 +18,6 @@ namespace MediaBrowser.Providers.Music
         /// <inheritdoc />
         public ExternalIdMediaType? Type => null;
 
-        /// <inheritdoc />
-        public string? UrlFormatString => null;
-
         /// <inheritdoc />
         public bool Supports(IHasProviderIds item)
             => item is MusicVideo;

+ 0 - 3
MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumExternalId.cs

@@ -18,9 +18,6 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
         /// <inheritdoc />
         public ExternalIdMediaType? Type => null;
 
-        /// <inheritdoc />
-        public string UrlFormatString => "https://www.theaudiodb.com/album/{0}";
-
         /// <inheritdoc />
         public bool Supports(IHasProviderIds item) => item is MusicAlbum;
     }

+ 31 - 0
MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumExternalUrlProvider.cs

@@ -0,0 +1,31 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Providers.Plugins.AudioDb;
+
+/// <summary>
+/// External artist URLs for AudioDb.
+/// </summary>
+public class AudioDbAlbumExternalUrlProvider : IExternalUrlProvider
+{
+    /// <inheritdoc/>
+    public string Name => "TheAudioDb Album";
+
+    /// <inheritdoc/>
+    public IEnumerable<string> GetExternalUrls(BaseItem item)
+    {
+        if (item.TryGetProviderId(MetadataProvider.AudioDbAlbum, out var externalId))
+        {
+            var baseUrl = "https://www.theaudiodb.com/";
+            switch (item)
+            {
+                case MusicAlbum:
+                    yield return baseUrl + $"album/{externalId}";
+                    break;
+            }
+        }
+    }
+}

+ 2 - 5
MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumImageProvider.cs

@@ -4,7 +4,6 @@
 
 using System.Collections.Generic;
 using System.IO;
-using System.Linq;
 using System.Net.Http;
 using System.Text.Json;
 using System.Threading;
@@ -50,9 +49,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
         /// <inheritdoc />
         public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken)
         {
-            var id = item.GetProviderId(MetadataProvider.MusicBrainzReleaseGroup);
-
-            if (!string.IsNullOrWhiteSpace(id))
+            if (item.TryGetProviderId(MetadataProvider.MusicBrainzReleaseGroup, out var id))
             {
                 await AudioDbAlbumProvider.Current.EnsureInfo(id, cancellationToken).ConfigureAwait(false);
 
@@ -70,7 +67,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
                 }
             }
 
-            return Enumerable.Empty<RemoteImageInfo>();
+            return [];
         }
 
         private List<RemoteImageInfo> GetImages(AudioDbAlbumProvider.Album item)

+ 0 - 3
MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalId.cs

@@ -18,9 +18,6 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
         /// <inheritdoc />
         public ExternalIdMediaType? Type => ExternalIdMediaType.Artist;
 
-        /// <inheritdoc />
-        public string UrlFormatString => "https://www.theaudiodb.com/artist/{0}";
-
         /// <inheritdoc />
         public bool Supports(IHasProviderIds item) => item is MusicArtist;
     }

+ 32 - 0
MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalUrlProvider.cs

@@ -0,0 +1,32 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Providers.Plugins.AudioDb;
+
+/// <summary>
+/// External artist URLs for AudioDb.
+/// </summary>
+public class AudioDbArtistExternalUrlProvider : IExternalUrlProvider
+{
+    /// <inheritdoc/>
+    public string Name => "TheAudioDb Artist";
+
+    /// <inheritdoc/>
+    public IEnumerable<string> GetExternalUrls(BaseItem item)
+    {
+        if (item.TryGetProviderId(MetadataProvider.AudioDbArtist, out var externalId))
+        {
+            var baseUrl = "https://www.theaudiodb.com/";
+            switch (item)
+            {
+                case MusicAlbum:
+                case Person:
+                    yield return baseUrl + $"artist/{externalId}";
+                    break;
+            }
+        }
+    }
+}

+ 5 - 8
MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistImageProvider.cs

@@ -4,7 +4,6 @@
 
 using System.Collections.Generic;
 using System.IO;
-using System.Linq;
 using System.Net.Http;
 using System.Text.Json;
 using System.Threading;
@@ -43,21 +42,19 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
         /// <inheritdoc />
         public IEnumerable<ImageType> GetSupportedImages(BaseItem item)
         {
-            return new ImageType[]
-            {
+            return
+            [
                 ImageType.Primary,
                 ImageType.Logo,
                 ImageType.Banner,
                 ImageType.Backdrop
-            };
+            ];
         }
 
         /// <inheritdoc />
         public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken)
         {
-            var id = item.GetProviderId(MetadataProvider.MusicBrainzArtist);
-
-            if (!string.IsNullOrWhiteSpace(id))
+            if (item.TryGetProviderId(MetadataProvider.MusicBrainzArtist, out var id))
             {
                 await AudioDbArtistProvider.Current.EnsureArtistInfo(id, cancellationToken).ConfigureAwait(false);
 
@@ -75,7 +72,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
                 }
             }
 
-            return Enumerable.Empty<RemoteImageInfo>();
+            return [];
         }
 
         private List<RemoteImageInfo> GetImages(AudioDbArtistProvider.Artist item)

+ 0 - 3
MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherAlbumExternalId.cs

@@ -18,9 +18,6 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
         /// <inheritdoc />
         public ExternalIdMediaType? Type => ExternalIdMediaType.Album;
 
-        /// <inheritdoc />
-        public string UrlFormatString => "https://www.theaudiodb.com/album/{0}";
-
         /// <inheritdoc />
         public bool Supports(IHasProviderIds item) => item is Audio;
     }

+ 0 - 3
MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherArtistExternalId.cs

@@ -18,9 +18,6 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
         /// <inheritdoc />
         public ExternalIdMediaType? Type => ExternalIdMediaType.OtherArtist;
 
-        /// <inheritdoc />
-        public string UrlFormatString => "https://www.theaudiodb.com/artist/{0}";
-
         /// <inheritdoc />
         public bool Supports(IHasProviderIds item) => item is Audio || item is MusicAlbum;
     }

+ 0 - 3
MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumArtistExternalId.cs

@@ -19,9 +19,6 @@ public class MusicBrainzAlbumArtistExternalId : IExternalId
     /// <inheritdoc />
     public ExternalIdMediaType? Type => ExternalIdMediaType.AlbumArtist;
 
-    /// <inheritdoc />
-    public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/artist/{0}";
-
     /// <inheritdoc />
     public bool Supports(IHasProviderIds item) => item is Audio;
 }

+ 28 - 0
MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumArtistExternalUrlProvider.cs

@@ -0,0 +1,28 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Providers.Plugins.MusicBrainz;
+
+/// <summary>
+/// External album artist URLs for MusicBrainz.
+/// </summary>
+public class MusicBrainzAlbumArtistExternalUrlProvider : IExternalUrlProvider
+{
+    /// <inheritdoc/>
+    public string Name => "MusicBrainz Album Artist";
+
+    /// <inheritdoc/>
+    public IEnumerable<string> GetExternalUrls(BaseItem item)
+    {
+        if (item is MusicAlbum)
+        {
+            if (item.TryGetProviderId(MetadataProvider.MusicBrainzAlbumArtist, out var externalId))
+            {
+                yield return Plugin.Instance!.Configuration.Server + $"/artist/{externalId}";
+            }
+        }
+    }
+}

+ 0 - 3
MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumExternalId.cs

@@ -19,9 +19,6 @@ public class MusicBrainzAlbumExternalId : IExternalId
     /// <inheritdoc />
     public ExternalIdMediaType? Type => ExternalIdMediaType.Album;
 
-    /// <inheritdoc />
-    public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/release/{0}";
-
     /// <inheritdoc />
     public bool Supports(IHasProviderIds item) => item is Audio || item is MusicAlbum;
 }

+ 28 - 0
MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumExternalUrlProvider.cs

@@ -0,0 +1,28 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Providers.Plugins.MusicBrainz;
+
+/// <summary>
+/// External album URLs for MusicBrainz.
+/// </summary>
+public class MusicBrainzAlbumExternalUrlProvider : IExternalUrlProvider
+{
+    /// <inheritdoc/>
+    public string Name => "MusicBrainz Album";
+
+    /// <inheritdoc/>
+    public IEnumerable<string> GetExternalUrls(BaseItem item)
+    {
+        if (item is MusicAlbum)
+        {
+            if (item.TryGetProviderId(MetadataProvider.MusicBrainzAlbum, out var externalId))
+            {
+                yield return Plugin.Instance!.Configuration.Server + $"/release/{externalId}";
+            }
+        }
+    }
+}

+ 0 - 3
MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalId.cs

@@ -19,9 +19,6 @@ public class MusicBrainzArtistExternalId : IExternalId
     /// <inheritdoc />
     public ExternalIdMediaType? Type => ExternalIdMediaType.Artist;
 
-    /// <inheritdoc />
-    public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/artist/{0}";
-
     /// <inheritdoc />
     public bool Supports(IHasProviderIds item) => item is MusicArtist;
 }

+ 32 - 0
MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalUrlProvider.cs

@@ -0,0 +1,32 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Providers.Plugins.MusicBrainz;
+
+/// <summary>
+/// External artist URLs for MusicBrainz.
+/// </summary>
+public class MusicBrainzArtistExternalUrlProvider : IExternalUrlProvider
+{
+    /// <inheritdoc/>
+    public string Name => "MusicBrainz Artist";
+
+    /// <inheritdoc/>
+    public IEnumerable<string> GetExternalUrls(BaseItem item)
+    {
+        if (item.TryGetProviderId(MetadataProvider.MusicBrainzArtist, out var externalId))
+        {
+            switch (item)
+            {
+                case MusicAlbum:
+                case Person:
+                    yield return Plugin.Instance!.Configuration.Server + $"/artist/{externalId}";
+
+                    break;
+            }
+        }
+    }
+}

+ 0 - 3
MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzOtherArtistExternalId.cs

@@ -19,9 +19,6 @@ public class MusicBrainzOtherArtistExternalId : IExternalId
     /// <inheritdoc />
     public ExternalIdMediaType? Type => ExternalIdMediaType.OtherArtist;
 
-    /// <inheritdoc />
-    public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/artist/{0}";
-
     /// <inheritdoc />
     public bool Supports(IHasProviderIds item) => item is Audio or MusicAlbum;
 }

+ 0 - 3
MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzReleaseGroupExternalId.cs

@@ -19,9 +19,6 @@ public class MusicBrainzReleaseGroupExternalId : IExternalId
     /// <inheritdoc />
     public ExternalIdMediaType? Type => ExternalIdMediaType.ReleaseGroup;
 
-    /// <inheritdoc />
-    public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/release-group/{0}";
-
     /// <inheritdoc />
     public bool Supports(IHasProviderIds item) => item is Audio or MusicAlbum;
 }

+ 28 - 0
MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzReleaseGroupExternalUrlProvider.cs

@@ -0,0 +1,28 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Providers.Plugins.MusicBrainz;
+
+/// <summary>
+/// External release group URLs for MusicBrainz.
+/// </summary>
+public class MusicBrainzReleaseGroupExternalUrlProvider : IExternalUrlProvider
+{
+    /// <inheritdoc/>
+    public string Name => "MusicBrainz Release Group";
+
+    /// <inheritdoc/>
+    public IEnumerable<string> GetExternalUrls(BaseItem item)
+    {
+        if (item is MusicAlbum)
+        {
+        if (item.TryGetProviderId(MetadataProvider.MusicBrainzReleaseGroup, out var externalId))
+            {
+                yield return Plugin.Instance!.Configuration.Server + $"/release-group/{externalId}";
+            }
+        }
+    }
+}

+ 28 - 0
MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzTrackExternalUrlProvider.cs

@@ -0,0 +1,28 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Providers.Plugins.MusicBrainz;
+
+/// <summary>
+/// External track URLs for MusicBrainz.
+/// </summary>
+public class MusicBrainzTrackExternalUrlProvider : IExternalUrlProvider
+{
+    /// <inheritdoc/>
+    public string Name => "MusicBrainz Track";
+
+    /// <inheritdoc/>
+    public IEnumerable<string> GetExternalUrls(BaseItem item)
+    {
+        if (item is Audio)
+        {
+        if (item.TryGetProviderId(MetadataProvider.MusicBrainzTrack, out var externalId))
+            {
+                yield return Plugin.Instance!.Configuration.Server + $"/track/{externalId}";
+            }
+        }
+    }
+}

+ 0 - 3
MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzTrackId.cs

@@ -19,9 +19,6 @@ public class MusicBrainzTrackId : IExternalId
     /// <inheritdoc />
     public ExternalIdMediaType? Type => ExternalIdMediaType.Track;
 
-    /// <inheritdoc />
-    public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/track/{0}";
-
     /// <inheritdoc />
     public bool Supports(IHasProviderIds item) => item is Audio;
 }

+ 0 - 3
MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetExternalId.cs

@@ -20,9 +20,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets
         /// <inheritdoc />
         public ExternalIdMediaType? Type => ExternalIdMediaType.BoxSet;
 
-        /// <inheritdoc />
-        public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "collection/{0}";
-
         /// <inheritdoc />
         public bool Supports(IHasProviderIds item)
         {

+ 0 - 3
MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieExternalId.cs

@@ -20,9 +20,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
         /// <inheritdoc />
         public ExternalIdMediaType? Type => ExternalIdMediaType.Movie;
 
-        /// <inheritdoc />
-        public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "movie/{0}";
-
         /// <inheritdoc />
         public bool Supports(IHasProviderIds item)
         {

+ 0 - 3
MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonExternalId.cs

@@ -19,9 +19,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
         /// <inheritdoc />
         public ExternalIdMediaType? Type => ExternalIdMediaType.Person;
 
-        /// <inheritdoc />
-        public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "person/{0}";
-
         /// <inheritdoc />
         public bool Supports(IHasProviderIds item)
         {

+ 0 - 3
MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesExternalId.cs

@@ -19,9 +19,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
         /// <inheritdoc />
         public ExternalIdMediaType? Type => ExternalIdMediaType.Series;
 
-        /// <inheritdoc />
-        public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "tv/{0}";
-
         /// <inheritdoc />
         public bool Supports(IHasProviderIds item)
         {

+ 95 - 0
MediaBrowser.Providers/Plugins/Tmdb/TmdbExternalUrlProvider.cs

@@ -0,0 +1,95 @@
+using System;
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using TMDbLib.Objects.TvShows;
+
+namespace MediaBrowser.Providers.Plugins.Tmdb;
+
+/// <summary>
+/// External URLs for TMDb.
+/// </summary>
+public class TmdbExternalUrlProvider : IExternalUrlProvider
+{
+    /// <inheritdoc/>
+    public string Name => "TMDB";
+
+    /// <inheritdoc/>
+    public IEnumerable<string> GetExternalUrls(BaseItem item)
+    {
+        switch (item)
+        {
+            case Series:
+                if (item.TryGetProviderId(MetadataProvider.Tmdb, out var externalId))
+                {
+                    yield return TmdbUtils.BaseTmdbUrl + $"tv/{externalId}";
+                }
+
+                break;
+            case Season season:
+                if (season.Series.TryGetProviderId(MetadataProvider.Tmdb, out var seriesExternalId))
+                {
+                    var orderString = season.Series.DisplayOrder;
+                    if (string.IsNullOrEmpty(orderString))
+                    {
+                        // Default order is airdate
+                        yield return TmdbUtils.BaseTmdbUrl + $"tv/{seriesExternalId}/season/{season.IndexNumber}";
+                    }
+
+                    if (Enum.TryParse<TvGroupType>(season.Series.DisplayOrder, out var order))
+                    {
+                        if (order.Equals(TvGroupType.OriginalAirDate))
+                        {
+                            yield return TmdbUtils.BaseTmdbUrl + $"tv/{seriesExternalId}/season/{season.IndexNumber}";
+                        }
+                    }
+                }
+
+                break;
+            case Episode episode:
+                if (episode.Series.TryGetProviderId(MetadataProvider.Imdb, out seriesExternalId))
+                {
+                    var orderString = episode.Series.DisplayOrder;
+                    if (string.IsNullOrEmpty(orderString))
+                    {
+                        // Default order is airdate
+                        yield return TmdbUtils.BaseTmdbUrl + $"tv/{seriesExternalId}/season/{episode.Season.IndexNumber}/episode/{episode.IndexNumber}";
+                    }
+
+                    if (Enum.TryParse<TvGroupType>(orderString, out var order))
+                    {
+                        if (order.Equals(TvGroupType.OriginalAirDate))
+                        {
+                            yield return TmdbUtils.BaseTmdbUrl + $"tv/{seriesExternalId}/season/{episode.Season.IndexNumber}/episode/{episode.IndexNumber}";
+                        }
+                    }
+                }
+
+                break;
+            case Movie:
+                if (item.TryGetProviderId(MetadataProvider.Tmdb, out externalId))
+                {
+                    yield return TmdbUtils.BaseTmdbUrl + $"movie/{externalId}";
+                }
+
+                break;
+            case Person:
+                if (item.TryGetProviderId(MetadataProvider.Tmdb, out externalId))
+                {
+                    yield return TmdbUtils.BaseTmdbUrl + $"person/{externalId}";
+                }
+
+                break;
+            case BoxSet:
+                if (item.TryGetProviderId(MetadataProvider.Tmdb, out externalId))
+                {
+                    yield return TmdbUtils.BaseTmdbUrl + $"collection/{externalId}";
+                }
+
+                break;
+        }
+    }
+}

+ 0 - 3
MediaBrowser.Providers/TV/Zap2ItExternalId.cs

@@ -18,9 +18,6 @@ namespace MediaBrowser.Providers.TV
         /// <inheritdoc />
         public ExternalIdMediaType? Type => null;
 
-        /// <inheritdoc />
-        public string UrlFormatString => "http://tvlistings.zap2it.com/overview.html?programSeriesId={0}";
-
         /// <inheritdoc />
         public bool Supports(IHasProviderIds item) => item is Series;
     }

+ 24 - 0
MediaBrowser.Providers/TV/Zap2ItExternalUrlProvider.cs

@@ -0,0 +1,24 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Providers.TV;
+
+/// <summary>
+/// External URLs for TMDb.
+/// </summary>
+public class Zap2ItExternalUrlProvider : IExternalUrlProvider
+{
+    /// <inheritdoc/>
+    public string Name => "Zap2It";
+
+    /// <inheritdoc/>
+    public IEnumerable<string> GetExternalUrls(BaseItem item)
+    {
+        if (item.TryGetProviderId(MetadataProvider.Zap2It, out var externalId))
+        {
+            yield return $"http://tvlistings.zap2it.com/overview.html?programSeriesId={externalId}";
+         }
+    }
+}

+ 12 - 32
MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs

@@ -547,16 +547,13 @@ namespace MediaBrowser.XbmcMetadata.Savers
                 writer.WriteElementString("aspectratio", hasAspectRatio.AspectRatio);
             }
 
-            var tmdbCollection = item.GetProviderId(MetadataProvider.TmdbCollection);
-
-            if (!string.IsNullOrEmpty(tmdbCollection))
+            if (item.TryGetProviderId(MetadataProvider.Tmdb, out var tmdbCollection))
             {
                 writer.WriteElementString("collectionnumber", tmdbCollection);
                 writtenProviderIds.Add(MetadataProvider.TmdbCollection.ToString());
             }
 
-            var imdb = item.GetProviderId(MetadataProvider.Imdb);
-            if (!string.IsNullOrEmpty(imdb))
+            if (item.TryGetProviderId(MetadataProvider.Imdb, out var imdb))
             {
                 if (item is Series)
                 {
@@ -573,16 +570,14 @@ namespace MediaBrowser.XbmcMetadata.Savers
             // Series xml saver already saves this
             if (item is not Series)
             {
-                var tvdb = item.GetProviderId(MetadataProvider.Tvdb);
-                if (!string.IsNullOrEmpty(tvdb))
+                if (item.TryGetProviderId(MetadataProvider.Tvdb, out var tvdb))
                 {
                     writer.WriteElementString("tvdbid", tvdb);
                     writtenProviderIds.Add(MetadataProvider.Tvdb.ToString());
                 }
             }
 
-            var tmdb = item.GetProviderId(MetadataProvider.Tmdb);
-            if (!string.IsNullOrEmpty(tmdb))
+            if (item.TryGetProviderId(MetadataProvider.Tmdb, out var tmdb))
             {
                 writer.WriteElementString("tmdbid", tmdb);
                 writtenProviderIds.Add(MetadataProvider.Tmdb.ToString());
@@ -690,64 +685,49 @@ namespace MediaBrowser.XbmcMetadata.Savers
                 }
             }
 
-            var externalId = item.GetProviderId(MetadataProvider.AudioDbArtist);
-
-            if (!string.IsNullOrEmpty(externalId))
+            if (item.TryGetProviderId(MetadataProvider.AudioDbArtist, out var externalId))
             {
                 writer.WriteElementString("audiodbartistid", externalId);
                 writtenProviderIds.Add(MetadataProvider.AudioDbArtist.ToString());
             }
 
-            externalId = item.GetProviderId(MetadataProvider.AudioDbAlbum);
-
-            if (!string.IsNullOrEmpty(externalId))
+            if (item.TryGetProviderId(MetadataProvider.AudioDbAlbum, out externalId))
             {
                 writer.WriteElementString("audiodbalbumid", externalId);
                 writtenProviderIds.Add(MetadataProvider.AudioDbAlbum.ToString());
             }
 
-            externalId = item.GetProviderId(MetadataProvider.Zap2It);
-
-            if (!string.IsNullOrEmpty(externalId))
+            if (item.TryGetProviderId(MetadataProvider.Zap2It, out externalId))
             {
                 writer.WriteElementString("zap2itid", externalId);
                 writtenProviderIds.Add(MetadataProvider.Zap2It.ToString());
             }
 
-            externalId = item.GetProviderId(MetadataProvider.MusicBrainzAlbum);
-
-            if (!string.IsNullOrEmpty(externalId))
+            if (item.TryGetProviderId(MetadataProvider.MusicBrainzAlbum, out externalId))
             {
                 writer.WriteElementString("musicbrainzalbumid", externalId);
                 writtenProviderIds.Add(MetadataProvider.MusicBrainzAlbum.ToString());
             }
 
-            externalId = item.GetProviderId(MetadataProvider.MusicBrainzAlbumArtist);
-
-            if (!string.IsNullOrEmpty(externalId))
+            if (item.TryGetProviderId(MetadataProvider.MusicBrainzAlbumArtist, out externalId))
             {
                 writer.WriteElementString("musicbrainzalbumartistid", externalId);
                 writtenProviderIds.Add(MetadataProvider.MusicBrainzAlbumArtist.ToString());
             }
 
-            externalId = item.GetProviderId(MetadataProvider.MusicBrainzArtist);
-
-            if (!string.IsNullOrEmpty(externalId))
+            if (item.TryGetProviderId(MetadataProvider.MusicBrainzArtist, out externalId))
             {
                 writer.WriteElementString("musicbrainzartistid", externalId);
                 writtenProviderIds.Add(MetadataProvider.MusicBrainzArtist.ToString());
             }
 
-            externalId = item.GetProviderId(MetadataProvider.MusicBrainzReleaseGroup);
-
-            if (!string.IsNullOrEmpty(externalId))
+            if (item.TryGetProviderId(MetadataProvider.MusicBrainzReleaseGroup, out externalId))
             {
                 writer.WriteElementString("musicbrainzreleasegroupid", externalId);
                 writtenProviderIds.Add(MetadataProvider.MusicBrainzReleaseGroup.ToString());
             }
 
-            externalId = item.GetProviderId(MetadataProvider.TvRage);
-            if (!string.IsNullOrEmpty(externalId))
+            if (item.TryGetProviderId(MetadataProvider.TvRage, out externalId))
             {
                 writer.WriteElementString("tvrageid", externalId);
                 writtenProviderIds.Add(MetadataProvider.TvRage.ToString());

+ 1 - 3
MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs

@@ -92,9 +92,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
         /// <inheritdoc />
         protected override void WriteCustomElements(BaseItem item, XmlWriter writer)
         {
-            var imdb = item.GetProviderId(MetadataProvider.Imdb);
-
-            if (!string.IsNullOrEmpty(imdb))
+            if (item.TryGetProviderId(MetadataProvider.Imdb, out var imdb))
             {
                 writer.WriteElementString("id", imdb);
             }

+ 1 - 3
MediaBrowser.XbmcMetadata/Savers/SeriesNfoSaver.cs

@@ -54,9 +54,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
         {
             var series = (Series)item;
 
-            var tvdb = item.GetProviderId(MetadataProvider.Tvdb);
-
-            if (!string.IsNullOrEmpty(tvdb))
+            if (item.TryGetProviderId(MetadataProvider.Tvdb, out var tvdb))
             {
                 writer.WriteElementString("id", tvdb);
 

+ 4 - 9
src/Jellyfin.LiveTv/Recordings/RecordingsMetadataManager.cs

@@ -344,15 +344,12 @@ public class RecordingsMetadataManager
                     await writer.WriteElementStringAsync(null, "credits", null, person).ConfigureAwait(false);
                 }
 
-                var tmdbCollection = item.GetProviderId(MetadataProvider.TmdbCollection);
-
-                if (!string.IsNullOrEmpty(tmdbCollection))
+                if (item.TryGetProviderId(MetadataProvider.TmdbCollection, out var tmdbCollection))
                 {
                     await writer.WriteElementStringAsync(null, "collectionnumber", null, tmdbCollection).ConfigureAwait(false);
                 }
 
-                var imdb = item.GetProviderId(MetadataProvider.Imdb);
-                if (!string.IsNullOrEmpty(imdb))
+                if (item.TryGetProviderId(MetadataProvider.Imdb, out var imdb))
                 {
                     if (!isSeriesEpisode)
                     {
@@ -365,8 +362,7 @@ public class RecordingsMetadataManager
                     lockData = false;
                 }
 
-                var tvdb = item.GetProviderId(MetadataProvider.Tvdb);
-                if (!string.IsNullOrEmpty(tvdb))
+                if (item.TryGetProviderId(MetadataProvider.Tvdb, out var tvdb))
                 {
                     await writer.WriteElementStringAsync(null, "tvdbid", null, tvdb).ConfigureAwait(false);
 
@@ -374,8 +370,7 @@ public class RecordingsMetadataManager
                     lockData = false;
                 }
 
-                var tmdb = item.GetProviderId(MetadataProvider.Tmdb);
-                if (!string.IsNullOrEmpty(tmdb))
+                if (item.TryGetProviderId(MetadataProvider.Tmdb, out var tmdb))
                 {
                     await writer.WriteElementStringAsync(null, "tmdbid", null, tmdb).ConfigureAwait(false);
 

+ 1 - 1
tests/Jellyfin.XbmcMetadata.Tests/Parsers/EpisodeNfoProviderTests.cs

@@ -26,7 +26,7 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
             var providerManager = new Mock<IProviderManager>();
 
             var imdbExternalId = new ImdbExternalId();
-            var externalIdInfo = new ExternalIdInfo(imdbExternalId.ProviderName, imdbExternalId.Key, imdbExternalId.Type, imdbExternalId.UrlFormatString);
+            var externalIdInfo = new ExternalIdInfo(imdbExternalId.ProviderName, imdbExternalId.Key, imdbExternalId.Type);
 
             providerManager.Setup(x => x.GetExternalIdInfos(It.IsAny<IHasProviderIds>()))
                 .Returns(new[] { externalIdInfo });

+ 1 - 1
tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs

@@ -34,7 +34,7 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
             var providerManager = new Mock<IProviderManager>();
 
             var tmdbExternalId = new TmdbMovieExternalId();
-            var externalIdInfo = new ExternalIdInfo(tmdbExternalId.ProviderName, tmdbExternalId.Key, tmdbExternalId.Type, tmdbExternalId.UrlFormatString);
+            var externalIdInfo = new ExternalIdInfo(tmdbExternalId.ProviderName, tmdbExternalId.Key, tmdbExternalId.Type);
 
             providerManager.Setup(x => x.GetExternalIdInfos(It.IsAny<IHasProviderIds>()))
                 .Returns(new[] { externalIdInfo });

+ 1 - 1
tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicAlbumNfoProviderTests.cs

@@ -24,7 +24,7 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
             var providerManager = new Mock<IProviderManager>();
 
             var musicBrainzArtist = new MusicBrainzArtistExternalId();
-            var externalIdInfo = new ExternalIdInfo(musicBrainzArtist.ProviderName, musicBrainzArtist.Key, musicBrainzArtist.Type, "MusicBrainzServer");
+            var externalIdInfo = new ExternalIdInfo(musicBrainzArtist.ProviderName, musicBrainzArtist.Key, musicBrainzArtist.Type);
 
             providerManager.Setup(x => x.GetExternalIdInfos(It.IsAny<IHasProviderIds>()))
                 .Returns(new[] { externalIdInfo });

+ 1 - 1
tests/Jellyfin.XbmcMetadata.Tests/Parsers/MusicArtistNfoParserTests.cs

@@ -24,7 +24,7 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
             var providerManager = new Mock<IProviderManager>();
 
             var musicBrainzArtist = new MusicBrainzArtistExternalId();
-            var externalIdInfo = new ExternalIdInfo(musicBrainzArtist.ProviderName, musicBrainzArtist.Key, musicBrainzArtist.Type, "MusicBrainzServer");
+            var externalIdInfo = new ExternalIdInfo(musicBrainzArtist.ProviderName, musicBrainzArtist.Key, musicBrainzArtist.Type);
 
             providerManager.Setup(x => x.GetExternalIdInfos(It.IsAny<IHasProviderIds>()))
                 .Returns(new[] { externalIdInfo });