aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Model/Entities/ProviderIdsExtensions.cs')
-rw-r--r--MediaBrowser.Model/Entities/ProviderIdsExtensions.cs89
1 files changed, 80 insertions, 9 deletions
diff --git a/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs b/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs
index 385a86d31c..09eba92d9e 100644
--- a/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs
+++ b/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs
@@ -1,14 +1,16 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
using System.Linq;
+using System.Text.RegularExpressions;
namespace MediaBrowser.Model.Entities;
/// <summary>
/// Class ProviderIdsExtensions.
/// </summary>
-public static class ProviderIdsExtensions
+public static partial class ProviderIdsExtensions
{
/// <summary>
/// Case-insensitive dictionary of <see cref="MetadataProvider"/> string representation.
@@ -21,6 +23,27 @@ public static class ProviderIdsExtensions
StringComparer.OrdinalIgnoreCase);
/// <summary>
+ /// The known id formats, keyed by provider name.
+ /// </summary>
+ private static readonly Dictionary<string, Func<string, bool>> _providerIdValidators =
+ new(StringComparer.OrdinalIgnoreCase)
+ {
+ [MetadataProvider.Imdb.ToString()] = value => ImdbIdRegex().IsMatch(value),
+ [MetadataProvider.Tmdb.ToString()] = IsPositiveNumber,
+ [MetadataProvider.TmdbCollection.ToString()] = IsPositiveNumber,
+ [MetadataProvider.AudioDbArtist.ToString()] = IsPositiveNumber,
+ [MetadataProvider.AudioDbAlbum.ToString()] = IsPositiveNumber,
+
+ // Every MusicBrainz id is an MBID.
+ [MetadataProvider.MusicBrainzAlbum.ToString()] = IsGuid,
+ [MetadataProvider.MusicBrainzAlbumArtist.ToString()] = IsGuid,
+ [MetadataProvider.MusicBrainzArtist.ToString()] = IsGuid,
+ [MetadataProvider.MusicBrainzReleaseGroup.ToString()] = IsGuid,
+ [MetadataProvider.MusicBrainzRecording.ToString()] = IsGuid,
+ [MetadataProvider.MusicBrainzTrack.ToString()] = IsGuid
+ };
+
+ /// <summary>
/// Checks if this instance has an id for the given provider.
/// </summary>
/// <param name="instance">The instance.</param>
@@ -102,6 +125,26 @@ public static class ProviderIdsExtensions
}
/// <summary>
+ /// Checks whether a value can be an id of the given provider.
+ /// </summary>
+ /// <param name="name">The provider name.</param>
+ /// <param name="value">The provider id.</param>
+ /// <returns><c>true</c> if the value has a plausible format for the provider; otherwise, <c>false</c>.</returns>
+ /// <remarks>
+ /// Providers regularly hand out an id belonging to a different service, e.g. an IMDb person id in the
+ /// TMDb field. Such an id is not just useless, it also makes the owning provider fail for the item.
+ /// </remarks>
+ public static bool IsValidProviderId(string? name, string? value)
+ {
+ if (string.IsNullOrWhiteSpace(name) || string.IsNullOrWhiteSpace(value))
+ {
+ return false;
+ }
+
+ return !_providerIdValidators.TryGetValue(name, out var isValid) || isValid(value);
+ }
+
+ /// <summary>
/// Sets a provider id.
/// </summary>
/// <param name="instance">The instance.</param>
@@ -121,6 +164,14 @@ public static class ProviderIdsExtensions
return false;
}
+ name = name.Trim();
+ value = value.Trim();
+
+ if (!IsValidProviderId(name, value))
+ {
+ return false;
+ }
+
// Ensure it exists
instance.ProviderIds ??= new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
@@ -153,7 +204,6 @@ public static class ProviderIdsExtensions
/// <param name="instance">The instance.</param>
/// <param name="name">The name, this should not contain a '=' character.</param>
/// <param name="value">The value.</param>
- /// <remarks>Due to how deserialization from the database works the name cannot contain '='.</remarks>
public static void SetProviderId(this IHasProviderIds instance, string name, string value)
{
ArgumentNullException.ThrowIfNull(instance);
@@ -166,17 +216,27 @@ public static class ProviderIdsExtensions
throw new ArgumentException("Provider id name cannot contain '='", nameof(name));
}
- // Ensure it exists
- instance.ProviderIds ??= new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ instance.TrySetProviderId(name, value);
+ }
- // Match on internal MetadataProvider enum string values before adding arbitrary providers
- if (_metadataProviderEnumDictionary.TryGetValue(name, out var enumValue))
+ /// <summary>
+ /// Replaces all provider ids, dropping the ones that cannot belong to the provider they are filed under.
+ /// </summary>
+ /// <param name="instance">The instance.</param>
+ /// <param name="providerIds">The provider ids to set.</param>
+ public static void SetProviderIds(this IHasProviderIds instance, IReadOnlyDictionary<string, string>? providerIds)
+ {
+ ArgumentNullException.ThrowIfNull(instance);
+
+ instance.ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ if (providerIds is null)
{
- instance.ProviderIds[enumValue] = value;
+ return;
}
- else
+
+ foreach (var (name, value) in providerIds)
{
- instance.ProviderIds[name] = value;
+ instance.TrySetProviderId(name, value);
}
}
@@ -213,4 +273,15 @@ public static class ProviderIdsExtensions
instance.ProviderIds?.Remove(provider.ToString());
}
+
+ private static bool IsPositiveNumber(string value)
+ => int.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out var id) && id > 0;
+
+ private static bool IsGuid(string value)
+ => Guid.TryParse(value, CultureInfo.InvariantCulture, out _);
+
+ // An IMDb id is a type prefix (tt for titles, nm for people, co for companies, ...) followed by
+ // digits. The prefix is optional because a bare number has always been accepted for a title.
+ [GeneratedRegex(@"^(tt|nm|co|ev|ch|ni)?[0-9]+$", RegexOptions.IgnoreCase)]
+ private static partial Regex ImdbIdRegex();
}