向こう岸

最近はもっぱら同人イベントの参加記録

コミックマーケット97サークル参加告知

 

コミックマーケット97のサークル参加告知です。

サークル名:バイトニック
参加日:12/31(火・4日目)
配置場所:南リ09b

新刊:
コミケWebカタログ用ツール作ってみた Chromeウェブストア公開編」
自作Chrome拡張機能Chromeウェブストアへの公開の流れをメインに書いているプログラミングの本です。
下記について書いています。

  • 選択した文字列を右クリックメニューからWebカタログでサークル検索を行うChrome拡張機能Chromeウェブストアへの公開
  • 同人誌委託書店通販履歴ページ記載のサークル名をWebカタログで検索するChrome拡張機能の改修

頒布価格:200円

また、既刊も頒布します。

上記同人誌に二つ目のツールのソースを掲載していますが、コピペできるようにここでもソースのみ掲載します。

同人誌委託書店通販履歴ページ記載のサークル名をWebカタログで検索するChrome拡張機能

manifest.json
{
    "name": "Shop History To Comike Web Catalog Search",
    "version": "0.1.1",
    "permissions": [
        "https://ec.toranoana.jp/"
    ],
    "content_scripts": [
        {
            "matches": ["https://www.melonbooks.co.jp/mypage/history.php"],
            "js": ["content_script_common.js", "content_script_melon.js"]
        },
        {
            "matches": ["https://ec.toranoana.shop/ec/app/mypage/order_detail/*"],
            "js": ["content_script_common.js", "content_script_tora.js"]
        }
    ],
    "background": {
        "scripts": ["background.js"],
        "persistent": false
    },
    "manifest_version": 2
}
content_script_tora.js
const search = (event) => {
    // とらのあなの注文伝票ページにはサークル名が載っていない
    // 商品詳細ページへのリンク要素を取得
    var linkList = event.target.parentNode.querySelectorAll("table > tbody > tr > td > span > a");
    
    linkList.forEach((elem) => {
        // リンク先URLを分割してパラメータ取得
        var href = elem.href;
        var dirs = href.split('/');
        var tld = dirs[2].split('.').pop();
        var siteType = dirs[3];
        var itemType = dirs[4];
        var itemCode = dirs[6];

        // メッセージによりバックグラウントスクリプトで商品詳細ページを取得してサークル名を抽出する
        // 直接URLを渡さないのはセキュリティ考慮のため
        chrome.runtime.sendMessage(
            {
                contentScriptQuery: 'toraCircleName',
                tld: tld,
                siteType: siteType,
                itemType: itemType,
                itemCode: itemCode
            },
            (response) => openSearchWindow(response.circleName)
        );
    });
};

// 各注文のステータス・配送業者部分のdiv要素
var orderStatusElems = document.querySelectorAll("div.table-sp");

// 各div要素にボタン追加
orderStatusElems.forEach((elem) => {
    var searchButton = document.createElement("button");
    searchButton.type = "button";
    searchButton.innerText = "Webカタログでサークルを検索";
    searchButton.style ="margin-bottom: 5px;";
    searchButton.addEventListener("click", search, false);

    elem.insertBefore(searchButton, elem.querySelector("table"));
});
background.js
chrome.runtime.onMessage.addListener(
    (request, sender, sendResponse) => {
      if (request.contentScriptQuery == 'toraCircleName') {
        // とらのあなの商品詳細ページHTMLを取得し、サークル名を抽出する
        var tld = request.tld;
        var siteType = request.siteType;
        var itemType = request.itemType;
        var itemCode = request.itemCode;

        // パラメータを正規表現でチェックし、文字種に問題なければ取得実行
        if (/^\w+$/.test(tld) && /^\w+$/.test(siteType) && /^\w+$/.test(itemType) && /^\d+$/.test(itemCode)) {
            var url = `https://ec.toranoana.${tld}/${siteType}/${itemType}/item/${itemCode}/`;
            fetch(url)
                .then((response) => {
                    if(response.ok) {
                        return response.text();
                    } else {
                        throw new Error(response.statusText);
                    }
                })
                .then((text) => {
                    // 取得HTMLをパースし、サークル名を抽出して応答を返す
                    var dom = (new DOMParser()).parseFromString(text, "text/html");
                    var circleNameElem = dom.querySelector(
                        'div.product-info > div > div.sub-circle > div:nth-child(2) > span.sub-p > a > span');
                    sendResponse({circleName: circleNameElem.innerText});
                })
                .catch(error => console.error(error));

            // 非同期で結果を返す
            return true;
        }
      }
    });
content_script_common.js
const openSearchWindow = (circleName) => {
    // サークル名を検索
    // 全日程及び落選が対象
    // 全ジャンル対象
    var keyword = encodeURIComponent(circleName);

    // ジャンルコード追加変更時にはパラメータ変更要
    var url = `https://webcatalog.circle.ms/Search/Result?c.Keyword=${keyword}&c.op=0&c.d1=true&c.d1=false&c.d2=true&c.d2=false&c.d3=true&c.d3=false&c.d4=true&c.d4=false&c.dl=true&c.dl=false&c.cn=true&c.cn=false&c.ck=true&c.ck=false&c.ca=true&c.ca=false&c.cb=false&c.ct=false&c.ctw=false&c.cpi=false&c.cu=false&c.cm=false&c.cno=false&c.cfm=false&c.cmo=0&c.gls=111&c.gls=112&c.gls=113&c.gls=114&c.gls=115&c.gls=116&c.gls=211&c.gls=212&c.gls=213&c.gls=221&c.gls=232&c.gls=233&c.gls=234&c.gls=300&c.gls=311&c.gls=312&c.gls=313&c.gls=314&c.gls=315&c.gls=321&c.gls=331&c.gls=332&c.gls=333&c.gls=334&c.gls=400&c.gls=431&c.gls=432&c.gls=500&c.gls=511&c.gls=531&c.gls=532&c.gls=534&c.gls=535&c.gls=600&c.gls=611&c.gls=700&c.gls=711&c.gls=811&c.gls=812&c.gls=813&c.gls=831&c.gls=833&c.gls=836&c.gls=911&c.gls=912&c.gls=998&page=1&c.SortOrderBy=0`
    window.open(url);
}
content_script_melon.js
const search = (event) => {
    var circleList = event.target.parentNode.parentNode.querySelectorAll(
        "table tbody tr td p.circle");
    
    circleList.forEach((elem) => openSearchWindow(elem.innerText));
};

// 各注文のステータス・配送業者部分のdiv要素
var orderStatusElems = document.querySelectorAll("div.status");

// 各div要素にボタン追加
orderStatusElems.forEach((elem) => {
    var searchButton = document.createElement("button");
    searchButton.type = "button";
    searchButton.innerText = "Webカタログでサークルを検索";
    searchButton.style ="margin-top: 5px;";
    searchButton.addEventListener("click", search, false);

    elem.appendChild(searchButton);
});