pilot

module
v0.0.0-...-d88c8eb Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 6, 2026 License: MIT

README

Pilot

A self-hosted TV series manager for home servers and the Beacon media stack.

License Go 1.25

Website · Bug Reports


Pilot is a self-hosted TV series manager with a React web UI and a REST API. It tracks a TV library, polls indexers for new episodes, grabs them through your download client, and files the finished downloads into season folders. It runs as a single Go binary, stores state in Postgres, and is configured from the UI or through environment variables.

Pilot stands on its own as a Sonarr alternative. It comes into its own as part of the Beacon Stack — alongside Pulse (centralized indexers + quality profiles), Prism (movies), and Haul (BitTorrent client) — where Pulse-managed indexers, cross-service quality profiles, and stall-aware torrent blocklisting all light up.

Features

Library management

  • Full TMDB integration for search, metadata, posters, and episode tracking
  • Per-series monitoring with configurable monitor types (all, future episodes, missing, none)
  • Season and episode-level monitoring controls
  • Season detail view with per-season episode counts and total size
  • Multi-cour anime split — shows like Jujutsu Kaisen that TMDB serves as a single 59-episode "Season 1" are projected into their broadcast cours (Season 1/2/3) using the Anime-Lists mapping, with cour boundaries inferred from air-date gaps when TMDB and AniDB disagree on season layout
  • Wanted page covering missing episodes and cutoff-unmet upgrades
  • Calendar view of upcoming and recently aired episodes
  • Library stats with breakdowns by quality, genre, network, and storage trends

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 words in the title don't get grabbed
  • Anime-aware search — series flagged as anime via the Anime-Lists mapping get absolute-numbering query forms (Show 48, Show - 48) alongside the S01E48 form, and TVDB-cour-tagged releases (Show S03E01) are accepted when they translate to the requested TMDB-relative episode
  • Interactive search modal with pack-type filters (Season Pack / Episodes / All), quality badges, click-to-sort columns (Size, Quality, Seeds), and an Episode Count tier in the comparator that surfaces season packs above individual episodes within the same quality
  • Dead-torrent detection — the stallwatcher polls your download client for stalled torrents and blocklists them, with a per-episode circuit breaker so a single bad release can't cause a retry storm
  • Manual search across all indexers with per-release scoring breakdown

Automation

  • Automatic RSS sync on a configurable schedule
  • Auto-search scored against your quality profile and custom formats
  • Auto-import of completed downloads with rename support
  • Configurable episode naming (standard, daily, anime)
  • Season folder organization
  • Import lists from TMDB, Trakt, Plex Watchlist, and custom URL lists
  • Activity log pruning

Integrations

  • Indexers: Newznab (NZBgeek, NZBFinder), Torznab (Prowlarr, Jackett), Pulse-managed indexers
  • Download clients: Haul, qBittorrent, Deluge, Transmission, SABnzbd, NZBGet
  • Media servers: Plex, Jellyfin, Emby
  • Notifications: Discord, Slack, Telegram, Pushover, Gotify, ntfy, email, webhook, custom command
  • Migration: one-click import of quality profiles, libraries, indexers, download clients, and monitored series from a running Sonarr instance

UI

  • Command palette (Cmd/Ctrl+K) 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 documentation at /api/docs

Operations

  • Single static Go binary, no runtime dependencies
  • Postgres backend
  • Zero telemetry, no analytics, no crash reporting, no phoning home
  • Auto-generated API key on first run
  • SSRF protection on outbound connections
  • Graceful shutdown with drain timeout

Getting started

Standalone

A single-service compose that runs Pilot with its own dedicated Postgres lives at docker/docker-compose.yml. Edit the /path/to/... lines and the placeholder password, then:

docker compose -f docker/docker-compose.yml up -d

The web UI is at http://localhost:8383. Pilot generates an API key on first run; find it in Settings → App Settings.

As part of the Beacon Stack

For the full setup — Pulse + Pilot + Prism + Haul + VPN — see beacon-stack/deploy. Standalone Pilot works on its own; running with the stack adds shared indexers, cross-service quality profiles, and stall-aware torrent blocklisting through Haul.

Build from source

Requires Go 1.25+ and Node 22+. The default Docker image includes ffmpeg/ffprobe for media scanning; install it separately if you build locally and want that feature.

git clone https://github.com/beacon-stack/pilot
cd pilot
cd web/ui && npm ci && npm run build && cd ../..
make build
./bin/pilot

Pilot listens on port 8383 by default. If something else already owns that port, override with PILOT_SERVER_PORT.

Configuration

Most settings live in the web UI. For the ones you'll want at container-start time, use environment variables or a YAML config file at /config/config.yaml (also searched at ~/.config/pilot/config.yaml and ./config.yaml).

