{{ album.title }}
+ {% if album.artist %} +{{ album.artist }}
+ {% endif %} + {% if album.description %} +{{ album.description }}
+ {% endif %} +diff --git a/Cargo.lock b/Cargo.lock index abfe2db..574405c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5059,6 +5059,7 @@ dependencies = [ "async-trait", "axum", "axum-extra", + "bytes", "chrono", "dotenvy", "fluent-templates", diff --git a/Cargo.toml b/Cargo.toml index af50745..8b9a81e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ tokio = { version = "1.45", default-features = false, features = [ "rt-multi-thread", ] } async-trait = { version = "0.1" } -axum = { version = "0.8" } +axum = { version = "0.8", features = ["multipart"] } tracing = { version = "0.1" } tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] } regex = { version = "1.11" } @@ -42,6 +42,7 @@ fluent-templates = { version = "0.13", features = ["tera"] } unic-langid = { version = "0.9" } # /view engine axum-extra = { version = "0.10", features = ["form"] } +bytes = { version = "1" } [[bin]] name = "universal_web-cli" diff --git a/REWRITE_SPEC.md b/REWRITE_SPEC.md index 708fb68..5a4148d 100644 --- a/REWRITE_SPEC.md +++ b/REWRITE_SPEC.md @@ -41,11 +41,11 @@ The old app ships these feature modules. Each must exist in the rewrite: - [ ] **Admin** — dashboard, user management, role assignment, audit log - [ ] **Blog** — articles CRUD, publish workflow, public listing, view counts - [ ] **Audio dashboard** — albums + tracks + tags CRUD, publish workflow -- [ ] **Audio streaming** — range-aware track/file streaming, raw upload +- [x] **Audio streaming** — range-aware track/file streaming, raw upload - [ ] **Audio player** — persistent bottom-bar player (frontend) -- [ ] **Images** — upload + serve, used as cover/featured images +- [x] **Images** — upload + serve, used as cover/featured images - [ ] **Theme** — per-user light/dark preference -- [ ] **Storage** — pluggable backend (fs default, S3/Azure/GCS capable) +- [x] **Storage** — pluggable backend (fs default, S3/Azure/GCS capable) - [ ] **Home + layout** — landing page, dynamic navbar, footer - [ ] **Swagger/OpenAPI** — API docs (optional, lower priority) @@ -366,11 +366,11 @@ Already generated in this directory — reuse, don't rebuild: 2. **Auth + sessions** — settle §3.1, get register/login/logout/me working, including admin-bootstrap. 3. **RBAC** — roles/permissions, the permission-loading middleware, guard helpers. -4. **Storage + images** — storage backend, image upload/serve (unblocks blog/audio +4. **Storage + images** — DONE: storage backend, image upload/serve (unblocks blog/audio cover images). 5. **Blog** — CRUD + publish + public pages. 6. **Audio dashboard** — albums, tracks (multipart upload), tags. -7. **Audio streaming + player** — range-aware endpoints, then the player in the GUI. +7. **Audio streaming + player** — DONE for range-aware endpoints; player remains GUI work. 8. **Admin** — dashboard, user management, role UI, audit log. 9. **Theme**, **home/layout/navbar**. 10. **Swagger/OpenAPI** (optional), tests, polish. diff --git a/assets/views/admin/audio/albums.html b/assets/views/admin/audio/albums.html new file mode 100644 index 0000000..dabd4ac --- /dev/null +++ b/assets/views/admin/audio/albums.html @@ -0,0 +1,63 @@ +{% extends "admin/base.html" %} + +{% block title %}Audio Albums{% endblock title %} + +{% block content %} +
Create albums and upload audio tracks.
+| Album | +Status | +Tracks | +Actions | +
|---|---|---|---|
| {{ row.album.title }} | ++ {% if row.album.published %} + Published + {% else %} + Draft + {% endif %} + | +{{ row.track_count }} | ++ + | +
Create a container for uploaded tracks.
+Uploaded tracks for this album.
+| Track | +File | +Featured | +Actions | +
|---|---|---|---|
| + {% if track.track_number %}{{ track.track_number }}. {% endif %}{{ track.title }} + | +{{ track.audio_file_id }} | ++ {% if track.featured %} + Yes + {% else %} + No + {% endif %} + | +
+
+ Play
+
+
+ |
+
{{ album.title }}
+