ツタンラーメンの忘備録

プログラミングや精神疾患、ラーメンについて書いていきます。たぶん。

常に最新ツイートがトップに来るようなChrome ExtensionをTypescriptで作る(執筆中)

「ホーム」ではトップツイートが優先的に表示されます
「ホーム」ではトップツイートが優先的に表示されます
イラっとしますね(唐突)

Twitterは無駄に流れてくるタイムラインを眺めるのが楽しいのになんでデフォルトが「ホーム」なんでしょうか。

最新ツイートが投稿順に表示されます
最新ツイートが投稿順に表示されます

Twitter立ち上げるたびに最新ツイートに変更しています。

DBじゃなくてCookieで持っているんですかね。

むっちゃイライラするので、自動的に最新ツイートが投稿順に流れるようにするChrome Extensionを作りましょう。

qiita.com

これでひな型を作ります。

Would you like more UI Features?

と聞かれるので、ここだけ注意してください。まあ全部とりあえずぶち込んでおけばいいって考えてもいいですが(私は遊びだったので全部ぶち込みました)

Content Scripts にチェックを入れてください。

windows 10 なので yarn を入れる必要があったりするのですが、そこはよしなに入れていきましょう。 エラーが出たら入れて、を繰り返したら特に問題なく完了しました。


とりあえずぶち込んだら、

$ yarn install

します。場合によっては npm install でもいいんじゃないでしょうか(試していないですが…)。

そこまで時間がかからず入れ終わるはずなので

$ yarn run dev:chrome

実行!!

あとは dist/chromeChrome拡張としてChromeにぶち込みます。

chrome://extensions/ にアクセスして

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

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

更新したらこのくるっと矢印を押してください
更新したらこのくるっと矢印を押してください
私はけっこうここではまったんですけど、 app\scripts\contentscript.ts を編集しても chrome://extensions/ の該当Extensionのくるっと回っている矢印で更新しないと反映されません。 なんというトラップ

さてここから app\scripts\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);

(この段階では画面をロードした瞬間に「ホーム」と「最新ツイート」を切り替えます。) 動いているGif

作成したエクステンションの動作
作成したExtensionの動作


解説というよりはまりどころ

  • 画面ロード時と全体が表示されるタイミングが違う

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

  • TypeScriptの画面ロード完了後に読み込まれるメソッドは?

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

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

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

  • 3を決めたがいいがどうやって取得する?

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

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

ここも地味にはまりました。検索かけても取得する方法で発火させる方法は全然出てこない。 document.createEvent( 'MouseEvents' ); マウスイベントを作った?上で event.initEvent("click", true, true); クリックイベントを登録?して(すみません、残り二つの引数の意味わかっていないです。最初動かなくて適当に入れたら動きました…)、

timeline_change_star.dispatchEvent(event);

実際に発火させます。

  • タイムラインを切り変えるためのボタンはどう押す?

これも地味にはまりました。 idclass もあてにならないので。

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

こんな実装に…。

  1. initEvent 二回する意味ある?

今検討中です。


リポジトリも置いておきますが上記ファイル以外は何の意味もないファイルです。

github.com