107 lines
3.3 KiB
Rust
107 lines
3.3 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
use std::fs;
|
|
use std::path::PathBuf;
|
|
use tauri::{AppHandle, Manager};
|
|
|
|
#[derive(Serialize, Deserialize, Clone)]
|
|
pub struct Settings {
|
|
#[serde(default = "default_sam_url")]
|
|
pub sam_url: String,
|
|
#[serde(default)]
|
|
pub sam_enabled: bool,
|
|
/// Model id chosen from the backend's /models list (e.g.
|
|
/// "sam2.1_hiera_small"). `None` lets the backend pick its default.
|
|
#[serde(default)]
|
|
pub sam_model: Option<String>,
|
|
#[serde(default = "default_cache_capacity")]
|
|
pub cache_capacity: usize,
|
|
/// ffmpeg `-hwaccel` argument. Empty string = software decode (default).
|
|
/// Recognized: "auto", "vaapi", "cuda", "vdpau". Applied on next
|
|
/// `open_video` or worker respawn.
|
|
#[serde(default)]
|
|
pub hwaccel: String,
|
|
/// Decimation factor used by playback (advance by N frames per tick) and
|
|
/// bulk extract (take every Nth frame in range). 1 = no decimation.
|
|
#[serde(default = "default_frame_skip")]
|
|
pub frame_skip: u64,
|
|
/// Maximum height (in pixels) of the canvas backing store during preview.
|
|
/// 0 = no cap beyond native resolution. Common presets: 2160 (4K),
|
|
/// 1440 (2K), 1080, 720, 480. Smaller → less draw cost.
|
|
#[serde(default)]
|
|
pub preview_max_height: u32,
|
|
}
|
|
|
|
fn default_sam_url() -> String {
|
|
"http://localhost:9090".into()
|
|
}
|
|
|
|
fn default_cache_capacity() -> usize {
|
|
crate::decoder::DEFAULT_CACHE_CAPACITY
|
|
}
|
|
|
|
fn default_frame_skip() -> u64 {
|
|
1
|
|
}
|
|
|
|
fn normalize(mut s: Settings) -> Settings {
|
|
s.cache_capacity = s.cache_capacity.clamp(
|
|
crate::decoder::MIN_CACHE_CAPACITY,
|
|
crate::decoder::MAX_CACHE_CAPACITY,
|
|
);
|
|
if s.frame_skip < 1 {
|
|
s.frame_skip = 1;
|
|
}
|
|
s
|
|
}
|
|
|
|
impl Default for Settings {
|
|
fn default() -> Self {
|
|
Self {
|
|
sam_url: default_sam_url(),
|
|
sam_enabled: false,
|
|
sam_model: None,
|
|
cache_capacity: default_cache_capacity(),
|
|
hwaccel: String::new(),
|
|
frame_skip: default_frame_skip(),
|
|
preview_max_height: 0,
|
|
}
|
|
}
|
|
}
|
|
|
|
fn settings_path(app: &AppHandle) -> Result<PathBuf, String> {
|
|
let dir = app
|
|
.path()
|
|
.app_local_data_dir()
|
|
.map_err(|e| format!("app data dir: {e}"))?;
|
|
fs::create_dir_all(&dir).map_err(|e| format!("mkdir {}: {e}", dir.display()))?;
|
|
Ok(dir.join("settings.json"))
|
|
}
|
|
|
|
pub fn load(app: &AppHandle) -> Result<Settings, String> {
|
|
let path = settings_path(app)?;
|
|
if !path.exists() {
|
|
return Ok(Settings::default());
|
|
}
|
|
let text = fs::read_to_string(&path).map_err(|e| format!("read {}: {e}", path.display()))?;
|
|
serde_json::from_str(&text)
|
|
.map(normalize)
|
|
.map_err(|e| format!("parse settings: {e}"))
|
|
}
|
|
|
|
pub fn save(app: &AppHandle, s: &Settings) -> Result<(), String> {
|
|
let path = settings_path(app)?;
|
|
let normalized = normalize(s.clone());
|
|
let text = serde_json::to_string_pretty(&normalized).map_err(|e| format!("serialize: {e}"))?;
|
|
fs::write(&path, text).map_err(|e| format!("write {}: {e}", path.display()))
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn get_settings(app: AppHandle) -> Result<Settings, String> {
|
|
load(&app)
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn save_settings(app: AppHandle, settings: Settings) -> Result<(), String> {
|
|
save(&app, &settings)
|
|
}
|