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>
117 lines
2.9 KiB
Rust
117 lines
2.9 KiB
Rust
use crate::database::schema::{favorites, image_exif, photo_insights, users, video_preview_clips};
|
|
use serde::Serialize;
|
|
|
|
#[derive(Insertable)]
|
|
#[diesel(table_name = users)]
|
|
pub struct InsertUser<'a> {
|
|
pub username: &'a str,
|
|
pub password: &'a str,
|
|
}
|
|
|
|
#[derive(Serialize, Queryable, Clone, Debug)]
|
|
pub struct User {
|
|
pub id: i32,
|
|
pub username: String,
|
|
#[serde(skip_serializing)]
|
|
pub password: String,
|
|
}
|
|
|
|
#[derive(Insertable)]
|
|
#[diesel(table_name = favorites)]
|
|
pub struct InsertFavorite<'a> {
|
|
pub userid: &'a i32,
|
|
pub path: &'a str,
|
|
}
|
|
|
|
#[derive(Serialize, Queryable, Clone, Debug)]
|
|
pub struct Favorite {
|
|
pub id: i32,
|
|
pub userid: i32,
|
|
pub path: String,
|
|
}
|
|
|
|
#[derive(Insertable)]
|
|
#[diesel(table_name = image_exif)]
|
|
pub struct InsertImageExif {
|
|
pub file_path: String,
|
|
pub camera_make: Option<String>,
|
|
pub camera_model: Option<String>,
|
|
pub lens_model: Option<String>,
|
|
pub width: Option<i32>,
|
|
pub height: Option<i32>,
|
|
pub orientation: Option<i32>,
|
|
pub gps_latitude: Option<f32>,
|
|
pub gps_longitude: Option<f32>,
|
|
pub gps_altitude: Option<f32>,
|
|
pub focal_length: Option<f32>,
|
|
pub aperture: Option<f32>,
|
|
pub shutter_speed: Option<String>,
|
|
pub iso: Option<i32>,
|
|
pub date_taken: Option<i64>,
|
|
pub created_time: i64,
|
|
pub last_modified: i64,
|
|
}
|
|
|
|
#[derive(Serialize, Queryable, Clone, Debug)]
|
|
pub struct ImageExif {
|
|
pub id: i32,
|
|
pub file_path: String,
|
|
pub camera_make: Option<String>,
|
|
pub camera_model: Option<String>,
|
|
pub lens_model: Option<String>,
|
|
pub width: Option<i32>,
|
|
pub height: Option<i32>,
|
|
pub orientation: Option<i32>,
|
|
pub gps_latitude: Option<f32>,
|
|
pub gps_longitude: Option<f32>,
|
|
pub gps_altitude: Option<f32>,
|
|
pub focal_length: Option<f32>,
|
|
pub aperture: Option<f32>,
|
|
pub shutter_speed: Option<String>,
|
|
pub iso: Option<i32>,
|
|
pub date_taken: Option<i64>,
|
|
pub created_time: i64,
|
|
pub last_modified: i64,
|
|
}
|
|
|
|
#[derive(Insertable)]
|
|
#[diesel(table_name = photo_insights)]
|
|
pub struct InsertPhotoInsight {
|
|
pub file_path: String,
|
|
pub title: String,
|
|
pub summary: String,
|
|
pub generated_at: i64,
|
|
pub model_version: String,
|
|
}
|
|
|
|
#[derive(Serialize, Queryable, Clone, Debug)]
|
|
pub struct PhotoInsight {
|
|
pub id: i32,
|
|
pub file_path: String,
|
|
pub title: String,
|
|
pub summary: String,
|
|
pub generated_at: i64,
|
|
pub model_version: String,
|
|
}
|
|
|
|
#[derive(Insertable)]
|
|
#[diesel(table_name = video_preview_clips)]
|
|
pub struct InsertVideoPreviewClip {
|
|
pub file_path: String,
|
|
pub status: String,
|
|
pub created_at: String,
|
|
pub updated_at: String,
|
|
}
|
|
|
|
#[derive(Serialize, Queryable, Clone, Debug)]
|
|
pub struct VideoPreviewClip {
|
|
pub id: i32,
|
|
pub file_path: String,
|
|
pub status: String,
|
|
pub duration_seconds: Option<f32>,
|
|
pub file_size_bytes: Option<i32>,
|
|
pub error_message: Option<String>,
|
|
pub created_at: String,
|
|
pub updated_at: String,
|
|
}
|