docs: document SetMinimized as single mutation point in AudioPlayerBar
This commit is contained in:
+24
-4
@@ -6,7 +6,7 @@ See the root `CLAUDE.md` for full architecture overview. This file covers what i
|
||||
|
||||
## One-line purpose
|
||||
|
||||
Dual-database authority for tracks (SQL metadata + FileDatabase binary), and AuthBlocks API host (JWT auth, role/admin seed). Seven track endpoints expose CRUD with upload+persist, delete+cleanup, paged listing, and metadata operations. ApiKey middleware for track endpoints, JWT + AuthBlocks endpoints for auth. CORS, forwarded headers. **FileDatabase implementation lives in `DeepDrftContent`; SQL services in `DeepDrftData`.**
|
||||
Dual-database authority for tracks (SQL metadata + FileDatabase binary) and images (FileDatabase binary), and AuthBlocks API host (JWT auth, role/admin seed). Seven track endpoints expose CRUD with upload+persist, delete+cleanup, paged listing, and metadata operations. Two image endpoints provide authenticated upload and unauthenticated streaming. ApiKey middleware for track/image endpoints, JWT + AuthBlocks endpoints for auth. CORS, forwarded headers. **FileDatabase implementation lives in `DeepDrftContent`; SQL services in `DeepDrftData`.**
|
||||
|
||||
## What lives here now (only)
|
||||
|
||||
@@ -104,10 +104,29 @@ Returns the WAV bytes from the `tracks` vault with optional offset support.
|
||||
|
||||
- **Header `ApiKey`**: required. Validated by `ApiKeyAuthenticationMiddleware`.
|
||||
- **Route parameter `id`** (long): the SQL track ID.
|
||||
- **Body**: `UpdateTrackMetadataRequest` with fields: `TrackName`, `Artist`, `Album?`, `Genre?`, `ReleaseDate?`.
|
||||
- Looks up SQL row by ID (returns `TrackDto`), updates the provided fields (nulls in the request clear optional fields), and persists the DTO via `ITrackService.Update`.
|
||||
- **Body**: `UpdateTrackMetadataRequest` with fields: `TrackName`, `Artist`, `Album?`, `Genre?`, `ReleaseDate?`, `ImagePath?` (tri-state: null = no change, "" = clear, value = set).
|
||||
- Looks up SQL row by ID (returns `TrackDto`), updates the provided fields (nulls in the request for optional metadata clear those fields; `ImagePath` follows tri-state logic), and persists the DTO via `ITrackService.Update`.
|
||||
- Returns 200 with the updated `TrackDto` on success. Returns 404 if track not found. Returns 500 on update error.
|
||||
|
||||
## The image endpoints (two endpoints)
|
||||
|
||||
### POST api/image/upload ([ApiKeyAuthorize])
|
||||
|
||||
**Authenticated endpoint.** Accepts an image file upload, stores it in the `images` vault, and returns the entry key.
|
||||
|
||||
- **Header `ApiKey`**: required. Validated by `ApiKeyAuthenticationMiddleware`.
|
||||
- **Form field `image`** (`IFormFile`, required): the image bytes (PNG, JPEG, or other format supported by `ImageProcessor`). Maximum file size 50 MB.
|
||||
- Calls `FileDatabase.RegisterResourceAsync("images", entryKey, imageBinary)` where `imageBinary` is produced by `ImageProcessor` (computes aspect ratio from headers, defaults 1.0 for unsupported formats).
|
||||
- Returns 200 with JSON `{ entryKey }` on success. Returns 400 for missing file. Returns 500 if processing or vault operations fail.
|
||||
|
||||
### GET api/image/{entryKey} (unauthenticated)
|
||||
|
||||
Returns image bytes from the `images` vault.
|
||||
|
||||
- **Route parameter `entryKey`** (string): the entry id inside the `images` vault.
|
||||
- Streams the image file directly from disk without buffering.
|
||||
- Returns 404 if image not found. Returns 500 if vault operations fail (with error swallowing — the vault returns `null`).
|
||||
|
||||
## ApiKey middleware behaviour
|
||||
|
||||
`ApiKeyAuthenticationMiddleware` runs on every request but only enforces on endpoints with `[ApiKeyAuthorize]` metadata.
|
||||
@@ -141,7 +160,8 @@ Configured in `Startup.ConfigureDomainServices()`, applied to all endpoints via
|
||||
2. Await `FileDatabase.FromAsync(VaultPath)` to load or create the database.
|
||||
3. Register `FileDatabase` as singleton.
|
||||
4. Ensure the `tracks` vault exists (type `MediaVaultType.Audio`, created on first boot if missing).
|
||||
5. Register singletons: `WavOffsetService`, `AudioProcessor`, `TrackService` (the `DeepDrftContent` version for vault operations).
|
||||
5. Ensure the `images` vault exists (type `MediaVaultType.Image`, created on first boot if missing) via `InitializeImageVault`.
|
||||
6. Register singletons: `WavOffsetService`, `AudioProcessor`, `ImageProcessor`, `TrackService` (the `DeepDrftContent` version for vault operations).
|
||||
|
||||
**In `Program.cs`** (SQL + AuthBlocks + wiring):
|
||||
|
||||
|
||||
@@ -101,6 +101,16 @@ Used by the content API to serve seek-beyond-buffer requests. The player asks fo
|
||||
|
||||
PCM-only today. Other formats (mp3, flac, aac, ogg, m4a) are listed in `MimeTypeExtensions` but not implemented. The processor validates RIFF/WAVE/PCM format — anything else is rejected.
|
||||
|
||||
## Image processor
|
||||
|
||||
`ImageProcessor.ProcessImageAsync(buffer, mimeType)`:
|
||||
|
||||
1. Accepts raw image bytes and MIME type (e.g., `image/png`, `image/jpeg`).
|
||||
2. Parses PNG or JPEG headers to extract image dimensions.
|
||||
3. Computes aspect ratio (width / height). Defaults to 1.0 if parsing fails or format is unsupported.
|
||||
4. Returns `ImageBinary` with MIME type and aspect ratio metadata.
|
||||
5. **No disk I/O**: operates on `byte[]` only — no file reading required.
|
||||
|
||||
## Content-side TrackService (orchestrator)
|
||||
|
||||
### AddTrackFromWavAsync(filePath)
|
||||
@@ -124,7 +134,7 @@ Safety call to ensure the `tracks` vault exists (creates if missing). Called on
|
||||
|
||||
## Vault constants
|
||||
|
||||
`VaultConstants.Tracks = "tracks"` — the one vault name in production use. New vault names go here when adding new vault types (e.g., `VaultConstants.Images = "images"` if image uploads are added).
|
||||
`VaultConstants.Tracks = "tracks"` and `VaultConstants.Images = "images"` — the vault names in production use. New vault names go here when adding new vault types.
|
||||
|
||||
## Service registration
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ Both are configured with JSON serializer settings (case-insensitive property mat
|
||||
|
||||
### Component integration
|
||||
- `AudioPlayerProvider.razor` is the cascading host. It injects `IStreamingPlayerService` (resolved to `StreamingAudioPlayerService` in DI), stores it in a cascade with `IsFixed="true"`, and keeps it alive across navigation.
|
||||
- `AudioPlayerBar.razor` is the dock UI. It cascades the player, binds buttons to `Play()` / `Pause()` / `Seek()` / `SetVolume()`, and displays current time / duration / progress bar. Subscribes to `IPlayerService.StateChanged` in `OnParametersSet` (reference-guarded, idempotent) and unsubscribes on dispose to re-render itself when the cascade updates.
|
||||
- `AudioPlayerBar.razor` is the dock UI. It cascades the player, binds buttons to `Play()` / `Pause()` / `Seek()` / `SetVolume()`, and displays current time / duration / progress bar. Minimize-state mutations (`Expand`, `ToggleMinimized`, `Close`) all route through a private `SetMinimized(bool value)` mutator, which guards no-ops, fires the `OnMinimized` callback, and calls `StateHasChanged()`. Subscribes to `IPlayerService.StateChanged` in `OnParametersSet` (reference-guarded, idempotent) and unsubscribes on dispose to re-render itself when the cascade updates.
|
||||
- `SpectrumVisualizer.razor` calls `AudioInteropService.GetSpectrumData()` on a timer, receives bar heights, renders via MudBlazor `MudChart` or custom canvas.
|
||||
- `TracksView.razor` injects `TracksViewModel` + cascaded `IStreamingPlayerService`. `PlayTrack(track)` calls `PlayerService.SelectTrackStreaming(track)`. Subscribes to `IPlayerService.StateChanged` in `OnParametersSet` and calls `StateHasChanged()` unconditionally on any state change, ensuring the gallery correctly reflects play/pause/track-change transitions. Active-track state is derived from `PlayerService.CurrentTrack` and `PlayerService.IsPlaying` (no local `_selectedTrack` field).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user