支援者現在コメ数データ表示(sm125732)

任意の名前のコメント合計と今日のコメント数・月累計・「〇時〇分現在」を取得して表示

// ==UserScript==
// @name         支援者現在コメ数データ表示(sm125732)
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  任意の名前のコメント合計と今日のコメント数・月累計・「〇時〇分現在」を取得して表示
// @match        https://www.nicovideo.jp/watch/sm125732*
// @grant        GM_xmlhttpRequest
// @connect      sosuteno.com
// ==/UserScript==

(function() {
    'use strict';

    if (window.commentPanelCreated) return;
    window.commentPanelCreated = true;

    let monthlyUrl = "https://sosuteno.com/jien/Index/202508user.html";

    // 現在の年月をYYYYMM形式で取得してURL差し替え
    const now = new Date();
    const yyyy = now.getFullYear();
    const mm = String(now.getMonth() + 1).padStart(2, "0");
    const yyyymm = `${yyyy}${mm}`;
    monthlyUrl = monthlyUrl.replace(/Index\/\d{6}user\.html$/, `Index/${yyyymm}user.html`);

    const liveUrl = "https://sosuteno.com/jien/Live/index2c.html";
    const todayUrl = "https://sosuteno.com/jien/Live/index2c.html";

    let total = 0;        // 月間合計
    let liveValue = 0;    // 本日(index2c.html)
    let todayValue = 0;   // 今日(index2c.html)
    let monthlySum = 0;   // 月累計(index2c.html)
    let currentText = ""; // 「〇時〇分現在」
    let completed = 0;

    // ===== 入力キーワード保存・読み込み =====
    const STORAGE_KEY = "commentKeyword";
    let keyword = localStorage.getItem(STORAGE_KEY) || "支援者名";

    function createPanel() {
        const container = document.createElement("div");
        container.style.cssText = `
            position: fixed !important;
            bottom: 20px !important;
            right: 20px !important;
            background-color: rgba(0,0,0,0.85) !important;
            color: white !important;
            padding: 12px !important;
            border-radius: 8px !important;
            z-index: 99999 !important;
            font-size: 16px !important;
            font-family: 'Meiryo'!important;
            white-space: pre-line !important;
            font-weight: bold !important;
        `;

        // 入力欄
        const input = document.createElement("input");
        input.type = "text";
        input.value = keyword;
        input.placeholder = "キーワードを入力";
        input.style.cssText = `
            width: 150px !important;
            margin-bottom: 6px !important;
            padding: 2px 4px !important;
        `;
        input.addEventListener("change", () => {
            keyword = input.value.trim() || "支援者名";
            localStorage.setItem(STORAGE_KEY, keyword);
        });

        // 表示領域
        const display = document.createElement("div");
        display.id = "commentResult";
        display.style.marginTop = "6px";

        container.appendChild(input);
        container.appendChild(display);
        document.body.appendChild(container);
    }

    function updateDisplay() {
        const panel = document.querySelector("#commentResult");
        if (panel) {
            panel.innerText =
                 currentText + "\n\n" +// ←「〇時〇分現在」
                "月間: " + total + " (" + monthlySum + ")\n"+
                "本日: " + liveValue + " (" + todayValue + ")";
        }
    }

    function fetchElectrode(url, isLive) {
        GM_xmlhttpRequest({
            method: "GET",
            url: url,
            responseType: "arraybuffer",
            onload: function(response) {
                let value = 0;
                try {
                    let decoder = new TextDecoder("shift-jis");
                    let text = decoder.decode(response.response);
                    let parser = new DOMParser();
                    let doc = parser.parseFromString(text, "text/html");
                    let tds = Array.from(doc.querySelectorAll("td"));
                    for (let i = 0; i < tds.length - 1; i++) {
                        if (tds[i].textContent.trim() === keyword) {
                            value = parseInt(tds[i + 1].textContent.trim(), 10) || 0;
                            break;
                        }
                    }
                } catch (e) {
                    value = 0;
                }
                total += value;
                if (isLive) liveValue = value;
                checkCompleted();
            },
            onerror: function() {
                if (isLive) liveValue = 0;
                checkCompleted();
            }
        });
    }

    function fetchToday(url) {
        GM_xmlhttpRequest({
            method: "GET",
            url: url,
            responseType: "arraybuffer",
            onload: function(response) {
                let tValue = 0;
                let mSum = 0;
                try {
                    let decoder = new TextDecoder("shift-jis");
                    let text = decoder.decode(response.response);

                    // 今日のコメント数
                    const today = new Date();
                    const yyyy = today.getFullYear();
                    const mm = String(today.getMonth() + 1).padStart(2, "0");
                    const dd = String(today.getDate()).padStart(2, "0");
                    const dateStr = `${yyyy}-${mm}-${dd}`;
                    const todayRegex = new RegExp(dateStr + "のコメント数: *(\\d+)");
                    const todayMatch = text.match(todayRegex);
                    if (todayMatch) {
                        tValue = parseInt(todayMatch[1], 10) || 0;
                    }

                    // 月累計
                    const monthRegex = /月累計: *(\d+)/;
                    const monthMatch = text.match(monthRegex);
                    if (monthMatch) {
                        mSum = parseInt(monthMatch[1], 10) || 0;
                    }

                    // 「〇時〇分現在の分集計データ」
                    const timeRegex = /(\d{1,2}時\d{1,2}分現在)の分集計データ/;
                    const timeMatch = text.match(timeRegex);
                    if (timeMatch) {
                        currentText = timeMatch[1];
                    } else {
                        currentText = "";
                    }
                } catch (e) {
                    tValue = 0;
                    mSum = 0;
                    currentText = "";
                }
                todayValue = tValue;
                monthlySum = mSum;
                checkCompleted();
            },
            onerror: function() {
                todayValue = 0;
                monthlySum = 0;
                currentText = "";
                checkCompleted();
            }
        });
    }

    function checkCompleted() {
        completed++;
        if (completed === 3) {
            updateDisplay();
        }
    }

    createPanel();
    fetchElectrode(monthlyUrl, false);
    fetchElectrode(liveUrl, true);
    fetchToday(todayUrl);

})();