// ==UserScript== // @name Minecraft Helper // @namespace http://tampermonkey.net/ // @version 0.5.0 // @description 为 Minecraft 玩家定制的实用脚本 // @author PRO // @license gpl-3.0 // @match https://www.minecraft.net/* // @match https://www.curseforge.com/* // @match https://modrinth.com/* // @icon https://www.minecraft.net/etc.clientlibs/minecraft/clientlibs/main/resources/img/minecraft-creeper-face.jpg // @grant unsafeWindow // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @require https://greasyfork.org/scripts/470224-tampermonkey-config/code/Tampermonkey%20Config.js?version=1216049 // @downloadURL none // ==/UserScript== (function () { 'use strict'; let name = 'Minecraft Helper'; let log = (s, error=false) => { if (error) { console.error(`[${name}] ${s}`); } else { console.log(`[${name}] ${s}`); } }; function processor_string_list(s) { return s.split(",").map((s) => s.trim()); } let config_descs = { general: { "general/timeout": { name: "通用等待时间", value: 500, processor: GM_config_builtin_processors.integer(1, undefined) } }, minecraft: { "minecraft/auto-stay": { name: "自动留下", value: true, processor: GM_config_builtin_processors.boolean } }, curseforge: { "curseforge/auto-mod": { name: "自动跳转到 MC Mods", value: true, processor: GM_config_builtin_processors.boolean }, "curseforge/highlight-files": { name: "高亮文件下载", value: true, processor: GM_config_builtin_processors.boolean }, "curseforge/highlight-border": { name: "高亮边框样式", value: "rgb(241, 100, 54) 0.2em solid", processor: undefined }, "curseforge/default-download": { name: "使用默认下载", value: true, processor: GM_config_builtin_processors.boolean }, "curseforge/shortcut": { name: "快捷键", value: true, processor: GM_config_builtin_processors.boolean } }, modrinth: { "modrinth/auto-mod": { name: "自动跳转到 MC Mods", value: true, processor: GM_config_builtin_processors.boolean }, "modrinth/shortcut": { name: "快捷键", value: true, processor: GM_config_builtin_processors.boolean }, "modrinth/default-filter/loader": { name: "默认 Loader", value: ["fabric"], processor: processor_string_list }, "modrinth/default-filter/version": { name: "默认 MC 版本", value: ["1.18.2", "1.19.2"], processor: processor_string_list }, "modrinth/default-filter/channel": { name: "默认 Channel", value: [], processor: processor_string_list } } }; function try_click(selector) { let ele = document.querySelector(selector); if (ele) ele.click(); } function setup_shortcuts(selectors, filter, timeout) { document.addEventListener("keydown", (e) => { if (document.activeElement.nodeName != "INPUT") { switch (e.key) { case "ArrowLeft": try_click(selectors[0]); break; case "ArrowRight": try_click(selectors[1]); break; case "f": filter(); break; case "s": if (selectors[2].length) { try_click(selectors[2]); window.setTimeout(() => { let search = document.querySelector(selectors[3]); if (search) search.focus(); }, timeout); } else { let search = document.querySelector(selectors[3]); if (search) search.focus(); } e.preventDefault(); break; default: break; } } else if (document.activeElement.value == "") { switch (e.key) { case "Escape": document.activeElement.blur(); break; case "ArrowLeft": try_click(selectors[0]); break; case "ArrowRight": try_click(selectors[1]); break; default: break; } } }) log("⚙️ Shortcuts installed!"); } let config_desc = config_descs.general; switch (window.location.host) { case 'www.minecraft.net': { Object.assign(config_desc, config_descs.minecraft); let config = GM_config(config_desc); if (config["minecraft/auto-stay"]) { try_click("#popup-btn"); log("✋ Auto stayed!"); } break; } case 'www.curseforge.com': { Object.assign(config_desc, config_descs.curseforge); let config = GM_config(config_desc); if (config["curseforge/auto-mod"] && window.location.pathname == '/') { log("🛣️ Navigating to mc mods..."); window.location.pathname = "/minecraft/mc-mods"; } if (config["curseforge/highlight-files"] && window.location.pathname != "/") { let tabs = document.getElementsByClassName("tabs"); if (tabs.length) { tabs = tabs[0]; for (let tab of tabs.children) { if (tab.textContent == "Files") { tab.style.border = config["curseforge/highlight-border"]; break; } } } } if (config["curseforge/default-download"]) { function cf_replace(menu) { menu.children[0].remove(); let down = menu.querySelector("#contextMenu").children[1]; let new_btn = document.createElement("button"); new_btn.innerHTML = 'Download'; new_btn.setAttribute("class", "btn-cta"); new_btn.onclick = (e) => { window.location.href = down.children[0].href; }; menu.insertBefore(new_btn, menu.children[0]); } let cfg = { attributes: false, childList: true, subtree: true }; let callback = (mutations, observer) => { for (let mutation of mutations) { if (mutation.addedNodes.length) { let menus = mutation.addedNodes[0].querySelectorAll("#menuButton"); if (menus.length) { for (let menu of menus) { cf_replace(menu); } } } } }; let content; if (window.location.pathname == "/minecraft/search") { content = document.querySelector(".search-page"); } else if (window.location.pathname.startsWith("/minecraft/mc-mods/")) { content = document.getElementsByClassName("tab-content")[0]; } else { break; } let observer = new MutationObserver(callback); observer.observe(content, cfg); let menus = document.querySelectorAll("#menuButton"); if (menus.length) { let cnt = 0; for (let menu of menus) { cnt++; cf_replace(menu); } log(`📥 Successfully replaced ${cnt} "Install" button(s).`); } } if (config["curseforge/shortcut"]) { setup_shortcuts([".btn-prev", ".btn-next", "", "input.search-input-field"], () => { try_click(".tabs > li > a[href$='/files']") }); } break; } case "modrinth.com": { Object.assign(config_desc, config_descs.modrinth); let config = GM_config(config_desc); if (window.location.pathname == "/" && config["modrinth/auto-mod"]) { log("🛣️ Navigating to mod search page..."); try_click(".button-group > a"); } function filter() { let router = document.getElementById("__nuxt").__vue_app__.$nuxt.$router; if (router.currentRoute.value.name === "type-id") { let path = router.currentRoute.value.path; if (path.endsWith("/")) path = path.slice(0, -1); router.replace({ path: router.currentRoute.value.path + "/versions", query: { "l": config["modrinth/default-filter/loader"], "g": config["modrinth/default-filter/version"], "c": config["modrinth/default-filter/channel"] } }); } } if (config["modrinth/shortcut"]) { setup_shortcuts([".left-arrow", ".right-arrow", ".navigation > a.nav-link", "#search"], filter); } break; } } })();