TV series manager

Pilot

A self-hosted TV series manager with a React web UI and a REST API. Tracks your TV library via TMDB, polls indexers for new episodes, grabs through your download client, and files completed downloads into season folders.

Port :8383 Go 1.25 Postgres MIT

What Pilot does

Library management

Full TMDB integration for search, metadata, posters, and episode tracking. Per-series monitoring with configurable monitor types. Season and episode-level monitoring controls, wanted page, and a calendar view of upcoming episodes.

Release handling

Quality profiles with resolution, source, codec, and HDR dimensions. Custom formats with regex matching and weighted scoring. Title-matched release filter — releases for other shows with overlapping title words don't get grabbed.

Dead-torrent detection

The stallwatcher polls your download client for stalled torrents and blocklists them. A per-episode circuit breaker caps auto-blocklist events at three strikes per 24 hours so a misconfigured indexer can't trigger a retry storm.

Automation

Automatic RSS sync on a configurable schedule. Auto-import of completed downloads with rename support. Import lists from TMDB, Trakt, Plex Watchlist, and custom URL lists. Season folder organization with configurable naming.

Integrations

Indexers: Newznab, Torznab, Pulse-managed. Download clients: Haul, qBittorrent, Deluge, Transmission, SABnzbd, NZBGet. Media servers: Plex, Jellyfin, Emby. Notifications: Discord, Slack, Telegram, Pushover, Gotify, ntfy, email, webhook.

Command palette

Cmd/Ctrl+K command palette with fuzzy search for pages, series, and actions. Dark and light themes with 10+ presets shared across the Beacon services. Live queue updates over WebSocket. OpenAPI docs at /api/docs.

Screenshots

React 19 + TypeScript UI embedded in the Go binary.

Library — series grid with poster art
Season detail — episode list with monitoring controls
Manual search — quality badges, episode count tier

Advanced features

Title matching

The release filter runs every parsed title through a matcher in internal/core/parser/parser.go that rejects titles whose parsed show name doesn't match the requested series after normalization. Year suffixes, bracketed edition tags, and common release-group stylings all pass through cleanly.

Stallwatcher circuit breaker

internal/core/stallwatcher/service.go polls the download client's stall endpoint on a configurable interval, classifies stalled torrents by reason, and blocklists them. The per-episode circuit breaker caps auto-blocklist events at three strikes per 24 hours.

Interactive search ranking

Season-level interactive search orders releases by Quality → Custom Format Score → Protocol → Episode Count. The Episode Count tier lifts season packs above individual episodes within the same quality tier. Pack-type filter pills (Season Pack / Episodes / All) default to Season Pack for season-scoped searches.

Sonarr migration

Pilot imports from a running Sonarr instance in one pass. Open Settings → Import, enter the Sonarr URL and API key, preview, and select categories. Supported: quality profiles, libraries, indexers, download clients, and monitored series.

Getting started with Pilot

Standalone Docker or full stack via beacon-stack/stack.

docker
docker run -d \
  --name pilot \
  -p 8383:8383 \
  -v /path/to/config:/config \
  -v /path/to/tv:/tv \
  ghcr.io/beacon-stack/pilot:latest

Open http://localhost:8383 — Pilot generates an API key on first run. Find it in Settings → App Settings.

Environment variables

VariableDefaultDescription
PILOT_SERVER_PORT8383Web UI and API port
PILOT_DATABASE_DSNPostgres DSN (required)
PILOT_AUTH_API_KEYautoAPI key; autogenerated on first run if unset
PILOT_PULSE_URLPulse control-plane URL (optional)
PILOT_LOG_LEVELinfodebug, info, warn, error
PILOT_LOG_FORMATjsonjson or text