mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-06-04 22:24:35 -04:00
Overhaul content ratings
This commit is contained in:
parent
720852f708
commit
ed2280a060
@ -3,6 +3,7 @@ using System.Collections.Concurrent;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -25,7 +26,7 @@ namespace Emby.Server.Implementations.Localization
|
|||||||
private const string CulturesPath = "Emby.Server.Implementations.Localization.iso6392.txt";
|
private const string CulturesPath = "Emby.Server.Implementations.Localization.iso6392.txt";
|
||||||
private const string CountriesPath = "Emby.Server.Implementations.Localization.countries.json";
|
private const string CountriesPath = "Emby.Server.Implementations.Localization.countries.json";
|
||||||
private static readonly Assembly _assembly = typeof(LocalizationManager).Assembly;
|
private static readonly Assembly _assembly = typeof(LocalizationManager).Assembly;
|
||||||
private static readonly string[] _unratedValues = { "n/a", "unrated", "not rated" };
|
private static readonly string[] _unratedValues = { "n/a", "unrated", "not rated", "nr" };
|
||||||
|
|
||||||
private readonly IServerConfigurationManager _configurationManager;
|
private readonly IServerConfigurationManager _configurationManager;
|
||||||
private readonly ILogger<LocalizationManager> _logger;
|
private readonly ILogger<LocalizationManager> _logger;
|
||||||
@ -194,6 +195,7 @@ namespace Emby.Server.Implementations.Localization
|
|||||||
{
|
{
|
||||||
var countryCode = _configurationManager.Configuration.MetadataCountryCode;
|
var countryCode = _configurationManager.Configuration.MetadataCountryCode;
|
||||||
|
|
||||||
|
// Fall back to US ratings if no country code is specified or country code does not exist.
|
||||||
if (string.IsNullOrEmpty(countryCode))
|
if (string.IsNullOrEmpty(countryCode))
|
||||||
{
|
{
|
||||||
countryCode = "us";
|
countryCode = "us";
|
||||||
@ -221,12 +223,14 @@ namespace Emby.Server.Implementations.Localization
|
|||||||
{
|
{
|
||||||
ArgumentException.ThrowIfNullOrEmpty(rating);
|
ArgumentException.ThrowIfNullOrEmpty(rating);
|
||||||
|
|
||||||
|
// Handle unrated content
|
||||||
if (_unratedValues.Contains(rating.AsSpan(), StringComparison.OrdinalIgnoreCase))
|
if (_unratedValues.Contains(rating.AsSpan(), StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fairly common for some users to have "Rated R" in their rating field
|
// Fairly common for some users to have "Rated R" in their rating field
|
||||||
|
rating = rating.Replace("Rated :", string.Empty, StringComparison.OrdinalIgnoreCase);
|
||||||
rating = rating.Replace("Rated ", string.Empty, StringComparison.OrdinalIgnoreCase);
|
rating = rating.Replace("Rated ", string.Empty, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
var ratingsDictionary = GetParentalRatingsDictionary();
|
var ratingsDictionary = GetParentalRatingsDictionary();
|
||||||
@ -257,6 +261,18 @@ namespace Emby.Server.Implementations.Localization
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove prefix country code to handle "DE-18"
|
||||||
|
index = rating.IndexOf('-', StringComparison.Ordinal);
|
||||||
|
if (index != -1)
|
||||||
|
{
|
||||||
|
var trimmedRating = rating.AsSpan(index).TrimStart('-').Trim();
|
||||||
|
|
||||||
|
if (!trimmedRating.IsEmpty)
|
||||||
|
{
|
||||||
|
return GetRatingLevel(trimmedRating.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Further improve by normalizing out all spaces and dashes
|
// TODO: Further improve by normalizing out all spaces and dashes
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
E,0
|
||||||
|
EC,0
|
||||||
|
T,7
|
||||||
|
M,18
|
||||||
|
AO,18
|
||||||
|
UR,18
|
||||||
|
RP,18
|
||||||
|
X,1000
|
||||||
|
XX,1000
|
||||||
|
XXX,1000
|
||||||
|
XXXX,1000
|
|
@ -1,7 +1,13 @@
|
|||||||
AU-G,1
|
Exempt,0
|
||||||
AU-PG,5
|
G,0
|
||||||
AU-M,6
|
7+,7
|
||||||
AU-MA15+,7
|
M,15
|
||||||
AU-R18+,9
|
MA,15
|
||||||
AU-X18+,10
|
MA15+,15
|
||||||
AU-RC,11
|
PG,16
|
||||||
|
16+,16
|
||||||
|
R,18
|
||||||
|
R18+,18
|
||||||
|
X18+,18
|
||||||
|
18+,18
|
||||||
|
X,1000
|
||||||
|
|
@ -1,6 +1,11 @@
|
|||||||
BE-AL,1
|
AL,0
|
||||||
BE-MG6,2
|
KT,0
|
||||||
BE-6,3
|
TOUS,0
|
||||||
BE-9,5
|
MG6,6
|
||||||
BE-12,6
|
6,6
|
||||||
BE-16,8
|
9,9
|
||||||
|
KNT,12
|
||||||
|
12,12
|
||||||
|
BE_14,14
|
||||||
|
16,16
|
||||||
|
18,18
|
||||||
|
|
@ -1,6 +1,8 @@
|
|||||||
BR-L,1
|
Livre,0
|
||||||
BR-10,5
|
L,0
|
||||||
BR-12,7
|
ER,9
|
||||||
BR-14,8
|
10,10
|
||||||
BR-16,8
|
12,12
|
||||||
BR-18,9
|
14,14
|
||||||
|
16,16
|
||||||
|
18,18
|
||||||
|
|
@ -1,6 +1,20 @@
|
|||||||
CA-G,1
|
E,0
|
||||||
CA-PG,5
|
G,0
|
||||||
CA-14A,7
|
TV-Y,0
|
||||||
CA-A,8
|
TV-G,0
|
||||||
CA-18A,9
|
TV-Y7,7
|
||||||
CA-R,10
|
TV-Y7-FV,7
|
||||||
|
PG,9
|
||||||
|
TV-PG,9
|
||||||
|
PG-13,13
|
||||||
|
13+,13
|
||||||
|
TV-14,14
|
||||||
|
14A,14
|
||||||
|
16+,16
|
||||||
|
NC-17,17
|
||||||
|
R,18
|
||||||
|
TV-MA,18
|
||||||
|
18A,18
|
||||||
|
18+,18
|
||||||
|
A,1000
|
||||||
|
Prohibited,1001
|
||||||
|
|
@ -1,8 +1,7 @@
|
|||||||
CO-T,1
|
T,0
|
||||||
CO-7,5
|
7,7
|
||||||
CO-12,7
|
12,12
|
||||||
CO-15,8
|
15,15
|
||||||
CO-18,10
|
18,18
|
||||||
CO-X,100
|
X,1000
|
||||||
CO-BANNED,15
|
Prohibited,1001
|
||||||
CO-E,15
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
|||||||
DE-0,1
|
Educational,0
|
||||||
FSK-0,1
|
Infoprogramm,0
|
||||||
DE-6,5
|
FSK-0,0
|
||||||
FSK-6,5
|
0,0
|
||||||
DE-12,7
|
FSK-6,6
|
||||||
FSK-12,7
|
6,6
|
||||||
DE-16,8
|
FSK-12,12
|
||||||
FSK-16,8
|
12,12
|
||||||
DE-18,9
|
FSK-16,16
|
||||||
FSK-18,9
|
16,16
|
||||||
|
FSK-18,18
|
||||||
|
18,18
|
||||||
|
|
@ -1,4 +1,7 @@
|
|||||||
DA-A,1
|
F,0
|
||||||
DA-7,5
|
A,0
|
||||||
DA-11,6
|
7,7
|
||||||
DA-15,8
|
11,11
|
||||||
|
12,12
|
||||||
|
15,15
|
||||||
|
16,16
|
||||||
|
|
@ -1,6 +1,24 @@
|
|||||||
ES-A,1
|
A,0
|
||||||
ES-APTA,1
|
A/fig,0
|
||||||
ES-7,3
|
A/i,0
|
||||||
ES-12,6
|
A/fig/i,0
|
||||||
ES-16,8
|
APTA,0
|
||||||
ES-18,11
|
TP,0
|
||||||
|
0+,0
|
||||||
|
6+,6
|
||||||
|
7/fig,7
|
||||||
|
7/i,7
|
||||||
|
7/i/fig,7
|
||||||
|
7,7
|
||||||
|
9+,9
|
||||||
|
10,10
|
||||||
|
12,12
|
||||||
|
12/fig,12
|
||||||
|
13,13
|
||||||
|
14,14
|
||||||
|
16,16
|
||||||
|
16/fig,16
|
||||||
|
18,18
|
||||||
|
18/fig,18
|
||||||
|
X,1000
|
||||||
|
Banned,1001
|
||||||
|
|
@ -1,10 +1,10 @@
|
|||||||
FI-S,1
|
S,0
|
||||||
FI-T,1
|
T,0
|
||||||
FI-7,4
|
K7,7
|
||||||
FI-12,5
|
7,7
|
||||||
FI-16,8
|
K12,12
|
||||||
FI-18,9
|
12,12
|
||||||
FI-K7,4
|
K16,16
|
||||||
FI-K12,5
|
16,16
|
||||||
FI-K16,8
|
K18,18
|
||||||
FI-K18,9
|
18,18
|
||||||
|
|
@ -1,5 +1,12 @@
|
|||||||
FR-U,1
|
Public Averti,0
|
||||||
FR-10,5
|
Tous Publics,0
|
||||||
FR-12,7
|
U,0
|
||||||
FR-16,9
|
0+,0
|
||||||
FR-18,10
|
6+,6
|
||||||
|
9+,9
|
||||||
|
10,10
|
||||||
|
12,12
|
||||||
|
14+,14
|
||||||
|
16,16
|
||||||
|
18,18
|
||||||
|
X,1000
|
||||||
|
|
@ -1,7 +1,22 @@
|
|||||||
GB-U,1
|
All,0
|
||||||
GB-PG,5
|
E,0
|
||||||
GB-12,6
|
G,0
|
||||||
GB-12A,7
|
U,0
|
||||||
GB-15,8
|
0+,0
|
||||||
GB-18,9
|
6+,6
|
||||||
GB-R18,15
|
7+,7
|
||||||
|
PG,8
|
||||||
|
9+,9
|
||||||
|
12,12
|
||||||
|
12+,12
|
||||||
|
12A,12
|
||||||
|
Teen,13
|
||||||
|
13+,13
|
||||||
|
14+,14
|
||||||
|
15,15
|
||||||
|
16,16
|
||||||
|
Caution,18
|
||||||
|
18,18
|
||||||
|
Mature,1000
|
||||||
|
Adult,1000
|
||||||
|
R18,1000
|
||||||
|
|
@ -1,6 +1,9 @@
|
|||||||
IE-G,1
|
G,4
|
||||||
IE-PG,5
|
PG,12
|
||||||
IE-12A,7
|
12,12
|
||||||
IE-15A,8
|
12A,12
|
||||||
IE-16,9
|
12PG,12
|
||||||
IE-18,10
|
15,15
|
||||||
|
15A,15
|
||||||
|
16,16
|
||||||
|
18,18
|
||||||
|
|
@ -1,4 +1,11 @@
|
|||||||
JP-G,1
|
A,0
|
||||||
JP-PG12,7
|
G,0
|
||||||
JP-15+,8
|
B,12
|
||||||
JP-18+,10
|
PG12,12
|
||||||
|
C,15
|
||||||
|
15+,15
|
||||||
|
R15+,15
|
||||||
|
16+,16
|
||||||
|
D,17
|
||||||
|
Z,18
|
||||||
|
18+,18
|
||||||
|
|
@ -1,7 +1,6 @@
|
|||||||
KZ-6-,0
|
K,0
|
||||||
KZ-6+,6
|
БА,12
|
||||||
KZ-12+,12
|
Б14,14
|
||||||
KZ-14+,14
|
E16,16
|
||||||
KZ-16+,16
|
E18,18
|
||||||
KZ-18+,18
|
HA,18
|
||||||
KZ-21+,21
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
MX-AA,1
|
A,0
|
||||||
MX-A,5
|
AA,0
|
||||||
MX-B,7
|
B,12
|
||||||
MX-B-15,8
|
B-15,15
|
||||||
MX-C,9
|
C,18
|
||||||
MX-D,10
|
D,1000
|
||||||
|
|
@ -1,6 +1,8 @@
|
|||||||
NL-AL,1
|
AL,0
|
||||||
NL-MG6,2
|
MG6,6
|
||||||
NL-6,3
|
6,6
|
||||||
NL-9,5
|
9,9
|
||||||
NL-12,6
|
12,12
|
||||||
NL-16,8
|
14,14
|
||||||
|
16,16
|
||||||
|
18,18
|
||||||
|
|
@ -1,6 +1,9 @@
|
|||||||
NO-A,1
|
A,0
|
||||||
NO-6,3
|
6,6
|
||||||
NO-9,4
|
7,7
|
||||||
NO-12,5
|
9,9
|
||||||
NO-15,8
|
11,11
|
||||||
NO-18,9
|
12,12
|
||||||
|
15,15
|
||||||
|
18,18
|
||||||
|
Not approved,1001
|
||||||
|
|
@ -1,11 +1,15 @@
|
|||||||
NZ-G,1
|
Exempt,0
|
||||||
NZ-PG,5
|
G,0
|
||||||
NZ-M,6
|
GY,13
|
||||||
NZ-R13,7
|
PG,13
|
||||||
NZ-RP13,7
|
R13,13
|
||||||
NZ-R15,8
|
RP13,13
|
||||||
NZ-RP16,9
|
R15,15
|
||||||
NZ-R16,9
|
M,16
|
||||||
NZ-R18,10
|
R16,16
|
||||||
NZ-R,10
|
RP16,16
|
||||||
NZ-MA,10
|
GA,18
|
||||||
|
R18,18
|
||||||
|
MA,1000
|
||||||
|
R,1001
|
||||||
|
Objectionable,1001
|
||||||
|
|
@ -1 +1,6 @@
|
|||||||
RO-AG,1
|
AG,0
|
||||||
|
AP-12,12
|
||||||
|
N-15,15
|
||||||
|
IM-18,18
|
||||||
|
IM-18-XXX,1000
|
||||||
|
IC,1001
|
||||||
|
|
@ -1,5 +1,6 @@
|
|||||||
RU-0+,1
|
0+,0
|
||||||
RU-6+,3
|
6+,6
|
||||||
RU-12+,7
|
12+,12
|
||||||
RU-16+,9
|
16+,16
|
||||||
RU-18+,10
|
18+,18
|
||||||
|
Refused classification,1001
|
||||||
|
|
@ -1,5 +1,10 @@
|
|||||||
SE-Btl,1
|
Alla,0
|
||||||
SE-Barntillåten,1
|
Barntillåten,0
|
||||||
SE-7,3
|
Btl,0
|
||||||
SE-11,5
|
0+,0
|
||||||
SE-15,8
|
7,7
|
||||||
|
9+,9
|
||||||
|
10+,10
|
||||||
|
11,11
|
||||||
|
14,14
|
||||||
|
15,15
|
||||||
|
|
@ -1,7 +1,22 @@
|
|||||||
UK-U,1
|
All,0
|
||||||
UK-PG,5
|
E,0
|
||||||
UK-12,7
|
G,0
|
||||||
UK-12A,7
|
U,0
|
||||||
UK-15,9
|
0+,0
|
||||||
UK-18,10
|
6+,6
|
||||||
UK-R18,15
|
7+,7
|
||||||
|
PG,8
|
||||||
|
9+,9
|
||||||
|
12,12
|
||||||
|
12+,12
|
||||||
|
12A,12
|
||||||
|
Teen,13
|
||||||
|
13+,13
|
||||||
|
14+,14
|
||||||
|
15,15
|
||||||
|
16,16
|
||||||
|
Caution,18
|
||||||
|
18,18
|
||||||
|
Mature,1000
|
||||||
|
Adult,1000
|
||||||
|
R18,1000
|
||||||
|
|
@ -1,23 +1,50 @@
|
|||||||
TV-Y,1
|
Approved,0
|
||||||
APPROVED,1
|
G,0
|
||||||
G,1
|
TV-G,0
|
||||||
E,1
|
TV-Y,0
|
||||||
EC,1
|
TV-Y7,7
|
||||||
TV-G,1
|
TV-Y7-FV,7
|
||||||
TV-Y7,3
|
PG,10
|
||||||
TV-Y7-FV,4
|
PG-13,13
|
||||||
PG,5
|
TV-PG,13
|
||||||
TV-PG,5
|
TV-PG-D,13
|
||||||
PG-13,7
|
TV-PG-L,13
|
||||||
T,7
|
TV-PG-S,13
|
||||||
TV-14,8
|
TV-PG-V,13
|
||||||
R,9
|
TV-PG-DL,13
|
||||||
M,9
|
TV-PG-DS,13
|
||||||
TV-MA,9
|
TV-PG-DV,13
|
||||||
NC-17,10
|
TV-PG-LS,13
|
||||||
AO,15
|
TV-PG-LV,13
|
||||||
RP,15
|
TV-PG-SV,13
|
||||||
UR,15
|
TV-PG-DLS,13
|
||||||
NR,15
|
TV-PG-DLV,13
|
||||||
X,15
|
TV-PG-DSV,13
|
||||||
XXX,100
|
TV-PG-LSV,13
|
||||||
|
TV-PG-DLSV,13
|
||||||
|
TV-14,14
|
||||||
|
TV-14-D,14
|
||||||
|
TV-14-L,14
|
||||||
|
TV-14-S,14
|
||||||
|
TV-14-V,14
|
||||||
|
TV-14-DL,14
|
||||||
|
TV-14-DS,14
|
||||||
|
TV-14-DV,14
|
||||||
|
TV-14-LS,14
|
||||||
|
TV-14-LV,14
|
||||||
|
TV-14-SV,14
|
||||||
|
TV-14-DLS,14
|
||||||
|
TV-14-DLV,14
|
||||||
|
TV-14-DSV,14
|
||||||
|
TV-14-LSV,14
|
||||||
|
TV-14-DLSV,14
|
||||||
|
NC-17,17
|
||||||
|
R,17
|
||||||
|
TV-MA,17
|
||||||
|
TV-MA-L,17
|
||||||
|
TV-MA-S,17
|
||||||
|
TV-MA-V,17
|
||||||
|
TV-MA-LS,17
|
||||||
|
TV-MA-LV,17
|
||||||
|
TV-MA-SV,17
|
||||||
|
TV-MA-LSV,17
|
||||||
|
|
@ -83,11 +83,11 @@ namespace Jellyfin.Server.Implementations.Tests.Localization
|
|||||||
await localizationManager.LoadAll();
|
await localizationManager.LoadAll();
|
||||||
var ratings = localizationManager.GetParentalRatings().ToList();
|
var ratings = localizationManager.GetParentalRatings().ToList();
|
||||||
|
|
||||||
Assert.Equal(23, ratings.Count);
|
Assert.Equal(50, ratings.Count);
|
||||||
|
|
||||||
var tvma = ratings.FirstOrDefault(x => x.Name.Equals("TV-MA", StringComparison.Ordinal));
|
var tvma = ratings.FirstOrDefault(x => x.Name.Equals("TV-MA", StringComparison.Ordinal));
|
||||||
Assert.NotNull(tvma);
|
Assert.NotNull(tvma);
|
||||||
Assert.Equal(9, tvma!.Value);
|
Assert.Equal(17, tvma!.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -100,21 +100,21 @@ namespace Jellyfin.Server.Implementations.Tests.Localization
|
|||||||
await localizationManager.LoadAll();
|
await localizationManager.LoadAll();
|
||||||
var ratings = localizationManager.GetParentalRatings().ToList();
|
var ratings = localizationManager.GetParentalRatings().ToList();
|
||||||
|
|
||||||
Assert.Equal(10, ratings.Count);
|
Assert.Equal(12, ratings.Count);
|
||||||
|
|
||||||
var fsk = ratings.FirstOrDefault(x => x.Name.Equals("FSK-12", StringComparison.Ordinal));
|
var fsk = ratings.FirstOrDefault(x => x.Name.Equals("FSK-12", StringComparison.Ordinal));
|
||||||
Assert.NotNull(fsk);
|
Assert.NotNull(fsk);
|
||||||
Assert.Equal(7, fsk!.Value);
|
Assert.Equal(12, fsk!.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("CA-R", "CA", 10)]
|
[InlineData("CA-R", "CA", 18)]
|
||||||
[InlineData("FSK-16", "DE", 8)]
|
[InlineData("FSK-16", "DE", 16)]
|
||||||
[InlineData("FSK-18", "DE", 9)]
|
[InlineData("FSK-18", "DE", 18)]
|
||||||
[InlineData("FSK-18", "US", 9)]
|
[InlineData("FSK-18", "US", 18)]
|
||||||
[InlineData("TV-MA", "US", 9)]
|
[InlineData("TV-MA", "US", 17)]
|
||||||
[InlineData("XXX", "asdf", 100)]
|
[InlineData("XXX", "asdf", 1000)]
|
||||||
[InlineData("Germany: FSK-18", "DE", 9)]
|
[InlineData("Germany: FSK-18", "DE", 18)]
|
||||||
public async Task GetRatingLevel_GivenValidString_Success(string value, string countryCode, int expectedLevel)
|
public async Task GetRatingLevel_GivenValidString_Success(string value, string countryCode, int expectedLevel)
|
||||||
{
|
{
|
||||||
var localizationManager = Setup(new ServerConfiguration()
|
var localizationManager = Setup(new ServerConfiguration()
|
||||||
@ -135,6 +135,9 @@ namespace Jellyfin.Server.Implementations.Tests.Localization
|
|||||||
UICulture = "de-DE"
|
UICulture = "de-DE"
|
||||||
});
|
});
|
||||||
await localizationManager.LoadAll();
|
await localizationManager.LoadAll();
|
||||||
|
Assert.Null(localizationManager.GetRatingLevel("NR"));
|
||||||
|
Assert.Null(localizationManager.GetRatingLevel("unrated"));
|
||||||
|
Assert.Null(localizationManager.GetRatingLevel("Not Rated"));
|
||||||
Assert.Null(localizationManager.GetRatingLevel("n/a"));
|
Assert.Null(localizationManager.GetRatingLevel("n/a"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user