// ==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://gf.qytechs.cn/scripts/470224-tampermonkey-config/code/Tampermonkey%20Config.js?version=1216049
// ==/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 = '<svg><use href="/images/sprite.svg#icon-download"></use></svg><span>Download</span>';
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;
}
}
})();