COTOHA API を使ってツイートを色付けする Chrome 拡張機能を作った

# 背景

最近何かと暗いニュースばかりでネガティブなことをつぶやきがちです。
自分のツイートくらいポジティブにしたいものです。
また自分 TL 上でネガティブなツイートもあまり見たくありません。
Twitter にはミュート機能が備わっていますが、ネガツイートは突然 TL に現れるため完全に防ぐことは不可能です。

今回は COTOHA API を使ってネガティブなツイートが現れていないか確認するための拡張機能を作っていきます。

# 機能の概要

やっていることは非常に簡単です。
Twitter を開いたときにツイートを取得して COTOHA API でポジネガ判定をするだけです。
ツイートの収集には Chrome の拡張機能上で Javascript をゴリゴリ書いてテキストベースで取得する想定です。
ポジネガノ判定には COTOHA API を使います。

### 完成イメージ
![スクリーンショット 2020-03-01 20.10.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119099/21f04257-26e6-5183-ce9d-73f96052e4b6.png)

赤色がポジティブなツイート、緑色が普通、青色がネガティブなツイートです。


# ポジネガ判定

判定は [COTOHA API](https://api.ce-cotoha.com/contents/index.html) の感情分析 API を使いました。
レスポンスは以下のような形です。

```json

{
  "result":
    {
    "sentiment":"Positive",
    "score":0.20766788536018937,
    "emotional_phrase":[
      {
        "form":"謳歌",
        "emotion":"喜ぶ,安心"
      }
    ]
  },
  "status":0,
  "message":"OK"
}
```

判定にはレスポンス中の `sentiment` を使います。

Chrome の拡張機能のためにも Javascript で Cotoha API にリクエストします。

```javascript:CotohaClient.js
import dotenv from 'dotenv'
import {
  Client
} from 'node-rest-client'

dotenv.config()

const ACCESS_TOKEN_URL = 'https://api.ce-cotoha.com/v1/oauth/accesstokens'
const BASE_URL = 'https://api.ce-cotoha.com/api/dev/nlp/v1/sentiment'
const CLIENT_ID = process.env.CLIENT_ID
const CLIENT_SECRET = process.env.CLIENT_SECRET

const client = new Client()
client.registerMethod("getAccessToken", ACCESS_TOKEN_URL, "POST")

export const postSentiment = async (sentence) => {
  const token = await getToken()
  return new Promise(function (resolve) {
    const xhr = new XMLHttpRequest()
    xhr.open("POST", BASE_URL, false)
    xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8")
    xhr.setRequestHeader("Authorization", `Bearer ${token}`)
    xhr.onload = function () {
      const data = JSON.parse(xhr.response)
      resolve(data)
    }
    xhr.onerror = function () {
      console.log("error")
    }
    xhr.send(JSON.stringify({
      sentence: sentence
    }))
  })
}

const getToken = () => {
  const data = {
    grantType: "client_credentials",
    clientId: CLIENT_ID,
    clientSecret: CLIENT_SECRET
  }
  const args = {
    data: data,
    headers: {
      "Content-Type": "application/json"
    }
  }
  return new Promise(function (resolve) {
    client.methods.getAccessToken(args, (data, res) => {
      resolve(data.access_token)
    })
  })
}
```
COTOHA API へリクエストするために Access Token の発行が必要だったのでリクエストのたびに発行しています。
API へのリクエストは fetch API だとなぜかうまく行かずに古き良き `XMLHttpRequest` を使っています。

# Chrome 拡張機能開発

簡単なものであれば `manifest.json` と javascript ファイルがあればすぐに作ることができます。
manifest.json とは拡張機能に必要な情報を書くことができ、拡張機能の名前やアイコン、実行する js ファイルや実行タイミングなどが細かく設定できます。

今回用意したのは以下のような内容です。

```manifest.json
{
  "name": "Twitter PosiNaga Checker",
  "version": "1.0.0",
  "manifest_version": 2,
  "description": "Twitter PosiNega Check Chrome Extension",
  "content_scripts": [{
    "matches": ["https://twitter.com/hiracky16"],
    "js": [
      "bundle.js"
    ],
    "run_at": "document_end",
    "all_frames": true
  }]
}
```

`content_script` は実行する js ファイルの指定や特定のページで実行する場合の条件を記述できます。
ここで大事なのが `run_at` です。
この値で実行タイミングを指定することができるのですが、今回ツイートを取得するのは DOM 構築後が望ましいため `document_end` を明示的にしていしました。

ただツイートの情報は非同期で取得されいるため js の実行を待たなければなりません。
document_end のドキュメントを見ると DOM 構築後に実行はするがサブリソースなどを読み込む前、つまり js 実行前に拡張機能のスクリプトが走ってしまうことが記されています。

対象ページの js 実行を待って Chrome 拡張機能の js を実行する方法が以下の通りです。

参考というかここから拝借
https://stackoverflow.com/questions/13917047/how-to-get-a-content-script-to-load-after-a-pages-javascript-has-executed

```
window.addEventListener ("load", main, false);

var jsInitChecktimer = setInterval (main, 1000);
function main () {
  if (document.querySelector('hogehoge') != null) {
    clearInterval(jsInitCheckTimer)

    // do something
  }
}
 

```

`hogehoge` では js 操作の後に現れる要素を指定します。
この要素が存在したら晴れて拡張機能を実行することができます。
clearInterval は setInterval を解除する構文ですね、初めて使いました。

これで所望の機能は実現できるのですが、ツイート取得を待つの同時に COTOHA API へのリクエストが間に入ってしまってページがめちゃくちゃ重くなってしまいました。。（要改善ですがそもそもできないかも）

あとはいい感じに js を書いてツイート取得してさっき作った COTOHA API のクライアントに渡して上げればポジネガ判定ができます。
一応ソースコードはこちら。
https://github.com/hiracky16/TwitterPosiNegaChecker

今回は色を変えるだけですが、ネガティブなツイート自体を消し去ることも可能だと思います。

# まとめ

書いている途中に同じようなテーマで取り組まれている方が見つかって、クオリティの高さにおののきましたが負けじと公開しました。
https://qiita.com/yossymura/items/177610fbd58b783534f2

この調査結果を見ると、ネガティブなツイートは一部の有名人に向けてのものが殆どらしく、そんな人達こそこのツールを使ってほしい！と思いました。

COTOHA API には利用制限（ developer だと 1 日 1000 回）があるためリリースはしません。
このツールが必要ない世界になってほしいなと願っております。 :pray: