Backend (Rust/Actix-web): - Add video_preview_clips table and PreviewDao for tracking preview generation - Add ffmpeg preview clip generator: 10 equally-spaced 1s segments at 480p with CUDA NVENC auto-detection - Add PreviewClipGenerator actor with semaphore-limited concurrent processing - Add GET /video/preview and POST /video/preview/status endpoints - Extend file watcher to detect and queue previews for new videos - Use relative paths consistently for DB storage (matching EXIF convention) Frontend (React Native/Expo): - Add VideoWall grid view with 2-3 column layout of looping preview clips - Add VideoWallItem component with ActiveVideoPlayer sub-component for lifecycle management - Add useVideoWall hook for batch status polling with 5s refresh - Add navigation button in grid header (visible when videos exist) - Use TextureView surface type to fix Android z-ordering issues - Optimize memory: players only mount while visible via FlatList windowSize - Configure ExoPlayer buffer options and caching for short clips - Tap to toggle audio focus, long press to open in full viewer Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
92 lines
2.9 KiB
Markdown
92 lines
2.9 KiB
Markdown
# API Contracts: VideoWall
|
|
|
|
## GET /video/preview
|
|
|
|
Retrieve the preview clip MP4 file for a given video. If the preview is not yet generated, triggers on-demand generation and returns 202.
|
|
|
|
**Authentication**: Required (Bearer token)
|
|
|
|
**Query Parameters**:
|
|
|
|
| Parameter | Type | Required | Description |
|
|
|-----------|------|----------|-------------|
|
|
| path | string | yes | Relative path of the source video from BASE_PATH |
|
|
|
|
**Responses**:
|
|
|
|
| Status | Content-Type | Body | Description |
|
|
|--------|-------------|------|-------------|
|
|
| 200 | video/mp4 | MP4 file stream | Preview clip is ready and served |
|
|
| 202 | application/json | `{"status": "processing", "path": "<path>"}` | Preview generation has been triggered; client should retry |
|
|
| 400 | application/json | `{"error": "Invalid path"}` | Path validation failed |
|
|
| 404 | application/json | `{"error": "Video not found"}` | Source video does not exist |
|
|
| 500 | application/json | `{"error": "Generation failed: <detail>"}` | Preview generation failed |
|
|
|
|
**Behavior**:
|
|
1. Validate path with `is_valid_full_path()`
|
|
2. Check if preview clip exists on disk and status is `complete` → serve MP4 (200)
|
|
3. If status is `pending` or no record exists → trigger generation, return 202
|
|
4. If status is `processing` → return 202
|
|
5. If status is `failed` → return 500 with error detail
|
|
|
|
---
|
|
|
|
## POST /video/preview/status
|
|
|
|
Check the preview generation status for a batch of video paths. Used by the mobile app to determine which previews are ready before requesting them.
|
|
|
|
**Authentication**: Required (Bearer token)
|
|
|
|
**Request Body** (application/json):
|
|
|
|
```json
|
|
{
|
|
"paths": [
|
|
"2024/vacation/beach.mov",
|
|
"2024/vacation/sunset.mp4",
|
|
"2024/birthday.avi"
|
|
]
|
|
}
|
|
```
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| paths | string[] | yes | Array of relative video paths from BASE_PATH |
|
|
|
|
**Response** (200, application/json):
|
|
|
|
```json
|
|
{
|
|
"previews": [
|
|
{
|
|
"path": "2024/vacation/beach.mov",
|
|
"status": "complete",
|
|
"preview_url": "/video/preview?path=2024/vacation/beach.mov"
|
|
},
|
|
{
|
|
"path": "2024/vacation/sunset.mp4",
|
|
"status": "processing",
|
|
"preview_url": null
|
|
},
|
|
{
|
|
"path": "2024/birthday.avi",
|
|
"status": "pending",
|
|
"preview_url": null
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| previews | object[] | Status for each requested path |
|
|
| previews[].path | string | The requested video path |
|
|
| previews[].status | string | One of: `pending`, `processing`, `complete`, `failed`, `not_found` |
|
|
| previews[].preview_url | string? | Relative URL to fetch the preview (only when status is `complete`) |
|
|
|
|
**Behavior**:
|
|
1. Accept up to 200 paths per request
|
|
2. Batch query the `video_preview_clips` table for all paths
|
|
3. For paths not in the table, return status `not_found` (video may not exist or hasn't been scanned yet)
|
|
4. Return results in the same order as the input paths
|