🏠 Home 

雀魂 Mortal 举报小帮手

自动选择 "Mortal 3.0" 并勾选 "显示 rating",同时在牌谱 URL 输入框旁添加复制按钮,并在「关于」弹框中添加截图按钮

  1. // ==UserScript==
  2. // @name 雀魂 Mortal 举报小帮手
  3. // @name:zh-TW 雀魂 Mortal 舉報小幫手
  4. // @name:zh-CN 雀魂 Mortal 举报小帮手
  5. // @name:ja 雀魂 Mortal レポートアシスタント & 牌譜 URL コピー & テーブルキャプチャ
  6. // @name:en Mahjong Soul Mortal Report Assistant & Copy Log URL & Table Capture
  7. // @author Scott
  8. // @version 0.5
  9. // @description 自动选择 "Mortal 3.0" 并勾选 "显示 rating",同时在牌谱 URL 输入框旁添加复制按钮,并在「关于」弹框中添加截图按钮
  10. // @description:zh-TW 自動選擇 "Mortal 3.0" 並勾選 "顯示 rating",同時在牌譜 URL 輸入框旁添加複製按鈕,並在「關於」彈框中添加截圖按鈕
  11. // @description:zh-CN 自动选择 "Mortal 3.0" 并勾选 "显示 rating",同时在牌谱 URL 输入框旁添加复制按钮,并在「关于」弹框中添加截图按钮
  12. // @description:ja "Mortal 3.0" を自動選択し、"表示 rating" をチェックし、牌譜 URL 入力欄にコピーボタンを追加し、「關於」彈框にスクリーンショットボタンを追加
  13. // @description:en Automatically select "Mortal 3.0" and check "Show rating", and add a copy button next to the log URL input field, and add a screenshot button in the "About" dialog
  14. // @match *://mjai.ekyu.moe/*
  15. // @grant none
  16. // @license MIT
  17. // @namespace https://greasyfork.org/zh-CN/users/1284613
  18. // ==/UserScript==
  19. (function () {
  20. "use strict";
  21. // ==================== 举报小帮手功能 ====================
  22. function selectMortalNetwork() {
  23. const selectElement = document.querySelector("#mortal-model-tag");
  24. if (selectElement) {
  25. selectElement.value = "3.0";
  26. selectElement.dispatchEvent(new Event("change", { bubbles: true }));
  27. }
  28. }
  29. function checkShowRating() {
  30. const ratingCheckbox = document.querySelector('input[name="show-rating"]');
  31. if (ratingCheckbox && !ratingCheckbox.checked) {
  32. ratingCheckbox.checked = true;
  33. ratingCheckbox.dispatchEvent(new Event("change", { bubbles: true }));
  34. }
  35. }
  36. function initReportHelper() {
  37. selectMortalNetwork();
  38. checkShowRating();
  39. }
  40. // ==================== 复制牌谱 URL 功能 ====================
  41. function addCopyButton() {
  42. const label = document.querySelector('label.radio');
  43. if (label) {
  44. const copyButton = document.createElement("button");
  45. copyButton.type = "button"; // 指定按钮类型
  46. copyButton.id = "copy-url-button";
  47. copyButton.className = "copy-button";
  48. copyButton.textContent = "复制 URL";
  49. label.appendChild(copyButton);
  50. }
  51. // 添加样式
  52. const style = document.createElement("style");
  53. style.textContent = `
  54. .copy-button {
  55. margin-left: 10px;
  56. padding: 5px 10px;
  57. background-color: #4CAF50;
  58. color: white;
  59. border: none;
  60. border-radius: 4px;
  61. cursor: pointer;
  62. }
  63. .copy-button:hover {
  64. background-color: #45a049;
  65. }
  66. `;
  67. document.head.appendChild(style);
  68. // 复制功能
  69. const inputField = document.querySelector('input[name="log-url"]');
  70. const copyButton = document.getElementById("copy-url-button");
  71. if (inputField && copyButton) {
  72. // 点击按钮复制
  73. copyButton.addEventListener("click", (event) => {
  74. event.preventDefault(); // 阻止默认行为
  75. event.stopPropagation(); // 阻止事件冒泡
  76. inputField.select();
  77. inputField.setSelectionRange(0, 99999); // 兼容移动设备
  78. document.execCommand("copy");
  79. alert("URL 已复制到剪贴板!");
  80. });
  81. // 点击输入框自动复制
  82. inputField.addEventListener("click", () => {
  83. inputField.select();
  84. inputField.setSelectionRange(0, 99999); // 兼容移动设备
  85. document.execCommand("copy");
  86. alert("URL 已复制到剪贴板!");
  87. });
  88. }
  89. }
  90. // ==================== 截取表格功能 ====================
  91. function addScreenshotButton() {
  92. // 找到「如遇界面 Bug,请提交问题至 GitHub。」這一句的元素
  93. const bugReportText = document.querySelector('#about-body-0 li:last-child span');
  94. if (bugReportText) {
  95. console.log('找到「如遇界面 Bug,请提交问题至 GitHub。」的文字元素,準備添加按鈕...');
  96. // 創建截圖按鈕
  97. const screenshotButton = document.createElement("button");
  98. screenshotButton.innerText = "截取表格";
  99. screenshotButton.style.marginLeft = "10px";
  100. screenshotButton.style.padding = "5px 10px";
  101. screenshotButton.style.backgroundColor = "#007bff";
  102. screenshotButton.style.color = "#fff";
  103. screenshotButton.style.border = "none";
  104. screenshotButton.style.borderRadius = "4px";
  105. screenshotButton.style.cursor = "pointer";
  106. // 將按鈕插入到指定文字的下方
  107. bugReportText.parentNode.insertBefore(screenshotButton, bugReportText.nextSibling);
  108. // 點擊按鈕時觸發截圖功能
  109. screenshotButton.addEventListener("click", function () {
  110. console.log("截圖按鈕被點擊,開始截圖...");
  111. // 獲取要截圖的 tbody 元素
  112. const tbodyElement = document.querySelector(".about-metadata tbody");
  113. if (tbodyElement && tbodyElement.children.length > 0) {
  114. console.log("找到 tbody 元素,內容如下:", tbodyElement.innerHTML);
  115. // 創建一個 canvas 元素
  116. const canvas = document.createElement("canvas");
  117. const ctx = canvas.getContext("2d");
  118. // 設置 canvas 大小
  119. const padding = 20; // 內邊距
  120. const cellHeight = 30; // 單元格高度
  121. const cellWidth = 150; // 單元格寬度
  122. const rows = tbodyElement.querySelectorAll("tr");
  123. const cols = rows[0].querySelectorAll("td").length;
  124. canvas.width = cols * cellWidth + padding * 2;
  125. canvas.height = rows.length * cellHeight + padding * 2;
  126. // 設置背景顏色
  127. ctx.fillStyle = "#ffffff"; // 白色背景
  128. ctx.fillRect(0, 0, canvas.width, canvas.height);
  129. // 設置表格樣式
  130. ctx.strokeStyle = "#000000"; // 黑色邊框
  131. ctx.lineWidth = 1;
  132. ctx.font = "14px Arial";
  133. ctx.textAlign = "center"; // 文字居中
  134. ctx.textBaseline = "middle"; // 文字垂直居中
  135. // 繪製表格內容
  136. let y = padding;
  137. rows.forEach((row) => {
  138. let x = padding;
  139. const cells = row.querySelectorAll("td");
  140. // 繪製單元格邊框
  141. ctx.strokeRect(x, y, cellWidth * cols, cellHeight);
  142. cells.forEach((cell) => {
  143. // 繪製單元格背景顏色
  144. ctx.fillStyle = "#f0f0f0"; // 灰色背景
  145. ctx.fillRect(x, y, cellWidth, cellHeight);
  146. // 繪製單元格文字
  147. ctx.fillStyle = "#000000"; // 黑色文字
  148. ctx.fillText(cell.innerText, x + cellWidth / 2, y + cellHeight / 2);
  149. x += cellWidth;
  150. });
  151. y += cellHeight;
  152. });
  153. // 將 canvas 轉換為圖片
  154. const image = canvas.toDataURL("image/png");
  155. // 創建一個鏈接元素,用於下載圖片
  156. const link = document.createElement("a");
  157. link.href = image;
  158. link.download = "Mortal.png"; // 設置圖片名稱
  159. link.click();
  160. console.log("圖片已生成並觸發下載。");
  161. } else {
  162. console.error("未找到指定的表格內容或內容為空!");
  163. alert("未找到指定的表格內容或內容為空!");
  164. }
  165. });
  166. } else {
  167. console.error("未找到「如遇界面 Bug,请提交问题至 GitHub。」的文字元素!");
  168. }
  169. }
  170. // ==================== 初始化 ====================
  171. function init() {
  172. initReportHelper(); // 初始化举报小帮手功能
  173. addCopyButton(); // 初始化复制牌谱 URL 功能
  174. // 監聽「關於」按鈕的點擊事件
  175. const aboutButton = document.querySelector("#about");
  176. if (aboutButton) {
  177. aboutButton.addEventListener("click", function () {
  178. // 等待彈出對話框內容加載完成
  179. setTimeout(() => {
  180. addScreenshotButton(); // 添加截圖按鈕
  181. }, 1000); // 延遲 1 秒以確保內容加載完成
  182. });
  183. }
  184. }
  185. // 等待 DOM 加载完成
  186. window.addEventListener("load", init);
  187. })();