Twitterから「いいね」を消し去るChrome拡張を作る

#1. よくないね

|<img width="589" alt="スクリーンショット 2017-12-22 18.51.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/64284/d0dd1598-3192-3d6c-c768-e0b5fcfd6a9e.png">|
|:-:|

Twitterを使っていて、間違って「いいね」してしまったことはないでしょうか？
全てのツイートに対して表示される❤️マークを押したが最後、「本当にいいねしますか」などの確認は一切なく、たとえ話したことのない人であっても無慈悲に通知を送ってしまうのです。よくないですね。

|<img width="634" alt="スクリーンショット 2017-12-22 23.01.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/64284/5fb4c975-4dc9-7f7c-f0c5-b6f4f013d42a.png">　|
|:-:|

Twitterはツイートを押すことで詳細を表示します。こちらにのみ「いいね」ボタンを表示し、タイムラインに表示されるツイートからは「いいね」ボタンを非表示にしてみましょう。


#2. 消し去る
と言うわけでタイトル通りChrome拡張を使って「いいね」を消し去ります。
HTMLとCSS、javascriptができれば作れるそうなので早速作ってみましょう。
実行環境はGoogle Chromeとテキストエディタだけです。

適当なディレクトリを作成し、後述するファイルを置いた後、URLにchrome://extensionsと入力することで拡張機能をページを開きます。

|<img width="804" alt="スクリーンショット 2017-12-23 1.23.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/64284/b9db6cfd-ce14-b7c9-4cbd-03ab7d1be696.png">|
|:-:|

右上のデベロッパーモードにチェックを入れ、「パッケージ化されていない拡張機能を読み込む」を押すことで簡単に拡張を登録することができます。

*※「パッケージ化されていない拡張機能を読み込む」を実行した後、ソースコードを変更しても、Chrome上では変更前のものが適用されるようです。ソースコードの変更を適用するには「リロード」と書かれた文字を押すことで解消されます。*

# 3.Chrome拡張
## 3.1 ManifestとContentScripts
ContentScriptsは特定のURLに対してDOMを書き換えるなどの操作する時に有効です。今回はtwitter.com以下の全てのURLに対して適用されるように設定しました。

Chrome拡張は始めにmanifest.jsonファイルを読み込み、その内容によって大きく動作が変化します。まずはこのファイルを書くことから始めましょう。

```json:manifest.json
{
	//必須
	"manifest_version": 2,			//manifestバージョン
	"name": "HideTwitterContents",	//chrome拡張の名前
	"version": "1",					//chrome拡張のバージョン

	//特定のURL読み込み時にjsを実行
	"content_scripts": [
		//Twitter読み込み時
		{
			"matches": ["https://twitter.com/*"],
			"js": ["hide-like.js"]
		}
	]
}
```

このようなmanifest.jsonファイルを作成しました。
上3行の要素はこのChrome拡張についての情報で、必ず書かなければいけません。
content_scripts要素にmatchesとjsを指定することで、特定のURL読み込み時に特定のjavascriptを実行できます。

## 3.2 DOM操作

|<img width="1183" alt="スクリーンショット 2017-12-23 0.05.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/64284/b077b098-85ba-4619-13b9-c15f63bd660b.png">|
|:-:|

忌々しい「いいね」ボタンは、ProfileTweet-action--favoriteクラスを持つ要素です。
早速javascriptからDOMを操作して、HTML内にあるProfileTweet-action--favoriteクラスを持つHTML要素を抹消して行きましょう。

```js:hide-like.js
//要素を取得
var elements = document.getElementsByClassName('ProfileTweet-action--favorite');
//いいねが全て消えるまで
while(elements.length != 0){
	//いいねの要素を削除
	elements[0].parentNode.removeChild(elements[0]);
}
```

getElementsByClassNameを用いて「いいね」ボタンを特定し全て根絶やしにするプログラムです。

実際に実行してみましょう。

|<img width="589" alt="スクリーンショット 2017-12-23 1.14.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/64284/07ef7d62-2461-9a78-2600-093ae3696ebe.png">|
|:-:|

すごいです。本当に消えるとは。

しかし、このChrome拡張はページを読み込み時だけ動くので、動的に読み込まれるツイートには「いいね」ボタンがそのまま残ってしまいます。

## 3.3 MutationObserver
後から追加されたツイートに対しても「いいね」ボタン抹消の洗礼を受けてもらいましょう。
javascriptのMutationObserverを使います。今回はツイートを子に持つHTML要素、stream-itemsクラスを監視対象に設定しました。

```js:hide-like.js
//いいねを消し去る
function hide_like(){
	//要素を取得
	var elements = document.getElementsByClassName('ProfileTweet-action--favorite');
	while(elements.length != 0){
		//いいねの要素を削除
		elements[0].parentNode.removeChild(elements[0]);
	}
}

//オブザーバーの作成
var observer = new MutationObserver(hide_like);
//監視の開始
observer.observe(document.getElementsByClassName('stream-items')[0], {
    attributes: true,
    childList:  true
});
hide_like();
```

これで新しく読み込まれたツイートに対しても「いいね」ボタンを消し去ることができました。

## 3.4 ページ跨ぎ
どうやら、twitter.com内でページを跨いだときはContentScriptsが呼び出されないようです。
ページ跨ぎ時でも残る\<body\>タグに「stream-itemsクラス変更時hide_like()を呼び出す」と設定しておきましょう。

最終的なjavascriptは以下のようになりました。

```js:hide-like.js
//いいねを消し去る
function hide_like(){
	//要素を取得
	var elements = document.getElementsByClassName('ProfileTweet-action--favorite');
	while(elements.length != 0){
		//いいねの要素を削除
		elements[0].parentNode.removeChild(elements[0]);
	}
}

//ストリーム変更時にいいねを消し去る
function ObserveStream(){
	//オブザーバーの作成
	var observer = new MutationObserver(hide_like);
	//監視の開始
	observer.observe(document.getElementsByClassName('stream-items')[0], {
	    attributes: true,
	    childList:  true
	});
	hide_like();
} 
//body変更時にObserveStreamを設定する。
//オブザーバーの作成
var observer = new MutationObserver(ObserveStream);
//監視の開始
observer.observe(document.getElementsByTagName("body")[0], {
    attributes: true
});
```

これでもう二度と「いいね」ボタンを間違って押すことはありません。

# 4. まとめ

+ 特定のサイトのHTMLを書き換える場合、ContentScriptsのChrome拡張が最適。
+ MutationObserverを使えば特定のHTML要素の変更を監視できる。
+ twitter.com内の移動はContentScriptsが呼ばれない。

jsを書き換えれば、twitter.com内の様々な要素を非表示にできるかもしれません。

[github](https://github.com/hal1437/HideTwitterContents)でソースコード公開してます。

# 参考文献

[Chrome拡張の開発方法まとめ　その1：概念編](https://qiita.com/edit-mode/items/26d7a22233ecdf48fed8#content-script)

[JavaScriptのMutationObserverでDOMの変化を監視する方法](https://qiita.com/munieru_jp/items/a6f1433652124a2165e4)