Add default audio/subtitle language config and in-TUI settings editor
* New audio_lang / subtitle_lang fields in config (file, CLI flags, env vars). Forwarded to mpv's alang/slang as a comma-separated ISO 639 priority list, e.g. "jpn,eng". * New Settings screen (press `s` in the main view) for editing server, user, password, and language preferences without leaving the app. Credential changes trigger re-authentication against the new endpoint; on success the libraries/resume list is refreshed. Everything is persisted back to the config file the app loaded from. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
1 parent
a9495389e8
commit
f0ebb4b9a4
8 files changed
+342
-13
No files matched your search
+20
-4
@@ -18,6 +18,16 @@ pub struct CliArgs {
|
||||
#[arg(short, long, env = "EMBY_PASSWORD")]
|
||||
pub password: Option<String>,
|
||||
|
||||
/// Preferred audio language(s), comma-separated ISO 639 codes (e.g. "jpn,eng").
|
||||
/// Forwarded to mpv's `alang`.
|
||||
#[arg(long, env = "EMBY_AUDIO_LANG")]
|
||||
pub audio_lang: Option<String>,
|
||||
|
||||
/// Preferred subtitle language(s), comma-separated ISO 639 codes (e.g. "eng,jpn").
|
||||
/// Forwarded to mpv's `slang`.
|
||||
#[arg(long, env = "EMBY_SUBTITLE_LANG")]
|
||||
pub subtitle_lang: Option<String>,
|
||||
|
||||
/// Path to config file. Defaults: ./config.toml then $XDG_CONFIG_HOME/emby-client/config.toml
|
||||
#[arg(short, long)]
|
||||
pub config: Option<PathBuf>,
|
||||
@@ -32,6 +42,8 @@ pub struct FileConfig {
|
||||
pub server: Option<String>,
|
||||
pub user: Option<String>,
|
||||
pub password: Option<String>,
|
||||
pub audio_lang: Option<String>,
|
||||
pub subtitle_lang: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -39,24 +51,26 @@ pub struct Config {
|
||||
pub server: String,
|
||||
pub user: String,
|
||||
pub password: String,
|
||||
pub audio_lang: Option<String>,
|
||||
pub subtitle_lang: Option<String>,
|
||||
}
|
||||
|
||||
/// Returns `(Some(config), save_target)` when all credentials are available,
|
||||
/// or `(None, save_target)` when at least one is missing — the caller can then
|
||||
/// prompt the user. `save_target` is the path where new credentials should
|
||||
/// be persisted if the user chooses to save them.
|
||||
pub fn load(args: &CliArgs) -> Result<(Option<Config>, Option<PathBuf>)> {
|
||||
let (file_cfg, save_target) = read_file_config(args.config.as_deref())?;
|
||||
|
||||
let server = args.server.clone().or(file_cfg.server);
|
||||
let user = args.user.clone().or(file_cfg.user);
|
||||
let password = args.password.clone().or(file_cfg.password);
|
||||
let audio_lang = args.audio_lang.clone().or(file_cfg.audio_lang);
|
||||
let subtitle_lang = args.subtitle_lang.clone().or(file_cfg.subtitle_lang);
|
||||
|
||||
let cfg = match (server, user, password) {
|
||||
(Some(server), Some(user), Some(password)) => Some(Config {
|
||||
server: server.trim_end_matches('/').to_string(),
|
||||
user,
|
||||
password,
|
||||
audio_lang,
|
||||
subtitle_lang,
|
||||
}),
|
||||
_ => None,
|
||||
};
|
||||
@@ -108,6 +122,8 @@ pub fn save(path: &Path, cfg: &Config) -> Result<()> {
|
||||
server: Some(cfg.server.clone()),
|
||||
user: Some(cfg.user.clone()),
|
||||
password: Some(cfg.password.clone()),
|
||||
audio_lang: cfg.audio_lang.clone(),
|
||||
subtitle_lang: cfg.subtitle_lang.clone(),
|
||||
};
|
||||
let text = toml::to_string_pretty(&file_cfg).context("serializing config")?;
|
||||
std::fs::write(path, text).with_context(|| format!("writing {}", path.display()))?;
|
||||
|
||||
Reference in new issue
Block a user