PokerHistory

Records all Poker history.

当前为 2024-02-24 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         PokerHistory
// @namespace    http://www.torn.com/
// @version      1.2
// @description  Records all Poker history.
// @author       bot_7420 [2937420]
// @match        https://www.torn.com/page.php?sid=holdem*
// @run-at       document-body
// @grant        GM_addStyle
// ==/UserScript==

(function () {
  "use strict";

  let db = null;
  let messageBoxObserver = null;

  initIndexDB();

  window.onload = function () {
    initCSS();
    initControlPanel();
    initPokerObserver();
  };

  function initIndexDB() {
    const openRequest = indexedDB.open("scriptPokerHistoryDB", 1);
    openRequest.onupgradeneeded = function (e) {
      console.log("PokerHistory: initIndexDB open onupgradeneeded");
      db = e.target.result;
      if (!db.objectStoreNames.contains("messageStore")) {
        console.log("PokerHistory: initIndexDB open onupgradeneeded create store");
        const objectStore = db.createObjectStore("messageStore", { keyPath: "autoId", autoIncrement: true });
      }
    };
    openRequest.onsuccess = function (e) {
      console.log("PokerHistory: initIndexDB open onsuccess");
      db = e.target.result;
    };
    openRequest.onerror = function (e) {
      console.error("PokerHistory: initIndexDB open onerror");
      console.dir(e);
    };
  }

  function dbWrite(message) {
    if (!db || !message) {
      return;
    }

    const transaction = db.transaction(["messageStore"], "readwrite");
    transaction.oncomplete = (event) => {
      //console.log("PokerHistory: dbWrite transaction oncomplete [" + message.text + "]");
    };
    transaction.onerror = (event) => {
      console.error("PokerHistory: dbWrite transaction onerror [" + message.text + "]");
    };

    const store = transaction.objectStore("messageStore");
    const request = store.put(message);
    request.onsuccess = (event) => {};
  }

  function dbReadAll() {
    if (!db) {
      console.error("PokerHistory: dbReadAll db is null");
    }

    const transaction = db.transaction(["messageStore"], "readonly");
    transaction.oncomplete = (event) => {
      console.log("PokerHistory: dbReadAll transaction oncomplete");
    };
    transaction.onerror = (event) => {
      console.error("PokerHistory: dbReadAll transaction onerror");
    };

    const store = transaction.objectStore("messageStore");
    return new Promise((resolve, reject) => {
      const resultList = [];
      store.openCursor().onerror = (event) => {
        resolve(resultList);
      };
      store.openCursor().onsuccess = (event) => {
        const cursor = event.target.result;
        if (cursor) {
          resultList.push(cursor.value);
          cursor.continue();
        } else {
          resolve(resultList);
        }
      };
    });
  }

  function initPokerObserver() {
    const $poker = $("div.holdemWrapper___D71Gy");
    const observerConfig = { attributes: false, childList: true, subtree: false };
    const observer = new MutationObserver(() => {
      reObserveMessageBox();
    });
    if ($poker.length === 1) {
      console.log("PokerHistory: observe poker page");
      observer.observe($poker[0], observerConfig);
      reObserveMessageBox();
    }
  }

  function reObserveMessageBox() {
    console.log("PokerHistory: reObserveMessageBox");
    if (!messageBoxObserver) {
      messageBoxObserver = new MutationObserver((mutated) => {
        handleMessageBoxChange(mutated);
      });
    }
    messageBoxObserver.disconnect();
    const $messageWrap = $("div.holdemWrapper___D71Gy div.messagesWrap___tBx9u");
    const observerConfig = { attributes: true, childList: true, subtree: false };
    messageBoxObserver.observe($messageWrap[0], observerConfig);
  }

  function handleMessageBoxChange(mutated) {
    if (mutated.length >= 40) {
      console.log("PokerHistory: handlePokerBoxChange disregarded " + mutated.length);
      return;
    }

    for (const mutation of mutated) {
      for (const node of mutation.addedNodes) {
        if (node.classList.contains("message___RlFXd")) {
          let message = {
            timestamp: new Date().getTime() / 1000,
            text: node.innerText,
          };
          dbWrite(message);
        }
      }
    }
  }

  function initCSS() {
    const isDarkmode = $("body").hasClass("dark-mode");
    GM_addStyle(`.poker-control-panel-popup {
                        position: fixed;
                        top: 10%;
                        left: 15%;
                        border-radius: 10px;
                        padding: 10px;
                        background: ${isDarkmode ? "#282828" : "#F0F0F0"};
                        z-index: 1000;
                        display: none;
                      }

                      .poker-control-panel-results {
                        padding: 10px;
                      }

                      .poker-control-player {
                        margin: 4px 4px 4px 4px !important;
                        display: inline-block !important;
                      }

                      .poker-control-panel-overlay {
                        position: fixed;
                        top: 0;
                        left: 0;
                        background: ${isDarkmode ? "#404040" : "#B0B0B0"};
                        width: 100%;
                        height: 100%;
                        opacity: 0.7;
                        z-index: 900;
                        display: none;
                      }

                      .poker-control-panel-item {
                        display: inline-block;
                        margin: 2px 2px 2px 2px;
                      }`);
  }

  function initControlPanel() {
    const $title = $("div#top-page-links-list");
    if ($title.length === 0) {
      console.log("PokerHistory: nowhere to put control panel button");
    }
    const $controlBtn = $(`<a id="pokerHistoryControl" class="t-clear h c-pointer right last">
                                  <span class="icon-wrap svg-icon-wrap">
                                    <span class="link-icon-svg">
                                        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 10.33"><defs><style>.cls-1{opacity:0.35;}.cls-2{fill:#fff;}.cls-3{fill:#777;}</style></defs><g id="Слой_2" data-name="Слой 2"><g id="icons"><g class="cls-1"><path class="cls-2" d="M10,5.67a2,2,0,0,1-4,0,1.61,1.61,0,0,1,0-.39A1.24,1.24,0,0,0,7.64,3.7a2.19,2.19,0,0,1,.36,0A2,2,0,0,1,10,5.67ZM8,1C3,1,0,5.37,0,5.37s3.22,5,8,5c5.16,0,8-5,8-5S13.14,1,8,1ZM8,9a3.34,3.34,0,1,1,3.33-3.33A3.33,3.33,0,0,1,8,9Z"></path></g><path class="cls-3" d="M10,4.67a2,2,0,0,1-4,0,1.61,1.61,0,0,1,0-.39A1.24,1.24,0,0,0,7.64,2.7a2.19,2.19,0,0,1,.36,0A2,2,0,0,1,10,4.67ZM8,0C3,0,0,4.37,0,4.37s3.22,5,8,5c5.16,0,8-5,8-5S13.14,0,8,0ZM8,8a3.34,3.34,0,1,1,3.33-3.33A3.33,3.33,0,0,1,8,8Z"></path></g></g></svg>
                                    </span>
                                  </span>
                                  <span>PokerHistory</span>
                                </a>`);
    $title.append($controlBtn);

    const $controlPanelDiv = $(`<div id="pokerControlPanel" class="poker-control-panel-popup">control</div>`);
    const $controlPanelOverlayDiv = $(`<div id="pokerControlOverlayPanel" class="poker-control-panel-overlay"></div>`);
    $controlPanelDiv.html(`
        <textarea readonly id="poker-results" cols="120" rows="30"></textarea>
        `);

    $title.append($controlPanelDiv);
    $title.append($controlPanelOverlayDiv);

    $controlBtn.click(function () {
      dbReadAll().then((result) => {
        let text = "";
        for (const message of result) {
          const timeStr = formatDateString(new Date(message.timestamp * 1000));
          text += timeStr + " " + message.text + "\n";
        }
        text += "Found " + result.length + " records\n";
        const $textarea = $("textarea#poker-results");
        $textarea.val(text);
        $textarea.scrollTop($textarea[0].scrollHeight);
      });

      $controlPanelDiv.fadeToggle(200);
      $controlPanelOverlayDiv.fadeToggle(200);
    });

    $controlPanelOverlayDiv.click(function () {
      $controlPanelDiv.fadeOut(200);
      $controlPanelOverlayDiv.fadeOut(200);
    });
  }

  function formatDateString(date) {
    const pad = (v) => {
      return v < 10 ? "0" + v : v;
    };
    let year = date.getFullYear();
    let month = pad(date.getMonth() + 1);
    let day = pad(date.getDate());
    let hour = pad(date.getHours());
    let min = pad(date.getMinutes());
    let sec = pad(date.getSeconds());
    return year + "/" + month + "/" + day + " " + hour + ":" + min + ":" + sec;
  }
})();