281 lines
13 KiB
Markdown
281 lines
13 KiB
Markdown
# 05 · Blueprints & REST API
|
|
|
|
DigiServer v2 registers **7 active blueprints** (`content_old.py` is legacy dead code and is not registered).
|
|
|
|
---
|
|
|
|
## 1. Blueprint Overview
|
|
|
|
| Blueprint | URL prefix | Module | Focus |
|
|
|---|---|---|---|
|
|
| `main_bp` | `/` | `blueprints/main.py` | Dashboard, health |
|
|
| `auth_bp` | `/` | `blueprints/auth.py` | Login/logout/register/password |
|
|
| `admin_bp` | `/admin` | `blueprints/admin.py` | Admin panel, HTTPS, build, users, logos |
|
|
| `players_bp` | `/players` | `blueprints/players.py` | Player management |
|
|
| `content_bp` | `/content` | `blueprints/content.py` | Media library + modern playlist management |
|
|
| `playlist_bp` | `/playlist` | `blueprints/playlist.py` | Legacy per-player playlist (redirects) |
|
|
| `api_bp` | `/api` | `blueprints/api.py` | Player-facing REST + deployment API |
|
|
|
|
---
|
|
|
|
## 2. `main` — Dashboard & Health (`/`)
|
|
|
|
| Route | Methods | Endpoint | Purpose |
|
|
|---|---|---|---|
|
|
| `/` | GET | `dashboard` | Counts (players/playlists/content), storage MB, 20 recent logs (cached 60s except `viewer` role) |
|
|
| `/health` | GET | `health` | Health JSON: `SELECT 1` DB ping + free disk space |
|
|
|
|
---
|
|
|
|
## 3. `auth` — Authentication (`/`)
|
|
|
|
| Route | Methods | Endpoint | Purpose |
|
|
|---|---|---|---|
|
|
| `/login` | GET/POST | `login` | bcrypt login, `remember`, `next` redirect, failed-attempt logging |
|
|
| `/logout` | GET | `logout` | Logs out + logs action |
|
|
| `/register` | GET/POST | `register` | Self-registration → default `viewer` role |
|
|
| `/change-password` | GET/POST | `change_password` | Change own password (verifies current) |
|
|
|
|
---
|
|
|
|
## 4. `admin` — Admin Panel (`/admin`)
|
|
|
|
**Security:** `@login_required` on all routes; `@admin_required` (custom decorator, `role == 'admin'`) on user-management.
|
|
|
|
### Users
|
|
| Route | Methods | Endpoint | Purpose |
|
|
|---|---|---|---|
|
|
| `/` | GET | `admin_panel` | Stats, recent logs, users, storage |
|
|
| `/user/create` | POST | `create_user` | Create user (username ≥3, password ≥6) |
|
|
| `/user/<id>/role` | POST | `change_user_role` | Change role (not own) |
|
|
| `/user/<id>/delete` | POST | `delete_user` | Delete user (not own) |
|
|
| `/user/<id>/password` | POST | `reset_user_password` | Admin reset password |
|
|
| `/users` | GET | `user_management` | User list page |
|
|
| `/theme` | POST | `change_theme` | light/dark theme |
|
|
|
|
### Media housekeeping
|
|
| Route | Methods | Endpoint | Purpose |
|
|
|---|---|---|---|
|
|
| `/leftover-media` | GET | `leftover_media` | Content not assigned to any playlist, by type + size |
|
|
| `/delete-leftover-images` | POST | — | Bulk-delete leftover images (+ archive + PlayerEdit) |
|
|
| `/delete-leftover-videos` | POST | — | Bulk-delete leftover videos |
|
|
| `/delete-single-leftover/<id>` | POST | — | Delete one leftover item |
|
|
|
|
### System / dependencies
|
|
| Route | Methods | Endpoint | Purpose |
|
|
|---|---|---|---|
|
|
| `/system/info` | GET | `system_info` | JSON: platform + psutil (CPU/mem/disk) |
|
|
| `/dependencies` | GET | `dependencies` | Checks LibreOffice, Poppler, FFmpeg, emoji fonts |
|
|
| `/install-libreoffice` | POST | — | `sudo -n install_libreoffice.sh` |
|
|
| `/install-emoji-fonts` | POST | — | `sudo -n install_emoji_fonts.sh` |
|
|
| `/logo/upload` | POST | `upload_logo` | Upload logo.png |
|
|
| `/logs/clear` | POST | `clear_logs` | Delete all `ServerLog` rows |
|
|
| `/customize-logos` | GET | `customize_logos` | Logo customization page |
|
|
| `/upload-header-logo` | POST | — | Save header_logo.png |
|
|
| `/upload-login-logo` | POST | — | Save login_logo.png |
|
|
|
|
### Editing users
|
|
| Route | Methods | Endpoint | Purpose |
|
|
|---|---|---|---|
|
|
| `/editing-users` | GET | `manage_editing_users` | List `PlayerUser` + per-user edit counts |
|
|
| `/editing-users/<id>/update` | POST | — | Rename editing user |
|
|
| `/editing-users/<id>/delete` | POST | — | Delete editing user |
|
|
|
|
### HTTPS (Caddy)
|
|
| Route | Methods | Endpoint | Purpose |
|
|
|---|---|---|---|
|
|
| `/https-config` | GET | `https_config` | HTTPS config page (auto-corrects DB flag if request is HTTPS) |
|
|
| `/https-config/update` | POST | `update_https_config` | Validate + save config → regenerate Caddyfile → reload Caddy |
|
|
| `/https-config/status` | GET | `https_config_status` | Config as JSON |
|
|
|
|
### Player build & deployment
|
|
| Route | Methods | Endpoint | Purpose |
|
|
|---|---|---|---|
|
|
| `/build-player` | GET | `build_player` | Build page + staged-code status |
|
|
| `/build-player` | POST | `build_player_action` | `build_files` / `save_config` / `build_and_config` → clone/refresh code, write `app_config.json`, persist `instance/player_build.json` |
|
|
|
|
---
|
|
|
|
## 5. `players` — Player Management (`/players`)
|
|
|
|
| Route | Methods | Endpoint | Purpose |
|
|
|---|---|---|---|
|
|
| `/` and `/list` | GET | `list` | Player list + live deployment-status polling data |
|
|
| `/add` | GET/POST | `add_player` | Create player; optional **background SSH deployment** |
|
|
| `/bulk/delete` | POST | — | JSON bulk delete |
|
|
| `/bulk/assign-playlist` | POST | — | JSON bulk assign to playlist |
|
|
| `/deployment-status` | GET | — | JSON deployment status for all players (polling) |
|
|
| `/<int:player_id>` | GET | — | Redirect to `manage_player` |
|
|
| `/<id>/edit` | GET/POST | — | Edit name/location (legacy) |
|
|
| `/<id>/delete` | POST | — | Delete player + feedback |
|
|
| `/<id>/regenerate-auth` | POST | — | New auth code |
|
|
| `/<id>/manage` | GET/POST | `manage_player` | Manage page: `update_credentials` / `assign_playlist`; feedback, edits, status |
|
|
| `/<id>/edited-media` | GET | `edited_media` | All edited media + user mapping |
|
|
| `/<id>/edited-media-report` | GET | `edited_media_report` | Tabular report |
|
|
| `/<id>/fullscreen` | GET | — | Player fullscreen (NO auth; optional `?auth=` check), cached playlist |
|
|
| `/<id>/reorder` | POST | — | Legacy stub → 400 "use Playlists page" |
|
|
| `/<id>/playlist/reorder` | POST | — | Legacy per-player reorder (JSON up/down) |
|
|
| `/<id>/playlist/remove` | POST | — | Legacy removal (bumps `playlist_version`) |
|
|
|
|
Helper: `get_player_playlist(player_id)` — `@cache.memoize(300)` builds playlist dicts (`url`, `type`, `duration`, `position`, `muted`, `audio`).
|
|
|
|
---
|
|
|
|
## 6. `content` — Media Library & Modern Playlist Management (`/content`)
|
|
|
|
> This is the **primary workflow** in v2 (1,519 lines).
|
|
|
|
### Library & uploads
|
|
| Route | Methods | Endpoint | Purpose |
|
|
|---|---|---|---|
|
|
| `/` | GET | `content_list` | Main page `content_list_new.html`: playlists, last-3 media, counts, players |
|
|
| `/media-library` | GET | `media_library` | All media by type + edit counts |
|
|
| `/media/<id>/delete` | POST | `delete_media` | Delete file + archive + edits; removes from playlists + bumps versions |
|
|
| `/upload-media-page` | GET | `upload_media_page` | Upload page (playlist selector) |
|
|
| `/upload-media` | POST | `upload_media` | Core upload: images optimized, videos validated, **PDF/PPTX → Full-HD PNGs**, large files → background threads |
|
|
|
|
### Web links
|
|
| Route | Methods | Endpoint | Purpose |
|
|
|---|---|---|---|
|
|
| `/add-weblink` | POST | `add_weblink` | Create weblink Content (http/https validated), optional playlist add |
|
|
| `/playlist/<id>/add-weblink` | POST | — | Create weblink + append to playlist |
|
|
|
|
### Playlist management
|
|
| Route | Methods | Endpoint | Purpose |
|
|
|---|---|---|---|
|
|
| `/playlist/create` | POST | — | Create playlist (name, description, orientation) |
|
|
| `/playlist/<id>/delete` | POST | — | Delete + unassign players |
|
|
| `/playlist/<id>/manage` | GET | `manage_playlist_content` | Ordered content + available library (no weblinks) |
|
|
| `/playlist/<id>/add-content` | POST | — | Add library content at next position |
|
|
| `/playlist/<id>/remove-content/<content_id>` | POST | — | Remove content (deletes orphan weblinks) |
|
|
| `/playlist/<id>/bulk-remove` | POST | — | JSON bulk remove |
|
|
| `/playlist/<id>/reorder` | POST | — | JSON reorder (position = index) |
|
|
| `/playlist/<id>/update-muted/<content_id>` | POST | — | Toggle muted |
|
|
| `/playlist/<id>/update-edit-enabled/<content_id>` | POST | — | Toggle `edit_on_player_enabled` |
|
|
| `/playlist/<id>/update-duration/<content_id>` | POST | — | Per-playlist duration (≥1s) |
|
|
| `/player/<id>/assign-playlist` | POST | — | Assign/unassign player to playlist |
|
|
|
|
**All playlist mutations** call `Playlist.increment_version()` and `cache.clear()`.
|
|
|
|
### Processing helpers (module-level)
|
|
`process_image_file`, `process_video_file_extended` (ffprobe), `process_pdf_file` (pdf2image @300 DPI → `_pageNNN.png`), `process_presentation_file` (LibreOffice → PDF → pdftoppm → Full-HD PNG), `create_fullhd_image`, `resize_image_to_fullhd`, `optimize_image_to_fullhd`, `process_file_in_background` (thread wrapper).
|
|
|
|
---
|
|
|
|
## 7. `playlist` — Legacy Per-Player Routes (`/playlist`)
|
|
|
|
Redirects/legacy — kept for compatibility:
|
|
| Route | Methods | Purpose |
|
|
|---|---|---|
|
|
| `/<int:player_id>` | GET | Redirect to modern manage page |
|
|
| `/<id>/add` | POST | Add content to player's playlist |
|
|
| `/<id>/remove/<content_id>` | POST | Remove + renumber |
|
|
| `/<id>/reorder` | POST | JSON reorder from `content_ids` |
|
|
| `/<id>/update-duration/<content_id>` | POST | Update duration |
|
|
| `/<id>/update-muted/<content_id>` | POST | Update muted |
|
|
| `/<id>/clear` | POST | Clear all items |
|
|
|
|
---
|
|
|
|
## 8. `api` — Player-Facing REST + Deployment API (`/api`)
|
|
|
|
**Custom decorators:** `rate_limit(max_requests, window)` (in-memory, IP/Bearer keyed) and `verify_player_auth` (validates Bearer `auth_code` → sets `request.player`).
|
|
|
|
### Health & auth
|
|
| Route | Methods | Endpoint | Purpose |
|
|
|---|---|---|---|
|
|
| `/health` | GET | `health_check` | API health (`version: 2.0.0`) |
|
|
| `/certificate` | GET | — | TLS certificate test |
|
|
| `/auth/player` | POST | `authenticate_player` | hostname + password/quickconnect → auth_code, playlist_id, orientation; sets online |
|
|
| `/auth/verify` | POST | `verify_auth_code` | Verify auth code → player info |
|
|
|
|
### Playlist delivery
|
|
| Route | Methods | Endpoint | Purpose |
|
|
|---|---|---|---|
|
|
| `/playlists` | GET | `get_playlist_by_quickconnect` | Kivy-compatible: `?hostname=&quickconnect_code=` → playlist + version + hashed quickconnect |
|
|
| `/playlists/<player_id>` | GET | `get_player_playlist` | Bearer-authed fetch (cached) |
|
|
| `/playlist-version/<player_id>` | GET | `get_playlist_version` | Lightweight refresh-poll version check |
|
|
|
|
**Payload keys the players expect** (from `get_cached_playlist`): `file_name`, `type`, `duration`, `position`, `url`, `description`, `edit_on_player_enabled`, `muted`, `audio` (`"on"`/`"off"`).
|
|
|
|
### Feedback & monitoring
|
|
| Route | Methods | Endpoint | Purpose |
|
|
|---|---|---|---|
|
|
| `/player-feedback` | POST | `receive_player_feedback` | Status (playing/paused/error/restarting); infers player; **auto-marks deployment `deployed`** |
|
|
| `/player-status/<player_id>` | GET | `get_player_status` | Online (5-min), latest feedback |
|
|
| `/system-info` | GET | — | Counts: players online/total, groups, content, 24h logs |
|
|
| `/content` | GET | — | List content with counts |
|
|
| `/logs` | GET | `get_logs` | Query logs (`limit`/`level`/`since`) |
|
|
|
|
### Edited media
|
|
| Route | Methods | Endpoint | Purpose |
|
|
|---|---|---|---|
|
|
| `/player-edit-media` | POST | `receive_edited_media` | Bearer-authed multipart upload of edited image + metadata; versionizes to `edited_media/<content_id>/`; records `PlayerEdit`; auto-creates `PlayerUser`; repoints `Content.filename`; bumps playlist version; clears cache |
|
|
|
|
### SSH deployment
|
|
| Route | Methods | Endpoint | Purpose |
|
|
|---|---|---|---|
|
|
| `/deploy/test-ssh` | POST | `test_ssh_connection` | Test SSH (sshpass/ssh) |
|
|
| `/deploy/player` | POST | `deploy_player` | Full remote deploy (`deploy_player_to_host`); API key = `sha256(name:hostname)[:32]` |
|
|
|
|
**Error handlers:** JSON 404 / 405 / 500.
|
|
|
|
---
|
|
|
|
## 9. API Call Flows (Mermaid)
|
|
|
|
### Player bootstrap (auth → playlist)
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant P as Player
|
|
participant A as /api
|
|
P->>A: POST /api/auth/player {hostname, password|quickconnect}
|
|
A->>A: Player.authenticate()
|
|
A-->>P: {auth_code, playlist_id, orientation}
|
|
P->>A: GET /api/playlists/<id> (Bearer auth_code)
|
|
A-->>P: playlist items + version
|
|
loop refresh poll
|
|
P->>A: GET /api/playlist-version/<id>
|
|
A-->>P: {version}
|
|
end
|
|
```
|
|
|
|
### Edited media upload
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant P as Player
|
|
participant A as /api
|
|
participant DB as SQLite
|
|
P->>A: POST /api/player-edit-media (Bearer, multipart image + metadata)
|
|
A->>DB: locate Content (filename / edited_media/<id>/ regex / last PlayerEdit)
|
|
A->>DB: move original → edited_media/<id>/original_*
|
|
A->>DB: save new version + side-car JSON
|
|
A->>DB: get_or_create PlayerUser (user_code)
|
|
A->>DB: create PlayerEdit
|
|
A->>DB: repoint Content.filename → latest edit (preserve original_filename)
|
|
A->>DB: Playlist.increment_version()
|
|
A-->>P: 200 OK
|
|
```
|
|
|
|
### Deployment
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant Admin as Admin UI
|
|
participant S as Server (app)
|
|
participant T as Background task
|
|
participant H as Player host
|
|
Admin->>S: add player / deploy
|
|
S->>T: background_player_deployment()
|
|
T->>H: sshpass test_ssh_connection()
|
|
T->>H: rsync staged code (or git clone/pull)
|
|
T->>H: write config/app_config.json
|
|
T->>H: temp passwordless sudo → install.sh → start.sh
|
|
T->>H: cleanup sudoers
|
|
T-->>S: update player.deployment_status = deployed|failed
|
|
Admin->>S: GET /players/deployment-status (poll)
|
|
```
|
|
|
|
---
|
|
|
|
> Next: [06 · Utils & Services](06-utils-services.md)
|