LoginSignup
2
0

[Tauri]クリップボードの文字を自動翻訳してデスクトップ通知で表示するアプリ

Last updated at Posted at 2023-10-12

はじめに

今回はTauriを使ってクリップボードの値を読み取って、自動翻訳しデスクトップ通知として表示するアプリを作成したので紹介します。

通知

このように通知を表示できます。
image_2.png

作る経緯

最近英語学習として英語のスクリプト付きの動画を見ているのですが、ちょくちょく分からない単語が出てきます。
別にその都度 コピー -> 別ブラウザのGoogle翻訳を開く -> ペーストとしてもいいのですが、この作業が意外と面倒なので同じ画面上に翻訳が出てくれるアプリを作ったら便利なのではと思い作成しました。

使用する外部ライブラリ

フロント

  • tailwindcss ... HTML内で直接スタイリングを作れる
  • react-hot-toast ... 簡単にフロントに通知機能を実装できる

バックエンド

  • reqwest ... httpリクエストを簡単に送信できる
  • tokio ... 非同期処理を行う
  • dotenv ... 環境変数を.envからロードできる
  • clipboard ... クリップボードを読み取りできる
  • lazy_static ... スレッド間で安全な値を扱える

コード解説

クリップボードの内容を取得する方法ですが、clipboardクレートを使用しています。
このクレートはget_contentsメソッドを使用し現在のクリップボードの値を取得できます。
なので、1秒間隔でクリップボードの値を取得し、前回の値と違っていた場合にその後の翻訳処理をおこなっています。
tokio::spawnrun関数を新しいタスクで実行しているのは、この関数がloopしていて、処理が終わらない(LOOP_FLAGがfalseになるまで)ためです。
また、 新しくタスクを生成し非同期関数をそのタスク内で行う場合、.awaitをまたいでSendトレイトを実装していない値は存在できません。そのため、ctxflagはその前にドロップするようにしています。

commands.rs
use crate::{config, transition};
use clipboard::{ClipboardContext, ClipboardProvider};
use lazy_static::lazy_static;
use reqwest;
use std::sync::Mutex;
use std::time::Duration;
use tauri::Window;

pub const BUNDLE_IDENTIFIER: &str = "com.taiyou.tauri-transition-helper";

// loop処理をしているかは `LOOP_FLAG` で管理
lazy_static! {
    static ref LOOP_FLAG: Mutex<bool> = Mutex::new(false);
}

#[tauri::command]
pub async fn start_monitor_from_flont(window: Window) {
    let _join = tokio::spawn(async move {
        run(window).await;
    });
}

#[tauri::command]
pub async fn stop_transition() {
    // lockで他のスレッドからは読み書きできないようにする
    let mut flag = LOOP_FLAG.lock().unwrap();
    *flag = true;
}

async fn run(window: Window) {
    let config_instance = config::Config::new().expect("Failed to load config");
    let api_key = config_instance.api_key;

    let mut ctx: ClipboardContext = match ClipboardProvider::new() {
        Ok(context) => context,
        Err(e) => {
            eprintln!("{}", e);
            return;
        }
    };

    let mut last_clipboard_content = String::new();
    let mut contents = None;

    let client = reqwest::Client::new();

    loop {
        {
            let flag = LOOP_FLAG.lock().unwrap();
            if *flag == true {
                break;
            }
        }

        // クリップボードからテキストを取得
        contents = match ctx.get_contents() {
            Ok(ctx_contents) => Some(ctx_contents),
            Err(e) => {
                eprintln!("Error: {}", e);
                None // エラーが発生した場合はNoneを設定
            }
        };

        // `content` が Some(value) であり、`last_clipboard_content` と異なる場合
        if contents.as_ref() != Some(&last_clipboard_content) {
            if let Some(c) = contents {
                println!("New clipboard content: {}", c);
                last_clipboard_content = c;

                // ここで翻訳とデスクトップ通知を行う
                match transition::run(&api_key, &last_clipboard_content, &client).await {
                    Ok(translated_text) => {
                        // 通知
                        if let Err(e) = window.emit("issueNotification", Some(translated_text)) {
                            eprintln!("Failed to emit event: {}", e);
                        }
                    }
                    Err(e) => {
                        eprintln!("Error: {}", e.to_string());
                    }
                }
            }
        }

        // 1秒待機(ポーリング間隔)
        tokio::time::sleep(Duration::from_secs(1)).await
    }

    // ループが終了したらFLAGをfalseにリセット
    let mut flag = LOOP_FLAG.lock().unwrap();
    *flag = false;
}

実際にアプリを使う

時前準備

このアプリを使うには時前準備が必要です...。
翻訳には Cloud Translate API というAPIを使っているのですが、APIの使用にはAPIキーが必要なのでまずはそれを取得しなければいけません。
といっても、簡単なので以下のような手段で取得しましょう。
https://webloco.webolha.com/other/google-translation-api/

料金に関して

このAPIは月々500,000文字まで翻訳が無料なので個人で使用するには全く問題ありません。
料金詳細はこちらから

アプリ取得方法

Mac

APIキーを取得したら、上記のGitHubページのReleaseからdmgファイルをダウンロードしてください。

Windows

少し面倒ですがGitHubリポジトリをcloneしてから、ローカルでbuildしてください。

おわりに

今回は、クリップボードを監視し取得した値を翻訳しデスクトップ通知で表示するアプリを作成しました。
もしも、間違った内容もっと良い書き方などありましたら、コメントで教えてくださるととても助かります。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0