Minecraft Helper

为 Minecraft 玩家定制的实用脚本

安装此脚本
作者推荐脚本

您可能也喜欢Wanta

安装此脚本
  1. // ==UserScript==
  2. // @name Minecraft Helper
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.5.7
  5. // @description 为 Minecraft 玩家定制的实用脚本
  6. // @author PRO
  7. // @license gpl-3.0
  8. // @match https://www.minecraft.net/*
  9. // @match https://www.curseforge.com/*
  10. // @match https://modrinth.com/*
  11. // @icon https://www.minecraft.net/etc.clientlibs/minecraft/clientlibs/main/resources/img/minecraft-creeper-face.jpg
  12. // @grant unsafeWindow
  13. // @grant GM_setValue
  14. // @grant GM_getValue
  15. // @grant GM_registerMenuCommand
  16. // @grant GM_unregisterMenuCommand
  17. // @grant GM_addValueChangeListener
  18. // @require https://update.gf.qytechs.cn/scripts/470224/1448594/Tampermonkey%20Config.js
  19. // ==/UserScript==
  20.  
  21. (function () {
  22. 'use strict';
  23. const name = 'Minecraft Helper';
  24. const log = (s, error=false) => {
  25. if (error) {
  26. console.error(`[${name}] ${s}`);
  27. } else {
  28. console.log(`[${name}] ${s}`);
  29. }
  30. };
  31. function _boolDesc(name, title = undefined, default_value = true) {
  32. return {
  33. name: name,
  34. value: default_value,
  35. input: "current",
  36. processor: "not",
  37. formatter: "boolean",
  38. autoClose: false,
  39. title: title
  40. };
  41. }
  42. function processorStrList(s) {
  43. return s.split(",").map((s) => s.trim());
  44. }
  45. const configDescs = {
  46. general: {
  47. "general/timeout": {
  48. name: "通用等待时间",
  49. value: 500,
  50. processor: "int_range-1-",
  51. autoClose: false,
  52. title: "单位:毫秒"
  53. }
  54. },
  55. minecraft: {
  56. "minecraft/auto-stay": _boolDesc("自动留下", "自动点击“留在 Minecraft.net”")
  57. },
  58. curseforge: {
  59. "curseforge/auto-mod": _boolDesc("自动跳转到 MC Mods", "自动跳转到 MC Mods"),
  60. "curseforge/highlight-files": _boolDesc("高亮文件下载", "高亮 Files 标签"),
  61. "curseforge/highlight-border": {
  62. name: "高亮边框样式",
  63. value: "rgb(241, 100, 54) 0.2em solid",
  64. processor: undefined,
  65. autoClose: false,
  66. title: "单位:毫秒"
  67. },
  68. "curseforge/shortcut": _boolDesc("快捷键", "添加快捷键支持")
  69. },
  70. modrinth: {
  71. "modrinth/auto-mod": _boolDesc("自动跳转到 MC Mods", "自动跳转到 MC Mods"),
  72. "modrinth/shortcut": _boolDesc("快捷键", "添加快捷键支持"),
  73. "modrinth/default-filter/loader": {
  74. name: "默认 Loader",
  75. value: ["fabric"],
  76. processor: processorStrList,
  77. autoClose: false,
  78. title: "搜索时默认使用的 Loader"
  79. },
  80. "modrinth/default-filter/version": {
  81. name: "默认 MC 版本",
  82. value: ["1.18.2", "1.19.2"],
  83. processor: processorStrList,
  84. autoClose: false,
  85. title: "搜索时默认使用的 MC 版本"
  86. },
  87. "modrinth/default-filter/channel": {
  88. name: "默认 Channel",
  89. value: [],
  90. processor: processorStrList,
  91. autoClose: false,
  92. title: "搜索时默认使用的 Channel"
  93. }
  94. }
  95. };
  96. /**
  97. * Try to click an element.
  98. * @param {string} selector The query selector.
  99. */
  100. function tryClick(selector) {
  101. const ele = document.querySelector(selector);
  102. if (ele) {
  103. ele.click();
  104. return true;
  105. }
  106. return false;
  107. }
  108. /**
  109. * Setup shortcuts.
  110. * @param {string[]} selectors The selectors. [left, right, pre-search, search]
  111. * @param {Function} filter The filter function.
  112. * @param {number} timeout Timeout in milliseconds.
  113. */
  114. function setupShortcuts(selectors, filter, timeout) {
  115. const nodeNames = ["INPUT", "TEXTAREA"];
  116. document.addEventListener("keydown", (e) => {
  117. if (!nodeNames.includes(document.activeElement.nodeName)) {
  118. switch (e.key) {
  119. case "ArrowLeft":
  120. tryClick(selectors[0]);
  121. break;
  122. case "ArrowRight":
  123. tryClick(selectors[1]);
  124. break;
  125. case "f":
  126. filter();
  127. break;
  128. case "s":
  129. if (selectors[2].length) {
  130. tryClick(selectors[2]);
  131. window.setTimeout(() => {
  132. const search = document.querySelector(selectors[3]);
  133. if (search) search.focus();
  134. }, timeout);
  135. } else {
  136. const search = document.querySelector(selectors[3]);
  137. if (search) search.focus();
  138. }
  139. e.preventDefault();
  140. break;
  141. default:
  142. break;
  143. }
  144. } else if (document.activeElement.value == "") {
  145. switch (e.key) {
  146. case "Escape":
  147. document.activeElement.blur();
  148. break;
  149. case "ArrowLeft":
  150. tryClick(selectors[0]);
  151. break;
  152. case "ArrowRight":
  153. tryClick(selectors[1]);
  154. break;
  155. default:
  156. break;
  157. }
  158. }
  159. })
  160. log("⚙️ Shortcuts installed!");
  161. }
  162. const configDesc = configDescs.general;
  163. switch (window.location.host) {
  164. case 'www.minecraft.net': {
  165. Object.assign(configDesc, configDescs.minecraft);
  166. const config = new GM_config(configDesc);
  167. const configProxy = config.proxy;
  168. if (configProxy["minecraft/auto-stay"]) {
  169. let attempts = 16;
  170. const timer = window.setInterval(() => {
  171. const success = tryClick("button[data-aem-contentname='close-icon']")
  172. || tryClick("button.btn.btn-link#popup-btn");
  173. if (success) {
  174. log("✋ Auto stayed!");
  175. window.clearInterval(timer);
  176. } else if (--attempts <= 0) {
  177. log("❌ Auto stay failed!", true);
  178. window.clearInterval(timer);
  179. }
  180. }, configProxy["general/timeout"]);
  181. }
  182. break;
  183. }
  184. case 'www.curseforge.com': {
  185. Object.assign(configDesc, configDescs.curseforge);
  186. const config = new GM_config(configDesc);
  187. const configProxy = config.proxy;
  188. if (configProxy["curseforge/auto-mod"] && window.location.pathname == '/') {
  189. log("🛣️ Navigating to mc mods...");
  190. window.location.pathname = "/minecraft/mc-mods";
  191. }
  192. const tabs = document.getElementsByClassName("tabs");
  193. let fileTab = undefined;
  194. if (tabs.length) {
  195. for (const tab of tabs[0].children) {
  196. if (tab.textContent == "Files") {
  197. fileTab = tab;
  198. break;
  199. }
  200. }
  201. }
  202. if (configProxy["curseforge/highlight-files"] && window.location.pathname != "/") {
  203. fileTab.style.border = configProxy["curseforge/highlight-border"];
  204. }
  205. if (configProxy["curseforge/shortcut"]) {
  206. setupShortcuts([".btn-prev", ".btn-next", "", "input.search-input-field"], () => { fileTab?.firstElementChild?.click(); });
  207. }
  208. break;
  209. }
  210. case "modrinth.com": {
  211. Object.assign(configDesc, configDescs.modrinth);
  212. const config = new GM_config(configDesc);
  213. const configProxy = config.proxy;
  214. if (window.location.pathname == "/" && configProxy["modrinth/auto-mod"]) {
  215. log("🛣️ Navigating to mod search page...");
  216. tryClick("a[href='/mods']");
  217. }
  218. function filter() {
  219. const router = document.getElementById("__nuxt").__vue_app__.$nuxt.$router;
  220. if (router.currentRoute.value.name === "type-id") {
  221. const path = router.currentRoute.value.path;
  222. router.replace({
  223. path: path + "/versions", query: {
  224. "l": configProxy["modrinth/default-filter/loader"],
  225. "g": configProxy["modrinth/default-filter/version"],
  226. "c": configProxy["modrinth/default-filter/channel"]
  227. }
  228. });
  229. }
  230. }
  231. if (configProxy["modrinth/shortcut"]) {
  232. setupShortcuts([".btn-wrapper > a[aria-label='Previous Page']", ".btn-wrapper > a[aria-label='Next Page']", "a[href='/mods']", "#search[placeholder='Search mods...']"], filter);
  233. }
  234. break;
  235. }
  236. }
  237. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址