Twitchのチャットを翻訳するChrome拡張を作ってみた

Twitchの英語チャットを日本語に自動翻訳するChrome拡張を作ってみました。
「作ってみた」程度のレベルなので、きちんと翻訳したい方は回れ右してください。
![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248832/b2250714-d1de-ba45-6785-375b302931c1.png)
## 概要
* Chrome Extension Manifest V3で開発
* Google App Script経由でGoogle Translation APIを利用
* Mutation observerでDOM要素の変更を監視、チャットが追加されたら自動で翻訳

## リポジトリ
[mimonelu/twitch-chat-translator](https://github.com/mimonelu/twitch-chat-translator)

## 詳細
### 翻訳APIの準備
まずは翻訳APIです。当然のようにGoogle Translation APIを使いますが、ご存知のように基本有料なので、 [こちらの記事](https://qiita.com/tanabee/items/c79c5c28ba0537112922) を参考に、Google App Scriptの翻訳機能を経由して利用することにしました（つまり利用者各位が自前で用意する必要があります）。
ただこれもご存知のように、 [1日あたりのアクセス数が5000回に制限](https://developers.google.com/apps-script/guides/services/quotas) されます。まぁ十分でしょう。

スクリプトを用意したらデプロイします。アクセスできるユーザーは当然「全員」、取扱注意です。
![screenshot 2022-05-04 16.46.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248832/f43f4ec7-1590-4d35-e054-8f980c19c4ed.png)
その後、発行されたデプロイIDを `background.js` の `XXXXXXXX` にコピペします。
![screenshot 2022-05-04 16.47.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248832/86e467dc-f9c5-e681-5d56-256c8ad83d80.png)

```javascript
const apiUrl = 'https://script.google.com/macros/s/XXXXXXXX/exec?source=en&target=ja&text=__TEXT__'
```

### Chrome拡張の準備
次に拡張機能本体を用意します。とは言ってもリポジトリをご覧の通り、2ファイルだけです。これらをテキトーなフォルダに入れて chrome://extensions/ を開き、 `パッケージ化されていない拡張機能を読み込む` からフォルダ直下を選択すれば準備完了です。
試しに [Twitch](https://www.twitch.tv/) のテキトーな配信画面で拡張機能を起動してみてください。間違いなくエラーが発生します。

### CORSの壁を（チートで）クリア
エラーは `background.js` の `fetch()` によるCORSが原因です。そこで当初は `manifest.json` に `host_permissions` などを追加したりしてみましたが、解消できませんでした。どうも最近のChrome拡張では `Access-Control-Allow-Origin` に `*` かSame Originを設定していない外部エンドポイントにはアクセスできないようです、たぶん。しかし昔はできたような？でも今はどうやってもできませんでした…。
というわけで、CORSを強制的に無効化するChrome拡張 [Cross Domain - CORS](https://chrome.google.com/webstore/detail/cross-domain-cors/mjhpgnbimicffchbodmgfnemoghjakai/related?hl=ja) を利用することにします。ズルです。でもいいんです、機能すれば。趣味だし。で、利用するには「Cross Domain - CORS」を起動し、 `https://www.twitch.tv/*` を `Add` 、そして `Save` すればOKです。
ただ、このアプリでCORSを無効化できるのであれば、やっぱり頑張れば無効化することができるんでしょうか？それともManifest Versionの違いでしょうか？Chrome拡張には疎いので今後の宿題にしますね（そして忘れる）。

### 新規チャットも自動で翻訳
以上で翻訳はできるようになりましたが、新しく追加されたチャットも自動で翻訳されるようにしたいですよね。ここは手っ取り早く `MutationObserver` でチャット欄のDOMを監視することにしました。特に言及することはないんですが、一点、 `MutationObserver.observe()`
 の第2引数には気を遣う必要がありそうです。中でも `subTree` と `childList` はDOM構造によっては値を変更する必要があるかもしれません。

### 実はブックマークレットでも可
「Cross Domain - CORS」を使っても良いのであれば、ブックマークレットでも実現可能であることに後から気付きました。ぎゃふん。だいぶ簡略化してはいますが、例えば以下のような感じでしょうか。

```javascript
javascript: (() => { document.querySelectorAll('[data-a-target="chat-message-text"]').forEach((node) => { const isTranslated = node.getAttribute('data-translated') === 'true'; if (!isTranslated) { node.setAttribute('data-translated', 'true'); fetch(`https://script.google.com/macros/s/XXXXXXXX/exec?source=en&target=ja&text=${node.innerText}`).then(async (response) => { const json = await response.json(); node.innerText = json.text; }); } }); })(); void 0;
```

## 課題
課題は腐るほどありますが、対応する予定は特にありません。
* 機能のON/OFFができない
* 英語→日本語しか想定していない
* バリデーションが不十分
* 原文を見ることができない／戻せない（ `title` 属性値に設定してはいるものの、不便）
* TwitchのDOM構造がリニューアルなどで変更された場合への対処がない
* TwitchのAPIを使うべきでは？

そもそもチャットを翻訳する必要性自体あまりないんですが（お下品なコメントも多いし）、趣味なので良しとします。
![www.twitch.tv_gladd(Desktop).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248832/0b49ec45-e636-ed0a-60eb-e6d0bd1c6bf8.png)