Metadata-Version: 2.4
Name: pearlarr
Version: 1.0.6
Summary: Automatically grab the releases SeaDex recommends for the anime in your Sonarr and Radarr libraries
Project-URL: Homepage, https://github.com/trevinbrooks/pearlarr
Project-URL: Repository, https://github.com/trevinbrooks/pearlarr
Project-URL: Changelog, https://github.com/trevinbrooks/pearlarr/blob/main/CHANGELOG.md
Project-URL: Bug Reports, https://github.com/trevinbrooks/pearlarr/issues
Author: bbtufty
Maintainer: trevinbrooks
License-Expression: GPL-3.0-or-later
License-File: LICENSE
Keywords: anime,radarr,seadex,sonarr,torrent
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Communications :: File Sharing
Classifier: Topic :: Multimedia :: Video
Classifier: Typing :: Typed
Requires-Python: >=3.13
Requires-Dist: beautifulsoup4==4.15.0
Requires-Dist: filelock==3.30.3
Requires-Dist: httpx==0.28.1
Requires-Dist: platformdirs==4.10.0
Requires-Dist: pydantic==2.13.4
Requires-Dist: pynyaa==3.0.0
Requires-Dist: pyyaml==6.0.3
Requires-Dist: qbittorrent-api==2026.7.0
Requires-Dist: rich==15.0.0
Requires-Dist: seadex==0.7.2
Requires-Dist: truststore==0.10.4
Requires-Dist: typer==0.27.0
Requires-Dist: urllib3>=2.7.0
Description-Content-Type: text/markdown

# Pearlarr

