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>
4.0 KiB
Implementation Plan: VideoWall
Branch: 001-video-wall | Date: 2026-02-25 | Spec: 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)
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)
# 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.