Document the new FastAPI server and WebUI
This commit is contained in:
@@ -404,52 +404,68 @@ Requirements & behaviour:
|
|||||||
|
|
||||||
## Server setup
|
## Server setup
|
||||||
|
|
||||||
The catalog + store API is a single-file, stdlib-only HTTP server
|
The server is a **FastAPI** app (`server/`) with an admin **WebUI** and a
|
||||||
(`app/api.py`) — no pip install needed on the server.
|
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
|
```bash
|
||||||
PSP_DATA_DIR=/data \
|
pip install -r requirements-server.txt
|
||||||
PSP_DATS_DIR=/data/dats \
|
|
||||||
PSP_DB_PATH=/data/library.sqlite \
|
PSP_DB_PATH=/data/library.sqlite \
|
||||||
PSP_COVERS_DIR=/data/covers \
|
PSP_COVERS_DIR=/data/covers \
|
||||||
PSP_GAMES_ROOTS=/data/umd_games \
|
|
||||||
PSP_VIDEO_ROOTS=/data/umd_videos \
|
|
||||||
PSP_STORE_DIR=/data/store \
|
PSP_STORE_DIR=/data/store \
|
||||||
PSP_API_TOKEN=<long-random-secret> \
|
PSP_STORE_VIDEOS_DIR=/data/store_videos \
|
||||||
python3 -m app.api --host 0.0.0.0 --port 8000
|
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 |
|
| 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?system=&q=&limit=&offset=` | search the catalog |
|
||||||
| `GET /api/releases/<id>` | one release + its rom hashes |
|
| `GET /api/releases/<id>` | release detail + metadata + rom hashes |
|
||||||
| `GET /api/library?system=&refresh=` | your scanned library |
|
| `PATCH /api/releases/<id>` | edit metadata *(editor+)* |
|
||||||
| `GET /api/cover/<id>` | cover image (fetched on demand) |
|
| `GET /api/cover/<id>` | cover image |
|
||||||
| `GET /api/covers/<name>.zip` | offline cover bundle (public) |
|
| `POST /api/cover/<id>` | upload/replace cover *(editor+)* |
|
||||||
| `GET /api/store` | list store archives *(token)* |
|
| `GET /api/store?system=games|videos` | list store archives |
|
||||||
| `GET /api/store/download/<name>` | stream one archive *(token)* |
|
| `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
|
Authentication is `Authorization: Bearer <token>` for the API and a session
|
||||||
`Authorization: Bearer <token>`. Leave it unset to allow anonymous access
|
cookie for the WebUI.
|
||||||
(not recommended).
|
|
||||||
|
|
||||||
### Docker (Unraid)
|
### Docker (Unraid)
|
||||||
|
|
||||||
`docker-compose.yml` builds the API image and attaches it to Unraid's `br0`
|
`docker-compose.yml` builds the server 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):
|
macvlan bridge so it gets its own LAN IP:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# in /path/to/psppt/
|
# 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
|
docker compose up -d --build
|
||||||
```
|
```
|
||||||
|
|
||||||
The compose file reads the LAN IP and Unraid share paths from `.env` and
|
The compose file reads the LAN IP and Unraid share paths from `.env` and mounts
|
||||||
mounts them into `/data/store`, `/data/umd_games` and `/data/umd_videos`
|
them into `/data/store`, `/data/store_videos`, `/data/umd_games` and
|
||||||
(the store is mounted read-only).
|
`/data/umd_videos` (the store mounts are writable so the WebUI can manage
|
||||||
|
archives).
|
||||||
|
|
||||||
### TLS (optional)
|
### TLS (optional)
|
||||||
|
|
||||||
@@ -460,10 +476,13 @@ ports 80/443 on your router to it.
|
|||||||
|
|
||||||
### Client
|
### Client
|
||||||
|
|
||||||
In the GUI: **Settings → Store** → enter the **Server URL** (e.g.
|
In the GUI: **Settings → Store** → enter the **Server URL**, **Server
|
||||||
`http://<server-ip>:8000` or `https://psp.example.com`) and the same **API
|
username**, and **Server password**, then **Save settings** (the app logs in
|
||||||
token**, then pick **Server** in the Store tab's source selector. Use
|
and stores the per-user token). Pick **Server** in the Store tab's source
|
||||||
**Archive.org** or **Local folder** the same way.
|
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
|
## PSP Sync
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user