flan 59aaebe108
secret-scan / gitleaks (push) Successful in 12s
Add a pinned secret-scanning workflow
Scans the full git history on push, pull request and weekly, so a credential
that was committed and later removed is still detected. The scanner archive is
pinned by version and verified by SHA-256 before it runs, and matched values
are redacted so they never reach the CI log.
2026-09-28 17:27:48 +00:00

Jellyfin Audience

A Jellyfin plugin that repairs ratings the server cannot parse, and maintains an audience tag so a user account can be narrowed to a manageable subset of a large library.

It runs in-process as a scheduled task. It needs no API key, no credential file and no external service.

Why it exists

Ratings Jellyfin cannot parse are a hole in parental controls

Jellyfin resolves an OfficialRating string to a numeric score. When it cannot, the item takes the same path as an unrated one, and unrated items are visible to everyone by default unless an account explicitly blocks unrated content.

That is not a theoretical problem. A real library scanned for this contained Singapore board ratings (M18, NC16, R21) on adult titles. Jellyfin could not parse any of them, so no age ceiling would have hidden them. It cuts the other way too: TP (Spain) and L (Brazil) both mean "all ages", and titles carrying them were being hidden from children as though unrated.

This plugin remaps those strings to their documented US equivalents and locks the result.

Allowed Tags fails closed

Narrowing an account with Allowed Tags is the right mechanism, but it is a whitelist: anything without the tag is invisible. A library that keeps growing would leave that account frozen at whatever was tagged on the day it was set up. So the tagging pass has to run on a schedule, not once.

What it does not do

It does not guess a rating from genre, synopsis, or anything else about the content. A wrong guess fails open, and failing open is the one outcome parental controls exist to prevent. Ratings it cannot map are logged as warnings and left untouched, for a person to decide.

Configuration

Dashboard, then Plugins, then Audience.

Setting Default Meaning
Enabled on Master switch for the scheduled task
RepairRatings on Remap unparseable board ratings
ApplyTags on Maintain the audience tag
TagName grandma Tag applied to matching titles
MaxRatingScore 14 Rating ceiling for tagging. Inclusive
MinCommunityRatingWhenUnrated 6.0 Community-rating floor for titles with no usable rating
RespectManualUntag on Honour the ledger, so manual untagging sticks

The US rating ladder is 0 G and TV-G, 7 TV-Y7, 10 PG and TV-PG, 13 PG-13, 14 TV-14, 17 R and TV-MA. Note that Jellyfin 10.11 rescored TV-PG from 13 to 10, so a ceiling carried over from an older install will not behave the way it used to.

MinCommunityRatingWhenUnrated is a weak gate on obscure titles, where a perfect score can rest on a handful of votes. It is a starting filter, not a verdict.

Curating the result

The rule is a first pass, not an opinion. To remove something, untag it in the Jellyfin UI. The ledger records that the item was tagged once, so the next run sees a deliberate removal and leaves it alone.

Turning off RespectManualUntag makes every run re-apply the rule, which undoes curation. It exists for the case where you want to reset and start again.

Building

Needs the .NET 9 SDK. On a machine where it is a user-local install rather than a system package, it will not be on the PATH of a non-interactive shell:

export DOTNET_ROOT="$HOME/.dotnet"
export PATH="$DOTNET_ROOT:$PATH"
dotnet build Jellyfin.Plugin.Audience/Jellyfin.Plugin.Audience.csproj -c Release

The output is Jellyfin.Plugin.Audience/bin/Release/net9.0/Jellyfin.Plugin.Audience.dll.

Installing

Copy the DLL and meta.json into a folder named Audience_1.0.0.0 inside Jellyfin's plugins directory, then restart the server. The plugin appears under Dashboard, Plugins, and its task appears under Scheduled Tasks as "Repair ratings and apply audience tags".

targetAbi is 10.11.0.0. That is deliberate and is not a mistake on a 12.x server: a plugin built against Jellyfin.Controller 10.11.11 loads and runs on Jellyfin 12.0. Do not raise it without confirming the newer package exists and the result still loads.

Releasing

To publish through a Jellyfin plugin catalog, zip the DLL and meta.json, host the zip, and add a repository manifest entry whose sourceUrl points at it. The sourceUrl must end in .zip, and the checksum field must be the MD5 of the actual published archive. No manifest is committed here, because a manifest carrying a placeholder checksum or a URL with nothing behind it produces a broken install for anyone who adds it.

Licence

GPL-3.0.

S
Description
Jellyfin plugin: repairs unparseable parental ratings and maintains an audience tag for reduced libraries
Readme
53 KiB
0 Stars 1 Watchers 0 Forks
Languages
C# 70.1%
HTML 29.9%