ユーザースクリプトでWebサイトを改造する

# ユーザースクリプトでWebサイトを改造する

## はじめに

　ユーザースクリプトは自分のブラウザーに設定しておくJavaScriptです。特定のアドレスにアクセスした際に発動するスクリプトを設定しておくことで、他の人が作ったサイトを独自のページに作り替えることができます。

　入力が面倒なフォームに一瞬で入力できるよう自動入力ボタンを作ったり、大した文章量もないのに複数ページに記事を分けるニュースサイトで記事全体を1ページに結合するということもできます。

　あくまで自分のブラウザーに設定しているスクリプトなので、他の人が同じサイトにアクセスした場合は通常のサイトが表示されます。

　ユーザースクリプトはブラウザーで表示しているWebページ上で実行させるので、ログインを自分で実装する必要がありません。APIを呼び出す必要もないので開発者登録も不要です。ログイン後のページにスクリプトを仕掛けておき、Cookieを送信すればよいだけです。

　その代わり、クロスオリジンの制約を受けます。ユーザースクリプトのために都合良くクロスオリジンを許可してくれたりしないので、異なるオリジンにはアクセスできません。ただ、そもそもの用途からすると十分かと思います。

　また、ユーザースクリプトは自分のブラウザーで動けばいいので古いブラウザとの互換性は気にする必要がありません。自分のブラウザーが対応している分にはclassもfetchもasync/awaitも使い放題です。babelやpolyfilも使わなくて大丈夫です。

## Tampermonkeyを導入する

　ユーザースクリプトを実行するためのブラウザ拡張は複数ありますが、私が使ってるのはTampermonkeyです。Tampermonkeyは[Firefox版](https://addons.mozilla.org/ja/firefox/addon/tampermonkey/?src=search)、Chrome版、Edge版それぞれあります。

　なお、私はFirefoxを使ってますので、このあと記載するスクリプトはFirefoxで動かしています。Edgeは構文エラーでしたが、Chromeは初期表示ができるところまでは確認済みです。

## 404ページにスクリプトを設定

　基本的にはユーザースクリプトは既存のページをちょっとだけ変える用途だと思いますが、大きく改造したい場合は本来の機能を阻害しないように適当な404ページに設定します。そして、もともとのコンテンツを捨ててしまって自分で新たにDOMを構築します。

　ひとまず、ここの時点のコードが次の通りです。ここでは「はてな匿名ダイアリー」の特定の404ページにアクセスし、コンテンツをごっそり消しています。ただ、ヘッダーは欲しくなることもあるので残してます。`#app`の配下にタグを追加する想定です。

```javascript
// ==UserScript==
// @name         カスタマイズ版匿名日記
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @require      https://cdn.jsdelivr.net/npm/vue
// @require      http://localhost/files/js/dayjs.min.js
// @match        https://anond.hatelabo.jp/customized
// @grant        none
// ==/UserScript==

class AnonymousDiary {
  constructor() {
    const original = document.createElement('div');
    document.body.appendChild(original);
    original.id = 'original';

    const app = document.createElement('div');
    document.body.appendChild(app);
    app.id = 'app';

    Array.apply(null, document.body.childNodes)
      .filter(child => child.id != 'original' && child.id != 'app')
      .forEach(child => {original.appendChild(child);});

    const queryForHide = '#hatena-anond, #original > p, #original > h1';
    Array.apply(null, document.querySelectorAll(queryForHide)).forEach(node => {
      node.style = 'display:none'
    });
  }
}

new AnonymousDiary();
```

## ライブラリを追加する

JavaScriptのライブラリを追加するのはファイル先頭のコメント部分に`@require`の行を追加するだけです。

```javascript
// @require      https://cdn.jsdelivr.net/npm/vue
// @require      http://localhost/files/js/dayjs.min.js
```

スタイルシートはもっと適切な追加方法があるのか分かりませんが、`<style>`タグを動的に追加します。

```javascript
const head = document.getElementsByTagName('head')[0];

const styleLink = document.createElement('link');
head.appendChild(styleLink);
styleLink.setAttribute('rel', 'stylesheet');
styleLink.setAttribute('type', 'text/css');
styleLink.setAttribute('href', 'https://bootswatch.com/4/litera/bootstrap.min.css');
```

## fetchで本来のページを取得する

ここはあまり説明できることが少ないのですが、次のようなコードを実行すると元々のコンテンツのDOMを取得できるので、それで404ページに独自のコンテンツを作り上げます。

```javascript
class AnonymousDiary {
  async getItems({page}) {
    const response = await fetch('https://anond.hatelabo.jp/?mode=top&page=' + page);
    const html = await response.text();
    const dom = new DOMParser().parseFromString(html, "text/html");

    // dom.bodyで<body>を取得できるのでなんやかんや実行する;
  }
}
new AnonymousDiary().getItems({page: 1});
```

## スクリーンショット

　上記の続きをひととおり実装したものをGitHubのリポジトリにアップロードしてあります。

https://github.com/kakei-akihiko/customized-anonymous-diary

　このリポジトリの`UserScript.js`をTampermonkeyに追加し、はてなラボにログインした状態で https://anond.hatelabo.jp/customized へアクセスすると次のスクリーンショットのようになります。

　上が改造版、下が通常のはてな匿名ダイアリーです。

![Sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157704/93c6323c-9901-95c5-539b-a31591466b11.png)

　あらためて見比べてみると、古い方へ5ページ移動するリンクを付け足すだけでもよかったんじゃないかという気もしてきます。