Document the new FastAPI server and WebUI
This commit is contained in:
@@ -404,52 +404,68 @@ Requirements & behaviour:
|
||||
|
||||
## Server setup
|
||||
|
||||
The catalog + store API is a single-file, stdlib-only HTTP server
|
||||
(`app/api.py`) — no pip install needed on the server.
|
||||
The server is a **FastAPI** app (`server/`) with an admin **WebUI** and a
|
||||
JSON API. It owns the catalog, metadata, covers, and the game/video store
|
||||
archives, and serves them to the desktop app. Users log in with a username +
|
||||
password; the app holds a **per-user API token** (roles: `admin`, `editor`,
|
||||
`user`).
|
||||
|
||||
Run it directly (dev):
|
||||
|
||||
```bash
|
||||
PSP_DATA_DIR=/data \
|
||||
PSP_DATS_DIR=/data/dats \
|
||||
pip install -r requirements-server.txt
|
||||
PSP_DB_PATH=/data/library.sqlite \
|
||||
PSP_COVERS_DIR=/data/covers \
|
||||
PSP_GAMES_ROOTS=/data/umd_games \
|
||||
PSP_VIDEO_ROOTS=/data/umd_videos \
|
||||
PSP_STORE_DIR=/data/store \
|
||||
PSP_API_TOKEN=<long-random-secret> \
|
||||
python3 -m app.api --host 0.0.0.0 --port 8000
|
||||
PSP_STORE_VIDEOS_DIR=/data/store_videos \
|
||||
PSP_ADMIN_USERNAME=admin \
|
||||
PSP_ADMIN_PASSWORD=<change-me> \
|
||||
uvicorn server.main:app --host 0.0.0.0 --port 8000
|
||||
```
|
||||
|
||||
Endpoints:
|
||||
On first boot it creates the `PSP_ADMIN_USERNAME` account (log in and change
|
||||
the password). The admin WebUI lives at `/`:
|
||||
|
||||
- **Dashboard** — storage, catalog counts, recent downloads.
|
||||
- **Games & Videos** — browse the catalog, edit metadata, upload covers.
|
||||
- **Store** — upload/delete game and video archives.
|
||||
- **Users** — create users, assign roles, reset passwords.
|
||||
|
||||
API endpoints:
|
||||
|
||||
| Endpoint | Description |
|
||||
|---|---|
|
||||
| `GET /api/summary` | release counts per system |
|
||||
| `POST /api/auth/login` | username/password → API token |
|
||||
| `GET /api/auth/me` | current user |
|
||||
| `GET /api/users`, `POST`, `PATCH`, `DELETE` | user management *(admin)* |
|
||||
| `GET /api/releases?system=&q=&limit=&offset=` | search the catalog |
|
||||
| `GET /api/releases/<id>` | one release + its rom hashes |
|
||||
| `GET /api/library?system=&refresh=` | your scanned library |
|
||||
| `GET /api/cover/<id>` | cover image (fetched on demand) |
|
||||
| `GET /api/covers/<name>.zip` | offline cover bundle (public) |
|
||||
| `GET /api/store` | list store archives *(token)* |
|
||||
| `GET /api/store/download/<name>` | stream one archive *(token)* |
|
||||
| `GET /api/releases/<id>` | release detail + metadata + rom hashes |
|
||||
| `PATCH /api/releases/<id>` | edit metadata *(editor+)* |
|
||||
| `GET /api/cover/<id>` | cover image |
|
||||
| `POST /api/cover/<id>` | upload/replace cover *(editor+)* |
|
||||
| `GET /api/store?system=games|videos` | list store archives |
|
||||
| `GET /api/store/download/<system>/<name>` | stream an archive *(user+)* |
|
||||
| `POST /api/store/upload`, `DELETE /api/store/<system>/<name>` | manage archives *(editor+)* |
|
||||
| `GET /api/stats` | dashboard numbers *(admin)* |
|
||||
|
||||
Token protection: set `PSP_API_TOKEN`; the client sends
|
||||
`Authorization: Bearer <token>`. Leave it unset to allow anonymous access
|
||||
(not recommended).
|
||||
Authentication is `Authorization: Bearer <token>` for the API and a session
|
||||
cookie for the WebUI.
|
||||
|
||||
### Docker (Unraid)
|
||||
|
||||
`docker-compose.yml` builds the API image and attaches it to Unraid's `br0`
|
||||
macvlan bridge so it gets its own LAN IP (e.g. `192.168.1.100`, plain HTTP on 8000):
|
||||
`docker-compose.yml` builds the server image and attaches it to Unraid's `br0`
|
||||
macvlan bridge so it gets its own LAN IP:
|
||||
|
||||
```bash
|
||||
# in /path/to/psppt/
|
||||
cp .env.example .env # then edit: LAN IP, share paths, API token
|
||||
cp .env.example .env # then edit: LAN IP, share paths, admin password
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
The compose file reads the LAN IP and Unraid share paths from `.env` and
|
||||
mounts them into `/data/store`, `/data/umd_games` and `/data/umd_videos`
|
||||
(the store is mounted read-only).
|
||||
The compose file reads the LAN IP and Unraid share paths from `.env` and mounts
|
||||
them into `/data/store`, `/data/store_videos`, `/data/umd_games` and
|
||||
`/data/umd_videos` (the store mounts are writable so the WebUI can manage
|
||||
archives).
|
||||
|
||||
### TLS (optional)
|
||||
|
||||
@@ -460,10 +476,13 @@ ports 80/443 on your router to it.
|
||||
|
||||
### Client
|
||||
|
||||
In the GUI: **Settings → Store** → enter the **Server URL** (e.g.
|
||||
`http://<server-ip>:8000` or `https://psp.example.com`) and the same **API
|
||||
token**, then pick **Server** in the Store tab's source selector. Use
|
||||
**Archive.org** or **Local folder** the same way.
|
||||
In the GUI: **Settings → Store** → enter the **Server URL**, **Server
|
||||
username**, and **Server password**, then **Save settings** (the app logs in
|
||||
and stores the per-user token). Pick **Server** in the Store tab's source
|
||||
selector. When a server is configured it is authoritative for covers and
|
||||
metadata — if it's unreachable the app shows an error instead of falling back
|
||||
to public sources. Use **Archive.org**, **Local folder**, or **NoPayStation**
|
||||
the same way as before.
|
||||
|
||||
## PSP Sync
|
||||
|
||||
|
||||
Reference in New Issue
Block a user