常に最新ツイートが一番上に来るChrome Extensionを作るためにいろいろやったけど手動でやった方が早いなってなった話

## 完成図

![完成動画](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156882/a40d51e7-433d-a5ad-5511-03e7cca3040a.gif)

トップツイート順なら最新ツイート順に並べなおします。

## 私たちのTwitterを取り戻すために

![トップツイート](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156882/dc1d5d03-6bdd-cd40-25cc-b2e97e02404e.png)

なぜ？
Twitterはなぜトップツイートという概念を生み出したのか。

私はTwitterを情報垂れ流しツールという場として見ています。

フォーマルではなくフランクで、誰もとりつくろわず、みんながバカ騒ぎして楽しむ。そんな場だと思っていました。
私はTwitterが大好きでした。

Twitterはいつまでも変わらず、そばで僕を見てくれていると思っていました。

でも `facebook` が気になるのか、Twitterはもう私のそばで笑っていません。

![最新ツイート](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156882/b95c2f34-dba6-6859-2421-4143b8af9ebc.png)

毎回手動で最新ツイート順に直しています。

データベースで持っていないのか、少しすると「トップツイート」に戻っています。

毎回手動で「最新ツイート」をクリックして戻すのがいやなので、Chromeエクステンションを作ります。

## 準備

Chrome Extensionを作るのには準備がいるのでひな型を作ってもらいます。

[TypeScriptで簡単にChrome Extensionを作る方法](https://qiita.com/Takumon/items/da2142cc06b243f83211)

windowsだと簡単に動かないかな～～と思っていましたが、問題なかったです。

ひながたを作っていると

```
Would you like more UI Features?
```
みたいに聞かれます。何をするExtensionを作るか、を選択できます。

試しなので全部潜影蛇手すればいいんですが、最低限いるのは `Content Scripts` です。

windowsだと `yarn` を入れる必要があったりしますが、**なかったら入れる** でどうにかなりました。

---
とりあえずいい感じにぶち込んだら

```sh
$ yarn install
```
このとき「もしかして別に `npm install` でも大丈夫だったんじゃないか」と思いましたが、試していないのでわかりません。
すべてが入ったら

```sh
$ yarn run dev:chrome
```

を実行します。あとは
`dist/chrome` をエクステンションとして `Chrome` にぶち込みます。

`chrome://extensions/` にアクセスしてパッケージ化されていない拡張機能を読み込みます。
![パッケージ化されていない拡張機能を読み込む](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156882/ba50219c-6f8c-5ec7-b6f8-555430c514c0.png)

上記画像の「パッケージ化されていない拡張機能を読み込む」から `dist` 以下の `chrome` を読み込みます。

開発ツールからコンソールを見ると成功していればなんか出ていると思います。 `app\scripts\contentscript.ts` の `console.log` に対応しています。

![くるっと更新](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156882/3b0f18db-293b-b1f9-5f98-0a3631e62aea.png)

ちょっとはまったこととしては上記実行は `hotreload` みたいな感じで修正すれば動くんですけど `contentscript` に関しては画像の矢印(更新ボタン)を押さないと変更が反映されません。

## コードを書いていく

とりあえず**潜影蛇手**

```contentscript.ts
window.addEventListener("load", Main);

function Main():void {
  let event = document.createEvent( 'MouseEvents' );
  setTimeout(() => {
    const top_tweet_label = document.querySelector('[aria-label="トップツイートがオフになります"]');
    const home_tweet_label = document.querySelector('[aria-label="トップツイートがオンになります"]');
    let timeline_change_star = home_tweet_label === null ? top_tweet_label : home_tweet_label;
    event.initEvent("click", true, true);
    if(timeline_change_star !== null){
      timeline_change_star.dispatchEvent(event);
      setTimeout(() => {
        let button_change_timeline_change = document.querySelector('[role="menu"] [role="menuitem"]');
        event.initEvent("click", true, true);
        if(button_change_timeline_change !== null){
          button_change_timeline_change.dispatchEvent(event);
        }
      }, 500);
    }
  }, 4000);
```

このコードだと起動のたびに最新ツイートとトップツイートを入れ替えます。

## はまったところ

### 二回マウスイベントを発火させないといけない

一回目の星クリックで **「ホーム」ではトップツイートが優先的に表示されます** というのが出て、その下の「**最新ツイート表示に切り替える**」で実際に切り替えられます。

### 画面ロード時と全体描画のタイミングが違う

よくあることなんですかね…。
とりあえず

```ts
window.addEventListener("load", Main);
```
ってしたらよしなに読み込んでくれると思ったのですが、実際はちょっとずらしているっぽいです。 `React` の動作なのかな。 とりあえず `setTimeout` で4秒後に実行にします。 だいたい3.5秒くらいで（私の環境では）ロードされました。 これはネットワークなどによって異なるため、ほんまは繰り返して成功したタイミングで！！とかやりたかったんですけど、無限ループでブラウザ落ちて（正確には閉じることすらできなくなった）だめだったので、暫定対応です。

### 画面ロード完了後に読み込まれるメソッドは？

```ts
window.addEventListener("load", Main);
```
いつも `jQuery` 使っていたので知らなかったです。

### タイムラインを並び順を変更するボタンをどうやって取得する？

`Class` は難読化のためか、まったく規則性がなくて使えない。
`id` もけっこう上にしかついていなくて、取得できない。
諦めかけていたのですが、「トップツイートがオフになります」「トップツイートがオンになります」これだけは不変であるようでした。これを取得することに

```ts
document.querySelector('[aria-label="トップツイートがオフになります"]');
``` 
いつも `jQuery` 使っていたので `querySelector` 初めて使いました

このボタンを押せばタイムラインを変更できるボタンが画面に出てきます。

### マウスイベントをどうやって発火させる？（そもそもマウスイベントでやるべきなのか、まだ検討中です）

ここも地味にはまりました。検索かけても取得する方法で発火させる方法は全然出てこない。

```ts
document.createEvent( 'MouseEvents' );
```
マウスイベントを作った？上で

```ts
event.initEvent("click", true, true);
```
クリックイベントを登録？して（すみません、残り二つの引数の意味わかっていないです。最初動かなくて適当に入れたら動きました…）

```ts
timeline_change_star.dispatchEvent(event);
```
実際に発火させます。

**ディスパァァァッチ！！**


### タイムラインを切り変えるためのボタンはどう押す？
これも地味にはまりました。 `id` も `class` もあてにならないので。

```ts
document.querySelector('[role="menu"] [role="menuitem"]');
```

こんな実装に…。

### initEvent 二回する意味ある？
今検討中です。

## 結論

動作の読み込み待ったり面倒なので拡張はやめました。
今は手動でやっています。

## 所感
作るのは楽しかったです。
Twitterは普通に `created_at` でタイムラインを並べてほしいと切に願ってやみません。

facebookとはりあわなくていいのです。

## 落書き

Twitter始めてからもう十年になります。オフ会もたくさんしました。
私も学生、周りもわいわい楽しんでいました。

みな社会人になり、社会の波にのまれみんなのツイートは減っていきました。
うつ病になった友人もいます。

タイムラインは活気がなくなり、ネガティブな言葉が増えてきます。
くだらないやり取りは減り、1日100ツイートしていた人はいい企業に入ってライブなどに行き、愚痴をこぼしながらも楽しそうです。

結婚した人もいます。
周りのフォロワーのフォロワーくらいの人が次々と結婚していきます。

一方、出会いがないと嘆き、合コンや彼女が欲しいというツイートも増えました。

良いとか悪いとかではないのです。
単純に私のいたタイムラインはもうそこにはありません。