詩と創作・思索のひろば

ドキドキギュンギュンダイアリーです!!!

Fork me on GitHub

ページ内のテキストを読めなくするChrome拡張を作った

世はまさにハイパーメディア時代。何をするにも視覚的なキャッチがないとやっていけない時代です。ブラウザのスクリーンショットを撮ることも多いでしょう。しかしプライベートな内容もそこに映り込んでしまうこともありがち。かといって画像をいちいち加工するのも面倒……というわけで、DOM操作によってテキストを隠す拡張を作りました。

GitHub - motemen/webextension-obfuscate-texts

2022-07-20 追記: Chrome Web Store に出ました

Obfuscate texts - Chrome ウェブストア

Manifest V3 で作ったせいでほかのブラウザは未対応。

スクリーンキャスト

Chrome extension: Obfuscate texts - YouTube

ページ内の要素を選択し、「Obfuscate」することで▗​▝​▌​▏​▇​▁みたいな文字列に置き換えます。スタイルシートがそのまま適用されるのでページに馴染みますね。

ほかにもいくつか様子を載せておきます。

以下は開発中に気づいたことや困ったことをランダムに。

文字幅を計算してる

やってることは見てのとおり、文書中のテキストをランダムなユニコードのブロック文字で置き換えているだけだけど、細かくいろいろやっている。ひと文字をひとつのブロック文字で置き換えると、元がアルファベットのときに横幅が広くなって元々の見た目と乖離するので、Canvas を使って文字の幅を計算してだいたい合うようにしている。

ゼロ幅スペース(U+200B)を挟む

同様にスタイルを崩さないために、文字にゼロ幅スペースを挟んでいる。これをしないと、うまいこと折り返しがおこなわれずに横長の要素が発生してしまう。

フレーム内のテキストは隠せない