[![PyPI](https://img.shields.io/pypi/v/pearlarr.svg?label=PyPI&style=flat-square)](https://pypi.org/project/pearlarr/)
[![Python](https://img.shields.io/pypi/pyversions/pearlarr.svg?label=Python&color=yellow&style=flat-square)](https://pypi.org/project/pearlarr/)
[![Actions](https://img.shields.io/github/actions/workflow/status/trevinbrooks/pearlarr/build.yaml?branch=main&style=flat-square)](https://github.com/trevinbrooks/pearlarr/actions)
[![License](https://img.shields.io/badge/license-GPL--3.0--or--later-blue.svg?label=License&style=flat-square)](https://github.com/trevinbrooks/pearlarr/blob/v1.0.6/LICENSE)

Pearlarr automatically grabs the releases [SeaDex](https://releases.moe) recommends for the anime in your [Sonarr](https://sonarr.tv) and [Radarr](https://radarr.video) libraries.

SeaDex is a community index of the best available release for each anime.
On a schedule, Pearlarr maps your library to SeaDex's entries and grabs anything missing or outdated through qBittorrent.
Each download can then flow into Sonarr and arrive as a notification on Discord:

<img src="https://raw.githubusercontent.com/trevinbrooks/pearlarr-assets/v1.0.6/example_post.png" width="520" alt="A Pearlarr grab notification in Discord: the release, its tracker, size, and audio, the episodes covered, the group being replaced, and SeaDex's notes">

## How it works

Each run walks your library title by title:

1. **Map** - Sonarr series and Radarr movies are resolved to AniList IDs (the key SeaDex indexes by) through three public ID-mapping sources.
2. **Check** - the title's SeaDex entry is fetched, unless the cache shows nothing relevant changed since the last run.
3. **Select** - the entry's torrents are cut down to the preferred release: your tag and tracker filters, SeaDex's "best" marks, your audio preference.
4. **Compare** - the picks are matched against what the arr already has (release groups, episodes, file sizes), so only missing or outdated releases go further.
5. **Grab** - the release is added to qBittorrent with your category and tags, a Discord notification goes out, and the result is cached.
6. **Import** (optional, Sonarr) - Pearlarr waits for the downloads to finish and shepherds them into Sonarr, stepping in with a manual import when Sonarr can't place the files itself.

Here is that walk on a three-title library - one title already has SeaDex's pick, two get grabbed, and the wait pass drives both imports home:

![A Pearlarr run: the boot steps connect to Sonarr and qBittorrent, three series are checked - Cowboy Bebop already has SeaDex's pick, while Frieren and Fullmetal Alchemist: Brotherhood are grabbed - and the wait pass shows live download progress until both imports land in Sonarr](https://raw.githubusercontent.com/trevinbrooks/pearlarr-assets/v1.0.6/demo_run.gif)

Runs are incremental and safe to repeat: results live in a SQLite cache, a title is re-checked only when SeaDex or your arr changed something, and an interrupted run never corrupts state.

## Install

> Coming from upstream SeaDexArr? The config format and data locations changed - see [migrating from upstream](https://github.com/trevinbrooks/pearlarr/blob/v1.0.6/docs/deployment.md#migrating-from-upstream-seadexarr) first.

### uv / pipx / pip

Pearlarr needs Python 3.13 or newer. [uv](https://docs.astral.sh/uv/) or pipx give it its own environment (and uv fetches a matching Python if your system's is too old):

```console
$ uv tool install pearlarr    # or: pipx install pearlarr
```

Plain `pip install pearlarr` works too, as does `pip install -e .` from a clone for the cutting edge.

### Docker Compose

Copy [docker-compose.example.yml](https://github.com/trevinbrooks/pearlarr/blob/v1.0.6/docker-compose.example.yml) to `docker-compose.yml` (or fold the `pearlarr` service into an existing stack), create the config directory yourself, and bring it up:

```console
$ mkdir -p ./config
$ docker compose up -d pearlarr
```

On first boot the container writes a starter `config.yml` into `./config` and restarts. Each run fails with a one-line error until the file is filled in.
Fill it in, then:

```console
$ docker compose restart pearlarr
$ docker compose logs -f pearlarr
```

The container schedules its own runs. Set `PEARLARR_CRON` to change the cadence.
One-off commands run through the same service:

```console
$ docker compose run --rm pearlarr run single --sonarr
$ docker compose run --rm pearlarr cache stats
```

Everything operational lives in [docs/deployment.md](https://github.com/trevinbrooks/pearlarr/blob/v1.0.6/docs/deployment.md): permissions and PUID/PGID, timezones, custom CAs, image tags, stopping safely, backups, upgrades.

## First run

The step-by-step version of this section, with expected output, is [docs/getting-started.md](https://github.com/trevinbrooks/pearlarr/blob/v1.0.6/docs/getting-started.md).

```console
$ pearlarr config init
$ pearlarr paths          # shows where config.yml landed
```

Fill in just your Sonarr and/or Radarr connection first, then run one pass:

```console
$ pearlarr run single
```

Without qBittorrent credentials, every run is a **preview**: Pearlarr evaluates your whole library and reports everything it *would* grab, but grabs nothing and records nothing.
That is the recommended way to check a new setup - read the preview's summary, adjust the config, repeat.
When the preview picks what you'd pick, add `qbittorrent.host`, `username`, and `password`, and the same command grabs for real.
(`run single --dry-run` simulates a run with no side effects even after credentials are set.)

Bare `pearlarr` runs the scheduled loop, one cycle every `schedule.interval_hours`. Under Docker the container's cron owns the cadence instead.

## Configuration

`config.yml` is nested YAML in nine groups:

- `sonarr` / `radarr` - connection details and per-arr behavior (unmonitored handling, torrent category).
- `qbittorrent` - WebUI credentials (blank = preview mode), tags, extra client options.
- `seadex` - how a release is chosen: tracker and tag filters, best/dual-audio preference, the private-release policy.
- `imports` - the wait-for-completion and Sonarr manual-import pass.
- `notifications` - the Discord webhook and a generic JSON webhook.
- `schedule` - the bare-metal loop's cadence.
- `mappings` - override or disable the ID-mapping sources.
- `advanced` - request pacing, cache lifetime, arr-activity detection, log level and format.

Every key, with its default, allowed values, and description, is in [docs/configuration.md](https://github.com/trevinbrooks/pearlarr/blob/v1.0.6/docs/configuration.md) - generated from the source, so it is always current.
The starter config carries the same documentation as comments, and a `$schema` line gives editors completion and validation.
The config is validated on load: an unknown or misspelled key fails with an error naming it rather than being silently ignored.

`pearlarr config validate` checks the file and reports what a run would use. `pearlarr config show` prints the effective configuration with secrets redacted - safe to paste into a bug report.

## Scope and limitations

- **Downloads come from public trackers only**, currently Nyaa, AnimeTosho, and RuTracker.
  A winning release on another public tracker is skipped with a warning and re-considered once support lands.
- **Private releases are never grabbed** - SeaDex carries no download link for them, and no private-tracker auth is supported.
  `seadex.private_releases` decides what happens when a title's preferred release is private-only.
- **qBittorrent is the only download client**. Usenet is out of scope.
  More clients and trackers are on the roadmap.
- **The supported interfaces** are the CLI, the config schema, the JSON event stream, and the notification payloads.
  Every Python import path is internal and may change without notice.
- **Support is best-effort by a single maintainer.**
  [SECURITY.md](https://github.com/trevinbrooks/pearlarr/blob/v1.0.6/SECURITY.md) states what is promised - notably that logs and `config show` output never contain secrets, so they are safe to paste.

## Compatibility

| | Supported |
| --- | --- |
| Sonarr | 4.x (the v3 API) |
| Radarr | 5.x (the v3 API) |
| qBittorrent | 4.1 or newer, WebUI enabled |
| Python | 3.13+ (the Docker image ships its own 3.14) |
| OS | Linux, macOS, Windows (CI covers Linux and Windows). Docker images for amd64 and arm64 |

## Documentation

- [docs/getting-started.md](https://github.com/trevinbrooks/pearlarr/blob/v1.0.6/docs/getting-started.md) - the first-sync walkthrough, install to verified grab.
- [docs/configuration.md](https://github.com/trevinbrooks/pearlarr/blob/v1.0.6/docs/configuration.md) - every setting: defaults, allowed values, semantics.
- [docs/cli.md](https://github.com/trevinbrooks/pearlarr/blob/v1.0.6/docs/cli.md) - every command and option, with the exit codes.
- [docs/deployment.md](https://github.com/trevinbrooks/pearlarr/blob/v1.0.6/docs/deployment.md) - Docker in depth, scheduling, backups, upgrades, uninstalling.
- [docs/output.md](https://github.com/trevinbrooks/pearlarr/blob/v1.0.6/docs/output.md) - console, logs, the JSON event stream, and webhook payloads.
- [docs/troubleshooting.md](https://github.com/trevinbrooks/pearlarr/blob/v1.0.6/docs/troubleshooting.md) - symptoms, the messages behind them, and the fixes.
- [docs/architecture.md](https://github.com/trevinbrooks/pearlarr/blob/v1.0.6/docs/architecture.md) - how Pearlarr is put together, and every external host it talks to.
- [CHANGELOG.md](https://github.com/trevinbrooks/pearlarr/blob/v1.0.6/CHANGELOG.md) - user-observable changes, with upgrade notes.
- [CONTRIBUTING.md](https://github.com/trevinbrooks/pearlarr/blob/v1.0.6/CONTRIBUTING.md) - dev setup, the quality gate, task playbooks.
- [SECURITY.md](https://github.com/trevinbrooks/pearlarr/blob/v1.0.6/SECURITY.md) - threat model, the redaction guarantee, reporting.

## Acknowledgements

Pearlarr began as a fork of [SeaDexArr](https://github.com/bbtufty/seadexarr) by [bbtufty](https://github.com/bbtufty).
Release data comes from the [SeaDex](https://releases.moe) project, which Pearlarr is not affiliated with.
ID mappings come from [AniBridge Mappings](https://github.com/anibridge/anibridge-mappings), [Kometa Anime-IDs](https://github.com/Kometa-Team/Anime-IDs), and [Anime-Lists](https://github.com/Anime-Lists/anime-lists).

Pearlarr is licensed under [GPL-3.0-or-later](https://github.com/trevinbrooks/pearlarr/blob/v1.0.6/LICENSE).
