Files
ImageApi/specs/001-video-wall/plan.md
Cameron 19c099360e Add VideoWall feature: server-side preview clip generation and mobile grid view
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>
2026-02-25 19:40:17 -05:00

80 lines
4.0 KiB
Markdown

# Implementation Plan: VideoWall
**Branch**: `001-video-wall` | **Date**: 2026-02-25 | **Spec**: [spec.md](./spec.md)
**Input**: Feature specification from `/specs/001-video-wall/spec.md`
## Summary
Add a VideoWall feature spanning the Rust API backend and React Native mobile app. The backend generates 480p MP4 preview clips (up to 10 seconds, composed of 10 equally spaced 1-second segments) using ffmpeg, extending the existing `OverviewVideo` pattern in `src/video/ffmpeg.rs`. The mobile app adds a VideoWall view using `expo-video` and FlatList to display a responsive 2-3 column grid of simultaneously looping, muted preview clips with audio-on-long-press. Preview clips are cached on disk, served via new API endpoints, and generated proactively by the file watcher.
## Technical Context
**Language/Version**: Rust (stable, Cargo) for backend API; TypeScript / React Native (Expo SDK 52) for mobile app
**Primary Dependencies**: actix-web 4, Diesel 2.2 (SQLite), ffmpeg/ffprobe (CLI), expo-video 3.0, expo-router 6.0, react-native-reanimated 4.1
**Storage**: SQLite (preview clip status tracking), filesystem (MP4 preview clips in `PREVIEW_CLIPS_DIRECTORY`)
**Testing**: `cargo test` for backend; manual testing for mobile app
**Target Platform**: Linux server (API), iOS/Android (mobile app via Expo)
**Project Type**: Mobile app + REST API (two separate repositories)
**Performance Goals**: <3s VideoWall load for 50 pre-generated previews; <30s per clip generation; <5MB per clip; smooth simultaneous playback of 6-12 clips
**Constraints**: Semaphore-limited concurrent ffmpeg processes (existing pattern); 480p resolution to keep bandwidth/CPU manageable; audio track preserved but muted by default
**Scale/Scope**: Hundreds to low thousands of videos per library; single user at a time
## Constitution Check
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
Constitution is an unfilled template — no project-specific gates defined. **PASS** (no violations possible).
Post-Phase 1 re-check: Still PASS — no gates to evaluate.
## Project Structure
### Documentation (this feature)
```text
specs/001-video-wall/
├── plan.md # This file
├── research.md # Phase 0 output
├── data-model.md # Phase 1 output
├── quickstart.md # Phase 1 output
├── contracts/ # Phase 1 output
│ └── api-endpoints.md
└── tasks.md # Phase 2 output (/speckit.tasks command)
```
### Source Code (repository root)
```text
# Backend (ImageApi - Rust)
src/
├── video/
│ ├── ffmpeg.rs # Add generate_preview_clip() using existing pattern
│ ├── actors.rs # Add PreviewClipGenerator actor (semaphore-limited)
│ └── mod.rs # Add generate_preview_clips() batch function
├── main.rs # Add GET /video/preview, POST /video/preview/status endpoints
│ # Extend file watcher to trigger preview generation
├── database/
│ ├── schema.rs # Add video_preview_clips table
│ └── models.rs # Add VideoPreviewClip model
│ └── preview_dao.rs # New DAO for preview clip status tracking
└── data/
└── mod.rs # Add PreviewClipRequest, PreviewStatusRequest types
# Frontend (SynologyFileViewer - React Native)
app/(app)/grid/
├── video-wall.tsx # New VideoWall view (FlatList grid)
└── _layout.tsx # Add video-wall route to stack
components/
└── VideoWallItem.tsx # Single preview clip cell (expo-video player)
hooks/
└── useVideoWall.ts # Preview clip fetching, status polling, audio state
```
**Structure Decision**: Mobile + API pattern. Backend changes extend existing `src/video/` module and `src/main.rs` handlers following established conventions. Frontend adds a new route under the existing grid stack navigator with a dedicated component and hook.
## Complexity Tracking
No constitution violations to justify.