Intelligent media access control for Jellyfin
- Filename Regex Patterns -- Match against filenames with regex for Jellyfin multi-version setups
- Per-User Assignments -- Assign different policies to different users
- Web Configuration -- Easy-to-use admin interface in Jellyfin dashboard
- Multi-Version Support -- Seamlessly filter available media versions per user
- Custom Intros -- Optional intro video per policy (e.g. a "lite" branding for restricted users)
- Dangling Symlink Protection -- Sources whose files don't exist on disk are automatically hidden
- Detailed Logging -- Full audit trail of access decisions
This plugin is designed for Jellyfin's multi-version naming convention, where multiple quality versions of the same movie live together:
movies/Movie (2021)/Movie (2021) - 2160p.mkv
movies/Movie (2021)/Movie (2021) - 1080p.mkv
movies/Movie (2021)/Movie (2021) - 720p.mkv
| Scenario | Solution |
|---|---|
| Bandwidth Management | Restrict remote users to lower-bitrate versions |
| Tiered Access | Premium users get 4K, standard users get 1080p |
| Device Optimization | Mobile users automatically get mobile-optimized versions |
Add this repository to your Jellyfin instance for automatic updates:
- Go to Dashboard > Plugins > Repositories
- Click Add and enter:
- Name:
Quality Gate - URL:
https://geiserx.github.io/quality-gate/manifest.json
- Name:
- Go to Catalog and install Quality Gate
- Restart Jellyfin
Docker
VERSION="3.2.0.0"
curl -L -o QualityGate.zip \
"https://github.com/GeiserX/quality-gate/releases/download/v${VERSION}/quality-gate_${VERSION}.zip"
unzip QualityGate.zip -d /path/to/jellyfin/plugins/QualityGate/
docker restart jellyfinOr add to your docker-compose.yml:
volumes:
- ./plugins/QualityGate:/config/plugins/QualityGateLinux (Native)
VERSION="3.2.0.0"
curl -L -o QualityGate.zip \
"https://github.com/GeiserX/quality-gate/releases/download/v${VERSION}/quality-gate_${VERSION}.zip"
sudo unzip QualityGate.zip -d /var/lib/jellyfin/plugins/QualityGate/
sudo chown -R jellyfin:jellyfin /var/lib/jellyfin/plugins/QualityGate/
sudo systemctl restart jellyfinWindows
- Download the latest release
- Extract to
%LOCALAPPDATA%\jellyfin\plugins\QualityGate\ - Restart Jellyfin from Services or the tray icon
macOS
VERSION="3.2.0.0"
curl -L -o QualityGate.zip \
"https://github.com/GeiserX/quality-gate/releases/download/v${VERSION}/quality-gate_${VERSION}.zip"
unzip QualityGate.zip -d ~/.local/share/jellyfin/plugins/QualityGate/Navigate to Dashboard > Quality Gate to configure the plugin.
Policies define which filename patterns are allowed or blocked. Click "Add Policy" to create one.
| Field | Description |
|---|---|
| Policy Name | A descriptive name (e.g., "720p Only", "No 4K") |
| Allowed Filename Patterns | Regex patterns matched against the filename. Files must match at least one pattern. |
| Blocked Filename Patterns | Regex patterns matched against the filename. Matching files are always blocked. |
| Custom Intro Video | Optional intro video for users under this policy. Disable the built-in "Local Intros" plugin if you only want Quality Gate intros. |
| Enabled | Toggle policy on/off |
Choose a policy from the Default Policy dropdown. This applies to ALL users who don't have a specific override.
- Select (No default -- Full Access) to allow unrestricted access by default
- Select a policy to restrict all users by default
The User Access table shows all Jellyfin users and their current policy:
- Use Default -- inherits the default policy
- Full Access -- no restrictions
- Any named policy -- applies that policy's rules
If an override or the default policy points to a deleted or disabled policy, the dropdown shows DENIED until you choose a replacement (fail-closed). This applies to both per-user overrides and the default policy.
Evaluation order:
- Blocked Filename Patterns: If filename matches any blocked regex -- BLOCKED
- Allowed Filename Patterns: If defined and filename doesn't match any -- BLOCKED
- File existence: If the file doesn't exist on disk (dangling symlink) -- BLOCKED
- Otherwise -- ALLOWED
| Allowed Pattern | Blocked Pattern | Filename | Result |
|---|---|---|---|
- 720p |
-- | Movie (2021) - 720p.mkv |
Allowed |
- 720p |
-- | Movie (2021) - 2160p.mkv |
Blocked |
| (empty) | - 2160p|- 4K |
Movie (2021) - 1080p.mkv |
Allowed |
| (empty) | - 2160p|- 4K |
Movie (2021) - 2160p.mkv |
Blocked |
Tip: Patterns are case-insensitive regex with a 1-second timeout to prevent ReDoS. Jellyfin also supports bracketed labels (e.g.
Movie (2021) - [1080p].mkv), so use\[?1080p\]?to match both formats.
Policy Name: 720p Only
Allowed Filename Patterns:
- 720p
Only files with - 720p in the filename are visible.
Policy Name: No 4K
Blocked Filename Patterns:
- 2160p
- 4K
Everything is visible except 4K versions.
Policy Name: Standard
Blocked Filename Patterns:
- 2160p
- 4K
- Remux
- Create "Standard" policy (block 4K as above)
- Set Default Policy to "Standard"
- Add Full Access overrides for premium users
-
Result Filter: The plugin uses an ASP.NET Core
IAsyncResultFilterthat intercepts API responses before serialization, operating on C# objects directly. -
MediaSource Filtering: When Jellyfin returns media sources/versions to the client, the filter removes blocked versions so they don't appear in the UI.
-
Filename Matching: Each media version's filename is matched against your policy's regex patterns. For symlinked files, both the symlink filename and the resolved target filename are checked.
-
File Existence: Sources whose files don't exist on disk (e.g. dangling symlinks from in-progress transcodes) are automatically hidden, preventing playback errors.
All quality versions must be in the same Jellyfin library using Jellyfin's multi-version naming. Each version needs a - label suffix (space, hyphen, space, label):
movies/
Movie (2021)/
Movie (2021) - 2160p.mkv
Movie (2021) - 1080p.mkv
Movie (2021) - 720p.mkv
Jellyfin merges these into a single item with multiple MediaSources. The plugin then filters which sources each user can see.
- .NET 9.0 SDK
- Git
git clone https://github.com/GeiserX/quality-gate.git
cd quality-gate/Jellyfin.Plugin.QualityGate
dotnet build -c ReleaseThe compiled plugin will be in bin/Release/net9.0/.
- This plugin handles access control -- review your policies carefully
- Only administrators can configure policies
- See SECURITY.md for vulnerability reporting
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
- smart-covers -- Cover extraction for books, audiobooks, comics, magazines, and music libraries with online fallback
- whisper-subs -- Automatically generates subtitles using local AI models powered by Whisper
- jellyfin-encoder -- Automatic 720p HEVC/AV1 transcoding service with optional symlink creation for Jellyfin multi-version support
- jellyfin-telegram-channel-sync -- Sync Jellyfin access with Telegram channel membership
This project is licensed under the GPL-3.0 License -- see the LICENSE file for details.
- Jellyfin -- The Free Software Media System
- The Jellyfin plugin development community