If we have a country code in the rating, treat as unrated if the country does not have the rating

This commit is contained in:
Shadowghost
2026-03-02 09:14:23 +01:00
parent 11e16df596
commit 3d4e4c4572
2 changed files with 92 additions and 23 deletions

View File

@@ -345,35 +345,70 @@ namespace Emby.Server.Implementations.Localization
}
}
// Try splitting by : to handle "Germany: FSK-18"
if (rating.Contains(':', StringComparison.OrdinalIgnoreCase))
// Try splitting by country prefix separator to handle "US:PG-13", "Germany: FSK-18", "DE-FSK-18"
if (TryGetRatingScoreBySeparator(rating, ':', out var result)
|| TryGetRatingScoreBySeparator(rating, '-', out result))
{
var ratingLevelRightPart = rating.AsSpan().RightPart(':');
if (ratingLevelRightPart.Length != 0)
{
return GetRatingScore(ratingLevelRightPart.ToString());
}
}
// Handle prefix country code to handle "DE-18"
if (rating.Contains('-', StringComparison.OrdinalIgnoreCase))
{
var ratingSpan = rating.AsSpan();
// Extract culture from country prefix
var culture = FindLanguageInfo(ratingSpan.LeftPart('-').ToString());
var ratingLevelRightPart = ratingSpan.RightPart('-');
if (ratingLevelRightPart.Length != 0)
{
// Check rating system of culture
return GetRatingScore(ratingLevelRightPart.ToString(), culture?.TwoLetterISOLanguageName);
}
return result;
}
return null;
}
private bool TryGetRatingScoreBySeparator(string rating, char separator, out ParentalRatingScore? result)
{
result = null;
if (rating.IndexOf(separator, StringComparison.Ordinal) < 0)
{
return false;
}
var ratingSpan = rating.AsSpan();
var countryPart = ratingSpan.LeftPart(separator).Trim().ToString();
var ratingPart = ratingSpan.RightPart(separator).Trim().ToString();
if (ratingPart.Length == 0)
{
return false;
}
string? resolvedCountryCode = null;
if (_allParentalRatings.ContainsKey(countryPart))
{
resolvedCountryCode = countryPart;
}
else
{
var culture = FindLanguageInfo(countryPart);
if (culture is not null)
{
resolvedCountryCode = culture.TwoLetterISOLanguageName;
}
}
if (resolvedCountryCode is not null
&& _allParentalRatings.TryGetValue(resolvedCountryCode, out var countryRatings))
{
if (countryRatings.TryGetValue(ratingPart, out result))
{
return true;
}
_logger.LogWarning(
"Rating '{Rating}' not found in the '{CountryCode}' rating system, treating as unrated",
rating,
resolvedCountryCode);
return true;
}
// Country not identified or no rating data available, try recursive lookup
result = GetRatingScore(ratingPart, resolvedCountryCode);
return true;
}
/// <inheritdoc />
public string GetLocalizedString(string phrase)
{

View File

@@ -222,6 +222,40 @@ namespace Jellyfin.Server.Implementations.Tests.Localization
Assert.Equal(expectedSubScore, score.SubScore);
}
[Theory]
[InlineData("US:INVALID", "US")] // Colon separator, known country code, unknown rating
[InlineData("us:INVALID", "US")] // Colon separator, lowercase country code
[InlineData("DE-INVALID", "US")] // Hyphen separator, known language prefix, unknown rating
[InlineData("ca:INVALID", "US")] // Colon separator, known country code (Canada)
public async Task GetRatingScore_UnknownRatingWithKnownCountry_ReturnsNull(string rating, string countryCode)
{
var localizationManager = Setup(new ServerConfiguration
{
MetadataCountryCode = countryCode
});
await localizationManager.LoadAll();
Assert.Null(localizationManager.GetRatingScore(rating));
}
[Theory]
[InlineData("us:R", "DE", 17, 0)] // Colon separator, explicit US country, valid US rating
[InlineData("US:PG-13", "DE", 13, 0)] // Colon separator, explicit US country, valid US rating
[InlineData("ca:R", "US", 18, 1)] // Colon separator, Canada country code, valid CA rating
public async Task GetRatingScore_ValidRatingWithCountrySeparator_ReturnsScore(string rating, string countryCode, int expectedScore, int? expectedSubScore)
{
var localizationManager = Setup(new ServerConfiguration
{
MetadataCountryCode = countryCode
});
await localizationManager.LoadAll();
var score = localizationManager.GetRatingScore(rating);
Assert.NotNull(score);
Assert.Equal(expectedScore, score.Score);
Assert.Equal(expectedSubScore, score.SubScore);
}
[Theory]
[InlineData("Default", "Default")]
[InlineData("HeaderLiveTV", "Live TV")]