use std::fs; use std::path::PathBuf; #[derive(Debug, Clone, serde::Deserialize)] #[allow(dead_code)] pub struct AsrSegment { pub start: f64, pub end: f64, pub text: String, } #[derive(Debug, Clone, serde::Deserialize)] #[allow(dead_code)] pub struct AsrData { #[serde(default)] pub segments: Vec, } #[allow(dead_code)] pub struct AsrOverlay { segments: Vec, current_text: String, } #[allow(dead_code)] impl AsrOverlay { pub fn new() -> Self { Self { segments: Vec::new(), current_text: String::new(), } } pub fn load_from_file(&mut self, video_path: &str) -> bool { // Try to find ASR JSON file in various locations let video_dir = PathBuf::from(video_path).parent().map(|p| p.to_path_buf()); let _video_stem = PathBuf::from(video_path) .file_stem() .and_then(|s| s.to_str()) .unwrap_or(""); let mut paths = Vec::new(); // In same directory as video if let Some(_dir) = &video_dir { paths.push(PathBuf::from(video_path).with_extension("asr.json")); } // In data directory let data_dir = PathBuf::from("/Users/accusys/momentry_core_0.1"); if let Ok(content) = fs::read_to_string(video_path) { let _ = content; } // Try probe file for UUID let uuid = self .find_uuid_from_probe(video_path) .or_else(|| lookup_uuid_from_db(video_path)); if let Some(uuid_val) = uuid { paths.push(data_dir.join(format!("{}.asr.json", uuid_val))); } for path in &paths { if path.exists() { if let Ok(content) = fs::read_to_string(path) { if let Ok(data) = serde_json::from_str::(&content) { self.segments = data.segments; println!( "Loaded {} ASR segments from {:?}", self.segments.len(), path ); return true; } } } } // Try to load from PostgreSQL if let Some(uuid) = lookup_uuid_from_db(video_path) { let db_path = PathBuf::from("/Users/accusys/momentry_core_0.1") .join(format!("{}.asr.json", uuid)); if db_path.exists() { if let Ok(content) = fs::read_to_string(&db_path) { if let Ok(data) = serde_json::from_str::(&content) { self.segments = data.segments; println!( "Loaded {} ASR segments from database file", self.segments.len() ); return true; } } } } false } #[allow(dead_code)] pub fn update(&mut self, current_time: f64) { self.current_text = String::new(); for segment in &self.segments { if current_time >= segment.start && current_time <= segment.end { self.current_text = segment.text.clone(); break; } } } #[allow(dead_code)] pub fn get_text(&self) -> &str { &self.current_text } #[allow(dead_code)] pub fn is_empty(&self) -> bool { self.segments.is_empty() } #[allow(dead_code)] fn find_uuid_from_probe(&self, video_path: &str) -> Option { let path_buf = PathBuf::from(video_path); let video_stem = path_buf.file_stem().and_then(|s| s.to_str()).unwrap_or(""); let probe_path = PathBuf::from("/Users/accusys/momentry_core_0.1") .join(format!("{}.probe.json", video_stem)); if probe_path.exists() { if let Ok(content) = fs::read_to_string(&probe_path) { if let Ok(probe) = serde_json::from_str::(&content) { return probe .get("uuid") .and_then(|v| v.as_str()) .map(|s| s.to_string()); } } } None } } #[allow(dead_code)] fn lookup_uuid_from_db(video_path: &str) -> Option { use std::process::Command as StdCommand; let filename = std::path::Path::new(video_path) .file_stem() .and_then(|s| s.to_str()) .unwrap_or(""); let output = StdCommand::new("psql") .args([ "-U", "accusys", "-h", "localhost", "-d", "momentry", "-t", "-A", "-c", &format!( "SELECT uuid FROM videos WHERE file_path LIKE '%{}%' LIMIT 1", filename ), ]) .output() .ok()?; if output.status.success() { let uuid = String::from_utf8_lossy(&output.stdout).trim().to_string(); if !uuid.is_empty() { return Some(uuid); } } None }