Variable Default Description
PILOT_SERVER_PORT 8383 Web UI and API port
PILOT_DATABASE_DSN Postgres DSN (required)
PILOT_AUTH_API_KEY auto API key; autogenerated on first run if unset
PILOT_PULSE_URL Pulse control-plane URL (optional)
PILOT_LOG_LEVEL info debug, info, warn, error
PILOT_LOG_FORMAT json json or text

Migrating from Sonarr

Pilot imports from a running Sonarr instance in one pass. Open Settings → Import, enter the Sonarr URL and API key, preview what will be brought over, and pick the categories to bring in. Supported:

  • Quality profiles
  • Libraries (root folders)
  • Indexers
  • Download clients
  • Series with monitoring state

Where Pilot fits in the Beacon stack

┌─────────────┐     registers      ┌──────────┐
│    Pulse    │◄───────────────────┤  Pilot   │
│ (control    │────managed─────────►  (TV)    │
│   plane)    │  indexers + profiles│          │
└─────────────┘                    └────┬─────┘
                                        │
                                 grab torrent
                                        ▼
                                   ┌─────────┐
                                   │  Haul   │
                                   │  (BT)   │
                                   └─────────┘

If the full stack is running, Pilot pulls shared indexers and quality profiles from Pulse, sends torrent grabs through Haul, and polls Haul's /api/v1/stalls endpoint to blocklist dead torrents. Standalone is fine — Pulse and Haul are optional.

Power user notes

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. If a legitimate release is being rejected, the matcher is the place to start.

Stallwatcher. 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 so a misconfigured indexer can't trigger a retry storm.

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

Regression suite. make test runs the full suite in about two seconds. The guarded files and the failure modes each test exists to prevent are listed in CLAUDE.md.

API surface. Everything the UI does is available through the REST API — OpenAPI docs at /api/docs.

Privacy

Pilot makes outbound connections only to services you explicitly configure: TMDB for metadata, your indexers, your download clients, your media servers, and your notification targets. No telemetry, no analytics, no crash reporting, no update checks. Credentials are stored locally and never written to logs.

Built with Claude

Pilot was built by one person with extensive help from Claude (Anthropic). Architecture, design decisions, bug triage, and this README are mine. Many of the keystrokes are not. If something in the code or the docs doesn't make sense, open an issue.

Development

make build    # compile to bin/pilot
make run      # build + run
make dev      # hot reload (requires air)
make test     # go test ./...
make check    # golangci-lint + tsc --noEmit
make sqlc     # regenerate sqlc code

Contributing

Bug reports, feature requests, and pull requests are welcome. Please open an issue before starting anything large.

License

MIT — see LICENSE.

Directories

