# ani-cli web Local web UI for a system-wide `ani-cli` install. Current version: `0.49.5` ## What it does - Search anime in `sub` or `dub`, with poster-style results shown below the selection panel and the first English alternate title when available - Queue downloads with folder, quality, media type, season, and episode controls - Choose which download backends queue jobs may use: `ani-cli`, `anipy-cli`, and `animdl` - Track shows in a watchlist with `Watching`, `Planned`, `Finished`, and `Dropped` categories - Expose a small JSON summary endpoint for Homepage dashboard widgets - Refresh watchlist episode counts manually or on a schedule - Auto-download missing episodes for `Watching` entries after later refreshes, with a per-show `Source name` override for `ani-cli` search - Move fully completed libraries into Jellyfin TV or movie folders with tracked background handoff jobs that also appear in the Queue page - Send optional Discord webhook notifications - Serve a checked-in `favicon.png` as the site favicon ## Pages - `/`: Search and queue downloads, with poster-card search results below the selection box and alternate English titles under the main name when available - `/queue`: Monitor downloads and Jellyfin handoff jobs, inspect logs, retry failed downloads, avoid duplicate re-queues for the same failed download, clear failed jobs, and remove finished jobs - `/watchlist`: Track shows, refresh them, download all available episodes, and manage auto-download settings such as `Source name`, library `Name`, season, and episode offset - `/config`: Save defaults, choose queue download methods and fallback retries, schedule refreshes, configure Jellyfin and Discord, manually reconcile watchlist download flags against the filesystem, monitor Jellyfin handoff progress, and view runtime info and the changelog ## Quick start Requirements: - `ani-cli` installed and available in `PATH` - Optional: `anipy-cli` and/or `animdl` installed and available in `PATH` if you want automatic fallback retries outside Docker - Common runtime tools used by `ani-cli`, especially `curl`, `ffmpeg`, `fzf`, `grep`, `openssl`, `sed`, `aria2c`, `botan`, and `yt-dlp` Run locally: ```sh ./ani-cli-web ``` Open: ```text http://127.0.0.1:8421/ ``` Useful flags and env: - `./ani-cli-web --debug` - `ANI_CLI_WEB_HOST=0.0.0.0` - `ANI_CLI_WEB_PORT=8421` - `ANI_CLI_WEB_JOB_STDOUT=true` - `ANI_CLI_BIN=/path/to/ani-cli` - `ANIPY_CLI_BIN=/path/to/anipy-cli` - `ANIMDL_BIN=/path/to/animdl` ## Docker Build: ```sh docker build -t ani-cli-web . ``` Docker builds the app from the current local checkout. Run: ```sh docker run --rm \ -p 8421:8421 \ -e USER_UID="$(id -u)" \ -e USER_GID="$(id -g)" \ -v "$(pwd)/downloads:/downloads" \ -v "$(pwd)/.ani-cli-web:/app/.ani-cli-web" \ ani-cli-web ``` Compose: ```sh USER_UID="$(id -u)" USER_GID="$(id -g)" docker compose up --build -d ``` Docker notes: - The container serves on `0.0.0.0:8421` - Downloads are written under `/downloads` - App state is stored under `/app/.ani-cli-web` - `USER_UID` and `USER_GID` help keep mounted files owned by your host user - `UPDATE_ON_START=true` runs `ani-cli --update` before startup - `ANI_CLI_WEB_JOB_STDOUT=true` mirrors download job output to container stdout for log collectors; set it to `false` to keep job output only in the Queue page - `botan` is installed inside the container for providers or scripts that need Botan cryptography tooling - `anipy-cli` and `animdl` are installed systemwide inside the container at `/usr/local/bin`, linked from `/usr/bin`, and included in the runtime `PATH`; `animdl` is isolated in a Python 3.11 virtualenv so its pinned dependencies stay executable ## Key behavior ### Watchlist - Adding a show tracks it without downloading immediately - Later manual refreshes or scheduled refreshes can queue missing episodes - `Download all` queues every currently available episode for the chosen mode - Successful downloads sync back into the watchlist - TV entries move to `Finished` when the selected downloaded mode reaches the expected episode count - Movie entries can be treated as complete after download and routed to movie storage ### Auto-download - Runs only for entries in `Watching` - Uses the per-show language, quality, `Source name` search override, season, library name, and optional episode offset settings - Can queue backlog episodes that were already available before the show was first tracked ### Download fallback - Optional and configured from `/config` - Queue jobs can use any checked combination of `ani-cli`, `anipy-cli`, and `animdl` - Checked methods are tried in this order: `ani-cli`, `anipy-cli`, then `animdl` - Selecting one method disables fallback retry; selecting multiple methods makes later methods automatic fallbacks - Fallback retries keep the queued episode numbers when fallback downloader filenames are renumbered from `1` - Docker images install `anipy-cli` and `animdl` automatically; non-Docker installs should provide the selected tools in `PATH` themselves ### Queue retries - Adding a download that exactly matches an existing failed queue job reuses that failed entry and sets it back to `pending` - This avoids stacking multiple failed rows for the same episode when you queue the same job again ### Jellyfin handoff - Optional and configured from `/config` - TV libraries move only after the show is finished and download-complete - Movie libraries move after download completion - Manual `Run now` scans the watchlist in a background job and shows live progress for processed entries, moved files, and the current destination path - Manual watchlist filesystem sync rechecks downloaded episode flags against the files currently present under the download library - Recent Jellyfin handoff jobs survive page reloads and show their latest status after app restarts ## Homepage widget API For Homepage's Custom API widget, use: ```text http://127.0.0.1:8421/api/watchlist/homepage ``` Example response: ```json { "watchlist": 12, "planned": 4, "finished": 31, "dropped": 2, "total": 49 } ``` This endpoint is intentionally small so Homepage can map the returned values directly into its widget fields. ## Runtime info The Config page runtime panel shows: - `ani-cli-web` version loaded from `VERSION` - Installed `ani-cli` version - Installed `anipy-cli` and `animdl` versions and dependency status - A `Changelog` button that opens a scrollable viewer backed by `CHANGELOG.md` ## Remote access By default the app only serves loopback clients. To allow LAN or remote access: ```sh ANI_CLI_WEB_ALLOW_REMOTE=1 ANI_CLI_WEB_AUTH_USERNAME=admin ANI_CLI_WEB_AUTH_PASSWORD=choose-a-long-random-password ``` Optional remote path restriction: ```sh ANI_CLI_WEB_REMOTE_PATH_ROOTS=/downloads:/srv/jellyfin-tv:/srv/jellyfin-movies ``` ## State and storage Project state is stored in: ```text ani-cli-web/.ani-cli-web/ ``` Main contents: - `config.json` - `remote-sessions.json` - `state.sqlite3` - `thumbnails/` Downloaded files are organized like this: ```text ANI_CLI_DOWNLOAD_DIR/tv/Show Name/Season 01/Show Name - S01E01.mp4 ANI_CLI_DOWNLOAD_DIR/movie/Movie Name/Movie Name.mp4 ``` ## Configuration Most users only need these environment variables: - `ANI_CLI_BIN` - `ANIPY_CLI_BIN` - `ANIMDL_BIN` - `ANI_CLI_WEB_HOST` - `ANI_CLI_WEB_PORT` - `ANI_CLI_WEB_ALLOW_REMOTE` - `ANI_CLI_WEB_AUTH_USERNAME` - `ANI_CLI_WEB_AUTH_PASSWORD` - `ANI_CLI_WEB_REMOTE_PATH_ROOTS` - `ANI_CLI_WEB_DEBUG` - `ANI_CLI_WEB_STATE_ROOT` Container-specific variables: - `UPDATE_ON_START` - `USER_UID` - `USER_GID` Everything else can usually be configured from `/config`. ## Testing Run the regression suite with: ```sh python3 -m unittest test_app.py ```