about summary refs log tree commit diff
path: root/src/translation
diff options
context:
space:
mode:
authorMalte Voos <git@mal.tc>2026-01-01 19:26:01 +0100
committerMalte Voos <git@mal.tc>2026-01-04 00:38:38 +0100
commitc8b942b1fbe8fdab1db0e0f56d3ed86a7486b578 (patch)
treecf344838c96ad9bd7bd97d0216c43d6a858f4a60 /src/translation
parent80a1c8234fc5b6f56bd1f2df4e6118e57631f523 (diff)
downloadlleap-c8b942b1fbe8fdab1db0e0f56d3ed86a7486b578.tar.gz
lleap-c8b942b1fbe8fdab1db0e0f56d3ed86a7486b578.zip
cache extracted subtitles & deepl translations HEAD main
Diffstat (limited to 'src/translation')
-rw-r--r--src/translation/deepl.rs65
1 files changed, 52 insertions, 13 deletions
diff --git a/src/translation/deepl.rs b/src/translation/deepl.rs
index f2e84d7..11510d5 100644
--- a/src/translation/deepl.rs
+++ b/src/translation/deepl.rs
@@ -1,6 +1,9 @@
-use std::{collections::BTreeMap, time::Duration};
+use std::{collections::BTreeMap, fmt::Display, time::Duration};
 
+use crate::util;
+use cached::proc_macro::io_cached;
 use deepl::DeepLApi;
+use deepl::ModelType;
 use relm4::prelude::*;
 
 use crate::{
@@ -66,30 +69,28 @@ impl AsyncComponent for DeeplTranslator {
 impl DeeplTranslator {
     async fn do_translate(&mut self, sender: AsyncComponentSender<Self>) {
         if let Some(stream_ix) = self.stream_ix {
-            let deepl = DeepLApi::with(&Settings::default().deepl_api_key()).new();
-
             let next_cue_to_translate = self.next_cues_to_translate.entry(stream_ix).or_insert(0);
 
-            if let Some(cue) = {
+            while let Some(cue) = {
                 SUBTITLE_TRACKS
                     .read()
                     .get(&stream_ix)
-                    .unwrap()
-                    .texts
-                    .get(*next_cue_to_translate)
+                    .and_then(|stream| stream.texts.get(*next_cue_to_translate))
                     .cloned()
             } {
-                match deepl
-                    .translate_text(cue, deepl::Lang::EN)
-                    .model_type(deepl::ModelType::PreferQualityOptimized)
-                    .await
+                match translate_text(TranslateRequest {
+                    input: cue.clone(),
+                    source_lang: None,            // TODO
+                    target_lang: deepl::Lang::EN, // TODO
+                })
+                .await
                 {
-                    Ok(mut resp) => {
+                    Ok(translated) => {
                         TRANSLATIONS
                             .write()
                             .entry(stream_ix)
                             .or_insert(Vec::new())
-                            .push(resp.translations.pop().unwrap().text);
+                            .push(translated);
 
                         *next_cue_to_translate = *next_cue_to_translate + 1;
                     }
@@ -100,7 +101,45 @@ impl DeeplTranslator {
             }
         }
 
+        // check every second for new cues to be translated
         relm4::tokio::time::sleep(Duration::from_secs(1)).await;
         sender.input(DeeplTranslatorMsg::DoTranslate);
     }
 }
+
+#[derive(Clone)]
+struct TranslateRequest {
+    input: String,
+    source_lang: Option<deepl::Lang>,
+    target_lang: deepl::Lang,
+}
+
+impl Display for TranslateRequest {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "{:?}-{}:{}",
+            self.source_lang, self.target_lang, self.input
+        )
+    }
+}
+
+#[io_cached(
+    disk = true,
+    create = r#"{ util::make_cache("deepl_translations") }"#,
+    map_error = r#"|err| err"#
+)]
+async fn translate_text(req: TranslateRequest) -> anyhow::Result<String> {
+    let deepl = DeepLApi::with(&Settings::default().deepl_api_key()).new();
+    let mut requester = deepl.translate_text(req.input, req.target_lang);
+    requester.model_type(ModelType::PreferQualityOptimized);
+    if let Some(source_lang) = req.source_lang {
+        requester.source_lang(source_lang);
+    }
+    let translated = requester.await?.translations.pop().unwrap().text;
+
+    // try to respect deepl's rate-limit
+    relm4::tokio::time::sleep(Duration::from_millis(500)).await;
+
+    Ok(translated)
+}