Find the gaps in your TV library — and let Sonarr fill them.
Scans your Jellyfin library, your Sonarr instance, or queries TMDB when neither has the data. Shows exactly what's missing per show, per season, per episode, with thumbnails, air dates, storage sizes, paths, and a one-click Search button that hands off to Sonarr.
Status: stable (v1.0.8). Works end-to-end on Jellyfin 10.11.x + Sonarr v3. Install via the plugin repository URL below or as a manual DLL drop.
- Features
- Screenshots
- Installation
- Configuration
- How each scan source works
- Accuracy
- Sending to Sonarr
- What this plugin stores
- Security
- Troubleshooting
- Building from source
- Support the project
- License
- Three scan sources
- Sonarr — trust Sonarr's
monitored+hasFileflags. Authoritative, fast. - Jellyfin / Virtual items — use Jellyfin's own missing-episode items (requires Display missing episodes within seasons in the library).
- Jellyfin / TMDB — query TMDB for each show's canonical episode list. Works without any Jellyfin library reconfiguration. Needs a free TMDB API key.
- Jellyfin / Gap detection — find numbering holes in what's on disk. No external deps, limited but useful.
- Sonarr — trust Sonarr's
- Accuracy layers — presence of an episode is derived from three sources, each filling gaps the others miss:
- Jellyfin library — non-virtual items the library scan imported.
- Filename parser — walks
series.Pathon disk and parsesS01E05/1x05/ multi-ep patterns. Catches files Jellyfin never imported (e.g. shows where the library lists 0 episodes despite 144 GB on disk). Falls back to Sonarr's path when Jellyfin's is stale. - Sonarr
hasFile(if configured) — the authoritative per-episode flag. Catches episodes stored in folders neither Jellyfin nor Sonarr's canonical path covers (scattered-release layouts). Also drops unmonitored-in-Sonarr episodes from the missing list when Only monitored is on.
- One-click Sonarr search — per episode, per season, per show, or everything currently visible.
- Auto-search (optional) — scan + dispatch to Sonarr on a schedule.
- Rescan this show — targeted refresh from the detail view, no full library scan.
- Active / Ignored tabs — hide shows you never care about; click an ignored card to open its detail with a Remove from ignore list button.
- All / TV / Anime filter + title search. Anime detection uses Sonarr's series type or Jellyfin genre/tag.
- Persistent results + rolling 25-scan history — survives restarts, clearable from the UI.
- Live progress — background scan with progress strip (X / Y series, current show, percentage). Leave the page, come back, and it picks up. Toast fires when done.
- Admin sidebar entry — Missing Episodes in the Jellyfin admin sidebar, not buried in Plugins.
- Storage + path — GB chip on each card (computed from on-disk size when Jellyfin can read the folder; from Sonarr otherwise). Series path in the detail view. Smart reconciliation: trust whichever side has files.
- Sorts — Most missing / Title / Recent / Size / Progress (least-complete first).
- Admin-only API — every endpoint requires the
RequiresElevationpolicy.
The whole plugin at a glance. Four stat cards at the top (shows with gaps, total missing, source, time since last scan), a collapsible scan-history block right below, the filter toolbar, and a poster grid sorted by most-missing by default. Each card has a red missing-count badge in the top-right corner and a dark monospace size chip in the bottom-left — fits a lot of signal into a small space without looking busy.
Closer look at the cards. Badges turn orange when the count is ≤2 so you can see at a glance which shows are "nearly done" vs "wildly behind". Anime detection auto-applies a small pill next to the title (sourced from Sonarr's seriesType or a Jellyfin genre/tag). Hover lift is subtle and hover-shadow softens, so scanning with your eyes doesn't feel like a slot machine.
Three independent filters (scope, type, text) plus five sorts: Most missing (default), Title, Recent (most recently aired missing episode first), Size (biggest-on-disk first, good for reclaiming space), and Progress (least-complete first, good for binge planning). The Search all button on the right hands every currently-visible missing episode — respecting all three filters — off to Sonarr in one batched EpisodeSearch, with a confirm dialog so you don't accidentally kick off 4,000 searches.
A rolling log of the last 25 scans — time, source, mode, missing total, show count, duration. Lets you eyeball trends ("did my missing count drop after last week's Sonarr run?") and surface pathological scans (the 440s outlier here is early-days before I put the single-series optimisation in).
Clicking a poster swaps the whole page for a dedicated detail view — no modal, no popup. Header carries the show's poster, missing count pill, network, status, Have / Total, completion percentage, on-disk size, and series path (not shown in this crop). Three action buttons: Search all missing (batched Sonarr search for just this show), Rescan this show (refreshes only this show, runs in ~1s under the same progress strip the full scan uses), and Ignore this show (hides it from scans, accessible later from the Ignored tab).
Seasons live below the header as an accordion. Each row shows Have / Total, the absolute missing count, and a mini progress bar. Seasons with zero gaps don't appear at all. Per-season Search season button lets you batch-request just one season without touching the others.
Pop any season open and you get proper episode rows — 16:9 thumbnail (from Sonarr's screenshot images or TMDB still_path), season/episode code, title, overview, air date, and a per-episode Search button. Queued episodes turn green with a ✓ so you know the click landed. Scroll is contained in the episode list, header stays visible.
The two segmented controls on the left are the core: Scan source (Sonarr or Jellyfin) and — only when Jellyfin is selected — Jellyfin method (Virtual items / TMDB / Gap detection). Both auto-save on click, no Save button needed. The method explainer changes text based on your picks and adds a note when Sonarr is configured, so there's no silent magic.
The rest of the settings row. Auto-send missing episodes to Sonarr turns on the background worker (scans on Auto-search every (hours) interval and dispatches every missing episode automatically). Only monitored, Ignore specials, and Ignore unaired are the three noise-reduction toggles — each does what it says. Test Sonarr and Test TMDB hit each service's health endpoint and surface the real error if it fails, so you find out you typed the URL wrong before your first scan, not after.
- Go to Dashboard → Plugins → Repositories → ➕
- Name:
Missing Episodes - URL:
https://raw.githubusercontent.com/ZL154/MissingEpisodesJellyfin/main/manifest.json
- Save → Catalog → install Missing Episodes
- Restart Jellyfin
- Dashboard → Missing Episodes → Settings to configure
- Download the latest zip from Releases.
- Extract the DLL into your Jellyfin plugin directory:
- Docker:
/config/plugins/MissingEpisodes_x.y.z.w/ - Linux:
/var/lib/jellyfin/plugins/MissingEpisodes_x.y.z.w/ - Windows:
%ProgramData%\Jellyfin\Server\plugins\MissingEpisodes_x.y.z.w\
- Docker:
- Restart Jellyfin.
- Dashboard → Missing Episodes (or the sidebar entry) → Settings.
- Sonarr URL (e.g.
http://sonarr.local:8989) and API key (Sonarr → Settings → General). Click Test Sonarr. - (Optional) TMDB API key — get one free at https://www.themoviedb.org/settings/api. Click Test TMDB. Only needed for the TMDB Jellyfin mode.
- Scan source:
- Sonarr — use Sonarr's data (best if Sonarr tracks every show).
- Jellyfin — use Jellyfin's library. Pick a method: Virtual items / TMDB / Gap detection.
- Toggles: Only monitored, Ignore specials, Ignore unaired.
- (Optional) Auto-send missing episodes to Sonarr + interval.
- Save, then Scan now.
GET /api/v3/seriesfor the series list.GET /api/v3/episode?seriesId=N&includeImages=trueper series.- Flags episodes where
hasFile == false, honoring your toggles. - Thumbnails come from Sonarr's episode
screenshotimages.
- Queries Jellyfin for
Episodeitems, expands the virtual ones (IsVirtualItem = true). - Requires Display missing episodes within seasons in your Jellyfin library settings + a library scan to create virtual items.
- Best fidelity — full Jellyfin metadata + artwork.
- For each series with a TMDB id, fetches
GET /3/tv/{id}+GET /3/tv/{id}/season/{n}. - Diffs the canonical TMDB list against what's actually on disk in Jellyfin.
- Catches whole missing seasons and trailing episodes that gap detection can't.
- Walks on-disk episode numbers per season, flags any
{1..max}not present. - No external dependencies. Limited (can't see missing final episodes or whole missing seasons).
If Sonarr is configured AND you're running a Jellyfin-source scan, the plugin matches shows by TVDB or TMDB id and stamps them with Sonarr episode IDs. That's what makes Search buttons work in any mode.
Every Jellyfin-mode scan combines up to three sources of "present" data, fighting library drift and scattered file layouts:
- Jellyfin's library — non-virtual episode items it's already indexed.
- Filename parser — walks
series.Pathand extracts coordinates fromS01E05,S01E05-E06,1x05, etc. filenames. If Jellyfin's path is stale/empty, the parser retries against Sonarr's path (when Sonarr is configured) — Sonarr tracks the live location. Whichever yields more content wins. - Sonarr
hasFileenrichment (when Sonarr is configured) — for every entry still in the missing list, the plugin checks Sonarr's per-episodehasFileflag. Episodes Sonarr marks as downloaded are dropped from missing regardless of which folder they live in. Catches scattered-release layouts (per-season release folders etc.) that neither path walk covers. When Only monitored is on, episodes Sonarr has unmonitored are also dropped (you've told Sonarr not to track them, so they shouldn't inflate your missing count).
If you leave both Sonarr and TMDB blank, accuracy is capped by what Jellyfin's library + the series folder tell us:
- Virtual items — needs Display missing episodes within seasons enabled in the library and a metadata scan.
- Gap detection — no library settings required, but can't detect missing seasons or episodes past the highest you have.
Either of those works standalone, but for libraries with files scattered across multiple folders you want Sonarr.
- Absolute-numbered anime filenames (e.g.
Gintama - 042) don't match theS##E##regex. Re-rename or use Sonarr source. - A filename has to contain S/E markers.
Pilot.mkvwon't be detected.
- Per-episode — inline Search button on each missing episode row.
- Per-season — header button on each season in the detail view.
- Search all missing (one show) — bottom of the detail view.
- Search all (across current filter) — toolbar button on the grid. Respects type, ignored, and text filters.
- Auto-search — background worker runs at the configured interval, full scan, dispatches everything.
Every path hits POST /api/v3/command with a batched EpisodeSearch.
All under the plugin's data folder (/config/plugins/Jellyfin.Plugin.MissingEpisodes/):
| File | Purpose |
|---|---|
last-result.json |
Full result of the most recent scan. Lazily loaded on first request after restart. |
history.json |
Rolling log of the last 25 scans (timestamps, totals, duration). |
Plugin configuration (URLs, API keys, toggles) lives in Jellyfin's own plugin config XML, not here.
To wipe: stop Jellyfin, delete the files, restart. Next scan regenerates them. History can also be cleared from the UI.
- Admin-only. Every API endpoint carries
[Authorize(Policy = "RequiresElevation")]. No anonymous endpoints. - No secret logging. Sonarr and TMDB API keys are passed to outbound HTTP calls only — never written to Jellyfin logs. Grepped every
_logger.Log*call to confirm. - No secrets in plugin data files.
last-result.jsonandhistory.jsonhold scan results only. API keys stay in Jellyfin's plugin config (as with any other plugin). - XSS-hardened. Image URLs from Sonarr / TMDB / Jellyfin are applied via
element.style.backgroundImage = 'url(' + JSON.stringify(url) + ')'rather than interpolated into inline HTML — a hostile upstream response can't break out of theurl()literal. - User-controlled strings escaped. All series/episode titles, network names, and paths rendered into the UI go through an
escapeHtmlhelper beforeinnerHTMLassignment. - No path traversal. File walks only touch
series.Pathfrom Jellyfin's library manager plus (optionally) Sonarr's path for the same series. No user-supplied paths accepted by any endpoint. - Safe logging. Series titles and paths appear in log messages only at
Debuglevel using structured parameters — ASP.NET Core's formatter prevents log injection. - No unbounded scans.
Progress.InProgressgates concurrent scans; refresh endpoint returns HTTP 409 while a scan runs.
"No scan yet" after a scan completed. Hard-refresh. Results persist to disk and a completion toast fires in the Jellyfin client, so a reload shouldn't lose them.
Search buttons greyed out. Either Sonarr isn't configured, or the selected shows have no Sonarr id yet. In Jellyfin-source mode the plugin enriches with Sonarr IDs only when a URL + API key is set.
Jellyfin / Virtual items returns 0 missing. Display missing episodes within seasons isn't enabled, or the library scan hasn't created virtual items yet. Enable it in Dashboard → Libraries → (library), run Scan Media Library, rescan. Or switch to TMDB mode.
Show reads as 0 episodes even though files exist. Fixed in 1.0.3 — the plugin now walks the folder and parses S##E## from filenames as a safety net. If you're on 1.0.3+ and still seeing this, check that the filenames actually contain S/E markers (not just an episode number).
"An error occurred while getting the plugin details from the repository." Harmless. Appears when the plugin was installed manually. To silence: add the manifest URL under Plugins → Repositories, then uninstall and reinstall from the catalog.
Rescan finished but the missing count didn't change. Rescan re-reads Sonarr/TMDB data — it doesn't wait for Sonarr to download anything. Give Sonarr a minute to grab a release, then rescan again.
Settings don't seem to save. Scan source / Jellyfin method segments auto-save on click. URL, API key, interval, checkboxes need the Save button. Reload to verify.
.NET 9 SDK required.
git clone https://github.com/ZL154/MissingEpisodesJellyfin.git
cd MissingEpisodesJellyfin/Jellyfin.Plugin.MissingEpisodes
dotnet build -c ReleaseDLL lands in bin/Release/net9.0/Jellyfin.Plugin.MissingEpisodes.dll.
Missing Episodes for Jellyfin is built and maintained in my spare time. If it's helping you keep your library tidy and you'd like to support ongoing development, any of these means a lot:
- ⭐ Star this repo — it's free and helps others find it
- 💖 Sponsor on GitHub — one-off or monthly, every dollar reaches the project
- ☕ Buy me a coffee on Ko-fi — one-off tips
Not expected, just appreciated. Issue reports and clear bug reports are equally valuable.
MIT — see LICENSE.
Not affiliated with Jellyfin, Sonarr, TMDB, or anyone else. Third-party plugin.








