metatube-community/jellyfin-plugin-metatube
MetaTube Plugin for Jellyfin/Emby
Slowing — last commit 6mo ago
worst of 4 axestop contributor handles 90% of recent commits; no tests detected
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 6mo ago
- ✓9 active contributors
- ✓MIT licensed
Show 4 more →Show less
- ✓CI configured
- ⚠Slowing — last commit 6mo ago
- ⚠Single-maintainer risk — top contributor 90% of recent commits
- ⚠No test directory detected
What would change the summary?
- →Use as dependency Mixed → Healthy if: diversify commit ownership (top <90%)
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Forkable" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/metatube-community/jellyfin-plugin-metatube)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/metatube-community/jellyfin-plugin-metatube on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: metatube-community/jellyfin-plugin-metatube
Generated by RepoPilot · 2026-05-10 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/metatube-community/jellyfin-plugin-metatube shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
WAIT — Slowing — last commit 6mo ago
- Last commit 6mo ago
- 9 active contributors
- MIT licensed
- CI configured
- ⚠ Slowing — last commit 6mo ago
- ⚠ Single-maintainer risk — top contributor 90% of recent commits
- ⚠ No test directory detected
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live metatube-community/jellyfin-plugin-metatube
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/metatube-community/jellyfin-plugin-metatube.
What it runs against: a local clone of metatube-community/jellyfin-plugin-metatube — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in metatube-community/jellyfin-plugin-metatube | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 218 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of metatube-community/jellyfin-plugin-metatube. If you don't
# have one yet, run these first:
#
# git clone https://github.com/metatube-community/jellyfin-plugin-metatube.git
# cd jellyfin-plugin-metatube
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of metatube-community/jellyfin-plugin-metatube and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "metatube-community/jellyfin-plugin-metatube(\\.git)?\\b" \\
&& ok "origin remote is metatube-community/jellyfin-plugin-metatube" \\
|| miss "origin remote is not metatube-community/jellyfin-plugin-metatube (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "Jellyfin.Plugin.MetaTube/Plugin.cs" \\
&& ok "Jellyfin.Plugin.MetaTube/Plugin.cs" \\
|| miss "missing critical file: Jellyfin.Plugin.MetaTube/Plugin.cs"
test -f "Jellyfin.Plugin.MetaTube/ApiClient.cs" \\
&& ok "Jellyfin.Plugin.MetaTube/ApiClient.cs" \\
|| miss "missing critical file: Jellyfin.Plugin.MetaTube/ApiClient.cs"
test -f "Jellyfin.Plugin.MetaTube/Providers/BaseProvider.cs" \\
&& ok "Jellyfin.Plugin.MetaTube/Providers/BaseProvider.cs" \\
|| miss "missing critical file: Jellyfin.Plugin.MetaTube/Providers/BaseProvider.cs"
test -f "Jellyfin.Plugin.MetaTube/Configuration/PluginConfiguration.cs" \\
&& ok "Jellyfin.Plugin.MetaTube/Configuration/PluginConfiguration.cs" \\
|| miss "missing critical file: Jellyfin.Plugin.MetaTube/Configuration/PluginConfiguration.cs"
test -f "Jellyfin.Plugin.MetaTube/Helpers/ProviderId.cs" \\
&& ok "Jellyfin.Plugin.MetaTube/Helpers/ProviderId.cs" \\
|| miss "missing critical file: Jellyfin.Plugin.MetaTube/Helpers/ProviderId.cs"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 218 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~188d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/metatube-community/jellyfin-plugin-metatube"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
MetaTube is a C# plugin for Jellyfin and Emby media servers that enriches movie and actor metadata by aggregating data from multiple external providers. It fetches and normalizes full metadata (titles, overviews, genres, directors, actors, studios), discovers trailers without downloading them, detects and crops actor faces for images, and can auto-translate metadata into user-preferred languages via scheduled tasks. Layered architecture: Jellyfin.Plugin.MetaTube root contains Plugin.cs (entry point), Providers/ folder (MovieProvider, ActorProvider, ImageProviders extending BaseProvider), Metadata/ folder (data models for API responses), Configuration/ folder (PluginConfiguration and HTML UI), ExternalIds/ folder (metadata provider adapters), ScheduledTasks/ folder (background jobs), and helper folders (Extensions/, Helpers/, Translation/).
👥Who it's for
Jellyfin and Emby server administrators who want richer, multi-source movie metadata without manual curation; content curators and home media enthusiasts who need automated face-detection-based image cropping and multilingual metadata support.
🌱Maturity & risk
Actively developed and production-ready. The project has GitHub Actions CI/CD setup (dotnetcore.yml), supports stable versions of Jellyfin 10.11.x and Emby 4.9.x, and has multiple release channels with pre-release support. Codebase is substantial (~87KB C#) with organized extension, provider, and configuration patterns indicating mature architecture.
Low-to-moderate risk: the plugin depends on external metadata providers (abstracted via ApiClient.cs and multiple provider classes), so upstream service outages could block functionality. Single-repository structure with no visible monorepo separation could complicate versioning. No test coverage visible in file list—critical for plugin reliability in production Jellyfin instances. Contributor activity and recent commit dates not visible from file structure alone.
Active areas of work
Active development with scheduled tasks for automatic metadata organization (OrganizeMetadataTask, GenerateTrailersTask, UpdatePluginTask), recent translation engine work (TranslationEngine.cs, TranslationHelper.cs, TranslationMode.cs), and face detection image cropping features. Stale issue workflow in place suggests ongoing maintenance.
🚀Get running
Clone: git clone https://github.com/metatube-community/jellyfin-plugin-metatube.git && cd jellyfin-plugin-metatube. Build with .NET SDK (C# project): dotnet build Jellyfin.Plugin.MetaTube/Jellyfin.Plugin.MetaTube.csproj. Output plugin DLL to Jellyfin plugins folder. No npm/Python installation needed for core plugin—Python files (1.8KB) appear to be utility/build scripts only.
Daily commands:
This is a plugin library, not a standalone application. Build with dotnet build and copy the compiled DLL to your Jellyfin plugins/ folder. Restart Jellyfin. Configure via the web UI using configPage.html settings. Run scheduled tasks manually or let them trigger on configured intervals.
🗺️Map of the codebase
Jellyfin.Plugin.MetaTube/Plugin.cs— Entry point and main plugin class that initializes the MetaTube plugin for Jellyfin; all contributors must understand the plugin lifecycleJellyfin.Plugin.MetaTube/ApiClient.cs— Core HTTP client that communicates with the MetaTube backend API; critical for all metadata fetching operationsJellyfin.Plugin.MetaTube/Providers/BaseProvider.cs— Abstract base class for all metadata providers (movies, actors, images); establishes the provider pattern used throughout the codebaseJellyfin.Plugin.MetaTube/Configuration/PluginConfiguration.cs— Plugin configuration schema and settings management; essential for understanding how plugin behavior is customizedJellyfin.Plugin.MetaTube/Helpers/ProviderId.cs— Provider ID mapping and constants; core utility for handling external provider identifiers across all modulesJellyfin.Plugin.MetaTube/ExternalIds/BaseExternalId.cs— Abstract base for external ID providers; defines how Jellyfin maps MetaTube IDs to external services
🛠️How to make changes
Add a new metadata provider (e.g., for TV Shows)
- Create a new provider class inheriting from BaseProvider in the Providers folder (
Jellyfin.Plugin.MetaTube/Providers/BaseProvider.cs) - Implement required abstract methods: GetSearchResults(), GetMetadata(), and HasMetadata() (
Jellyfin.Plugin.MetaTube/Providers/MovieProvider.cs) - Add corresponding external ID provider class inheriting from BaseExternalId (
Jellyfin.Plugin.MetaTube/ExternalIds/BaseExternalId.cs) - Register the provider in Plugin.cs via GetExportedTypes() and plugin instance initialization (
Jellyfin.Plugin.MetaTube/Plugin.cs) - Add new provider ID constant to ProviderId.cs if using a new external ID type (
Jellyfin.Plugin.MetaTube/Helpers/ProviderId.cs)
Add a new scheduled task (e.g., daily metadata refresh)
- Create new task class in ScheduledTasks folder inheriting from IScheduledTask (
Jellyfin.Plugin.MetaTube/ScheduledTasks/GenerateTrailersTask.cs) - Implement Name, Key, Category, Description, and Execute() method (
Jellyfin.Plugin.MetaTube/ScheduledTasks/GenerateTrailersTask.cs) - Register task in Plugin.cs by adding to GetExportedTypes() for Jellyfin discovery (
Jellyfin.Plugin.MetaTube/Plugin.cs) - Optionally add configuration options to PluginConfiguration.cs if the task is configurable (
Jellyfin.Plugin.MetaTube/Configuration/PluginConfiguration.cs)
Add support for a new translation language or mode
- Add new translation mode constant to TranslationMode.cs enumeration (
Jellyfin.Plugin.MetaTube/Translation/TranslationMode.cs) - Update TranslationEngine.cs to handle the new translation mode in Translate() method (
Jellyfin.Plugin.MetaTube/Translation/TranslationEngine.cs) - Add configuration UI options in configPage.html if user selection is needed (
Jellyfin.Plugin.MetaTube/Configuration/configPage.html) - Update PluginConfiguration.cs to persist new language/mode preferences (
Jellyfin.Plugin.MetaTube/Configuration/PluginConfiguration.cs) - Call TranslationHelper methods from relevant providers (MovieProvider, ActorProvider) during metadata retrieval (
Jellyfin.Plugin.MetaTube/Providers/MovieProvider.cs)
Add a new image provider type (e.g., backgrounds or banners)
- Create new image provider class in Providers folder inheriting from BaseProvider, similar to MovieImageProvider (
Jellyfin.Plugin.MetaTube/Providers/MovieImageProvider.cs) - Implement GetImages() to fetch and parse image metadata from API response (
Jellyfin.Plugin.MetaTube/ApiClient.cs) - Register image provider in Plugin.cs to enable automatic Jellyfin discovery (
Jellyfin.Plugin.MetaTube/Plugin.cs) - Optionally extend configPage.html to allow users to enable/disable specific image types (
Jellyfin.Plugin.MetaTube/Configuration/configPage.html)
🪤Traps & gotchas
No visible environment variable configuration in file list—check PluginConfiguration.cs for required API keys or authentication tokens to external metadata providers. Face detection appears integrated but no ML model files visible in structure; verify a pre-trained model is bundled or downloaded at runtime. The plugin depends on Jellyfin/Emby's metadata organization system; incompatible naming conventions will break metadata matching (consult wiki/naming-rules). Scheduled tasks use Jellyfin's scheduler; tasks must not conflict with large library scans. Translation feature may incur external API costs depending on which translation service is integrated—check Configuration.
🏗️Architecture
💡Concepts to learn
- Metadata Provider Adapter Pattern — MetaTube abstracts multiple external metadata sources (IMDb, TheMovieDB, etc.) behind BaseProvider; understanding this pattern is key to adding new providers or modifying existing ones
- Jellyfin Plugin SDK Architecture — The plugin must conform to Jellyfin's provider interface contract (IMetadataProvider, IImageProvider, IExternalId); understanding this contract is essential for any contribution
- Levenshtein Distance (Edit Distance) — Used in Helpers/Levenshtein.cs for fuzzy matching movie titles against external databases when exact matches fail; critical for search accuracy
- Face Detection & Image Cropping — MetaTube integrates face detection to crop primary images with faces centered; this prevents showing black bars or wrong subjects in movie posters
- Scheduled Task Pattern — Background jobs (GenerateTrailersTask, OrganizeMetadataTask, UpdatePluginTask) run on Jellyfin's scheduler; understanding task lifecycle prevents conflicts and resource exhaustion
- External ID Provider Pattern — ExternalIds/ folder defines how MetaTube maps Jellyfin items to external databases (IMDb ID, TMDB ID, etc.); this enables cross-provider metadata matching
- Multilingual Metadata Translation — TranslationEngine.cs enables automatic translation of metadata (titles, overviews) to user's preferred language; requires integration with translation APIs or offline models
🔗Related repos
jellyfin/jellyfin-plugin-template— Official Jellyfin plugin development template; defines the SDK and plugin structure that MetaTube extendsjellyfin/jellyfin— Core Jellyfin media server; MetaTube depends on its plugin APIs and metadata system for integrationMediaBrowser/Emby.Plugins— Emby plugin ecosystem; MetaTube supports Emby 4.9.x as alternative host to Jellyfinjarvis/EmbyStat— Emby/Jellyfin companion tool for metadata analysis; users often pair with MetaTube for complete metadata managementyjhphoto/MediaServerSubtitleProvider— Sibling plugin ecosystem project that mirrors MetaTube's architecture for metadata provider abstraction
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add unit tests for Levenshtein.cs string matching algorithm
The Helpers/Levenshtein.cs file implements a critical string-matching algorithm used for actor/movie name fuzzy matching during metadata retrieval. There are no test files in the repo structure. Adding unit tests would prevent regressions in matching accuracy, which directly impacts metadata quality for users. This is especially important for edge cases (empty strings, special characters, unicode names).
- [ ] Create Tests/Jellyfin.Plugin.MetaTube.Tests.csproj with xUnit framework
- [ ] Add Tests/Helpers/LevenshteinTests.cs with test cases for: identical strings, completely different strings, unicode names, empty strings, and various distance thresholds
- [ ] Add test project reference to jellyfin-plugin-metatube.sln
- [ ] Update .github/workflows/dotnetcore.yml to run dotnet test during CI
Add integration tests for BaseProvider.cs metadata retrieval with mock ApiClient
The Providers/BaseProvider.cs is the foundation for ActorProvider.cs and MovieProvider.cs. Without tests, changes to the provider pipeline risk breaking metadata retrieval across the plugin. Creating integration tests with a mocked ApiClient would validate the entire fetch-parse-transform flow and catch issues early.
- [ ] Create Tests/Providers/BaseProviderTests.cs with Moq for mocking ApiClient.cs
- [ ] Add test cases for: successful metadata retrieval, API errors, empty results, response parsing with ProviderIds
- [ ] Add tests for error handling in Metadata/ErrorInfo.cs responses
- [ ] Ensure tests validate ProviderIdsExtensions.cs functionality during provider execution
Add GitHub Actions workflow for code quality checks (StyleCop/SonarAnalyzer)
The repo has dotnetcore.yml for builds but lacks static analysis. With 15+ C# files covering providers, extensions, and helpers, adding StyleCop analyzer would enforce consistent code style and catch potential bugs (null references, unused variables). This is especially valuable for a community plugin with multiple contributors.
- [ ] Add StyleCopAnalyzers NuGet package to Jellyfin.Plugin.MetaTube.csproj
- [ ] Create .editorconfig in repo root to define code style rules
- [ ] Add GitHub Actions job in .github/workflows/dotnetcore.yml to run: dotnet format --verify-no-changes and dotnet build /p:EnforceCodeStyleInBuild=true
- [ ] Document style guidelines in a CONTRIBUTING.md file with reference to .editorconfig
🌿Good first issues
- Add unit tests for Levenshtein.cs string matching logic (Helpers/Levenshtein.cs) to ensure fuzzy matching accuracy across movie title variations
- Document and add examples for the SubstitutionTable pattern used in Helpers/SubstitutionTable.cs—unclear how custom substitution rules are configured
- Implement retry logic and timeout handling in ApiClient.cs for external provider failures; currently no visible circuit breaker or exponential backoff for unreliable metadata sources
⭐Top contributors
Click to expand
Top contributors
- @xjasonlyu — 90 commits
- @zyd16888 — 2 commits
- @zijiren233 — 2 commits
- @Topbcy — 1 commits
- @zh-ww — 1 commits
📝Recent commits
Click to expand
Recent commits
f7c1f33— Chore: optimize log format (#586) (xjasonlyu)ea44830— Feature: match movies using Levenshtein (#585) (xjasonlyu)d5daf56— Feature(Emby): support toggling auto update (#584) (xjasonlyu)85b4921— Chore: add Japanese README (#583) (xjasonlyu)261657d— Chore: standardize use of provider name and id (#576) (xjasonlyu)71d5b35— Fix: hide provider URLs for other movies (#575) (Topbcy)17e663c— Fix: display provider URLs in Jellyfin (#572) (xjasonlyu)5d114d7— Chore: update manifest script (#568) (xjasonlyu)4822905— Chore: update supported Jellyfin versions (#566) (xjasonlyu)05a8f7f— Feature: add support for Jellyfin 10.11 (#565) (xjasonlyu)
🔒Security observations
The Jellyfin MetaTube plugin has moderate security posture. Key concerns include: (1) External API data handling and validation risks across multiple providers, (2) Potential credential exposure in configuration management, (3) Missing dependency analysis preventing CVE assessment, and (4) Translation engine input validation. No critical vulnerabilities were identified based on visible code structure, but actual implementation details in ApiClient.cs, configuration handling, and provider implementations require detailed code review. The plugin interacts with external metadata sources and should implement comprehensive input validation, secure credential storage, and output sanitization throughout.
- Medium · Potential API Client Credential Exposure —
Jellyfin.Plugin.MetaTube/ApiClient.cs. The ApiClient.cs file handles API communications but without visibility into its implementation, there's a risk of hardcoded credentials, insufficient TLS validation, or insecure credential storage in transit or at rest. Fix: Ensure all API credentials are stored in secure configuration, use environment variables or secure vaults. Validate that TLS certificate verification is enabled. Implement proper secret management. - Medium · Configuration File Security —
Jellyfin.Plugin.MetaTube/Configuration/. The PluginConfiguration.cs and configPage.html handle plugin settings. Without visibility into implementation, there's potential risk of storing sensitive data (API keys, tokens) in plain text configuration files. Fix: Never store API keys or tokens in plain text configuration files. Use encrypted configuration storage, secure vaults, or environment variables. Sanitize all user inputs in configPage.html to prevent XSS. - Medium · External Data Processing Without Visible Validation —
Jellyfin.Plugin.MetaTube/Providers/. Multiple metadata providers (ActorProvider.cs, MovieProvider.cs, ExternalUrlProvider.cs) consume external data from APIs. Insufficient input validation could lead to injection attacks or processing of malicious data. Fix: Implement comprehensive input validation for all external API responses. Validate data types, lengths, and formats. Implement schema validation for JSON responses. Sanitize all data before using in templates or displaying to users. - Medium · Translation Engine Data Injection Risk —
Jellyfin.Plugin.MetaTube/Translation/TranslationEngine.cs. The TranslationEngine.cs processes user content and external translations. Without proper sanitization, this could be vulnerable to injection attacks, especially if translations are used in dynamic code execution or template rendering. Fix: Validate and sanitize all translation input. Avoid using eval() or dynamic code execution. Use parameterized templates. Ensure translated content is properly escaped when rendered. - Low · Missing Dependency Visibility —
Jellyfin.Plugin.MetaTube/Jellyfin.Plugin.MetaTube.csproj. No dependency file (packages.config, .csproj details, or package-lock.json) was provided for analysis. This prevents assessment of known vulnerable dependencies. Fix: Review the .csproj file and all NuGet dependencies for known CVEs. Use 'dotnet list package --vulnerable' command regularly. Keep all dependencies updated to latest secure versions. - Low · Scheduled Task Security —
Jellyfin.Plugin.MetaTube/ScheduledTasks/. Scheduled tasks (GenerateTrailersTask.cs, OrganizeMetadataTask.cs, UpdatePluginTask.cs) may execute with elevated privileges. Insufficient validation could allow privilege escalation or unintended operations. Fix: Implement proper authorization checks in all scheduled tasks. Log all task executions. Validate all input parameters. Run tasks with minimal necessary privileges. Implement rate limiting for update operations. - Low · External Levenshtein Algorithm Use —
Jellyfin.Plugin.MetaTube/Helpers/Levenshtein.cs. Custom Levenshtein.cs helper could have performance vulnerabilities (ReDoS-like behavior) or logic flaws if used with untrusted input for string matching. Fix: Validate input string lengths before Levenshtein computation. Implement timeout mechanisms for computations. Consider using well-tested libraries instead of custom implementations.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.