< Summary - Jellyfin

Information
Class: MediaBrowser.Model.Entities.ProviderIdsExtensions
Assembly: MediaBrowser.Model
File(s): /srv/git/jellyfin/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs
Line coverage
93%
Covered lines: 75
Uncovered lines: 5
Coverable lines: 80
Total lines: 287
Line coverage: 93.7%
Branch coverage
85%
Covered branches: 29
Total branches: 34
Branch coverage: 85.2%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 5/16/2026 - 12:15:55 AM Line coverage: 90% (45/50) Branch coverage: 79.1% (19/24) Total lines: 2165/20/2026 - 12:15:44 AM Line coverage: 90% (45/50) Branch coverage: 75% (18/24) Total lines: 21610/29/2026 - 12:17:11 AM Line coverage: 93.7% (75/80) Branch coverage: 85.2% (29/34) Total lines: 287 5/16/2026 - 12:15:55 AM Line coverage: 90% (45/50) Branch coverage: 79.1% (19/24) Total lines: 2165/20/2026 - 12:15:44 AM Line coverage: 90% (45/50) Branch coverage: 75% (18/24) Total lines: 21610/29/2026 - 12:17:11 AM Line coverage: 93.7% (75/80) Branch coverage: 85.2% (29/34) Total lines: 287

Coverage delta

Coverage delta 11 -11

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
HasProviderId(...)100%11100%
HasProviderId(...)100%11100%
TryGetProviderId(...)100%44100%
TryGetProviderId(...)100%11100%
GetProviderId(...)100%11100%
GetProviderId(...)100%11100%
IsValidProviderId(...)100%66100%
TrySetProviderId(...)83.33%121292.85%
TrySetProviderId(...)100%11100%
SetProviderId(...)50%2285.71%
SetProviderIds(...)100%44100%
SetProviderId(...)100%11100%
RemoveProviderId(...)0%620%
RemoveProviderId(...)50%22100%
IsPositiveNumber(...)100%22100%
IsGuid(...)100%11100%

File(s)

