たなちの備忘録

自分の知識をストックしていくためのブログ

【SHOWROOM】星集めを自動化してみた2【Chrome拡張】

スポンサーリンク

前回つくったものは流石に使いにくすぎたので改良。 画面にボタンをつけて、指定した数のタブを公式枠の配信者のものだけ開くようにした。

ファイルは以下の通り。

.
├── background.js
├── myscript.js
├── jquery-2.1.1.min.js
├── manifest.json
├── icon16_star.png
└── star_btn.png

manifest.json

  "web_accessible_resources": [
    "*"
  ],
  "background": {
    "scripts": [
      "jquery-2.1.1.min.js",
      "background.js"
    ],
    "persistent": false
  }

前回のコードに付け足したのは、「web_accessible_resources」と「background」。

web_accessible_resources

Webページで使用するリソースのパスを指定する。今回はディレクトリを切っていないけど、imageやcss等を使用するときに使用する。

Manifest - Web Accessible Resources - Google Chrome

background

文字通り、常にバックグラウンドで動いてるページ。拡張機能を一元管理する目的で使う。Webページに挿入しないため、「Content Scripts」のようなAPI利用制限はない。「Content Scripts」には次のような特徴がある。

・chrome.*APIが一部のものしか用いることが出来ない(公式ドキュメントを参照)
・ページ内で定義されている変数や関数にアクセスができない(DOMにはアクセスできる)

Chrome拡張の開発方法まとめ その1:概念編 - Qiita

"persistent": falseにすると必要になったら動き、不必要になったら遊休状態になり、メモリが開放されるようになるとのこと。Event Page方式らしい。

参考: Chromeのオリジナル拡張機能を開発しよう(ソースコードあり) | 株式会社LIG

myscript.js

$(function() {

    // ボタンの属性設定
    $('<button>').attr({
        type: 'button',
        id: 'collectStarBtn',
    }).appendTo('▲▲▲▲▲▲'); // ▲は「ジャンル」のIDあたりを適当に

    $('#collectStarBtn').text('星集め');

    var imgURL = chrome.extension.getURL("star_btn.png");
    $('<img>').attr({
        id: 'collectStarImg',
        width: "12",
        height: "12",
        src: imgURL
    }).appendTo('#collectStarBtn');

    $('#collectStarBtn').click(function() {

        var limitStr = window.prompt("配信中の画面を開きますか?タブ数を入力してください(最大:20)", "10");

        // キャンセル
        if(limitStr == null){
            exit;
        }

        var limit = parseInt(limitStr, 10);

        if(!Number.isNaN(limit)){
                
            if(limit > 20 || limit < 1){
                window.alert('1~20の値を入力して下さい。');
                exit;
            }

            var url = "";
            var roomName = "";
            var domain = "https://www.showroom-live.com";
            var list = $('xxxxxxx'); // 入室のクラス名

            var tabCnt=0;

            for(var i=0, l=list.length; i<l; i++) {
                roomName = document.getElementsByClassName('xxxxxxxxxx')[i].getAttribute('href');
                console.log(roomName.slice(1)); 

                    // アマチュア枠の判定     
                    if(roomName.slice(1).match(/[^0-9a-f]/)){
                        url = domain + roomName;
                        // メッセージ送信する
                        chrome.runtime.sendMessage(url);
                        tabCnt++;
                    }
                    // 指定した数のタブを開くと停止
                    if (tabCnt >= limit){
                        break;
                    }
                };
        }else{
                window.alert('入力値が不正です。');
        }
    });
});

ボタンの画像に設定するリソースのパスを読み込む。imgタグのsrcにリソースを指定する。

var imgURL = chrome.extension.getURL("star_btn.png");

chrome.extension - Google Chrome

アマチュア枠の判定は、URLが16進数かどうかで区別できるので正規表現を使用して行う。

if(roomName.slice(1).match(/[^0-9a-f]/)){}

正規表現チェッカー PHP: preg_match() / JavaScript: match()

javascriptでparseInt()を使用する場合は、第二引数に基数を指定する必要がある。そうしないと、10進数と認識されずに想定外の値が返されることがあるとのこと。

第1引数のstringが「0」で始まるときは、第2引数のradixは8(8進法)または10(10進法)とされます。厳密には、基数がどちらになるかは実装によります。ECMAScript 5 の仕様では10(10進法)です。ただし、まだすべてのブラウザがサポートしている訳ではありません。したがって、parseInt()関数を使うとき基数は必ず与えてください。

parseInt() - JavaScript | MDN

var limit = parseInt(limitStr, 10);

Content Scriptで使用できないAPIを使用するために、メッセージを使用する。content_script.jsのchrome.runtime.sendMessageが実行されると、Background Page側でchrome.runtime.onMessageイベントが発火する。渡したパラメータをbackground.jsで受け取って処理する。

// メッセージ送信する
chrome.runtime.sendMessage(url);

background.js

ここでは、URLを指定してタブを生成してそのタブの情報を取得する。ツイートボタンをクリックする処理書けば、勝手にツイートしてくれる。

タブの生成が成功したらcallback関数で、処理を呼び出している。

chrome.runtime.onMessage.addListener(function (message) {
    chrome.tabs.create({
        url: message
    }, OnTabCreated);
});

function OnTabCreated(tabInfo)
{
    console.log("tab id:" + tabInfo.id);
    // xxxxはボタンのクラス名
    chrome.tabs.executeScript(tabInfo.id, {code: "document.getElementById('xxxxxxxx').click();"}, null);
    setTimeout(() => {
        chrome.tabs.remove(tabInfo.id)
    }, 60000);
}

(追記)もしツイートする文言を変えるなら、こんな感じ。●●●●はテキストエリアのクラス名

chrome.tabs.executeScript(tabInfo.id
    , {code: "\
    var defaultText = document.getElementById('●●●●').value; \
    var postText = 'hoge' + defaultText;\
    document.getElementById('●●●●').value = postText;\
    document.getElementById('xxxxxxxx').click();"}
    , null);

タブの情報を取得するのに必要な情報は下記のリンクが参考になった。

chrome.tabs - Google Chrome

Y.A.M の 雑記帳: Google Chrome Extension タブの情報を取得

デバッグページ

また、background.js のデバッグを行うページは、拡張機能の管理ページで該当の拡張機能の下に表示されている「バックグラウンド ページ」のリンクをクリックすると表示される。content scriptは拡張機能を実行するページでデバッグできるが、background.jsは異なる。