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

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.