/srv/git/jellyfin/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Diagnostics.CodeAnalysis;
 4using System.Globalization;
 5using System.Linq;
 6using System.Text.RegularExpressions;
 7
 8namespace MediaBrowser.Model.Entities;
 9
 10/// <summary>
 11/// Class ProviderIdsExtensions.
 12/// </summary>
 13public static partial class ProviderIdsExtensions
 14{
 15    /// <summary>
 16    /// Case-insensitive dictionary of <see cref="MetadataProvider"/> string representation.
 17    /// </summary>
 518    private static readonly Dictionary<string, string> _metadataProviderEnumDictionary =
 519        Enum.GetValues<MetadataProvider>()
 520            .ToDictionary(
 521                enumValue => enumValue.ToString(),
 522                enumValue => enumValue.ToString(),
 523                StringComparer.OrdinalIgnoreCase);
 24
 25    /// <summary>
 26    /// The known id formats, keyed by provider name.
 27    /// </summary>
 528    private static readonly Dictionary<string, Func<string, bool>> _providerIdValidators =
 529        new(StringComparer.OrdinalIgnoreCase)
 530        {
 531            [MetadataProvider.Imdb.ToString()] = value => ImdbIdRegex().IsMatch(value),
 532            [MetadataProvider.Tmdb.ToString()] = IsPositiveNumber,
 533            [MetadataProvider.TmdbCollection.ToString()] = IsPositiveNumber,
 534            [MetadataProvider.AudioDbArtist.ToString()] = IsPositiveNumber,
 535            [MetadataProvider.AudioDbAlbum.ToString()] = IsPositiveNumber,
 536
 537            // Every MusicBrainz id is an MBID.
 538            [MetadataProvider.MusicBrainzAlbum.ToString()] = IsGuid,
 539            [MetadataProvider.MusicBrainzAlbumArtist.ToString()] = IsGuid,
 540            [MetadataProvider.MusicBrainzArtist.ToString()] = IsGuid,
 541            [MetadataProvider.MusicBrainzReleaseGroup.ToString()] = IsGuid,
 542            [MetadataProvider.MusicBrainzRecording.ToString()] = IsGuid,
 543            [MetadataProvider.MusicBrainzTrack.ToString()] = IsGuid
 544        };
 45
 46    /// <summary>
 47    /// Checks if this instance has an id for the given provider.
 48    /// </summary>
 49    /// <param name="instance">The instance.</param>
 50    /// <param name="name">The of the provider name.</param>
 51    /// <returns><c>true</c> if a provider id with the given name was found; otherwise <c>false</c>.</returns>
 52    public static bool HasProviderId(this IHasProviderIds instance, string name)
 2053        => instance.TryGetProviderId(name, out _);
 54
 55    /// <summary>
 56    /// Checks if this instance has an id for the given provider.
 57    /// </summary>
 58    /// <param name="instance">The instance.</param>
 59    /// <param name="provider">The provider.</param>
 60    /// <returns><c>true</c> if a provider id with the given name was found; otherwise <c>false</c>.</returns>
 61    public static bool HasProviderId(this IHasProviderIds instance, MetadataProvider provider)
 1962        => instance.HasProviderId(provider.ToString());
 63
 64    /// <summary>
 65    /// Gets a provider id.
 66    /// </summary>
 67    /// <param name="instance">The instance.</param>
 68    /// <param name="name">The name.</param>
 69    /// <param name="id">The provider id.</param>
 70    /// <returns><c>true</c> if a provider id with the given name was found; otherwise <c>false</c>.</returns>
 71    public static bool TryGetProviderId(this IHasProviderIds instance, string name, [NotNullWhen(true)] out string? id)
 72    {
 23673        ArgumentNullException.ThrowIfNull(instance);
 74
 23475        if (instance.ProviderIds is null)
 76        {
 377            id = null;
 378            return false;
 79        }
 80
 23181        var foundProviderId = instance.ProviderIds.TryGetValue(name, out id);
 82        // This occurs when searching with Identify (and possibly in other places)
 22983        if (string.IsNullOrEmpty(id))
 84        {
 11785            id = null;
 11786            foundProviderId = false;
 87        }
 88
 22989        return foundProviderId;
 90    }
 91
 92    /// <summary>
 93    /// Gets a provider id.
 94    /// </summary>
 95    /// <param name="instance">The instance.</param>
 96    /// <param name="provider">The provider.</param>
 97    /// <param name="id">The provider id.</param>
 98    /// <returns><c>true</c> if a provider id with the given name was found; otherwise <c>false</c>.</returns>
 99    public static bool TryGetProviderId(this IHasProviderIds instance, MetadataProvider provider, [NotNullWhen(true)] ou
 100    {
 122101        return instance.TryGetProviderId(provider.ToString(), out id);
 102    }
 103
 104    /// <summary>
 105    /// Gets a provider id.
 106    /// </summary>
 107    /// <param name="instance">The instance.</param>
 108    /// <param name="name">The name.</param>
 109    /// <returns>System.String.</returns>
 110    public static string? GetProviderId(this IHasProviderIds instance, string name)
 111    {
 51112        instance.TryGetProviderId(name, out string? id);
 49113        return id;
 114    }
 115
 116    /// <summary>
 117    /// Gets a provider id.
 118    /// </summary>
 119    /// <param name="instance">The instance.</param>
 120    /// <param name="provider">The provider.</param>
 121    /// <returns>System.String.</returns>
 122    public static string? GetProviderId(this IHasProviderIds instance, MetadataProvider provider)
 123    {
 50124        return instance.GetProviderId(provider.ToString());
 125    }
 126
 127    /// <summary>
 128    /// Checks whether a value can be an id of the given provider.
 129    /// </summary>
 130    /// <param name="name">The provider name.</param>
 131    /// <param name="value">The provider id.</param>
 132    /// <returns><c>true</c> if the value has a plausible format for the provider; otherwise, <c>false</c>.</returns>
 133    /// <remarks>
 134    /// Providers regularly hand out an id belonging to a different service, e.g. an IMDb person id in the
 135    /// TMDb field. Such an id is not just useless, it also makes the owning provider fail for the item.
 136    /// </remarks>
 137    public static bool IsValidProviderId(string? name, string? value)
 138    {
 213139        if (string.IsNullOrWhiteSpace(name) || string.IsNullOrWhiteSpace(value))
 140        {
 3141            return false;
 142        }
 143
 210144        return !_providerIdValidators.TryGetValue(name, out var isValid) || isValid(value);
 145    }
 146
 147    /// <summary>
 148    /// Sets a provider id.
 149    /// </summary>
 150    /// <param name="instance">The instance.</param>
 151    /// <param name="name">The name, this should not contain a '=' character.</param>
 152    /// <param name="value">The value.</param>
 153    /// <remarks>Due to how deserialization from the database works the name cannot contain '='.</remarks>
 154    /// <returns><c>true</c> if the provider id got set successfully; otherwise, <c>false</c>.</returns>
 155    public static bool TrySetProviderId(this IHasProviderIds instance, string? name, string? value)
 156    {
 368157        ArgumentNullException.ThrowIfNull(instance);
 158
 159        // When name contains a '=' it can't be deserialized from the database
 368160        if (string.IsNullOrWhiteSpace(name)
 368161            || string.IsNullOrWhiteSpace(value)
 368162            || name.Contains('=', StringComparison.Ordinal))
 163        {
 222164            return false;
 165        }
 166
 146167        name = name.Trim();
 146168        value = value.Trim();
 169
 146170        if (!IsValidProviderId(name, value))
 171        {
 3172            return false;
 173        }
 174
 175        // Ensure it exists
 143176        instance.ProviderIds ??= new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
 177
 178        // Match on internal MetadataProvider enum string values before adding arbitrary providers
 143179        if (_metadataProviderEnumDictionary.TryGetValue(name, out var enumValue))
 180        {
 127181            instance.ProviderIds[enumValue] = value;
 182        }
 183        else
 184        {
 16185            instance.ProviderIds[name] = value;
 186        }
 187
 143188        return true;
 189    }
 190
 191    /// <summary>
 192    /// Sets a provider id.
 193    /// </summary>
 194    /// <param name="instance">The instance.</param>
 195    /// <param name="provider">The provider.</param>
 196    /// <param name="value">The value.</param>
 197    /// <returns><c>true</c> if the provider id got set successfully; otherwise, <c>false</c>.</returns>
 198    public static bool TrySetProviderId(this IHasProviderIds instance, MetadataProvider provider, string? value)
 191199        => instance.TrySetProviderId(provider.ToString(), value);
 200
 201    /// <summary>
 202    /// Sets a provider id.
 203    /// </summary>
 204    /// <param name="instance">The instance.</param>
 205    /// <param name="name">The name, this should not contain a '=' character.</param>
 206    /// <param name="value">The value.</param>
 207    public static void SetProviderId(this IHasProviderIds instance, string name, string value)
 208    {
 77209        ArgumentNullException.ThrowIfNull(instance);
 76210        ArgumentException.ThrowIfNullOrWhiteSpace(name);
 76211        ArgumentException.ThrowIfNullOrWhiteSpace(value);
 212
 213        // When name contains a '=' it can't be deserialized from the database
 73214        if (name.Contains('=', StringComparison.Ordinal))
 215        {
 0216            throw new ArgumentException("Provider id name cannot contain '='", nameof(name));
 217        }
 218
 73219        instance.TrySetProviderId(name, value);
 73220    }
 221
 222    /// <summary>
 223    /// Replaces all provider ids, dropping the ones that cannot belong to the provider they are filed under.
 224    /// </summary>
 225    /// <param name="instance">The instance.</param>
 226    /// <param name="providerIds">The provider ids to set.</param>
 227    public static void SetProviderIds(this IHasProviderIds instance, IReadOnlyDictionary<string, string>? providerIds)
 228    {
 4229        ArgumentNullException.ThrowIfNull(instance);
 230
 3231        instance.ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
 3232        if (providerIds is null)
 233        {
 1234            return;
 235        }
 236
 12237        foreach (var (name, value) in providerIds)
 238        {
 4239            instance.TrySetProviderId(name, value);
 240        }
 2241    }
 242
 243    /// <summary>
 244    /// Sets a provider id.
 245    /// </summary>
 246    /// <param name="instance">The instance.</param>
 247    /// <param name="provider">The provider.</param>
 248    /// <param name="value">The value.</param>
 249    public static void SetProviderId(this IHasProviderIds instance, MetadataProvider provider, string value)
 70250        => instance.SetProviderId(provider.ToString(), value);
 251
 252    /// <summary>
 253    /// Removes a provider id.
 254    /// </summary>
 255    /// <param name="instance">The instance.</param>
 256    /// <param name="name">The name.</param>
 257    public static void RemoveProviderId(this IHasProviderIds instance, string name)
 258    {
 0259        ArgumentNullException.ThrowIfNull(instance);
 0260        ArgumentException.ThrowIfNullOrEmpty(name);
 261
 0262        instance.ProviderIds?.Remove(name);
 0263    }
 264
 265    /// <summary>
 266    /// Removes a provider id.
 267    /// </summary>
 268    /// <param name="instance">The instance.</param>
 269    /// <param name="provider">The provider.</param>
 270    public static void RemoveProviderId(this IHasProviderIds instance, MetadataProvider provider)
 271    {
 1272        ArgumentNullException.ThrowIfNull(instance);
 273
 1274        instance.ProviderIds?.Remove(provider.ToString());
 1275    }
 276
 277    private static bool IsPositiveNumber(string value)
 66278        => int.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out var id) && id > 0;
 279
 280    private static bool IsGuid(string value)
 31281        => Guid.TryParse(value, CultureInfo.InvariantCulture, out _);
 282
 283    // An IMDb id is a type prefix (tt for titles, nm for people, co for companies, ...) followed by
 284    // digits. The prefix is optional because a bare number has always been accepted for a title.
 285    [GeneratedRegex(@"^(tt|nm|co|ev|ch|ni)?[0-9]+$", RegexOptions.IgnoreCase)]
 286    private static partial Regex ImdbIdRegex();
 287}