Google Chromeの拡張を作ってみたい② 画像置換

スポンサーリンク
スポンサーリンク

画像を置換

画像を置換するやつを作りたいけど、そんなすぐ書ける人でもないので、そういう拡張を作った記事があったのでそちらを読む。

Chrome Extension Tutorial — Replace Images in Any Website with Pikachu
What’s a better way to learn how to make a Chrome extension than making the web cuter with Pikachu images?

画像をピカチュウに置き換えるやつ。

スポンサーリンク

manifest.json

{
  "name": "Pikachu Everywhere",
  "version": "0.1",
  "description": "Replace every image with Pikachu images.",
  "manifest_version": 2,
  "icons": {
    "16": "assets/images/icon16.png",
    "32": "assets/images/icon32.png",
    "48": "assets/images/icon48.png",
    "128": "assets/images/icon128.png"
  }
}

ここは特に変わらず。こちらの拡張は、コンテンツスクリプトを使うみたい。なので

,
    "content_scripts": [{
        "matches": [""],
        "all_frames": true,
        "js":      ["assets/js/contentScript.js"]
    }]

と追記。matchesが適用サイト。all_framesが指定されたURL要件に一致するすべてのフレームに挿入するか、タブの一番上のフレームにのみ挿入するかを指定、フレームってなんですかね。jsがcontentScript.jsを置いてる場所で相対パスでフォルダ作ってそん中に入れた。

スポンサーリンク

contentScript.js

確認

console.log("Pikachu Everywhere - Content Script is Running");

取りあえず動くか確認用。

動いとりますね。

ピカチュウAPI

Some Random Api • 404

こちらを使う。これ面白いね。アクセスすると

{"link":"https://i.imgur.com/oH5Vi6I.gif"}

みたいなJSONを返してくれるサイトみたい。

流れ

  1. Webページ上のすべての画像要素を取得します。
  2. APIにGETリクエストを実行して、ランダムなピカチュウ画像リンクを取得します。
  3. 画像要素のsrc属性を、取得したリンクに置き換えます。

ふむふむ。この2のところがコンテンツスクリプトだけじゃできないから、その部分はバックグラウンドを使うみたい。コンテンツスクリプトはWebページ依存だけど、バックグラウンドはそうじゃないから、クロスオリジンリクエストを処理できる、のか。クロスオリジンリクエストっつーのはAのサイトに書かれたjsからBのサイトにリクエストを投げるみたいなことらし。これはさせないようにしてるってことなんかな。

コンテンツスクリプトから送信されたバックグラウンドスクリプトでメッセージをリッスンします。Webページが開くたびに、コンテンツスクリプトが実行され、画像のURLを要求するメッセージをバックグラウンドスクリプトに送信します。バックグラウンドスクリプトは、その後、ピカチュウAPIへの非同期呼び出しを実行し、リンクを取得してコンテンツスクリプトに送り返します。

っていう流れ。難しそ。

sendMessege

コンテンツスクリプトとバックグラウンドスクリプトのやり取りっていうのがメッセージでやるらしい。とりあえずコンテンツスクリプトからメッセージを送信する。

let images = document.getElementsByTagName('img');
for(let i = 0; i < images.length; i++){
  chrome.runtime.sendMessage({msg: 'image', index: i}, function({data, index}){
    images[index].src = data.link;
  });
}

画像要素を取得してから、その全てをなめてく。chrome.runtime.sendMessageでメッセージ送る。メッセージはJSON形式のオブジェクトで、ここでは形式と、画像のインデックスを送ってるみたい。メッセージが返ってきたらコールバックが呼ばれる。dataが多分APIの取得結果が入って、indexは送ったデータがそのまま返ってくるような感じかなぁ。ほんでimgタグのsrcに返答のデータのリンクを設定するみたいな感じかね。

スポンサーリンク

background.js

background.jsでメッセージを受け取って、APIでJSONを受け取って、それをコンテンツスクリプトに返す。

chrome.runtime.onMessage.addListener(function (message, sender, senderResponse) {
    if (message.msg === "image") {
        fetch('https://some-random-api.ml/pikachuimg')
            .then(response => response.text())
            .then(data => {
                let dataObj = JSON.parse(data);
                senderResponse({ data: dataObj, index: message.index });
            })
            .catch(error => console.log("error", error))
        return true;  // Will respond asynchronously.
    }
});

chrome.runtime.onMessage.addListenerは設定するとメッセージが送られてくるのを待つみたいなやつ。で、送られてきたらコールバック関数を実行する感じ。messageに送られてきたデータ、senderが送ってきた対象、senderResponseが送り返すデータ(JSON)。message.msg === “image”でコンテンツスクリプトから送られてきたデータかを判断してから、fetchする、fetchってなんですか。

Fetch の使用
従来、このような機能は XMLHttpRequest を使用して実現されてきました。 Fetch はそれのより良い代替となるもので、サービスワーカーのような他の技術から簡単に利用することができます。 Fetch は CORS や HTTP 拡張のような HTTP に関連する概念をまとめて定義する場所でもあります。

説明があった。HTTPでのやり取りを分かりやすくやってくれるやつみたい。ネットワークでのやり取りは応答待ちがあって、待ってる間に処理が次に進んだりしちゃうと困るから、応答が来てから次の処理に進むみたいな時に使うやつみたい。非同期処理ってやつか。ちゅーことで、

fetch(‘https://some-random-api.ml/pikachuimg’)でAPIにアクセス。この=>矢印みたいなのはアロー関数とかアロー式っていうらしい。thenっていうのが、アクセスした結果が返ってきたら、って感じで、これだけで非同期な処理ができるようでっす。初めてなので、アロー関数を使わない書き方にすると

.then(function (response) {
    return response.text()
})

こんな書き方になるはず。だからAPIにリクエスト送った返事をテキストに変換してるんだと思う。そんでdata、このdataはどっから出てきたんだと思ったけど多分textに変換した結果が入ってんだろうな、を、JSON形式にパースして、senderResponseにdataとindexをつけて入れて返すみたい。この時senderResponseはコンテンツスクリプト内のプログラムで使えるような形式じゃないとだめだし、この場合dataObjの中にはAPIから取得した

{"link":"https://i.imgur.com/oH5Vi6I.gif"}

が入ってるはず。catchはfetch中にエラーが起きたらそこに飛んでエラーですよってコンソールに表示するやつ。return trueが、このリスナ内の処理は非同期処理がありますよーってやるために書くみたい。これが無いと、非同期処理であることを無視して処理が次に進むらしい。そんで、APIを利用してる時は、manifestに許可が必要みたい。

,
    "permissions": [
        "https://some-random-api.ml/*"
    ]

うむ。

スポンサーリンク

結果

試しにブログトップに行ってみたら

あれ?広告とアイコンぐらいしか変わってない。なんでだろーと思ってソース見てみたらエントリーのとこに使われてる画像はsrcじゃなくて、data-srcとかsrcsetとかがあった。

data-srcはよく分かんなかったので、srcsetの方に変えてみたら

変わってないのもあるけどほぼなった。webむつかしーね。

コメント

タイトルとURLをコピーしました