PlexLibrarian

PlexLibrarian

Docker app from UnraidUser-0614219466's Repository

Overview

Library health insights for your Plex server. Find stale content, track viewing patterns, and reclaim disk space. Includes a Sign in with Plex setup wizard — or set PLEX_URL and PLEX_TOKEN to skip OAuth entirely.
Plex Librarian

Plex Librarian

Find unwatched media, manage users, save bandwidth and space.

CI status Docker pulls GitHub Container Registry Unraid Community Apps MIT License

Install · Features · Integrations · Configuration · Get help

Plex Librarian dashboard

Plex Librarian is a tool for managing and maintaining Plex servers. It's intended as a simpler alternative to heavier tools with similar functionality, while offering some unique cleanup tools of its own. The goal is to reclaim terabytes of storage in as few clicks as possible, using sensible defaults.

What it does

Capability What you get
🧹 Stale media discovery Find unwatched or long-unwatched movies, shows, TV seasons, and music; filter and sort by age, size, play count, and more.
💾 Duplicate detection Surface duplicate movie and episode versions and see how much space each copy consumes.
🔎 Episode Gaps Audit TV seasons for missing numbers between the first and last episode already present in Plex, with irregular metadata called out separately.
👥 User insights Review viewing activity, inactive accounts, and signals that may indicate account sharing.
🔗 Sonarr & Radarr coordination Remove a title through the app that manages it, preventing an immediate re-download. Multiple instances are supported.
🌱 Hardlink & torrent cleanup Delete verified qBittorrent files and the library hardlink created by an Arr import in one guided workflow. Plex Librarian can also clean up orphaned download-side hardlinks after the torrent is gone.

Installation

Unraid

Open Plex Librarian in Community Apps, or search for Plex Librarian from the Apps tab. Keep the defaults, select Apply, then open the web UI from the Docker page and choose Sign in with Plex. Plex Librarian discovers your server and starts its first sync.

Normal operation does not require access to your media shares. Plex, Sonarr, or Radarr performs managed deletion using its own mounts and permissions. Only the optional orphan-download cleanup needs the additional read-only library and read/write download mounts described below.

Docker Compose

Create a compose.yml file:

services:
  plex-librarian:
    image: edon231/plex-librarian:latest
    container_name: plex-librarian
    ports:
      - "8288:8080"
    volumes:
      - plex-librarian-data:/data
      # Optional: required only for verified orphan-hardlink cleanup.
      # - /path/to/library:/media:ro
      # - /path/to/downloads:/downloads:rw
    restart: unless-stopped

volumes:
  plex-librarian-data:

Start the container, open http://<docker-host>:8288, and choose Sign in with Plex:

docker compose up -d

Images are published for AMD64 and ARM64 to Docker Hub and GitHub Container Registry. Use edon231/plex-librarian:latest for the newest stable release, or pin a full version such as edon231/plex-librarian:0.1.0 for predictable upgrades. The equivalent GHCR image is ghcr.io/brycepearce/plex-librarian. The edge tag tracks the latest successful build from main and may contain unreleased changes.

Sonarr, Radarr, Seerr, and qBittorrent

Connect Sonarr and Radarr

Plex Librarian can coordinate whole-title deletion with Radarr for movies and Sonarr for TV. Arr removes the title and its files, then Plex Librarian asks Plex to refresh the affected library.

Before anything is queued, the confirmation dialog verifies the mapped Arr title and shows the folder it manages. Radarr's deleteFiles operation owns removal of the complete title folder, including its safeguards for shared or nested movie paths. If a library is not mapped, coordinated deletion is refused; Delete from Plex only must be selected explicitly.

Open Settings → Media connections, add an instance with its URL and API key (found in Sonarr/Radarr under Settings → General → Security), then map each library under Library mappings.

Use a URL reachable from inside the Plex Librarian container, such as http://192.168.1.20:8989 or http://sonarr:8989 on a shared Docker network. Do not use localhost, which points back at Plex Librarian itself.

Remove a stale TV season

Open a TV library's Stale analysis page and switch Shows to Seasons. Season age is conservative: the newest episode addition determines the added date, and the most recent play of any episode determines the last-watched date. This keeps one recently added or watched episode from making the whole season look older than it is.

Whole-season removal accepts one season at a time. The confirmation preview re-reads its exact Plex episode membership. When Sonarr coordination is selected, Plex Librarian keeps the series, unmonitors that season's episodes, and deletes only EpisodeFiles proven to belong entirely to the selected season. A file shared with another season, ambiguous multi-instance ownership, or changed path mapping blocks the operation. Plex only is an explicit fallback and may allow Sonarr to download a monitored season again.

Optional qBittorrent cleanup uses the same fail-closed ownership checks as duplicate-season cleanup. It is offered only when every selected payload path and the complete download job manifest can be attributed to this season.

Optional qBittorrent cleanup