Chrome 拡張の制限。ページ内のテキストの置き換えを行うにはページにアクセスする権限が必要だが、そのために最初からあらゆる URL(*://*/*)の権限を要求するのはあまりに行儀が悪い。activeTab なら、ユーザがアクションを起こしたタブのページに対してのみ権限をもらえて、これが適切。しかしこの場合フレーム内にはアクセスできないらしい。ページ内のテキストをすべて不可読にしようとしても、広告やソーシャルボタンだけ生き残っていて人類滅亡後の世界っぽくなる。

452944 - Add activeTab.allFrames permission - chromium

Shadow DOM 内のテキストも隠せない

これは Selection の都合らしい。最近シャドードムが増えてきたのでちょっと困る。

もともと3年前のアイデアだった

https://motemen.hatenablog.com/entry/2019/06/gas-taskcal のスクリーンショットを撮るのに同じようなことをしていたけど、このときは手作業でやってた。

Googleカレンダーをターミナルからキーボードで操作する

全部キーボードで済ませたいシリーズです。

多忙な現代人の一日はその日の予定チェックから始まるわけです。普段であれば定期的な間隔で組まれたミーティングのリズムに身を委ねればいいわけですが、そこに非定型的なミーティングが紛れ込んでくる。これは採用面接など外部との機会であることが多く、そのぶん重要です。事前に入れてあるものを避けて予定を組もうとすると、参加者の数に応じて困難さが増していくので、ある程度は既存のものに被せて予定に招待してもらうことにしていると、いつの間にかダブルブッキングの嵐になっている。直前になって慌てて一方のミーティングに参加しないことを告げる……みたいなことを繰り返していてはいけませんね。

そういうわけで事前にカレンダーの重複を確認して、必要に応じて辞退したり再調整したりしたい。だけどそれを Google カレンダーのウェブ UI からマウスでポチポチやるのは非常につらい……。一応キーボードショートカットもあるんだけど、予定に応じる・辞退するのに tab キーを何度も叩く必要があり、効率的とは言えない。

そこで今回はターミナルで動く Google カレンダークライアントを作ってみたいと思います! 自分の要求は:

  • ある日の自分の予定を一望できる
  • 重複している予定がすぐにわかる
  • 予定への承諾・辞退が簡単にできる
  • 以上をキーボードで簡単に実現できる

作ったのがこちら。

GitHub - motemen/gcal-tui

こんな感じに動きます

人工的な予定で例を示すと、こんな感じ。

Screencast

ポイントは

  • j/k によるナビゲーションだけでなく、
  • tab でアクションの必要な予定にジャンプできる
    • 返事をしていない招待や、重複のある予定など
    • 重複のある予定のグループは ! マークで表示される
  • A または D で予定の招待に即座に返答できる
  • キャプチャには登場しないけど、もっと細かいことをしたければ o で Google カレンダーを開くこともできる

という点。これでキーボードから手を離すことなく予定の整理ができるようになった。われながら便利。

使い方

Google Cloud で OAuth 用の認証情報を取得する必要がある。これを JSON 形式でダウンロードして、<config_home>/gcal-tui/credentials.json に配置する。config_home は Go の os.UserConfigDir で得られるようなもの。

こういった手元用のツールで自分のための認可ができればよい場合には Application Default Credentials (ADC) を使うのがよい、と id:pokutuna に教えてもらったけど、なんかスコープによってはうまくいかないことがあるようで挙動が読めなかったので OAuth に逃げた。これが ADC でできるなら手数が減ってうれしい……。

今後の研究

Patches welcome です。

  • 予定の詳細ページがほしい
  • 予定を移動する機能がほしい
    • これは相手のスケジュールを調べたりしないといけないのでけっこう大変そう
  • 予定を辞退する際にコメントを残したい
  • メールに添付された ical ファイルをこれで開いて、特定の予定の詳細を開けるようにしたい
    • Google カレンダーの予定詳細ビュー、カレンダーの中のどこを示してるのかぜんぜんわからないので……

参考文献

YouTube 動画を字幕によるナビゲーションつきで埋め込める Web Component を書いた

前の記事 でそうしていたんだけど、YouTube には字幕をつけられるので、ページに埋め込んだ際にその字幕までテキストとして表示してやれば親切である。ついでにそこまで早送りしてくれるとなおいい。

前回はべたっと書き下したものを、再利用性に期待して web component として書いてみる。できあがりは以下のような感じで使えるようになる。

<youtube-transcription-player videoid="<videoId>" vttsource="<vttSource>"></youtube-transcription-player>

vttSource は WebVTT 形式のリソースへの URL か、またはテキストが WebVTT であるような要素への #ID

ただし任意の動画について字幕を簡単に取得できる API はないようなので、自分で取得・生成する必要がある。自分がアップロードした動画であれば、自動生成された字幕を編集・ダウンロードできるので、それを使うのがよい、と思う。

リポジトリはこちら。

GitHub - motemen/webcomponent-youtube-transcription-player

デモもある。自分のまともな動画が前回のエントリのために撮ったものしかないので、同じサムネを2週間ほど見続けることになって頭がおかしくなりそうだ。

このデモにあるとおり、

<script type="module" crossorigin src="https://motemen.github.io/webcomponent-youtube-transcription-player/youtube-transcription-player.es.js"></script>

してやると <youtube-transcription-player> タグを使いはじめられます。

さらに JSPM という CDN の提供している importmap を使えば、バンドルせずに使用もできるらしい: youtube-transcription-player jspm demo - CodeSandbox

Lit で Web Component を作る

Web Component のためのフレームワークはいろいろあるようだけど、Lit を使ってみた。むかし触ったことのある Polymer の精神的後継のようだった。コードを書く部分については特に困りごともなかったと思う。

しかし作りはじめるためのスターターキットが

とたくさんあってその関係もわからないのだった……。最終的に @open-wc/create というものを使った。これはコンポーネントを公開するところまで含めたタスクが用意されていて手厚かった。あとビルド関係もシンプルで、最初は Vite とかも出てこない。これは Modern Web という勢力の Going Buildless という思想に依るようで、ブラウザが賢くなっていくのであればトランスパイラやバンドラはいらないよね……ということらしい。まあ ES Module 対応してない npm モジュールをなんとかするコードを書く羽目にはなったし、<script> でかんたんに呼び出せるようにバンドラも入れたけど。

はてなで一緒に働きませんか?