A TypeScript web app for LG webOS TVs (webOS 5 / Chromium 68 and newer), driven by the remote: Movies and Series search with the Trakt lists, Library with status, title and file-property filters and download marks, seasons and episodes, release search and grab, Downloads, Calendar, Settings and Log. It talks to Radarr, Sonarr, SABnzbd and Trakt directly (they answer cross-origin requests); the arr-tui config is baked in at build time and can be changed on the TV. dev/screenshots/server.py answers cross-origin requests and accepts writes for it; webos/dev/drive.mjs drives the app in Chromium for screenshots. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
157 lines
10 KiB
Markdown
157 lines
10 KiB
Markdown
# arr-tui
|
||
|
||
A terminal UI to search for movies and series with [Radarr](https://radarr.video) and
|
||
[Sonarr](https://sonarr.tv), pick releases by hand, and follow the downloads in
|
||
[SABnzbd](https://sabnzbd.org).
|
||
|
||

|
||
|
||
- **Movies / Series**: search as you type, add titles with a quality profile and root folder,
|
||
optionally start the automatic search.
|
||
- **Trending, most watched, anticipated**: while the search box is empty, Movies and Series show
|
||
lists from [Trakt](https://trakt.tv): trending now, most watched this week, anticipated, popular,
|
||
and the US box office for movies. `[` and `]` switch lists; titles already in your library are
|
||
ticked, the others can be added right there (Enter). Needs a free Trakt client ID (see Configure).
|
||
- **Library**: movies and series with their status; the dot before a title turns blue while it
|
||
is downloading, and the details say how far. In a series' seasons and episodes too.
|
||
- **Cache**: posters (30 days, at most 200 MB), casts (7 days) and the Radarr/Sonarr lookups of
|
||
Trakt list titles (3 days) are kept between runs in
|
||
`~/.cache/arr-tui` (`$XDG_CACHE_HOME`; `~/Library/Caches/arr-tui` on macOS), so they show at
|
||
once after a restart. Deleting the folder is always safe.
|
||
- **Season posters**: in a series' seasons and episodes, the poster follows the selected season.
|
||
- **Cast**: with a Trakt client ID, the details pane also lists the director (or the creators of a
|
||
series) and the cast with their roles, below the plot, in every view.
|
||
- **Interactive search**: list the releases Radarr/Sonarr find (approved or rejected, with reasons),
|
||
sort and filter them (by approval, quality, x265 / x264 / AV1, HDR, Dolby Vision, audio format, language), and grab one. Series: pick a season or a single episode first.
|
||
- **Posters**: the detail panes show the poster at the top right; title, facts, path and plot
|
||
flow along its left side and continue at full width below it. In kitty and Ghostty it is a real
|
||
image at the terminal's full resolution (Kitty graphics protocol with Unicode placeholders, so
|
||
popups and dialogs cover it like text). Everywhere else it is drawn with colored block characters,
|
||
which works over SSH and in any terminal with colors. Library items use the copy stored in
|
||
Radarr/Sonarr; search results are downloaded from the metadata provider's image host (TMDb,
|
||
TheTVDB). Turn it off with `"ui": {"covers": false}`. `"ui": {"cover_style": ...}` picks the
|
||
drawing: `auto` (default: real images where the terminal is known to support them, otherwise
|
||
plain cells in macOS Terminal, sextants on terminals known to have the glyphs or when fontconfig
|
||
finds an installed font with them (not over SSH), else quadrants), `kitty` (force real images),
|
||
`sextant` (2x3 pixels per cell, needs a font with the Symbols for Legacy Computing block) or
|
||
`quadrant` (2x2, every font has them) or `cells` (one colored cell per pixel, no glyphs; for
|
||
terminals whose block characters come out uneven, like macOS Terminal). Inside tmux or screen the
|
||
block styles are used. If a poster looks wrong, set `quadrant`, or `cells` if the rows look shifted.
|
||
- **Calendar**: the next two weeks of movie releases (cinemas, digital, physical) and airing episodes
|
||
in one list grouped by day, with poster and plot. Move by weeks, include unmonitored items, search
|
||
for releases or start an automatic search from there.
|
||
- **Downloads**: SABnzbd queue and history plus the Radarr/Sonarr queues. Pause/resume, delete,
|
||
retry failed downloads, remove from the arr queue and blocklist.
|
||
- **Config (F6)**: edit everything in the config file from inside the program, in one list you move
|
||
through with the arrow keys: service addresses and API keys, the add-form defaults (quality profile and root folder, picked from the lists the server has), refresh interval, posters, theme, notifications. *Test*
|
||
checks the values you typed before saving; *Save* writes the file (permissions kept, `0600` for a
|
||
new file) and applies the changes at once, no restart. Values that come from `ARR_TUI_*`
|
||
environment variables are greyed out and are never written to the file.
|
||
- **Log (F7)**: actions report through popups that fade away; the log keeps the history.
|
||
- **Download notifications**: a popup (and a log entry) when a SABnzbd download finishes or fails,
|
||
whichever view is open. SABnzbd's history is checked every 15 seconds; downloads that finished
|
||
before arr-tui started are not announced. `"ui": {"notify_downloads": false}` turns it off,
|
||
`"bell": true` also rings the terminal bell.
|
||
- **Themes**: fixed dark and light color sets that look the same in every terminal, whatever its
|
||
color theme. `"ui": {"theme": ...}` is `auto` (default: light when the terminal reports a light
|
||
background, else dark), `dark` or `light`; it can also be switched in the Config view, which
|
||
recolors everything at once.
|
||
- Connection indicators for all three services in the top right; `F9` shows every key.
|
||
|
||
Requires Radarr/Sonarr v3+ API (Radarr 5/6, Sonarr 4) and SABnzbd 4+. Only Usenet releases are
|
||
shown for grabbing, torrents are hidden.
|
||
|
||
## Screenshots
|
||
|
||
The screenshots show a made-up library (invented titles, generated posters), taken in Ghostty,
|
||
where posters are real images.
|
||
|
||
| | |
|
||
|---|---|
|
||
|  |  |
|
||
| **Movies / Series**: search as you type | **Releases**: pick one by hand |
|
||
|  |  |
|
||
| **Seasons and episodes** of a series | **Downloads** from SABnzbd, Radarr and Sonarr |
|
||
|  |  |
|
||
| **Calendar** of the next two weeks | **Config** inside the program |
|
||
|  |  |
|
||
| **Trending, most watched, anticipated** from Trakt | **Light theme** |
|
||
|
||
## Install
|
||
|
||
```sh
|
||
go install git.stinnesbeck.com/nils/arr-tui/cmd/arr-tui@latest
|
||
```
|
||
|
||
or build from a checkout (`make build`), or `make dist` for cross-compiled binaries in `dist/`.
|
||
|
||
## Configure
|
||
|
||
Just start `arr-tui`: on the first start it creates `$XDG_CONFIG_HOME/arr-tui/config.json`
|
||
(usually `~/.config/arr-tui/config.json`, or the file given with `--config path`) and opens the
|
||
Config view (F6), where you enter the address and API key of each service and save. API keys are in
|
||
each app under Settings → General. A service left empty is not used (e.g. no SABnzbd), its indicator
|
||
stays grey. You can also write the file yourself, starting from `config.example.json`:
|
||
|
||
```json
|
||
{
|
||
"radarr": { "url": "http://localhost:7878", "apikey": "...", "default_quality_profile": "HD-1080p", "default_root_folder": "/movies" },
|
||
"sonarr": { "url": "http://localhost:8989", "apikey": "...", "default_quality_profile": "HD-1080p", "default_root_folder": "/tv" },
|
||
"sabnzbd": { "url": "http://localhost:8080", "apikey": "..." },
|
||
"ui": { "refresh_seconds": 3, "covers": true, "cover_style": "auto", "theme": "auto", "notify_downloads": true, "bell": false }
|
||
}
|
||
```
|
||
|
||
`default_*` are optional preselections in the add dialog. URL and key can also come from the
|
||
environment: `ARR_TUI_{RADARR,SONARR,SABNZBD}_{URL,APIKEY}`, which takes precedence over the file.
|
||
|
||
The trending, most watched and anticipated lists need a Trakt client ID (free, no Trakt account
|
||
of yours is touched): sign in at [trakt.tv](https://trakt.tv), create an app under
|
||
[Settings → Your API Apps → New Application](https://trakt.tv/oauth/applications/new) (any name;
|
||
redirect URI `urn:ietf:wg:oauth:2.0:oob`), and enter its **Client ID** in the Config view under
|
||
Trakt, or as `"trakt": {"client_id": "..."}` in the file, or in `ARR_TUI_TRAKT_CLIENT_ID`.
|
||
Keep the file private (`chmod 600`); it holds your API keys.
|
||
|
||
## Keys
|
||
|
||
| Key | Action |
|
||
|---|---|
|
||
| `F1`–`F7` | switch view (Movies, Series, Library, Downloads, Calendar, Config, Log) |
|
||
| `Tab`, `Shift+Tab` | switch panel within a view |
|
||
| `F9` | help |
|
||
| `/` | focus search box |
|
||
| `[`, `]`, `r` (Movies / Series, empty search) | previous / next Trakt list, reload it |
|
||
| `Enter` | add selected title |
|
||
| `i` | interactive release search |
|
||
| `Tab`, `f`, `F`, `/`, `t`, `s`, `d`, `i`/`Enter`, `r` (library) | movies/series list, status filter, file-property filter, text filter, monitor, search, remove, releases/episodes, reload |
|
||
| `[`, `]`, `t`, `u`, `Enter`, `s` (calendar) | week back / forward, today, unmonitored, releases, search |
|
||
| `Enter`, `i`, `s`, `t` (episodes) | expand season / releases, release search, search, monitor |
|
||
| `Enter`/`g`, `s`, `f`, `F` (release list) | grab, cycle sort, hide rejected, filter by properties |
|
||
| `p`, `d`, `t`, `b`, `r` (downloads) | pause, delete, retry, blocklist, refresh |
|
||
| `Esc` | back / close dialog |
|
||
| `Ctrl+C` | quit |
|
||
|
||
## On the TV (LG webOS)
|
||
|
||
[webos/](webos/README.md) has the same views as a TV app for LG webOS (2020 models and newer),
|
||
driven by the remote: search and Trakt lists, Library with filters, seasons and episodes, release
|
||
search and grab, Downloads, Calendar. It is built with your config baked in and installed in the
|
||
TV's Developer Mode; see [webos/README.md](webos/README.md).
|
||
|
||
## Development
|
||
|
||
`dev/` has a compose file with pinned Radarr, Sonarr and SABnzbd containers plus a fake indexer;
|
||
see [dev/README.md](dev/README.md).
|
||
`make test` runs vet and the unit tests. The screenshots are made with
|
||
`dev/screenshots/take.sh` (see [its README](dev/screenshots/README.md)). The design and
|
||
milestone history are in [SPECS.md](SPECS.md).
|
||
|
||
Releases: tag and push, then `scripts/release.sh` (or `make release`) builds the binaries and publishes
|
||
them on Gitea with the matching `CHANGELOG.md` section. It needs an access token with write access
|
||
to the repository in `$GITEA_TOKEN` or `~/.config/arr-tui-release-token`; `--check` verifies
|
||
everything without publishing, `--dry-run` builds without publishing.
|
||
|
||
## License
|
||
|
||
MIT, see [LICENSE](LICENSE).
|