Add qBittorrent under Settings → Media connections to inspect live torrents associated with Sonarr/Radarr import history or verified direct path mappings. The deletion preview shows the bounded payload tree plus the job's tracker host, ratio, upload total, and cumulative seeding time. When explicitly selected, Plex Librarian removes the verified job and asks qBittorrent to delete its downloaded payload before Arr deletes the remaining library hardlink.

Plex Librarian does not locate or independently delete a saved .torrent file. If an association cannot be verified, that item remains Arr-only. In a bulk selection, qBittorrent cleanup applies only to rows with a verified job, and the preview identifies the Plex, Sonarr, Radarr, and qBittorrent actions for every item.

Orphan hardlink cleanup

Retained Radarr import history can point to an old download path after its torrent has disappeared. Plex Librarian shows these paths as unmanaged leftovers by default. To inspect the common hardlink case, edit the Radarr connection, expand Orphan download cleanup, and configure:

  • The library root reported by Radarr and its read-only Plex Librarian mount.
  • The download root reported by Radarr and its read/write Plex Librarian mount.

For example, Radarr paths under /data/media and /data/torrents could map to Plex Librarian mounts /media and /downloads. Radarr roots may also be Windows drive or UNC paths such as D:\Media; the Plex Librarian mount is always the absolute Linux path visible inside its container.

Plex Librarian removes an orphaned source file only when the source and current Radarr-managed destination are regular files on the same filesystem with the same inode. It rechecks that identity immediately before unlinking, rejects symbolic links and paths outside the configured download root, and prunes only empty directories. Radarr-tracked media, subtitle, and metadata sidecars inside the same historical payload are eligible under that exact rule. Untracked sidecars, samples, metadata, and mixed directory contents are retained and explained in the preview.

Inspection stops after a shared 5,000-entry budget per preview or 12 directory levels and reports the unverified remainder; directories are never recursively deleted. Multi-file torrents are removed with their payload only when every manifest file is attributable to the selected Arr title. Mixed or partially attributed packs remain untouched.

The two mounts must refer to the same underlying filesystems Radarr sees. Their container paths can differ because the web UI stores the translation, but the local library and download roots must be separate, non-overlapping paths. Configure Radarr's Import Extra Files setting for sidecars such as sub, idx, and srt so Radarr can track them with the managed movie folder.

Use the qBittorrent Web UI URL as seen from the Plex Librarian container. Enter its username and password, or leave both blank only when qBittorrent's authentication bypass explicitly trusts the Plex Librarian host or subnet. Desktop qBittorrent users must first enable Web User Interface (Remote control). Private tracker passkeys are never returned to the browser; only the tracker hostname is displayed.

Configuration

Most settings live in the web UI. Under Settings → Automatic sync, you can enable daily refreshes, choose the local-time hour and IANA time zone, and decide whether the app catches up after being offline for more than 24 hours. The page previews the next scheduled window, and named zones follow daylight saving changes automatically. If a daylight-saving jump removes the chosen local hour, that day's scheduled run is skipped.

These environment variables are available for Docker and advanced Unraid installations:

Variable Required Description
DB_PATH No SQLite database path. Default: /data/librarian.db
PORT No Container HTTP port. Default: 8080
PLEX_URL No Direct Plex server URL; use with PLEX_TOKEN to skip the setup wizard
PLEX_TOKEN No Plex authentication token; use with PLEX_URL
QBITTORRENT_URL No qBittorrent Web UI URL; overrides connections saved in the web UI
QBITTORRENT_USERNAME No qBittorrent Web UI username; omit only when authentication bypass trusts this container
QBITTORRENT_PASSWORD No qBittorrent Web UI password; omit only when authentication bypass trusts this container
LIBRARY_SYNC_CONCURRENCY No Maximum libraries synced in parallel. Default: 3
FETCH_CONCURRENCY No Maximum concurrent Plex page requests per library. Default: 8
SYNC_STALL_TIMEOUT_MINUTES No Abort a sync after this many minutes without progress. Default: 15
LOG_RETENTION_DAYS No Days to retain sync history and activity; use 0 to retain indefinitely. Default: 180

The concurrency defaults are intentionally conservative because Plex Librarian often shares a host with Plex. Raise them only when the host has capacity to spare.

For a bind mount instead of the Docker-managed volume shown above, map any persistent host directory to /data. This makes the database easy to include in a file-based backup routine.

Sonarr, Radarr, and Seerr are configured in the web UI so multiple instances can be managed independently. qBittorrent can also be configured there; the QBITTORRENT_* variables are power-user overrides and take precedence over database-backed connections.

Manual Plex configuration

Set both PLEX_URL and PLEX_TOKEN to bypass the Plex authorization wizard. Environment variables take precedence over credentials saved through the web UI.

