Files
ani-web/README.md
T
jozamudi c697500c7d multi-user auth (CLI-created accounts), per-user history, test suite
- server/users.py replaces credentials.py: users.json (0600), PBKDF2,
  one-time migration of the legacy single password to user admin
  (history.json -> history/admin.json)
- accounts are CLI-managed only: python -m server.users add|rm|list
  (no self-signup on an internet-exposed app); /signup route removed,
  login page back to username + password
- per-user 30-day signed session cookie (payload carries the
  username), per-user lockout, GET /api/me, POST /account/delete
- per-user watch history: server/data/history/<user>.json; ANIWEB_DATA
  env override for the data dir
- header chip: logged-in user, logout, delete account
- tests/: throwaway-server suite (port 8399, temp data dir) — 9 HTTP
  tests + 2 Playwright browser tests (login UI, real video playback
  behind auth); runs via python tests/run.py
2026-08-19 16:17:56 +00:00

70 lines
2.8 KiB
Markdown

# ani-web
Web front-end for the [ani-cli](https://github.com/pystardust/ani-cli)
workflow: search, browse, and stream anime in the browser via anidb.app.
## Quick start
```sh
uv venv .venv
uv pip install --python .venv/bin/python -r requirements.txt
.venv/bin/python -m server.users add <you> # create your account (one-time)
./run.sh
```
Open <http://localhost:8321>. `run.sh` restarts cleanly if the server
is already running; logs go to `server.log`. The server refuses to
start without at least one user (a legacy `credentials.json`
password, if any, is migrated to user `admin`).
Account management (no self-signup by design):
```sh
.venv/bin/python -m server.users add <name> # add user (prompted password)
.venv/bin/python -m server.users rm <name> # remove user + their history
.venv/bin/python -m server.users list # list users
```
## Features
- Per-user accounts (CLI-created, no self-signup): 30-day signed
session cookie, 5 wrong attempts → 15-min lockout per user.
PBKDF2-SHA256 hashes in `server/data/users.json` (0600).
- Per-user watch history (`server/data/history/<user>.json`);
in-header chip with logout + delete-account.
- Search with poster grid, detail view with synopsis + season tabs
- HLS playback (vendored hls.js), browser ABR across 1080/720/360p
- Dub/sub toggle
- Autoplays the first episode (or resumes the last watched one); if the
browser blocks autoplay, a "click to play" overlay appears
- Server-persisted watch history (`server/data/history.json`): watch
position saved every ~10s, resume where you left off, top-5 "recently
played" on the home page — shared across browsers and devices
## Layout
```
server/ FastAPI app (app.py) + anidb.app fetchers (upstream.py)
upstream.py is the ONLY Cloudflare-facing code
static/ front-end: index.html, app.js, style.css, hls.min.js (vendored)
run.sh launch/restart the server
SPEC.md design + the verified anidb.app data flow
```
## Dev notes
- anidb.app is behind Cloudflare; all upstream requests use
`curl_cffi` Chrome TLS impersonation. If that ever stops working,
everything is isolated in `server/upstream.py`.
- The video CDN sends no CORS headers, so playback goes through the
backend HLS proxy (`/stream/{token}`), which rewrites playlist URIs.
- `python server/upstream.py` runs a self-check of the fetchers
(search → details → episodes → dub stream for Chainsaw Man).
- `python tests/run.py` runs the full test suite against a throwaway
server (:8399, temp data dir — never touches the real data). Browser
tests need playwright (`pip install playwright && playwright install
chromium`); they're skipped if absent.
- Episode titles are not available: anidb's episode API only returns
`{id, number, number2, filler}`. Adding titles needs a free
MyAnimeList API key.