Back to Portfolio

Case Study · 03 · OSS · MIT

oneshot-zap

X の各ポストに⚡を足し、1 クリック で「スパム報告 → ブロック」まで実行する Chrome 拡張

Problem

スパム報告は、毎回 5 タップかかる

X に流れてくる露骨なスパムを処理するには、… → ポストを報告 → スパム → 次へ → ブロック → 完了 という多段のダイアログを毎回手で踏む必要がある。1 件なら大したことはないが、まとめて湧くスパムを相手にすると、この繰り返しがそのまま負担になる。

世にある「ワンクリックブロック」系の拡張は ブロックだけ で止まり、報告まではしてくれない。報告はプラットフォーム側の対処につながる一手なのに、面倒さゆえに省略されがち。報告も込みで一発で終わらせる道具が見当たらなかったので、自分で作った。

Approach

公式 UI の報告フローを、そのまま自動でなぞる

API ではなく 実際の報告フローを DOM 操作でなぞる 方針にした。コンテントスクリプトで各ポストのアクションバー右端に⚡ボタンを注入し、押されたら … → ポストを報告 → スパム → 次へ → ブロック → 完了 のダイアログを順に自動クリックして最後まで進める。結果はトーストで返す。公式 UI を借りることで、非公開 API に依存せず "人間がやる操作" の自動化に徹している。

この手の自動化の弱点は、X 側の DOM 変更でセレクタが壊れる こと。フロー定義を src/flow.ts に各ステップ(caret / report / 「スパム」/ Next /「さんをブロック」/ 完了)として一箇所に集約し、壊れたらそこだけ直せる形にした。タイミング依存も避けられないため、要素の出現を待つ前提でステップを組んでいる。

取り返しのつかない操作なので、安全側に倒した。初期状態では実行前に 確認モーダル を出し、オプションページから ON/OFF を切り替えられる(OFF で 1 クリック即実行)。日本語 UI 前提で文言セレクタを組むため、表示言語が日本語のときのみ動作する明示的な制約も置いた。「本物のスパムにのみ使う」前提を README とモーダルの両方で念押ししている。

ロジックは DOM から切り離してテストした。フロー進行を純粋な手続きとして書き、Vitest + happy-dom で各ステップのセレクタ解決と分岐を単体検証。ビルドは esbuild でバンドルし、pnpm dist が icons 生成 → typecheck → build を通して拡張ルートとなる dist/ を吐く流れにしている。

⚡ ワンクリック実行

各ポストのアクションバーに⚡を注入。1 押しで報告 → ブロックまでのダイアログを自動で踏破し、人手の 5 タップを 1 クリックに畳む。

報告 + ブロックの自動操作

ブロックのみで止まる類似拡張と違い、スパム報告のフローを最後まで自動で進めてからブロックする。プラットフォーム側の対処につなげる一手まで含む。

確認モーダル(切替可)

取り消し不可の操作なので、初期状態は実行前に確認を表示。オプションページのトグルで OFF にすると、確認なしの 1 クリック即実行に切り替わる。

壊れにくいフロー定義

DOM 依存のセレクタを src/flow.ts の各ステップに集約。X 側の UI 変更で壊れても、実フローを 1 度なぞって該当ステップだけ更新すれば復旧できる。

トースト通知

処理の成否をトーストで即時フィードバック。ダイアログが裏で進むため、何が起きたかを画面上で確認できるようにした。

Platform
Chrome 拡張 (Manifest / コンテントスクリプト + オプションページ)
Language
TypeScript 5 (strict, @types/chrome)
Build
esbuild (pnpm dist = icons → typecheck → build → dist/)
Testing
Vitest 2 + happy-dom (フロー進行の単体テスト)
Core
src/flow.ts — 報告→ブロックのステップ定義を集約
License
MIT (public repo)

Result

5 タップの操作が、⚡ひとつになった

c12o-dev/oneshot-zap として MIT で公開。pnpm dist でビルドした dist/ を「パッケージ化されていない拡張機能」として読み込めば動く。報告 → ブロックの多段ダイアログが⚡ひとつに畳まれ、スパム処理の手数が体感で大きく減った。

"取り消せない自動操作" という性質に正面から向き合い、デフォルトで確認モーダルを挟む / 日本語 UI に限定する / 本物のスパム限定を明記する、という安全側の設計を一通り入れている。便利さと不可逆性のトレードオフを、UI とドキュメントの両方で扱った題材になった。

Learnings

作って分かったこと

他人の DOM を自動化するなら、壊れる前提で設計する

X の UI はこちらの都合で変わる。セレクタとステップを flow.ts の 1 箇所に集約しておくと、壊れたときの修復が「実フローを 1 度なぞって直す」だけで済む。脆さは消せないので、直しやすさで受ける。

不可逆な操作には、摩擦をデフォルトで残す

1 クリック即実行は気持ちいいが、誤爆のコストが高い。確認モーダルを初期 ON にして、慣れたユーザーだけが自分で外せる設計にした。便利さは、安全のデフォルトを崩さずに段階的へ開ける。

DOM 自動化でも、ロジックは切り離せばテストできる

フロー進行を手続きとして DOM から分離し、happy-dom 上で Vitest にかけた。ブラウザ拡張=テスト不能と諦めず、セレクタ解決と分岐だけでも単体で固めると、リファクタの安心感がまるで違う。

言語前提は、隠さず明示的な制約にする

文言ベースのセレクタは表示言語に縛られる。これを曖昧に握りつぶさず「日本語 UI のときのみ動作」と明言したことで、想定外の環境での誤動作を設計段階で締め出せた。