Use a direct local Plex URL when possible, such as http://192.168.1.100:32400. To locate a token in Plex Web, open an item's three-dot menu, select Get Info → View XML, and copy the X-Plex-Token parameter from the resulting URL.

Optional Plex webhooks

Plex Pass users can configure a webhook for faster viewing-activity updates between full syncs. In Plex Web, open Settings → Webhooks → Add Webhook and enter:

http://<plex-librarian-host>:8288/api/webhook/plex

The webhook records playback lifecycle events used for watch-state and user activity insights. It follows the same trusted-network security model as the rest of the application.

Backups and security

All application data lives under /data, including the SQLite database, Plex credentials, Sonarr/Radarr API keys, mappings, and activity history. Back up this directory and treat the backup as sensitive.

Plex Librarian is designed for a trusted self-hosted network. If remote access is required, place it behind a reverse proxy that provides authentication and TLS.

Support and contributing

Found a bug or have an idea? Open an issue. Pull requests are welcome; please run the workspace validation command before submitting a change.

deno task fmt       # apply the repository formatting rules
deno task verify    # formatting, lint, type-checking, tests, and production build

The project uses Deno 2.9.5, matching the Docker image and CI. To catch problems automatically before commits and pushes, install the repository's Git hooks once after cloning:

deno task hooks:install

Development transparency

AI-assisted development tools are used in this project. AI-assisted changes are reviewed, tested, and maintained under the same standards as other contributions. Project maintainers remain responsible for the resulting code, documentation, and releases.

Plex Librarian is open-source software available under the MIT License.

Install PlexLibrarian on Unraid in a few clicks.

Find PlexLibrarian in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.

Open the Apps tab on your Unraid server Search Community Apps for PlexLibrarian Review the template variables and paths Click Install

Related apps

Explore more like this

Explore all

Details

Repository
ghcr.io/brycepearce/plex-librarian:latest
Last Updated2026-08-23
First Seen2026-07-04

Runtime arguments

Web UI
http://[IP]:[PORT:8080]/
Network
bridge
Shell
sh
Privileged
false
Extra Params
--init

Template configuration

Web UI PortPorttcp

Port for the Plex Librarian web UI.

Target
8080
Default
8288
Value
8288
Config PathPathrw

Persistent app data directory for the database and saved settings. The default is ready to use.

Target
/data
Default
/mnt/user/appdata/plex-librarian
Value
/mnt/user/appdata/plex-librarian
Library Inspection PathPathro

Optional. Read-only library mount used to verify Radarr orphan-download hardlinks. After adding it, configure the matching Radarr and local roots under Settings > Media connections.

Target
/media
Download Cleanup PathPathrw

Optional. Download mount beneath which Plex Librarian may unlink files proven to be hardlinks of current Arr-managed media. Never map a broader root than necessary.

Target
/downloads
Plex URLVariable

Optional. URL of your Plex Media Server (e.g. http://192.168.1.100:32400). Set this together with Plex Token to bypass the OAuth setup wizard.

Target
PLEX_URL
Plex TokenVariable

Optional. Your Plex authentication token. Set this together with Plex URL to bypass the OAuth setup wizard.

Target
PLEX_TOKEN
Database PathVariable

Full path inside the container where the SQLite database file lives. Only change this if you have a specific reason to.

Target
DB_PATH
Default
/data/librarian.db
Value
/data/librarian.db
qBittorrent URLVariable

Optional power-user override. qBittorrent Web UI URL reachable from this container. Configure qBittorrent in the web UI instead for multiple instances.

Target
QBITTORRENT_URL
qBittorrent UsernameVariable

qBittorrent Web UI username. Leave blank only when authentication bypass trusts this container.

Target
QBITTORRENT_USERNAME
qBittorrent PasswordVariable

qBittorrent Web UI password. Leave blank only when authentication bypass trusts this container.

Target
QBITTORRENT_PASSWORD
Library Sync ConcurrencyVariable

Max number of libraries synced in parallel. Kept low by default to avoid competing with Plex for resources on the same host — only raise this on dedicated hardware.

Target
LIBRARY_SYNC_CONCURRENCY
Default
3
Value
3
Fetch ConcurrencyVariable

Max concurrent Plex page requests per library. Kept low by default to avoid competing with Plex for resources on the same host — only raise this on dedicated hardware.

Target
FETCH_CONCURRENCY
Default
8
Value
8
Sync Stall Timeout (minutes)Variable

Abort a sync if it reports no progress for this many minutes — e.g. the Plex server going offline mid-sync. Only raise this if you have a very slow or high-latency Plex connection triggering false positives.

Target
SYNC_STALL_TIMEOUT_MINUTES
Default
15
Value
15
Log Retention (days)Variable

Days to keep sync history and activity feed entries before they're automatically deleted. Raise this to retain history longer, or set to 0 to keep them forever.

Target
LOG_RETENTION_DAYS
Default
180
Value
180