Path Synopsis
cmd
pilot command
internal
api
api/ws
Package ws implements a WebSocket hub that bridges the internal event bus to connected browser clients.
Package ws implements a WebSocket hub that bridges the internal event bus to connected browser clients.
appinfo
Package appinfo centralises the application's display name.
Package appinfo centralises the application's display name.
core/activity
Package activity provides a persistent activity log that records events from the in-memory event bus so they survive restarts and are queryable.
Package activity provides a persistent activity log that records events from the in-memory event bus so they survive restarts and are queryable.
core/blocklist
Package blocklist manages the release blocklist used to skip known-bad releases.
Package blocklist manages the release blocklist used to skip known-bad releases.
core/dbutil
Package dbutil provides shared helpers for database-layer operations.
Package dbutil provides shared helpers for database-layer operations.
core/downloader
Package downloader manages download client configurations and orchestrates adding releases to the appropriate download client.
Package downloader manages download client configurations and orchestrates adding releases to the appropriate download client.
core/importer
Package importer handles completed downloads by linking episode files into the library directory tree, creating episode_files records, and marking episodes as having a file on disk.
Package importer handles completed downloads by linking episode files into the library directory tree, creating episode_files records, and marking episodes as having a file on disk.
core/importlist
Package importlist manages import list configurations and syncs series from external sources (TMDb, Trakt, Plex, etc.) into the library.
Package importlist manages import list configurations and syncs series from external sources (TMDb, Trakt, Plex, etc.) into the library.
core/indexer
Package indexer manages indexer configurations and orchestrates release searches.
Package indexer manages indexer configurations and orchestrates release searches.
core/library
Package library manages Pilot library records and their series counts.
Package library manages Pilot library records and their series counts.
core/mediamanagement
Package mediamanagement provides access to global media management settings (episode naming formats, colon replacement, extra file importing, etc.).
Package mediamanagement provides access to global media management settings (episode naming formats, colon replacement, extra file importing, etc.).
core/mediaserver
Package mediaserver manages media server configurations (Plex, Emby, Jellyfin).
Package mediaserver manages media server configurations (Plex, Emby, Jellyfin).
core/notification
Package notification manages notification channel configurations and dispatches test events to verify connectivity.
Package notification manages notification channel configurations and dispatches test events to verify connectivity.
core/parser
Package parser extracts structured metadata (show name, season, episode numbers, quality, release group, etc.) from release filenames and titles.
Package parser extracts structured metadata (show name, season, episode numbers, quality, release group, etc.) from release filenames and titles.
core/provider
Package provider resolves effective third-party API keys at lookup time.
Package provider resolves effective third-party API keys at lookup time.
core/queue
Package queue tracks active downloads and synchronises their status with the download clients.
Package queue tracks active downloads and synchronises their status with the download clients.
core/renamer
Package renamer applies naming format templates to produce filesystem-safe filenames for imported TV episode files.
Package renamer applies naming format templates to produce filesystem-safe filenames for imported TV episode files.
core/show
Package show manages TV series records in the Pilot library.
Package show manages TV series records in the Pilot library.
core/stallwatcher
Package stallwatcher is the Pilot-side consumer of Haul's stall detection.
Package stallwatcher is the Pilot-side consumer of Haul's stall detection.
core/stats
Package stats provides library statistics and analytics.
Package stats provides library statistics and analytics.
db
dbutil
Package dbutil provides shared helpers for database-layer operations.
Package dbutil provides shared helpers for database-layer operations.
metadata/animelist
Package animelist consumes the Anime-Lists/anime-lists community XML and exposes per-TMDB-id lookups for downstream consumers (the show refresh path and the search query builder).
Package animelist consumes the Anime-Lists/anime-lists community XML and exposes per-TMDB-id lookups for downstream consumers (the show refresh path and the search query builder).
metadata/tmdbtv
Package tmdbtv provides a TMDB API v3 client for TV series data.
Package tmdbtv provides a TMDB API v3 client for TV series data.
parser
Package parser implements a comprehensive, unified release name parser.
Package parser implements a comprehensive, unified release name parser.
pulse
Package pulse integrates Prism with the Pulse control plane.
Package pulse integrates Prism with the Pulse control plane.
ratelimit
Package ratelimit provides per-key token-bucket rate limiters for indexer queries.
Package ratelimit provides per-key token-bucket rate limiters for indexer queries.
registry
Package registry holds plugin factories and instantiates plugin instances from stored JSON configuration.
Package registry holds plugin factories and instantiates plugin instances from stored JSON configuration.
safedialer
Package safedialer provides HTTP transports that protect against SSRF attacks by filtering outbound connections to sensitive network addresses.
Package safedialer provides HTTP transports that protect against SSRF attacks by filtering outbound connections to sensitive network addresses.
scheduler
Package scheduler runs recurring background jobs at fixed intervals.
Package scheduler runs recurring background jobs at fixed intervals.
scheduler/jobs
Package jobs provides the built-in scheduler job definitions.
Package jobs provides the built-in scheduler job definitions.
sonarrimport
Package sonarrimport fetches data from a running Sonarr instance and creates matching records in Pilot's database using the existing service layer.
Package sonarrimport fetches data from a running Sonarr instance and creates matching records in Pilot's database using the existing service layer.
trakt
Package trakt provides a minimal HTTP client for the Trakt API v2.
Package trakt provides a minimal HTTP client for the Trakt API v2.
pkg
plugin
Package plugin defines the public interfaces and value types for Pilot's plugin system.
Package plugin defines the public interfaces and value types for Pilot's plugin system.
plugins
downloaders/deluge
Package deluge implements the plugin.DownloadClient interface for the Deluge Web API (JSON-RPC over HTTP).
Package deluge implements the plugin.DownloadClient interface for the Deluge Web API (JSON-RPC over HTTP).
downloaders/haul
Package haul implements the plugin.DownloadClient interface for Beacon Haul, the native Beacon torrent download client.
Package haul implements the plugin.DownloadClient interface for Beacon Haul, the native Beacon torrent download client.
downloaders/nzbget
Package nzbget implements the plugin.DownloadClient interface for NZBGet's JSON-RPC API.
Package nzbget implements the plugin.DownloadClient interface for NZBGet's JSON-RPC API.
downloaders/qbittorrent
Package qbittorrent implements the plugin.DownloadClient interface for qBittorrent Web API v2.
Package qbittorrent implements the plugin.DownloadClient interface for qBittorrent Web API v2.
downloaders/sabnzbd
Package sabnzbd implements the plugin.DownloadClient interface for SABnzbd's REST API.
Package sabnzbd implements the plugin.DownloadClient interface for SABnzbd's REST API.
downloaders/transmission
Package transmission implements the plugin.DownloadClient interface for the Transmission RPC API.
Package transmission implements the plugin.DownloadClient interface for the Transmission RPC API.
importlists/custom_list
Package custom_list provides a Pilot import list plugin that fetches series from a user-provided JSON URL.
Package custom_list provides a Pilot import list plugin that fetches series from a user-provided JSON URL.
importlists/plex_watchlist_tv
Package plex_watchlist_tv provides a Pilot import list plugin that fetches TV shows from a Plex user's watchlist via the Plex metadata API.
Package plex_watchlist_tv provides a Pilot import list plugin that fetches TV shows from a Plex user's watchlist via the Plex metadata API.
importlists/tmdb_popular_tv
Package tmdb_popular_tv provides a Pilot import list plugin that fetches the current most popular TV series from TMDB.
Package tmdb_popular_tv provides a Pilot import list plugin that fetches the current most popular TV series from TMDB.
importlists/tmdb_trending_tv
Package tmdb_trending_tv provides a Pilot import list plugin that fetches trending TV series from TMDB.
Package tmdb_trending_tv provides a Pilot import list plugin that fetches trending TV series from TMDB.
importlists/trakt_list_tv
Package trakt_list_tv provides a Pilot import list plugin that fetches TV shows from a Trakt user's watchlist or custom list.
Package trakt_list_tv provides a Pilot import list plugin that fetches TV shows from a Trakt user's watchlist or custom list.
importlists/trakt_popular_tv
Package trakt_popular_tv provides a Pilot import list plugin that fetches Trakt's most popular TV shows.
Package trakt_popular_tv provides a Pilot import list plugin that fetches Trakt's most popular TV shows.
importlists/trakt_trending_tv
Package trakt_trending_tv provides a Pilot import list plugin that fetches Trakt's trending TV shows (most watched right now).
Package trakt_trending_tv provides a Pilot import list plugin that fetches Trakt's trending TV shows (most watched right now).
indexers/newznab
Package newznab implements the Newznab indexer plugin for Pilot.
Package newznab implements the Newznab indexer plugin for Pilot.
indexers/torznab
Package torznab implements the Torznab indexer plugin for Pilot.
Package torznab implements the Torznab indexer plugin for Pilot.
mediaservers/emby
Package emby implements a Pilot media server plugin for Emby.
Package emby implements a Pilot media server plugin for Emby.
mediaservers/jellyfin
Package jellyfin implements a Pilot media server plugin for Jellyfin.
Package jellyfin implements a Pilot media server plugin for Jellyfin.
mediaservers/plex
Package plex implements a Pilot media server plugin for Plex.
Package plex implements a Pilot media server plugin for Plex.
notifications/command
Package command implements a Pilot notification plugin that executes a user-provided script from /config/scripts/ on each event.
Package command implements a Pilot notification plugin that executes a user-provided script from /config/scripts/ on each event.
notifications/discord
Package discord implements a Pilot notification plugin that sends events as rich embed messages to a Discord channel via a Discord webhook URL.
Package discord implements a Pilot notification plugin that sends events as rich embed messages to a Discord channel via a Discord webhook URL.
notifications/email
Package email implements a Pilot notification plugin that sends events as plain-text emails via an SMTP server.
Package email implements a Pilot notification plugin that sends events as plain-text emails via an SMTP server.
notifications/gotify
Package gotify implements a Pilot notification plugin that sends events to a Gotify server via its REST API.
Package gotify implements a Pilot notification plugin that sends events to a Gotify server via its REST API.
notifications/ntfy
Package ntfy implements a Pilot notification plugin that sends events to an ntfy server (ntfy.sh or self-hosted).
Package ntfy implements a Pilot notification plugin that sends events to an ntfy server (ntfy.sh or self-hosted).
notifications/pushover
Package pushover implements a Pilot notification plugin that sends events via the Pushover API.
Package pushover implements a Pilot notification plugin that sends events via the Pushover API.
notifications/slack
Package slack implements a Pilot notification plugin that sends events to a Slack channel via an Incoming Webhook URL.
Package slack implements a Pilot notification plugin that sends events to a Slack channel via an Incoming Webhook URL.
notifications/telegram
Package telegram implements a Pilot notification plugin that sends events to a Telegram chat via the Bot API.
Package telegram implements a Pilot notification plugin that sends events to a Telegram chat via the Bot API.
notifications/webhook
Package webhook implements a Pilot notification plugin that sends events as JSON HTTP POST requests to a user-configured URL.
Package webhook implements a Pilot notification plugin that sends events as JSON HTTP POST requests to a user-configured URL.
tools
obfuscate command
Command obfuscate emits go-build ldflag fragments that bake a XOR-obfuscated third-party provider key into the binary.
Command obfuscate emits go-build ldflag fragments that bake a XOR-obfuscated third-party provider key into the binary.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL