Files
momentry_core/src/player/asr_overlay.rs
accusys 383201cacd feat: Initial v0.9 release with API Key authentication
## v0.9.20260325_144654

### Features
- API Key Authentication System
- Job Worker System
- V2 Backup Versioning

### Bug Fixes
- get_processor_results_by_job column mapping

Co-authored-by: OpenCode
2026-03-25 14:53:41 +08:00

182 lines
5.1 KiB
Rust

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<AsrSegment>,
}
#[allow(dead_code)]
pub struct AsrOverlay {
segments: Vec<AsrSegment>,
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::<AsrData>(&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::<AsrData>(&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<String> {
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::<serde_json::Value>(&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<String> {
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
}