// ==UserScript== // @name 榭洛科特的背包 // @version 1.7.0.1 // @author Alk // @license GPL 3.0 // @description 原名GBF周回本胜利跳过。已重构。现支持:1.关闭左/右侧边栏,2.攻击后刷新,3.胜利跳过,4.帝王指令自动刷新,5.太阳自动刷新 待追加:6.五神复活增益显示。 // @match *.granbluefantasy.jp // @grant unsafeWindow // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // @run-at document-start // @namespace https://greasyfork.org/users/1455240 // @icon https://raw.githubusercontent.com/enorsona/thirdparty/refs/heads/master/sherurotes_carrybag.ico // @downloadURL none // ==/UserScript== // ========== 设置项 ========== const battle_json_names = ['normal_attack_result.json', 'ability_result.json', 'fatal_chain_result.json', 'summon_result.json'] const settings_strings = { refresh_attack: 'AttackRefresh', hide_left_sb: 'HideLeftSidebar', hide_right_sb: 'HideRightSidebar', refresh_koenig_dekret: 'KoenigDekretRefresh', refresh_coronal_ejection: 'CoronalEjection', replace_refresh_with_back: 'ReplaceRefreshWithBack', allow_auto_redirect: 'AllowAutoRedirect', auto_redirect_url: 'AutoRedirectURL', } // ========== 状态读取 ========== const checkEnabledAttackRefresh = () => { return GM_getValue(settings_strings.refresh_attack, true); }; const checkEnabledHideLeftSidebar = () => { return GM_getValue(settings_strings.hide_left_sb, false); }; const checkEnabledHideRightSidebar = () => { return GM_getValue(settings_strings.hide_right_sb, false); }; const checkEnabledKoenigDekretAutoRefresh = () => { return GM_getValue(settings_strings.refresh_koenig_dekret, true); }; const checkEnabledCoronalEjectionAutoRefresh = () => { return GM_getValue(settings_strings.refresh_coronal_ejection, true); }; const checkEnabledReplaceRefreshWithBack = () => { return GM_getValue(settings_strings.replace_refresh_with_back, false); } const checkAllowAutoRedirect = () => { return GM_getValue(settings_strings.allow_auto_redirect, false); } const checkAutoRedirectURL = () => { return GM_getValue(settings_strings.auto_redirect_url, 0); } let rrwb_enabled = checkEnabledReplaceRefreshWithBack(); let ar_enabled = checkEnabledAttackRefresh(); let kdr_enabled = checkEnabledKoenigDekretAutoRefresh(); let cer_enabled = checkEnabledCoronalEjectionAutoRefresh(); let aar_enabled = checkAllowAutoRedirect(); // ========== 切换刷新功能 ========== const switchEnabledAttackRefresh = () => { const current = checkEnabledAttackRefresh(); GM_setValue(settings_strings.refresh_attack, !current); reload(); }; const switchEnabledHideLeftSidebar = () => { const current = checkEnabledHideLeftSidebar(); GM_setValue(settings_strings.hide_left_sb, !current); reload(); }; const switchEnabledHideRightSidebar = () => { const current = checkEnabledHideRightSidebar(); GM_setValue(settings_strings.hide_right_sb, !current); reload(); }; const switchEnabledKoenigDekretAutoRefresh = () => { const current = checkEnabledKoenigDekretAutoRefresh(); GM_setValue(settings_strings.refresh_koenig_dekret, !current); reload(); }; const switchEnabledCoronalEjectionAutoRefresh = () => { const current = checkEnabledCoronalEjectionAutoRefresh(); GM_setValue(settings_strings.refresh_coronal_ejection, !current); reload(); }; const switchEnabledReplaceRefreshWithBack = () => { const current = checkEnabledReplaceRefreshWithBack(); GM_setValue(settings_strings.replace_refresh_with_back, !current); reload(); }; const switchAllowAutoRedirect = () => { const current = checkAllowAutoRedirect(); GM_setValue(settings_strings.allow_auto_redirect, !current); reload(); }; const getAutoRedirectURL = () => { const current = location.hash; GM_setValue(settings_strings.auto_redirect_url, current); reload(); } // ========== 注册菜单 ========== const registerMenu = () => { GM_registerMenuCommand( `启用替换刷新为后退:${checkEnabledReplaceRefreshWithBack() ? '已开启' : '已关闭'}`, switchEnabledReplaceRefreshWithBack ); GM_registerMenuCommand( `启用自动跳转至召唤选择界面:${checkAllowAutoRedirect() ? '已开启' : '已关闭'}`, switchAllowAutoRedirect ); GM_registerMenuCommand( `当前召唤石选择界面URL:${checkAutoRedirectURL()}`, getAutoRedirectURL ); GM_registerMenuCommand( `攻击后自动刷新:${checkEnabledAttackRefresh() ? '已开启' : '已关闭'}`, switchEnabledAttackRefresh ); GM_registerMenuCommand( `关闭左侧边栏:${checkEnabledHideLeftSidebar() ? '已开启' : '已关闭'}`, switchEnabledHideLeftSidebar ); GM_registerMenuCommand( `关闭右侧边栏:${checkEnabledHideRightSidebar() ? '已开启' : '已关闭'}`, switchEnabledHideRightSidebar ); GM_registerMenuCommand( `启用帝王指令刷新:${checkEnabledKoenigDekretAutoRefresh() ? '已开启' : '已关闭'}`, switchEnabledKoenigDekretAutoRefresh ); GM_registerMenuCommand( `启用太阳召唤刷新:${checkEnabledCoronalEjectionAutoRefresh() ? '已开启' : '已关闭'}`, switchEnabledCoronalEjectionAutoRefresh ); }; registerMenu(); // ========== 工具 ========== const checkIsMobile = () => { const userAgent = navigator.userAgent.toLowerCase(); return /iphone|ipad|android|mobile|windows phone|blackberry/.test(userAgent); }; const getRandomInt = (min, max) => { return Math.floor(Math.random() * (max - min + 1)) + min; } // ========== URL 与 JSON 解析 ========== const tryParseJSON = (response) => { try { return JSON.parse(response); } catch (e) { return response; } }; const checkURL = (base) => { const url = new URL(base); const parts = url.pathname.split('/'); return { is_battle: battle_json_names.includes(parts[3]), is_attack: parts[3] === battle_json_names[0], is_skill: parts[3] === battle_json_names[1], is_fc: parts[3] === battle_json_names[2], is_summon: parts[3] === battle_json_names[3], }; }; const checkWin = (scenario) => { const win = scenario.find(s => s.cmd === "win"); if (win) { return win.is_last_raid === 1 ? 1 : 2; } return 0; }; const checkIsKoenigDekret = (scenario) => { return ( scenario[0].cmd === 'ability' && scenario[0].voice === 'voice/3040425000_ability_us2.mp3' && scenario[0].name === 'ケーニヒ・ベシュテレン' ) || false; } const checkIsCoronalEjection = (scenario) => { return ( scenario[2].cmd === 'ability' && scenario[2].name === '火属性ダメージ/3番目までに配置された火属性キャラがターン進行時に攻撃行動を2回行う' ) || false; } // ========== 页面控制函数 ========== const reload = () => { if (rrwb_enabled) { goback(); } else { setTimeout(() => { location.reload(true); }, getRandomInt(0, 200)) } } const goback = () => { setTimeout(() => { history.go(-1); }, getRandomInt(0, 200)) } const aar = () => { const hash = location.hash.split('/')[0]; const target = '#result_multi'; console.log(hash, target); if(hash === target) { const aru = checkAutoRedirectURL(); if (aru !== 0) { location.href = location.origin + '/' + aru; } } } // ========== 拦截并处理XHR ========== const customLoad = (xhr, result) => { const response = tryParseJSON(xhr.response); const status = checkWin(response.scenario); if (status === 1) { goback(); } else if (status === 0) { if (result.is_attack && ar_enabled) { reload(); } else if (kdr_enabled && checkIsKoenigDekret(response.scenario)) { reload() } else if (cer_enabled && checkIsCoronalEjection(response.scenario)) { reload(); } } else { reload(); } }; // ========== Hook XMLHttpRequest ========== const origSend = unsafeWindow.XMLHttpRequest.prototype.send; unsafeWindow.XMLHttpRequest.prototype.send = function (...args) { this.addEventListener('load', () => { const checkURLResult = checkURL(this.responseURL); const process_needed = checkURLResult.is_battle; if (process_needed) { customLoad(this, checkURLResult); } }); origSend.apply(this, args); }; // ========== 隐藏左侧边栏 ========== (() => { if (checkIsMobile()) return; if (checkEnabledHideLeftSidebar()) { window.addEventListener('load', () => { try { const target = document.body.firstElementChild; if (target && target.firstElementChild) { target.removeChild(target.firstElementChild); } } catch (e) { console.warn('隐藏左边栏失败:', e); } }); } })(); (() => { if (checkEnabledHideRightSidebar()) { window.addEventListener('load', () => { try { const target = document.querySelector('div#submenu'); if (target) { target.remove(); } } catch (e) { console.warn('隐藏右边栏失败:', e); } }); } })(); (() => { if(aar_enabled) { window.onload = () => { aar() } window.addEventListener('popstate', () => { if(checkAllowAutoRedirect()) { setTimeout(aar, getRandomInt(0, 200)) } } ) } })();