diff options
Diffstat (limited to 'MediaBrowser.Model/Entities')
| -rw-r--r-- | MediaBrowser.Model/Entities/MediaStream.cs | 30 | ||||
| -rw-r--r-- | MediaBrowser.Model/Entities/ProviderIdsExtensions.cs | 89 |
2 files changed, 104 insertions, 15 deletions
diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index f057714bea..67af843626 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -810,6 +810,11 @@ namespace MediaBrowser.Model.Entities return (VideoRange.Unknown, VideoRangeType.Unknown); } + var isPq = string.Equals(ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase); + var isHlg = string.Equals(ColorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase); + // Invalid DV only retains HDR when the base layer explicitly signals PQ or HLG. + var baseVideoRange = isPq || isHlg ? VideoRange.HDR : VideoRange.SDR; + var codecTag = CodecTag; var dvProfile = DvProfile; var rpuPresentFlag = RpuPresentFlag == 1; @@ -834,7 +839,7 @@ namespace MediaBrowser.Model.Entities 4 => (VideoRange.HDR, VideoRangeType.DOVIWithHLG), 2 => (VideoRange.SDR, VideoRangeType.DOVIWithSDR), // Out of Dolby Spec files should be marked as invalid - _ => (VideoRange.HDR, VideoRangeType.DOVIInvalid) + _ => (baseVideoRange, VideoRangeType.DOVIInvalid) }, 7 => (VideoRange.HDR, VideoRangeType.DOVIWithEL), 10 => dvBlCompatId switch @@ -844,11 +849,26 @@ namespace MediaBrowser.Model.Entities 2 => (VideoRange.SDR, VideoRangeType.DOVIWithSDR), 4 => (VideoRange.HDR, VideoRangeType.DOVIWithHLG), // Out of Dolby Spec files should be marked as invalid - _ => (VideoRange.HDR, VideoRangeType.DOVIInvalid) + _ => (baseVideoRange, VideoRangeType.DOVIInvalid) }, _ => (VideoRange.SDR, VideoRangeType.SDR) }; + var expectedTransfer = dvRangeSet.Item2 switch + { + VideoRangeType.DOVIWithHDR10 or VideoRangeType.DOVIWithEL => "smpte2084", + VideoRangeType.DOVIWithHLG => "arib-std-b67", + _ => null + }; + + if (expectedTransfer is not null + && (!string.Equals(ColorSpace, "bt2020nc", StringComparison.OrdinalIgnoreCase) + || !string.Equals(ColorTransfer, expectedTransfer, StringComparison.OrdinalIgnoreCase) + || !string.Equals(ColorPrimaries, "bt2020", StringComparison.OrdinalIgnoreCase))) + { + return (baseVideoRange, VideoRangeType.DOVIInvalid); + } + if (Hdr10PlusPresentFlag == true) { return dvRangeSet.Item2 switch @@ -862,13 +882,11 @@ namespace MediaBrowser.Model.Entities return dvRangeSet; } - var colorTransfer = ColorTransfer; - - if (string.Equals(colorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase)) + if (isPq) { return Hdr10PlusPresentFlag == true ? (VideoRange.HDR, VideoRangeType.HDR10Plus) : (VideoRange.HDR, VideoRangeType.HDR10); } - else if (string.Equals(colorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase)) + else if (isHlg) { return (VideoRange.HDR, VideoRangeType.HLG); } 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(); } |
