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:
janisslsmandClaude Opus 4.7 committed 2026-05-18 02:12:08 +03:00
1 parent a9495389e8
commit f0ebb4b9a4
8 files changed
+342 -13

No files matched your search

+20 -4
View File
@@ -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()))?;