feat(arr): wire translation backends into daemon
Forward each translate-* feature from arr-daemon to arr-subs, add the missing OpenAI model bootstrap key, and construct the compiled and credentialed backends at startup so the translate endpoint stops answering 503 unconditionally.
This commit is contained in:
@@ -131,6 +131,7 @@ fn api_state(
|
||||
config.opensubtitles_username.clone(),
|
||||
config.opensubtitles_password.clone(),
|
||||
))
|
||||
.with_translation_backends(translation_backends(config))
|
||||
.with_jellyfin(jellyfin)
|
||||
.with_syncer(arr_subs::Syncer::new().with_binary(config.alass_path.clone())))
|
||||
}
|
||||
@@ -480,10 +481,6 @@ fn jellyfin_client(config: &Config) -> Result<arr_api::jellyfin::JellyfinClient,
|
||||
/// search *runs* is the `providers_enabled` setting the API reads per
|
||||
/// request. OpenSubtitles.com needs a registered API key to be called at all,
|
||||
/// so without one it is not offered; Podnapisi is anonymous and always is.
|
||||
///
|
||||
/// Translation backends are not wired: none is implemented yet (#191-#193),
|
||||
/// and `AppState` defaults to an empty registry, which makes a manual
|
||||
/// translation answer "no such engine" rather than fail obscurely.
|
||||
fn subtitle_providers(
|
||||
opensubtitles_api_key: Option<String>,
|
||||
username: Option<String>,
|
||||
@@ -511,3 +508,95 @@ fn subtitle_providers(
|
||||
|
||||
providers
|
||||
}
|
||||
|
||||
/// The translation backends this deployment can offer (DESIGN.md §15,
|
||||
/// issue #216).
|
||||
///
|
||||
/// Which cargo features this binary was built with decides what could ever
|
||||
/// be here (`compiled_engines`); credentials decide what actually is, same
|
||||
/// split `subtitle_providers` makes for search. Which one of these a
|
||||
/// translation *uses* is the `translation_engine` database setting, read per
|
||||
/// request (#198) — this only decides which ids exist to be picked.
|
||||
#[cfg_attr(
|
||||
not(any(
|
||||
feature = "translate-openai",
|
||||
feature = "translate-deepl",
|
||||
feature = "translate-google",
|
||||
feature = "translate-command"
|
||||
)),
|
||||
allow(unused_variables, unused_mut)
|
||||
)]
|
||||
fn translation_backends(config: &Config) -> Vec<std::sync::Arc<dyn arr_subs::Backend>> {
|
||||
let mut backends: Vec<std::sync::Arc<dyn arr_subs::Backend>> = Vec::new();
|
||||
|
||||
#[cfg(feature = "translate-openai")]
|
||||
{
|
||||
let openai_config = arr_subs::OpenAiConfig {
|
||||
api_key: config.translate_openai_api_key.clone(),
|
||||
};
|
||||
let backend = match &config.translate_openai_base_url {
|
||||
Some(base_url) => arr_subs::OpenAi::with_base_url(
|
||||
config.translate_openai_model.clone(),
|
||||
openai_config,
|
||||
base_url,
|
||||
),
|
||||
None => arr_subs::OpenAi::new(config.translate_openai_model.clone(), openai_config),
|
||||
};
|
||||
match backend {
|
||||
Ok(backend) => backends.push(std::sync::Arc::new(backend)),
|
||||
Err(error) => tracing::warn!(%error, "OpenAI-compatible translator not available"),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "translate-deepl")]
|
||||
{
|
||||
if let Some(auth_key) = config.translate_deepl_api_key.clone() {
|
||||
let deepl_config = arr_subs::DeepLConfig { auth_key };
|
||||
let backend = match &config.translate_deepl_base_url {
|
||||
Some(base_url) => arr_subs::DeepL::with_base_url(deepl_config, base_url),
|
||||
None => arr_subs::DeepL::new(deepl_config),
|
||||
};
|
||||
match backend {
|
||||
Ok(backend) => backends.push(std::sync::Arc::new(backend)),
|
||||
Err(error) => tracing::warn!(%error, "DeepL not available"),
|
||||
}
|
||||
} else {
|
||||
tracing::info!("no DeepL auth key configured; that translator is off");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "translate-google")]
|
||||
{
|
||||
if let Some(api_key) = config.translate_google_api_key.clone() {
|
||||
let google_config = arr_subs::GoogleConfig { api_key };
|
||||
let backend = match &config.translate_google_base_url {
|
||||
Some(base_url) => arr_subs::Google::with_base_url(google_config, base_url),
|
||||
None => arr_subs::Google::new(google_config),
|
||||
};
|
||||
match backend {
|
||||
Ok(backend) => backends.push(std::sync::Arc::new(backend)),
|
||||
Err(error) => tracing::warn!(%error, "Google Translate not available"),
|
||||
}
|
||||
} else {
|
||||
tracing::info!("no Google Translate API key configured; that translator is off");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "translate-command")]
|
||||
{
|
||||
if let Some(template) = config.translate_command_template.clone() {
|
||||
let command_config = arr_subs::CommandConfig {
|
||||
template,
|
||||
timeout: arr_subs::COMMAND_DEFAULT_TIMEOUT,
|
||||
};
|
||||
match arr_subs::Command::new(command_config) {
|
||||
Ok(backend) => backends.push(std::sync::Arc::new(backend)),
|
||||
Err(error) => tracing::warn!(%error, "remote-command translator not available"),
|
||||
}
|
||||
} else {
|
||||
tracing::info!("no remote-command template configured; that translator is off");
|
||||
}
|
||||
}
|
||||
|
||||
backends
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user