This commit is contained in:
Liwanyi 2022-09-14 18:14:52 +08:00
parent 8b540b46fb
commit 26c9227461
45 changed files with 1609 additions and 2364 deletions

View File

@ -8,6 +8,11 @@
<JetCodeStyleSettings> <JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings> </JetCodeStyleSettings>
<TypeScriptCodeStyleSettings version="0">
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
<option name="SPACES_WITHIN_IMPORTS" value="true" />
<option name="SPACES_WITHIN_INTERPOLATION_EXPRESSIONS" value="true" />
</TypeScriptCodeStyleSettings>
<codeStyleSettings language="kotlin"> <codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</codeStyleSettings> </codeStyleSettings>

13
global.d.ts vendored
View File

@ -77,12 +77,13 @@ declare interface Navigator {
declare interface TornGetActionParams { declare interface TornGetActionParams {
type: 'post' | 'get', type: 'post' | 'get',
data: { action?: string,
step: string, data?: {
id: number, step?: string,
key: string, id?: number,
type: string key?: string,
type?: string
}, },
success: Function, success: Function,
before: Function before?: Function
} }

75
src/WHNext.ts Normal file
View File

@ -0,0 +1,75 @@
import Global from "./interface/GlobalVars";
import getWhSettingObj from "./func/utils/getWhSettingObj";
import elementReady from "./func/utils/elementReady";
import depoHelper from "./func/module/depoHelper";
import travelHelper from "./func/module/travelHelper";
import attackHelper from "./func/module/attackHelper";
export default function (glob: Global) {
// 啤酒提醒
if (getWhSettingObj()['_15Alarm']) glob.beer.start();
// 点击4条转跳对应的页面
if (getWhSettingObj()['barsRedirect']) {
const eb = document.getElementById('barEnergy') as HTMLAnchorElement;
const nb = document.getElementById('barNerve') as HTMLAnchorElement;
const hb = document.getElementById('barHappy') as HTMLAnchorElement;
const lb = document.getElementById('barLife') as HTMLAnchorElement;
if (eb) {
eb.addEventListener('click', () => location.href = '/gym.php');
eb.href = '/gym.php';
} else {
elementReady('#barEnergy').then(eb => {
eb.addEventListener('click', () => location.href = '/gym.php');
(eb as HTMLAnchorElement).href = '/gym.php';
});
}
if (nb) {
nb.addEventListener('click', () => location.href = '/crimes.php');
nb.href = '/crimes.php';
} else {
elementReady('#barNerve').then(nb => {
nb.addEventListener('click', () => location.href = '/crimes.php');
(nb as HTMLAnchorElement).href = '/crimes.php';
});
}
if (hb) {
hb.addEventListener('click', () => location.href = '/item.php#boosters-items');
hb.href = '/item.php#boosters-items';
} else {
elementReady('#barHappy').then(hb => {
hb.addEventListener('click', () => location.href = '/item.php#boosters-items');
(hb as HTMLAnchorElement).href = '/item.php#boosters-items';
});
}
if (lb) {
lb.addEventListener('click', () => location.href = '/item.php#medical-items');
lb.href = '/item.php#medical-items';
} else {
elementReady('#barLife').then(lb => {
lb.addEventListener('click', () => location.href = '/item.php#medical-items');
(lb as HTMLAnchorElement).href = '/item.php#medical-items';
});
}
}
/**
*
* TODO
*/
if (getWhSettingObj()['removeScripts']) {
document.querySelectorAll('script[src*="google"]').forEach(item => item.remove());
document.querySelectorAll('#gtm_tag').forEach(item => item.remove());
document.querySelectorAll('script[src*="chat/gonline"]').forEach(item => item.remove());
document.querySelectorAll('head script[nonce]').forEach(item => item.remove());
}
// 存钱相关
depoHelper(glob);
// 飞行相关
travelHelper(glob).then();
// 战斗相关
attackHelper(glob).then();
}

View File

@ -0,0 +1,271 @@
import Device from "../../enum/Device";
import Global from "../../interface/GlobalVars";
import elementReady from "../utils/elementReady";
import getWhSettingObj from "../utils/getWhSettingObj";
import addActionBtn from "../utils/addActionBtn";
import addStyle from "../utils/addStyle";
import getRandomInt from "../utils/getRandomInt";
import log from "../utils/log";
export default async function attackHelper(glob: Global): Promise<null> {
let { href, device, $zhongNode } = glob;
// 攻击页面
if (href.contains(/loader\.php\?sid=attack/)) {
let stop_reload = false;
const { quickAttIndex, quickFinishAtt, attReload } = getWhSettingObj();
// 光速刷新按钮
addActionBtn('光速刷新', doAttackReload, $zhongNode);
// 自刷新
let audio_played_flag;
// @ts-ignore
if (attReload !== 6 && stop_reload !== true) {
const selector_device_map = {
'pc': '#defender div[class^="modal___"]',
'mobile': '#attacker div[class^="modal___"]',
'tablet': '',
};
const selector = selector_device_map[device];
elementReady(selector).then(elem => {
if (!elem.querySelector('button')) {
if (getWhSettingObj().attReload === 0 && stop_reload !== true) {
// window.location.reload();
doAttackReload();
} else {
let reload_flag;
const timeout = getWhSettingObj().attReload * 1000 + getRandomInt(-500, 500);
log.info(`[WH] ${ timeout / 1000 }s 后自动刷新`);
window.setInterval(() => {
if (reload_flag === undefined) {
reload_flag = true;
} else if (stop_reload !== true) {
// window.location.reload();
doAttackReload();
}
}, timeout);
}
} else if (audio_played_flag === undefined) {
audio_played_flag = true;
let play_time = 0;
const audio_play_id = window.setInterval(() => {
const $audio = document.createElement('audio');
$audio.src = 'https://www.torn.com/js/chat/sounds/Warble_1.mp3';
$audio.play().then();
play_time++;
if (play_time === 3) clearInterval(audio_play_id);
}, 600);
}
});
}
// 光速拔刀
if (quickAttIndex !== 6) {
const btn = await elementReady('div[class^="modal___"] button');
log.info(btn);
if (!btn.innerText.toLowerCase().includes('fight')) return;
// 判断是否存在脚踢
const hasKick = !!document.querySelector('#weapon_boots');
// modal层
const modal: HTMLElement = document.querySelector('div[class^="modal___"]');
log.info(`当前设备类型是${ device }`);
// 区分设备
switch (device) {
case Device.PC: {
log.info(`开始调整按钮位置`);
// 隐藏modal层
modal.style.display = 'none';
// 根据选择的武器调整css
let css_top = '0';
switch (getWhSettingObj()['quickAttIndex']) {
case 1: { // weapon_second
css_top = '97px';
break;
}
case 2: { // weapon_melee
css_top = '194px';
break;
}
case 3: { // weapon_temp
css_top = '291px';
break;
}
case 4: // weapon_fists
case 5: { // weapon_boots
css_top = '375px';
break;
}
}
const css_rule = `
.wh-move-btn #defender div[class^="modal___"]{display: block;width: 0 !important;top: ${ css_top };left: -169px !important;}
.wh-move-btn #defender div[class^="dialog___"]{border:0;width:159px;height:96px;}
.wh-move-btn #defender div[class^="colored___"]{display:block;padding:0;}
.wh-move-btn #defender div[class^="title___"]{height:0;}
.wh-move-btn #defender button{width: 100%;margin:17px 0;height: 60px;}
`;
addStyle(css_rule);
document.body.classList.add('wh-move-btn');
// 绑定点击事件 联动【光速跑路】
btn.onclick = () => {
if (quickFinishAtt !== 3) {
btn.remove();
// 停止自动刷新
stop_reload = true;
} else {
document.body.classList.remove('wh-move-btn');
}
};
break;
}
case Device.MOBILE: {
log.info(`开始调整按钮位置`);
// 加入css
let css_top = '0';
let slot_height = '76px';
// 判断有没有脚踢
if (hasKick) {
// 根据选择的武器调整
switch (getWhSettingObj()['quickAttIndex']) {
case 1: { // weapon_second
css_top = '76px';
break;
}
case 2: { // weapon_melee
css_top = '152px';
break;
}
case 3: { // weapon_temp
css_top = '228px';
break;
}
case 4: { // weapon_fists
css_top = '304px';
break;
}
case 5: { // weapon_boots
css_top = '380px';
break;
}
}
} else {
const slot = document.querySelector('#weapon_main') as HTMLElement;
const height = slot.offsetHeight + 1;
// TODO 待验证
slot_height = height + 'px';
// 根据选择的武器调整
switch (getWhSettingObj().quickAttIndex) {
case 1: { // weapon_second
css_top = `${ height }px`;
break;
}
case 2: { // weapon_melee
css_top = `${ height * 2 }px`;
break;
}
case 3: { // weapon_temp
css_top = `${ height * 3 }px`;
break;
}
case 4: { // weapon_fists
css_top = `${ height * 4 }px`;
break;
}
case 5: { // weapon_boots
css_top = `${ height * 5 }px`;
break;
}
}
}
const css_rule = `
.wh-move-btn #attacker div[class^="modal___"]{display: block;width: 0;top: ${ css_top };left:0;height:0;}
.wh-move-btn #attacker div[class^="dialog___"]{border:0;width:80px;height:${ slot_height };}
.wh-move-btn #attacker div[class^="colored___"]{display:block;padding:0;}
.wh-move-btn #attacker div[class^="title___"]{height:0;}
.wh-move-btn #attacker button{width:100%;margin:0;height:63px;white-space:normal;}
`;
addStyle(css_rule);
document.body.classList.toggle('wh-move-btn');
btn.onclick = () => {
if (getWhSettingObj().quickFinishAtt !== 3) {
btn.remove();
// 停止自动刷新
stop_reload = true;
} else {
document.body.classList.toggle('wh-move-btn');
}
};
break;
}
case Device.TABLET: {
break;
}
}
// 自动开打
if (getWhSettingObj()['autoStartFinish'] === true) {
if (btn.innerText.includes('(')) {
let interval_id = window.setInterval(() => {
if (!btn) {
clearInterval(interval_id);
return;
}
try {
btn.click();
} catch {
}
}, 100);
} else {
btn.click();
}
}
}
// 光速跑路
if (quickFinishAtt !== 3) {
const user_btn_select = ['leave', 'mug', 'hosp'][getWhSettingObj()['quickFinishAtt']];
const wrap = document.querySelector('#react-root');
log.info('光速跑路选项选中:', user_btn_select);
new MutationObserver(() => {
const btn_arr = document.querySelectorAll('div[class^="dialogButtons___"] button') as unknown as HTMLButtonElement[];
if (btn_arr.length > 1) btn_arr.forEach(btn => {
btn = btn as HTMLButtonElement;
const flag = btn.innerText.toLowerCase().includes(user_btn_select);
log.info('按钮内容:', btn.innerText, ',是否包含选中:', flag);
if (!flag) btn.style.display = 'none';
// 自动结束
else if (getWhSettingObj()['autoStartFinish'] === true) {
try {
btn.click();
} catch {
}
}
});
}).observe(wrap, { subtree: true, attributes: true, childList: true });
}
return;
}
// 错误的攻击页面
if (getWhSettingObj()['attRelocate'] && href.includes('loader2.php')) {
const spl = window.location.href.trim().split('=');
const uid = spl[spl.length - 1];
if (!/^\d+$/.test(uid)) return;
window.location.href = `https://www.torn.com/loader.php?sid=attack&user2ID=${ uid }`;
return;
}
}
// 战斗页面快速刷新
function doAttackReload() {
if (!window.ReactDOM) return;
let react_root = document.querySelector('#react-root');
if (!react_root.querySelector('#attacker')) return;
let script = document.querySelector('script[src*="/builds/attack/"]');
let url = script.src;
if (!url.contains('app.js')) return;
window.ReactDOM.unmountComponentAtNode(react_root);
script.remove();
let node = document.createElement('script');
node.src = url;
node.type = 'text/javascript';
document.head.appendChild(node);
}

View File

@ -0,0 +1,261 @@
import elementReady from "../utils/elementReady";
import getWhSettingObj from "../utils/getWhSettingObj";
import addStyle from "../utils/addStyle";
import log from "../utils/log";
import Global from "../../interface/GlobalVars";
import addActionBtn from "../utils/addActionBtn";
import WHNotify from "../utils/WHNotify";
import jQueryAjax from "../utils/jQueryAjax";
import ajaxFetch from "../utils/ajaxFetch";
export default function (glob: Global) {
let { href, $zhongNode } = glob;
let channel: 'CMPY' | 'FAC';
const selector = { 'CMPY': "div#funds div.deposit", 'FAC': "div#armoury-donate div.cash" };
// 公司
if (href.includes('companies.php')) {
channel = "CMPY";
// 公司转跳存钱
if (!href.includes('funds') && getWhSettingObj()['companyRedirect']) {
const btn = document.getElementById('ui-id-9');
if (btn) {
btn.click();
log.info('已自动打开存钱页面');
}
}
// 收起冰蛙表格
if (getWhSettingObj()['companyBWCollapse']) {
elementReady('#effectiveness-wrap').then(BWtable_node => {
document.body.classList.add('wh-bwtable-ctrl');
addStyle(`.wh-bwtable-ctrl #effectiveness-wrap {display:none !important;}`);
const btn = document.createElement('button');
btn.innerHTML = '展开冰蛙表格';
btn.addEventListener('click', () => {
document.body.classList.toggle('wh-bwtable-ctrl');
btn.innerText = btn.innerText === '展开冰蛙表格' ? '收起冰蛙表格' : '展开冰蛙表格';
});
BWtable_node.before(btn);
});
}
// 一键存钱按钮
addActionBtn('一键存钱', companyDeposit, $zhongNode);
}
// 帮派
if (href.includes('factions.php')) {
channel = "FAC";
// 一键存钱按钮
addActionBtn('一键存钱', factionDeposit, $zhongNode);
}
// 存钱框浮动
if (getWhSettingObj()['floatDepo'] && channel) {
document.body.classList.add('wh-depo-helper');
addStyle(`.wh-depo-helper div#funds div.deposit,
.wh-depo-helper div#armoury-donate div.cash{position: fixed !important;
top: 150px;
right: 12px;
box-shadow: 0 0 8px 1px #00000091;
background: #f2f2f2;
z-index: 999999;}`);
elementReady(selector[channel]).then(node => {
const close_btn = document.createElement('button');
close_btn.addEventListener('click', () => {
document.body.classList.remove('wh-depo-helper');
close_btn.remove();
});
close_btn.innerHTML = '恢复原位';
close_btn.style.float = 'right';
node.prepend(close_btn);
});
}
// GT交易存钱
if (location.pathname.startsWith('/trade.php')) {
// GT助手
let node_link = null;
let handle = () => {
let { addRFC } = window;
// 不重复加载、已关闭的交易不加载
if (node_link !== null || location.hash.includes('logview')) return;
log.info('已添加GT助手');
// 获取交易id
let query_params = location.hash.slice(1);
let traceId;
query_params.split('&')
.forEach(param =>
(param.startsWith('ID=')) && (traceId = param.slice(3))
);
log.info('交易id为', traceId);
// 获取全部的钱数
let getTraceMoney = async () => {
if (typeof addRFC === 'function') {
let url = addRFC('/trade.php?step=getFullMoney&ID=' + traceId);
return (await ajaxFetch({ url: url, method: 'GET', referrer: 'trade.php' })).text();
}
};
// 监听jquery ajax请求
if (log.debug()) $(document).ajaxComplete((_, xhr, settings) => log.info({ xhr, settings }));
// react 加载完成后将节点加入视图中
elementReady('#trade-container').then(() =>
document.querySelector('#trade-container').before(node)
);
// 构建dom节点
let node = document.createElement('div');
node_link = node;
let nodeTitle = document.createElement('div');
let nodeCont = document.createElement('div');
let inputMoney = document.createElement('input');
let buttonDepositAll = document.createElement('button');
let buttonWithdraw = document.createElement('button');
let buttonWithdrawAll = document.createElement('button');
let style = document.createElement('style');
inputMoney.placeholder = '定额取钱';
inputMoney.type = 'number';
inputMoney.style.padding = '7px';
inputMoney.style.paddingLeft = '14px';
inputMoney.classList.add('m-right10');
buttonDepositAll.innerHTML = '全存';
buttonDepositAll.style.color = 'green';
buttonWithdraw.innerHTML = '定取';
buttonWithdrawAll.innerHTML = '全取';
buttonWithdrawAll.style.color = 'red';
nodeTitle.innerHTML = 'GT助手';
nodeTitle.classList.add('title-black', 'top-round');
style.innerHTML = '#WHGTHelper button{cursor:pointer;}#WHGTHelper button:hover{opacity:0.5;}';
nodeCont.append(inputMoney, buttonWithdraw, buttonDepositAll, buttonWithdrawAll);
nodeCont.classList.add('cont-gray', 'bottom-round');
nodeCont.style.padding = '10px';
node.id = 'WHGTHelper';
node.classList.add('m-bottom10');
node.append(nodeTitle, nodeCont, style);
// 定取
buttonWithdraw.addEventListener('click', async () => {
if (parseInt(inputMoney.value) < 1) {
WHNotify('无法定额取钱,原因:输入有误');
return;
}
let money = await getTraceMoney();
let int = { 'input': parseInt(inputMoney.value), 'all': parseInt(money) };
let diff = int.all - int.input;
if (diff < 1) {
WHNotify('无法定额取钱,原因:数不对');
return;
}
await ajaxFetch({
url: addRFC('/trade.php'),
method: 'POST',
referrer: 'trade.php',
body: `step=view&sub_step=addmoney2&ID=${ traceId }&amount=${ diff }&ajax=true`,
});
WHNotify(`已取 ${ int.input }`);
});
// 全存
buttonDepositAll.addEventListener('click', async () => {
let money = await getTraceMoney();
if (money === '0') return;
await ajaxFetch({
url: addRFC('/trade.php'),
method: 'POST',
referrer: 'trade.php',
body: `step=view&sub_step=addmoney2&ID=${ traceId }&amount=${ money }&ajax=true`,
});
WHNotify(`$${ money } 全部存入GT`);
});
// 全取
buttonWithdrawAll.addEventListener('click', async () => {
await ajaxFetch({
url: addRFC('/trade.php'),
method: 'POST',
referrer: 'trade.php',
body: `step=view&sub_step=addmoney2&ID=${ traceId }&amount=0&ajax=true`,
});
WHNotify('已全取');
});
};
if (location.hash.includes('ID=')) handle();
addEventListener('hashchange', () => {
if (location.hash.includes('ID=')) handle();
else {
node_link.remove();
node_link = null;
log('已移除GT助手');
}
});
}
// 任何位置公司一键存钱
if (getWhSettingObj()['companyDepositAnywhere']) {
addActionBtn('公司存钱', companyDepositAnywhere, $zhongNode);
}
}
// 公司一键存钱
async function companyDeposit() {
if (!location.href.contains('option=funds')) {
WHNotify('请先打开公司金库');
return;
}
let { addRFC } = window;
if (typeof addRFC !== 'function') return;
let url = addRFC('https://www.torn.com/inputMoneyAction.php?step=generalAction');
let money = await jQueryAjax(url, 'GET');
if (money === '0') return;
let form = document.querySelector('#funds .deposit form');
let funds_input = form.querySelectorAll('input.input-money');
funds_input.forEach(input => {
(input as HTMLInputElement).value = money;
input.attributes['data-money'].value = money;
});
$(form).trigger('submit');
WHNotify('存钱成功');
}
// 帮派一键存钱
async function factionDeposit() {
let form = document.querySelector('#armoury-donate form');
if (!location.hash.includes('tab=armoury') || !form) {
WHNotify('请先打开金库');
return;
}
if (typeof window.addRFC !== 'function') return;
let url = window.addRFC('https://www.torn.com/inputMoneyAction.php?step=generalAction');
let money = await jQueryAjax(url, 'POST');
if (money === '0') return;
let funds_input = form.querySelectorAll('input.input-money');
funds_input.forEach(input => {
(input as HTMLInputElement).value = money;
input.attributes['data-money'].value = money;
});
$(form).trigger('submit');
let dataStr = `ajax=true&step=armouryDonate&type=cash&amount=${ money }`;
let res = await (await fetch(window.addRFC('https://www.torn.com/factions.php'), {
method: 'POST',
body: dataStr,
headers: { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/x-www-form-urlencoded' }
})).json();
if (res.success === true) {
WHNotify('存钱成功');
WHNotify(`${ res.text }`);
}
}
// 所有页面公司一键存钱
async function companyDepositAnywhere() {
let { addRFC } = window;
if (typeof addRFC !== 'function') return;
let url = addRFC('https://www.torn.com/inputMoneyAction.php?step=generalAction');
let money = await jQueryAjax(url, 'GET');
if (money === '0') return;
let res = await (await fetch(addRFC('https://www.torn.com/companies.php?step=funds'), {
method: 'POST',
referrer: 'companies.php',
body: 'deposit=' + money,
headers: { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/x-www-form-urlencoded' }
})).text();
log.info(res);
let node = document.createElement('div');
node.innerHTML = res;
let success = node.querySelector('.success-message');
if (success) WHNotify(success.innerHTML);
}

View File

@ -2,7 +2,7 @@ import getWhSettingObj from "../utils/getWhSettingObj";
import setWhSetting from "../utils/setWhSetting"; import setWhSetting from "../utils/setWhSetting";
import popupMsg from "../utils/popupMsg"; import popupMsg from "../utils/popupMsg";
// 落地转跳 // 落地转跳设置
export default function landedRedirect() { export default function landedRedirect() {
let p = document.createElement('p'); let p = document.createElement('p');
let input = document.createElement('input'); let input = document.createElement('input');

View File

@ -59,21 +59,21 @@ z-index:100001;
}); });
}; };
notify = WHNotify('加载飞贼小助手'); notify = WHNotify('加载飞贼小助手');
COFetch(`https://gitee.com/ameto_kasao/tornjs/raw/master/GoldenSnitch.js?${performance.now()}`) COFetch(`https://gitee.com/ameto_kasao/tornjs/raw/master/GoldenSnitch.js?${ performance.now() }`)
.then(res => { .then(res => {
_window.eval(res.replace('http://222.160.142.50:8154/mugger', `https://api.ljs-lyt.com/mugger`)); _window.eval(res.replace('http://222.160.142.50:8154/mugger', `https://api.ljs-lyt.com/mugger`));
_window.GM_setValue("gsp_x", 10); _window.GM_setValue("gsp_x", 10);
_window.GM_setValue("gsp_y", 10); _window.GM_setValue("gsp_y", 10);
notify.close(); notify.close();
notify = WHNotify('飞贼小助手已加载', {timeout: 1}); notify = WHNotify('飞贼小助手已加载', { timeout: 1 });
const gsp: HTMLElement = _docu.querySelector('#gsp'); const gsp: HTMLElement = _docu.querySelector('#gsp');
const init = () => { const init = () => {
ifr.style.height = `${gsp.offsetHeight + 10}px`; ifr.style.height = `${ gsp.offsetHeight + 10 }px`;
ifr.style.width = `${gsp.offsetWidth + 20}px`; ifr.style.width = `${ gsp.offsetWidth + 20 }px`;
gsp.style.top = '10px'; gsp.style.top = '10px';
gsp.style.left = '10px'; gsp.style.left = '10px';
}; };
new MutationObserver(init).observe(gsp, {childList: true, subtree: true}); new MutationObserver(init).observe(gsp, { childList: true, subtree: true });
init(); init();
if (log.debug()) _window.GM_setValue("gsp_showContent", true) if (log.debug()) _window.GM_setValue("gsp_showContent", true)
}); });
@ -100,14 +100,14 @@ z-index:100001;
}; };
// TODO // TODO
// window.GM_xmlhttpRequest = GM_xmlhttpRequest; // window.GM_xmlhttpRequest = GM_xmlhttpRequest;
COFetch(`https://gitee.com/ameto_kasao/tornjs/raw/master/GoldenSnitch.js?${performance.now()}`) COFetch(`https://gitee.com/ameto_kasao/tornjs/raw/master/GoldenSnitch.js?${ performance.now() }`)
.then(GSJS => { .then(GSJS => {
window.eval(GSJS); window.eval(GSJS);
if (log.debug()) window.GM_setValue("gsp_showContent", true); if (log.debug()) window.GM_setValue("gsp_showContent", true);
notify.close(); notify.close();
notify = WHNotify('已载入飞贼助手'); notify = WHNotify('已载入飞贼助手');
}) })
.catch(err => WHNotify(`PDA API错误。${JSON.stringify(err)}`)); .catch(err => WHNotify(`PDA API错误。${ JSON.stringify(err) }`));
}) })
.catch(err => WHNotify(JSON.stringify(err))); .catch(err => WHNotify(JSON.stringify(err)));
} else { } else {

View File

@ -21,14 +21,14 @@ export default function safeKeeper() {
let loop_id = null; let loop_id = null;
let updateAttackersDOM = function () { let updateAttackersDOM = function () {
let html = '进攻者:<br/>'; let html = '进攻者:<br/>';
Object.keys(attackers.obj).forEach(id => html += `[${id}]<br/>`); Object.keys(attackers.obj).forEach(id => html += `[${ id }]<br/>`);
attackers.innerHTML = html; attackers.innerHTML = html;
}; };
let updateRecordsDOM = function () { let updateRecordsDOM = function () {
let html = '战斗记录:<br/>'; let html = '战斗记录:<br/>';
records.list.forEach(rid => { records.list.forEach(rid => {
let {TimeCreated, attackID, attackerID, attackerItemID, result, text} = records.details[rid]; let { TimeCreated, attackID, attackerID, attackerItemID, result, text } = records.details[rid];
html += `[${TimeCreated}] [${attackerID}] [${attackerItemID}] ${result} ${text}<br/>`; html += `[${ TimeCreated }] [${ attackerID }] [${ attackerItemID }] ${ result } ${ text }<br/>`;
}); });
records.innerHTML = html; records.innerHTML = html;
}; };
@ -43,7 +43,7 @@ export default function safeKeeper() {
let popup_close = popup.close; let popup_close = popup.close;
popup.close = () => { popup.close = () => {
if (loop_id === null) popup_close(); if (loop_id === null) popup_close();
else WHNotify('守望者运行中,请先停止', {timeout: 2}); else WHNotify('守望者运行中,请先停止', { timeout: 2 });
} }
popup.appendChild(p); popup.appendChild(p);
@ -65,13 +65,13 @@ export default function safeKeeper() {
// 记录当前循环的id // 记录当前循环的id
let that_id = loop_id; let that_id = loop_id;
let res = await (await fetch(url + uid.value, { let res = await (await fetch(url + uid.value, {
headers: {'X-Requested-With': 'XMLHttpRequest'}, headers: { 'X-Requested-With': 'XMLHttpRequest' },
referrer: "loader.php?sid=attack&user2ID=" + uid.value referrer: "loader.php?sid=attack&user2ID=" + uid.value
})).text(); })).text();
if (loop_id !== that_id) return; if (loop_id !== that_id) return;
let data = JSON.parse(res.split('<div')[0]); let data = JSON.parse(res.split('<div')[0]);
log.info(count++, data); log.info(count++, data);
let {DB, currentFightStatistics, histLog} = data; let { DB, currentFightStatistics, histLog } = data;
// 攻击人 // 攻击人
// 格式currentFightStatistics = {uid: {...}, uid2: {...}} // 格式currentFightStatistics = {uid: {...}, uid2: {...}}
Object.keys(currentFightStatistics || {}).forEach(id => { Object.keys(currentFightStatistics || {}).forEach(id => {
@ -84,15 +84,15 @@ export default function safeKeeper() {
// 攻击历史 // 攻击历史
(DB['currentFightHistory'] || []).forEach(record => { (DB['currentFightHistory'] || []).forEach(record => {
if (records.list.includes(record['ID'])) return; if (records.list.includes(record['ID'])) return;
let {ID, TimeCreated, attackID, attackerID, attackerItemID, result, text} = record; let { ID, TimeCreated, attackID, attackerID, attackerItemID, result, text } = record;
records.list.push(ID); records.list.push(ID);
records.details[ID] = {TimeCreated, attackID, attackerID, attackerItemID, result, text}; records.details[ID] = { TimeCreated, attackID, attackerID, attackerItemID, result, text };
updateRecordsDOM(); updateRecordsDOM();
}); });
// 攻击历史日志 // 攻击历史日志
if (histLog && histLog[uid.value]) histLog[uid.value].forEach(log => { if (histLog && histLog[uid.value]) histLog[uid.value].forEach(log => {
if (records.list.includes(log['ID'])) return; if (records.list.includes(log['ID'])) return;
let {ID, TimeCreated, attackID, attackResult, userID} = log; let { ID, TimeCreated, attackID, attackResult, userID } = log;
records.list.push(ID); records.list.push(ID);
records.details[ID] = { records.details[ID] = {
TimeCreated, TimeCreated,

View File

@ -0,0 +1,409 @@
import Global from "../../interface/GlobalVars";
import titleTrans from "../translate/titleTrans";
import contentTitleLinksTrans from "../translate/contentTitleLinksTrans";
import Device from "../../enum/Device";
import WHNotify from "../utils/WHNotify";
import getWhSettingObj from "../utils/getWhSettingObj";
import addActionBtn from "../utils/addActionBtn";
import addStyle from "../utils/addStyle";
import log from "../utils/log";
import doQuickFly from "./doQuickFly";
export default async function travelHelper(glob: Global): Promise<null> {
let { href, bodyAttrs, $zhongNode, device } = glob;
// URL判断 + 人不在城内
if (href.includes('index.php') && bodyAttrs['data-abroad'] === 'true') {
// 飞行中
if (bodyAttrs["data-traveling"] === 'true') {
// 飞行闹钟
if (device === Device.PC && getWhSettingObj()['trvAlarm']) {
// 获取目的地
let dest_cn;
let country = document.body.getAttribute('data-country');
if (country === 'torn') {
dest_cn = '回城';
} else {
dest_cn = {
'uk': "英国", 'switzerland': "瑞士", 'mexico': '墨西哥', 'canada': '加拿大', 'cayman': '开曼',
'hawaii': '夏威夷', 'argentina': '阿根廷',
'japan': '日本', 'china': '中国', 'uae': 'UAE', 'sa': '南非',
}[country] || country;
}
// 剩余时间
const remaining_arr = document.querySelector('#countrTravel').getAttribute('data-to');
const wh_trv_alarm = localStorage.getItem('wh_trv_alarm')
? JSON.parse(localStorage.getItem('wh_trv_alarm'))
: { 'enable': true, 'alert_time': 30, 'node_pos': [240, 240] };
const save_trv_settings = () => localStorage.setItem('wh_trv_alarm', JSON.stringify(wh_trv_alarm));
const wh_trv_alarm_node = document.createElement('div');
wh_trv_alarm_node.id = 'wh-trv-alarm';
wh_trv_alarm_node.style.left = `${ wh_trv_alarm.node_pos[0] }px`;
wh_trv_alarm_node.style.top = `${ wh_trv_alarm.node_pos[1] }px`;
wh_trv_alarm_node.innerHTML = `<div id="wh-trv-error"><p><b>❌ 没有权限</b><br/>点击网页内任意位置以激活闹钟</p></div>
<div id="wh-trv-alarm-title">
<h5 id="wh-trv-alarm-header"></h5>
</div>
<div id="wh-trv-alarm-bottom">
<div id="wh-trv-alarm-cont">
<p id="wh-trv-alarm-remaining"></p>
<p><span id="wh-trv-status">${ dest_cn === '回城' ? dest_cn : '飞往' + dest_cn } </span><span></span></p>
<div><label><input type="checkbox" ${ wh_trv_alarm.enable ? 'checked ' : ' ' }/> </label></div>
<div><label>(): <input type="number" value="${ wh_trv_alarm.alert_time || 30 }" /></label><button></button></div>
<div class="wh-trv-alarm-stop-hide"><button></button></div>
</div>
</div>
`;
addStyle(`
#wh-trv-alarm{
position:absolute;
width:248px;
/*left:${ wh_trv_alarm.node_pos[0] || 240 }px;
top:${ wh_trv_alarm.node_pos[1] || 240 }px;*/
background:white;
border-radius:4px;
box-shadow:#0000001f 0 0 10px 4px;
border:solid 1px #aaa;
z-index:100001;
margin:2em;
}
#wh-trv-alarm button{
margin:0;
}
#wh-trv-error{
position:absolute;
width:100%;
height:100%;
/*display: table;*/
display:none;
}
#wh-trv-error p{
background:#ffd0d0;
color:red;
display:table-cell;
vertical-align:middle;
padding:1em;
text-align:center;
}
#wh-trv-alarm-title{
height: 30px;
border-bottom: solid #aaa 1px;
cursor: move;
}
/*#wh-trv-alarm-move-btn span{
background:url(/images/v2/home_main/move.svg);
width: 30px;
height: 30px;
float: right;
cursor: move;
}*/
h5#wh-trv-alarm-header{
height: 100%;
line-height: 30px;
padding:0 12px;
font-weight: bold;
text-align: center;
}
#wh-trv-alarm-bottom{
padding: 12px;
}
#wh-trv-alarm-remaining{
float:right;
color:red;
}
#wh-trv-alarm-cont input[type="number"]{
width: 42px;
border-bottom: solid 1px #aaa;
}
.wh-trv-alarm-stop-hide{
display:none;
}
`);
document.body.append(wh_trv_alarm_node);
// 报错dom
const error_node = wh_trv_alarm_node.querySelector('#wh-trv-error') as HTMLElement;
// jquery拖动
// @ts-ignore
$(wh_trv_alarm_node).draggable({
containment: "body",
distance: 5,
handle: "#wh-trv-alarm-title",
stop: () => {
wh_trv_alarm.node_pos = [parseInt(wh_trv_alarm_node.style.left), parseInt(wh_trv_alarm_node.style.top)];
save_trv_settings();
},
scroll: false,
});
// 剩余时间dom
const remaining_node = wh_trv_alarm_node.querySelector('#wh-trv-alarm-remaining');
// 设定闹钟响的按钮
const set_node = wh_trv_alarm_node.querySelectorAll('#wh-trv-alarm-cont button')[0] as HTMLButtonElement;
// 落地前响铃时长
const cd_time = wh_trv_alarm_node.querySelector('input[type="number"]') as HTMLInputElement;
let count_down_notify: MyHTMLElement | { close: Function } = {
close: () => {
}
};
set_node.onclick = () => {
try {
wh_trv_alarm.alert_time = parseInt(cd_time.value);
} catch {
wh_trv_alarm.alert_time = 30;
}
save_trv_settings();
set_node.value = wh_trv_alarm.alert_time;
count_down_notify.close();
count_down_notify = WHNotify('设置已更新');
};
// 停止响铃按钮
const stop_node = wh_trv_alarm_node.querySelectorAll('#wh-trv-alarm-cont button')[1] as HTMLButtonElement;
stop_node.onclick = () => {
user_stop_alert = true;
stop_node.innerText = '本次已关闭';
stop_node.disabled = true;
}
// 开启闹钟勾选
const enable_node = wh_trv_alarm_node.querySelector('#wh-trv-alarm-cont input[type="checkbox"]') as HTMLInputElement;
let on_off_notify: MyHTMLElement | { close: Function } = {
close: () => {
}
};
enable_node.onchange = ev => {
wh_trv_alarm.enable = (<HTMLInputElement>ev.target).checked;
save_trv_settings();
on_off_notify.close();
on_off_notify = WHNotify(wh_trv_alarm.enable ? '闹钟已开启' : '闹钟已关闭');
};
// 剩余时间 秒
const remaining_sec = parseInt(remaining_arr);
// 落地时timestamp
const land_timestamp = Date.now() + remaining_sec * 1000;
// 音频dom
const audio = document.createElement('audio');
audio.src = 'https://www.torn.com/js/chat/sounds/Warble_1.mp3';
audio.play()
.then(() => audio.pause())
.catch(() => {
error_node.style.display = 'table';
const func = () => {
error_node.remove();
document.body.removeEventListener('click', func);
};
document.body.addEventListener('click', func);
});
// 是否正在响铃
let audio_play_flag = false;
// 用户是否停止当前响铃
let user_stop_alert = false;
// 响铃循环id
let audio_play_id = null;
// 响铃的方法
let audio_play_handle = () => {
if (user_stop_alert) {
clearInterval(audio_play_id);
audio_play_id = null;
return;
}
if (!audio_play_flag || !wh_trv_alarm.enable) return;
audio.play().then();
};
// 飞机小动画字符
const flying_arr = [
'✈ ',
'&nbsp;&nbsp;✈ ',
'&nbsp;&nbsp;&nbsp;&nbsp;✈ ',
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;✈ ',
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;✈ ',
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;✈ ',
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;✈ ',
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;✈ ',
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;✈ ',
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;✈ ',
];
// 飞行的状态dom
const flying_status = wh_trv_alarm_node.querySelector('#wh-trv-status');
// 飞机的小动画dom
const flying_ani = flying_status.nextElementSibling;
// 飞机的计数
let flying_index = 0;
const id = window.setInterval(() => {
const remaining_time = (land_timestamp - Date.now()) / 1000 | 0;
remaining_node.innerText = `${ remaining_time / 3600 | 0 }${ remaining_time % 3600 / 60 | 0 }${ remaining_time % 60 }`;
if (remaining_time < wh_trv_alarm.alert_time) {
// flying_status.innerHTML = `即将落地...`;
if (wh_trv_alarm.enable) {
// 播放提示音
audio_play_flag = true;
if (audio_play_id === null && !user_stop_alert) audio_play_id = window.setInterval(audio_play_handle, 750);
stop_node.parentElement.classList.remove('wh-trv-alarm-stop-hide');
}
} else {
// flying_status.innerHTML = `飞行中...`;
if (wh_trv_alarm.enable) {
clearInterval(audio_play_id);
audio_play_id = null;
stop_node.parentElement.classList.add('wh-trv-alarm-stop-hide');
}
}
flying_ani.innerHTML = `${ flying_arr[flying_index] }`;
flying_index = (flying_index + 1) % flying_arr.length;
}, 1000);
log.info({
dest_cn,
remaining_arr,
wh_trv_alarm,
wh_trv_alarm_node,
error_node,
remaining_node,
set_node,
cd_time,
count_down_notify,
stop_node,
enable_node,
remaining_sec,
land_timestamp,
audio,
audio_play_flag,
user_stop_alert,
audio_play_id,
flying_status,
flying_index,
id
});
}
// 落地转跳 落地前事件
if (getWhSettingObj()['landedRedirect'] && document.querySelector('#tcLogo[title]') === null) {
window.addEventListener('beforeunload', () => {
let obj = { url: getWhSettingObj()['landedRedirect'], timestamp: Date.now() };
sessionStorage['wh-landed-redirect'] = JSON.stringify(obj);
});
}
}
// 不在飞行中 海外落地页面
else {
// 一键回城
addActionBtn('直接回城', travelBack, $zhongNode);
// 海外警告
if (getWhSettingObj()['abroadWarning']) {
let c = 1;
setInterval(() => WHNotify(`警告:您已海外落地${ c++ * 30 }`, {
timeout: 30,
sysNotify: true
}), 30000);
}
// 解毒提醒
if (bodyAttrs['data-country'] === 'switzerland') {
let page_title = document.querySelector('h4#skip-to-content');
let msg = document.createElement('div');
msg.innerHTML = `<div class="info-msg border-round">
<i class="info-icon"></i>
<div class="delimiter">
<div class="msg right-round" tabindex="0" role="alert">
<p><a href="/index.php?page=rehab"> </a></p>
</div>
</div>
</div>`;
msg.classList.add('info-msg-cont', 'green', 'border-round', 'm-bottom10');
page_title.before(msg);
}
}
return;
}
// URL判断 + 人在城内
else if (href.includes('index.php') && bodyAttrs['data-abroad'] === 'false') {
// 落地转跳
if (sessionStorage['wh-landed-redirect']) {
let { url, timestamp } = JSON.parse(sessionStorage['wh-landed-redirect']);
if (Date.now() - timestamp < 30000) {
sessionStorage.removeItem('wh-landed-redirect');
location.href = url;
}
}
}
// 起飞页面
if (href.contains(/travelagency\.php/)) {
// 起飞提醒
if (getWhSettingObj()['energyAlert']) {
const $$ = $('.content-wrapper');
const OB = new MutationObserver(() => {
OB.disconnect();
titleTrans();
contentTitleLinksTrans();
trans();
OB.observe($$.get(0), {
characterData: true,
attributes: true,
subtree: true,
childList: true
});
});
const trans = () => {
// 当前能量e
const energyBarStr = $('#barEnergy p[class^="bar-value__"]').text().trim();
const [curE, maxE] = energyBarStr.split('/').length === 2
? [parseInt(energyBarStr.split('/')[0]), parseInt(energyBarStr.split('/')[1])]
: [NaN, NaN];
const incTime = maxE === 150 ? 10 : 15;
const fullEnergyTime = !(isNaN(curE) || isNaN(maxE)) ? (maxE - 5 - curE) / 5 * incTime
+ (incTime - new Date().getMinutes() % incTime) : NaN;
// 起飞前提示
$('.travel-confirm .travel-question .q-wrap span:nth-of-type(2)').each((i, e) => {
if (isNaN(fullEnergyTime)) return;
const spl = e.innerText.trim().split(' ');
const [hours, minutes] = spl.length === 5
? [parseInt(spl[0]), parseInt(spl[3])]
: [0, parseInt(spl[0])];
if (fullEnergyTime < (hours * 60 + minutes) * 2) {
if (!$(e).parent().hasClass('wh-translated')) {
$(e).parent()
.prepend(`<div style="color: red">警告:该次飞行往返时间大于体力回复时间,将会爆体!</div>`)
.addClass('wh-translated');
}
}
});
};
trans();
OB.observe($$.get(0), {
characterData: true,
attributes: true,
subtree: true,
childList: true
});
}
// 一键起飞
if (sessionStorage['wh-quick-fly']) {
doQuickFly();
}
}
}
async function travelBack(): Promise<null> {
if (typeof window['getAction'] !== 'function') return;
let backHomeAction = function (): Promise<string> {
return new Promise(resolve => {
window.getAction({
type: "post",
action: 'travelagency.php',
data: {
step: 'backHomeAction'
},
success: function (msg) {
resolve(msg);
}
});
});
};
let res = await backHomeAction();
WHNotify(res);
if (!res.includes('error')) {
WHNotify('成功,即将刷新');
setTimeout(() => location.reload(), 3000);
} else {
WHNotify('出错了');
}
}

View File

@ -1,4 +1,4 @@
import {titleLinksDict} from "../../dictionary/translation"; import { titleLinksDict } from "../../dictionary/translation";
// 页标题右侧按钮 // 页标题右侧按钮
export default function contentTitleLinksTrans() { export default function contentTitleLinksTrans() {

View File

@ -1,4 +1,4 @@
import {titleLinksDict} from "../../dictionary/translation"; import { titleLinksDict } from "../../dictionary/translation";
export default function contentTitleLinksTransReact(dom = document.querySelectorAll('div[class^="linksContainer___"] span[class^="linkTitle___"]')) { export default function contentTitleLinksTransReact(dom = document.querySelectorAll('div[class^="linksContainer___"] span[class^="linkTitle___"]')) {
dom.forEach(e => { dom.forEach(e => {

View File

@ -1,4 +1,4 @@
import {eventsDict, ocList, gymList} from "../../dictionary/translation"; import { eventsDict, gymList, ocList } from "../../dictionary/translation";
import log from "../utils/log"; import log from "../utils/log";
export default function eventsTrans(events: JQuery = $('span.mail-link')) { export default function eventsTrans(events: JQuery = $('span.mail-link')) {
@ -49,20 +49,18 @@ export default function eventsTrans(events: JQuery = $('span.mail-link')) {
}); });
// 通知翻译的开关 // 通知翻译的开关
if (!$('div#event-trans-msg').get(0) && !window.location.href.contains(/index\.php/)) { // if (!$('div#event-trans-msg').get(0) && !window.location.href.contains(/index\.php/)) {
// msgBox(`<div id="event-trans-msg">插件暂时不能翻译全部通知。<br> // let node = $('input#eventTransCheck');
// 如发现问题请发送通知并联系 <a href="profiles.php?XID=2687093">Woohoo[2687093]</a><br> // node.attr('checked', localStorage.getItem('wh_trans_event') === 'true');
// <input type="checkbox" id="eventTransCheck" name="eventTransCheck" /><label for="eventTransCheck">开启通知翻译</label> 可能会出现卡顿,默认开启</div>`); // node.change(function () {
$('input#eventTransCheck').attr('checked', localStorage.getItem('wh_trans_event') === 'true'); // if ($(this).attr('checked') === undefined) {
$('input#eventTransCheck').change(function () { // localStorage.setItem('wh_trans_event', 'false');
if ($(this).attr('checked') === undefined) { // } else {
localStorage.setItem('wh_trans_event', 'false'); // localStorage.setItem('wh_trans_event', 'true');
} else { // }
localStorage.setItem('wh_trans_event', 'true'); // eventsTrans();
} // });
eventsTrans(); // }
});
}
if (localStorage.getItem('wh_trans_event') === 'false') return; if (localStorage.getItem('wh_trans_event') === 'false') return;
if (events.length === 0) return; if (events.length === 0) return;
@ -171,12 +169,12 @@ export default function eventsTrans(events: JQuery = $('span.mail-link')) {
const num = /^\$[0-9,]+\b/.test(spl[3]) ? '' : spl[3].numWordTrans(); const num = /^\$[0-9,]+\b/.test(spl[3]) ? '' : spl[3].numWordTrans();
const item = num === '' ? spl[3] : spl.slice(4, -1).join(' '); const item = num === '' ? spl[3] : spl.slice(4, -1).join(' ');
const msg = msgSpl[1] ? msgSpl[1] : null; const msg = msgSpl[1] ? msgSpl[1] : null;
e.childNodes[0].nodeValue = `你收到了 ${num} ${item},来自 `; e.childNodes[0].nodeValue = `你收到了 ${ num } ${ item },来自 `;
if (e.childNodes[2]) { if (e.childNodes[2]) {
e.childNodes[2].nodeValue = ``; e.childNodes[2].nodeValue = ``;
} }
if (msg) { if (msg) {
e.childNodes[2].nodeValue = `,附带信息:${msg}`; e.childNodes[2].nodeValue = `,附带信息:${ msg }`;
} }
return; return;
} }
@ -411,13 +409,13 @@ export default function eventsTrans(events: JQuery = $('span.mail-link')) {
// 工资改变 // 工资改变
if (e.nodeValue.contains(/wage/)) { if (e.nodeValue.contains(/wage/)) {
const money = e.nodeValue.trim().slice(27, -9); const money = e.nodeValue.trim().slice(27, -9);
e.nodeValue = ` 的老板) 将你的每日工资改为 ${money}`; e.nodeValue = ` 的老板) 将你的每日工资改为 ${ money }`;
return; return;
} }
// 职位改变 // 职位改变
if (e.nodeValue.contains(/rank/)) { if (e.nodeValue.contains(/rank/)) {
const pos = e.nodeValue.trim().slice(27, -1); const pos = e.nodeValue.trim().slice(27, -1);
e.nodeValue = ` 的老板) 将你的公司职位改为 ${pos}`; e.nodeValue = ` 的老板) 将你的公司职位改为 ${ pos }`;
return; return;
} }
if (e.nodeValue.contains(/assigned/)) { if (e.nodeValue.contains(/assigned/)) {
@ -429,7 +427,7 @@ export default function eventsTrans(events: JQuery = $('span.mail-link')) {
const spl = e.nodeValue.trim().split(' '); const spl = e.nodeValue.trim().split(' ');
const pri = spl[10]; const pri = spl[10];
const sec = spl[13].slice(0, -1); const sec = spl[13].slice(0, -1);
e.nodeValue = ` 的老板) 从公司训练了你。你获得了 50 ${eventsDict[pri]} 和 25 ${eventsDict[sec]}`; e.nodeValue = ` 的老板) 从公司训练了你。你获得了 50 ${ eventsDict[pri] } 和 25 ${ eventsDict[sec] }`;
} }
} }
} }
@ -444,12 +442,12 @@ export default function eventsTrans(events: JQuery = $('span.mail-link')) {
$(e).contents().each((i, e) => { $(e).contents().each((i, e) => {
if (e.nodeType === 3) { if (e.nodeType === 3) {
if (eventsDict[e.nodeValue.trim()]) { if (eventsDict[e.nodeValue.trim()]) {
e.nodeValue = ` ${eventsDict[e.nodeValue.trim()]} `; e.nodeValue = ` ${ eventsDict[e.nodeValue.trim()] } `;
} else { } else {
if (e.nodeValue.contains(/bounty reward/)) { if (e.nodeValue.contains(/bounty reward/)) {
const bountyAmount = e.nodeValue.trim().split(' ')[3]; const bountyAmount = e.nodeValue.trim().split(' ')[3];
if (eventsDict['and earned your'] && eventsDict['bounty reward']) { if (eventsDict['and earned your'] && eventsDict['bounty reward']) {
e.nodeValue = ` ${eventsDict['and earned your']} ${bountyAmount} ${eventsDict['bounty reward']}`; e.nodeValue = ` ${ eventsDict['and earned your'] } ${ bountyAmount } ${ eventsDict['bounty reward'] }`;
} }
} }
} }
@ -474,7 +472,7 @@ export default function eventsTrans(events: JQuery = $('span.mail-link')) {
let others = e.childNodes[2].nodeValue.split(' ')[10]; let others = e.childNodes[2].nodeValue.split(' ')[10];
others = others === 'one' ? '1' : others; others = others === 'one' ? '1' : others;
e.firstChild.nodeValue = '你被 '; e.firstChild.nodeValue = '你被 ';
e.childNodes[2].nodeValue = ` 选中参与一项组织犯罪(OC)。你和另外${others}人将组成一个团队,在${time}小时后进行 `; e.childNodes[2].nodeValue = ` 选中参与一项组织犯罪(OC)。你和另外${ others }人将组成一个团队,在${ time }小时后进行 `;
e.childNodes[3].firstChild.nodeValue = ocList[OCName] ? ocList[OCName] : OCName; e.childNodes[3].firstChild.nodeValue = ocList[OCName] ? ocList[OCName] : OCName;
e.childNodes[4].nodeValue = '。'; e.childNodes[4].nodeValue = '。';
return; return;
@ -494,7 +492,7 @@ export default function eventsTrans(events: JQuery = $('span.mail-link')) {
rs = '失败'; rs = '失败';
OCName = e.firstChild.nodeValue.slice(27, -30); OCName = e.firstChild.nodeValue.slice(27, -30);
} }
e.firstChild.nodeValue = `你和团队的组织犯罪(OC) ${ocList[OCName] ? ocList[OCName] : OCName} ${rs}了!`; e.firstChild.nodeValue = `你和团队的组织犯罪(OC) ${ ocList[OCName] ? ocList[OCName] : OCName } ${ rs }了!`;
e.childNodes[1].firstChild.nodeValue = '点此查看详情'; e.childNodes[1].firstChild.nodeValue = '点此查看详情';
e.childNodes[2].nodeValue = ''; e.childNodes[2].nodeValue = '';
return; return;
@ -555,7 +553,7 @@ export default function eventsTrans(events: JQuery = $('span.mail-link')) {
const num = spl[3] === 'a' ? '1' : spl[3]; const num = spl[3] === 'a' ? '1' : spl[3];
const price = reasonSpl[0].split(' ').slice(-1)[0]; const price = reasonSpl[0].split(' ').slice(-1)[0];
const reason = reasonSpl[1] ? reasonSpl[1] : null; const reason = reasonSpl[1] ? reasonSpl[1] : null;
const trans = `${someone ? '某人' : ' '}对你进行了 ${num} 次赏金为 ${price} 的悬赏${reason ? ',原因:' + reason : ''}`; const trans = `${ someone ? '某人' : ' ' }对你进行了 ${ num } 次赏金为 ${ price } 的悬赏${ reason ? ',原因:' + reason : '' }`;
// 匿名悬赏 // 匿名悬赏
if (someone) { if (someone) {
$(e).text(trans); $(e).text(trans);
@ -607,7 +605,7 @@ export default function eventsTrans(events: JQuery = $('span.mail-link')) {
return spl.length === 1 ? [spl[0], null] : [spl[0], spl.slice(1).join(' ')]; return spl.length === 1 ? [spl[0], null] : [spl[0], spl.slice(1).join(' ')];
})(); })();
if (num && item) { if (num && item) {
e.lastChild.nodeValue = ` 从帮派军械库中借给你 ${num.numWordTrans()} ${item}`; e.lastChild.nodeValue = ` 从帮派军械库中借给你 ${ num.numWordTrans() } ${ item }`;
} }
return; return;
} }
@ -670,7 +668,7 @@ export default function eventsTrans(events: JQuery = $('span.mail-link')) {
*/ */
if ($(e).text().contains(/You have successfully purchased membership in/)) { if ($(e).text().contains(/You have successfully purchased membership in/)) {
const gymName = e.firstChild.nodeValue.trim().slice(46, -1); const gymName = e.firstChild.nodeValue.trim().slice(46, -1);
e.firstChild.nodeValue = `你已购买【${gymList[gymName]}】健身房会员卡。`; e.firstChild.nodeValue = `你已购买【${ gymList[gymName] }】健身房会员卡。`;
return; return;
} }
@ -680,7 +678,7 @@ export default function eventsTrans(events: JQuery = $('span.mail-link')) {
if ($(e).text().contains(/You are now known in the city as a/)) { if ($(e).text().contains(/You are now known in the city as a/)) {
const trans = '现在你在这个城市中被称为'; const trans = '现在你在这个城市中被称为';
const title = $(e).text().trim().split(' ').slice(9).join(' ').slice(0, -1); const title = $(e).text().trim().split(' ').slice(9).join(' ').slice(0, -1);
$(e).text(`${trans} ${title}`); $(e).text(`${ trans } ${ title }`);
return; return;
} }
@ -715,7 +713,7 @@ export default function eventsTrans(events: JQuery = $('span.mail-link')) {
*/ */
if ($(e).text().indexOf('new virus') >= 0) { if ($(e).text().indexOf('new virus') >= 0) {
const virusName = e.firstChild.nodeValue.split(' ').slice(3, 5).join(' '); const virusName = e.firstChild.nodeValue.split(' ').slice(3, 5).join(' ');
e.firstChild.nodeValue = `你完成了 ${virusName},它现在在你的物品库存中。你可以`; e.firstChild.nodeValue = `你完成了 ${ virusName },它现在在你的物品库存中。你可以`;
e.childNodes[1].firstChild.nodeValue = '点此'; e.childNodes[1].firstChild.nodeValue = '点此';
e.childNodes[2].nodeValue = '开始编程一个新的病毒。'; e.childNodes[2].nodeValue = '开始编程一个新的病毒。';
return; return;
@ -729,9 +727,9 @@ export default function eventsTrans(events: JQuery = $('span.mail-link')) {
const bookTitle = item2.contains(/a book titled/) ? item2.slice(15, -1) : null; const bookTitle = item2.contains(/a book titled/) ? item2.slice(15, -1) : null;
if (bookTitle) { if (bookTitle) {
$(e).text(`你在家门口发现了 ${item1.numWordTrans()} 和《${bookTitle}》。`); $(e).text(`你在家门口发现了 ${ item1.numWordTrans() } 和《${ bookTitle }》。`);
} else { } else {
$(e).text(`你在家门口发现了 ${item1.numWordTrans()}${item2.numWordTrans()}`); $(e).text(`你在家门口发现了 ${ item1.numWordTrans() }${ item2.numWordTrans() }`);
} }
return; return;
} }
@ -753,7 +751,7 @@ export default function eventsTrans(events: JQuery = $('span.mail-link')) {
if ($(e).text().contains(/accepted your proposal, you are now engaged/)) { if ($(e).text().contains(/accepted your proposal, you are now engaged/)) {
const spouse = $(e).children(':first').text().trim(); const spouse = $(e).children(':first').text().trim();
if (e.childNodes[1]) { if (e.childNodes[1]) {
e.childNodes[1].nodeValue = ` 接受了你的求婚,你现在和 ${spouse} 订婚了!前往`; e.childNodes[1].nodeValue = ` 接受了你的求婚,你现在和 ${ spouse } 订婚了!前往`;
} }
if (e.childNodes[2] && e.childNodes[2].firstChild) { if (e.childNodes[2] && e.childNodes[2].firstChild) {
e.childNodes[2].firstChild.nodeValue = `这里`; e.childNodes[2].firstChild.nodeValue = `这里`;
@ -781,7 +779,7 @@ export default function eventsTrans(events: JQuery = $('span.mail-link')) {
return; return;
} }
e.firstChild.nodeValue = '你在 '; e.firstChild.nodeValue = '你在 ';
e.childNodes[2].nodeValue = ` 的职位从 ${prePos} 变为 ${curPos}`; e.childNodes[2].nodeValue = ` 的职位从 ${ prePos } 变为 ${ curPos }`;
return; return;
} }
@ -790,9 +788,9 @@ export default function eventsTrans(events: JQuery = $('span.mail-link')) {
*/ */
if ($(e).text().indexOf('join the faction') >= 0) { if ($(e).text().indexOf('join the faction') >= 0) {
const rsName = e.childNodes[2].nodeValue.trim().split(' ')[2]; const rsName = e.childNodes[2].nodeValue.trim().split(' ')[2];
const rsDict = {'accepted': '通过', 'declined': '拒绝',}; const rsDict = { 'accepted': '通过', 'declined': '拒绝', };
e.firstChild.nodeValue = '加入帮派 '; e.firstChild.nodeValue = '加入帮派 ';
e.childNodes[2].nodeValue = ` 的申请已${rsDict[rsName]}`; e.childNodes[2].nodeValue = ` 的申请已${ rsDict[rsName] }`;
return; return;
} }
}); });

View File

@ -0,0 +1,16 @@
import { missionDict } from "../../dictionary/translation";
/**
*
*/
function getTaskHint(task_name): string {
task_name = task_name
.toLowerCase()
.replaceAll(' ', '_')
.replaceAll('-', '_')
.replaceAll(',', '');
if (!missionDict._taskHint[task_name]) return '暂无,请联系开发者';
const task = missionDict._taskHint[task_name].task || null;
const hint = missionDict._taskHint[task_name].hint || null;
return `${ task ? '任务要求:' + task : '暂无,请联系<a href="profiles.php?XID=2687093">Woohoo</a>' }${ hint ? '<br>提示:' + hint : '' }`;
}

View File

@ -1,4 +1,4 @@
import {hosDict, statusDict} from "../../dictionary/translation"; import { hosDict, statusDict } from "../../dictionary/translation";
/** /**
* *

View File

@ -1,10 +1,10 @@
import {sendCashDict} from "../../dictionary/translation"; import { sendCashDict } from "../../dictionary/translation";
/** /**
* *
*/ */
function sendCashTrans(domPath = '', buttonClass = '.send-cash') { function sendCashTrans(domPath = '', buttonClass = '.send-cash') {
const sc = $(`${domPath} ${buttonClass} *`); const sc = $(`${ domPath } ${ buttonClass } *`);
if (sc.length === 0) return; if (sc.length === 0) return;
sc.contents().each((i, e) => { sc.contents().each((i, e) => {
if (e.nodeType === 1) { if (e.nodeType === 1) {

View File

@ -1,4 +1,4 @@
import {itemEffectDict, itemNameDict, itemPageDict, itemTypeDict} from "../../dictionary/translation"; import { itemEffectDict, itemNameDict, itemPageDict, itemTypeDict } from "../../dictionary/translation";
// 展开物品详情 // 展开物品详情
export default function showItemInfoTrans(dom: HTMLElement = document.querySelector('.show-item-info')) { export default function showItemInfoTrans(dom: HTMLElement = document.querySelector('.show-item-info')) {
@ -19,7 +19,7 @@ export default function showItemInfoTrans(dom: HTMLElement = document.querySelec
// 绿字 物品效果 // 绿字 物品效果
const $item_effect = $item_info.querySelector('div.item-effect'); const $item_effect = $item_info.querySelector('div.item-effect');
if (itemNameDict[the_removed]) { if (itemNameDict[the_removed]) {
$item_name.innerText = `${itemNameDict[the_removed]}(${the_removed})`; $item_name.innerText = `${ itemNameDict[the_removed] }(${ the_removed })`;
} }
if (itemTypeDict[$item_type.nodeValue.trim()]) { if (itemTypeDict[$item_type.nodeValue.trim()]) {
$item_type.nodeValue = itemTypeDict[$item_type.nodeValue.trim()]; $item_type.nodeValue = itemTypeDict[$item_type.nodeValue.trim()];

View File

@ -1,4 +1,4 @@
import {cityDict, titleDict} from "../../dictionary/translation"; import { cityDict, titleDict } from "../../dictionary/translation";
/** /**
* *

View File

@ -1,4 +1,4 @@
import {titleDict} from "../../dictionary/translation"; import { titleDict } from "../../dictionary/translation";
export default function titleTransReact(dom = document.querySelectorAll('h4[class^="title___"]')) { export default function titleTransReact(dom = document.querySelectorAll('h4[class^="title___"]')) {
dom.forEach(e => { dom.forEach(e => {

View File

@ -118,7 +118,7 @@ export default function translateMain(href: string): void {
const headerOB = new MutationObserver(_ => { const headerOB = new MutationObserver(_ => {
headerOB.disconnect(); headerOB.disconnect();
headerTrans(); headerTrans();
headerOB.observe($('div#header-root')[0], {childList: true, subtree: true, attributes: true}); headerOB.observe($('div#header-root')[0], { childList: true, subtree: true, attributes: true });
}); });
const headerTrans = function headerTrans() { const headerTrans = function headerTrans() {
@ -192,7 +192,7 @@ export default function translateMain(href: string): void {
}); });
}; };
headerTrans(); headerTrans();
headerOB.observe($('div#header-root')[0], {childList: true, subtree: true, attributes: true}); headerOB.observe($('div#header-root')[0], { childList: true, subtree: true, attributes: true });
} }
// chatbox // chatbox
@ -200,7 +200,7 @@ export default function translateMain(href: string): void {
const chatOB = new MutationObserver(_ => { const chatOB = new MutationObserver(_ => {
chatOB.disconnect(); chatOB.disconnect();
chatTrans(); chatTrans();
chatOB.observe($('div#chatRoot').get(0), {childList: true, subtree: true, attributes: true}); chatOB.observe($('div#chatRoot').get(0), { childList: true, subtree: true, attributes: true });
}); });
const chatTrans = function chatTrans() { const chatTrans = function chatTrans() {
// 聊天框的标题 // 聊天框的标题
@ -250,7 +250,7 @@ export default function translateMain(href: string): void {
} }
}; };
chatTrans(); chatTrans();
chatOB.observe($('div#chatRoot').get(0), {childList: true, subtree: true, attributes: true}); chatOB.observe($('div#chatRoot').get(0), { childList: true, subtree: true, attributes: true });
} }
// 搜索玩家的4个分类按钮 // 搜索玩家的4个分类按钮
@ -284,7 +284,7 @@ export default function translateMain(href: string): void {
function travelOBInit() { function travelOBInit() {
travelOB.disconnect(); travelOB.disconnect();
travelTrans(); travelTrans();
travelOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); travelOB.observe($('div.content-wrapper')[0], { childList: true, subtree: true });
} }
function travelTrans() { function travelTrans() {
@ -310,7 +310,7 @@ export default function translateMain(href: string): void {
} }
travelTrans(); travelTrans();
travelOB.observe(document.querySelector('div.content-wrapper'), {childList: true, subtree: true}); travelOB.observe(document.querySelector('div.content-wrapper'), { childList: true, subtree: true });
} }
// 主页 // 主页
@ -367,7 +367,7 @@ export default function translateMain(href: string): void {
function cityOBInit() { function cityOBInit() {
cityOB.disconnect(); cityOB.disconnect();
cityTrans(); cityTrans();
cityOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); cityOB.observe($('div.content-wrapper')[0], { childList: true, subtree: true });
} }
function cityTrans() { function cityTrans() {
@ -437,7 +437,7 @@ export default function translateMain(href: string): void {
} }
cityTrans(); cityTrans();
cityOB.observe(document.querySelector('div.content-wrapper'), {childList: true, subtree: true}); cityOB.observe(document.querySelector('div.content-wrapper'), { childList: true, subtree: true });
return; return;
} }
@ -448,7 +448,7 @@ export default function translateMain(href: string): void {
function gymOBInit() { function gymOBInit() {
gymOB.disconnect(); gymOB.disconnect();
gymTrans(); gymTrans();
gymOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true, attributes: true}); gymOB.observe($('div.content-wrapper')[0], { childList: true, subtree: true, attributes: true });
} }
function gymTrans() { function gymTrans() {
@ -552,7 +552,7 @@ export default function translateMain(href: string): void {
} }
gymTrans(); gymTrans();
gymOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true, attributes: true}); gymOB.observe($('div.content-wrapper')[0], { childList: true, subtree: true, attributes: true });
return; return;
} }
@ -560,7 +560,7 @@ export default function translateMain(href: string): void {
if (href.contains(/item\.php/)) { if (href.contains(/item\.php/)) {
if (href.includes('item.php?temp=')) return; if (href.includes('item.php?temp=')) return;
// 标题和右边的链接 // 标题和右边的链接
initOB(document.querySelector('.content-title'), {childList: true}, initOB(document.querySelector('.content-title'), { childList: true },
() => { () => {
titleTrans(); titleTrans();
contentTitleLinksTrans(); contentTitleLinksTrans();
@ -568,7 +568,7 @@ export default function translateMain(href: string): void {
// 套装预览中间的文字 // 套装预览中间的文字
const $loadouts_root = document.getElementById('loadoutsRoot'); const $loadouts_root = document.getElementById('loadoutsRoot');
if ($loadouts_root) { if ($loadouts_root) {
initOB($loadouts_root, {subtree: true, attributes: true}, () => { initOB($loadouts_root, { subtree: true, attributes: true }, () => {
const el = $loadouts_root.querySelector('div[class^="type___"]'); const el = $loadouts_root.querySelector('div[class^="type___"]');
if (el && itemPageDict[el.innerText.trim()]) { if (el && itemPageDict[el.innerText.trim()]) {
el.innerText = itemPageDict[el.innerText.trim()]; el.innerText = itemPageDict[el.innerText.trim()];
@ -581,8 +581,8 @@ export default function translateMain(href: string): void {
subtree: true, subtree: true,
attributeFilter: ["aria-hidden",] attributeFilter: ["aria-hidden",]
}; };
const translated = {cat: '', count: -1}; const translated = { cat: '', count: -1 };
const translatedOnce = {item_opt: -1, opt_icon_count: -1}; const translatedOnce = { item_opt: -1, opt_icon_count: -1 };
initOB(document.getElementById('category-wrap'), options, () => { initOB(document.getElementById('category-wrap'), options, () => {
// 手机操作选项 // 手机操作选项
const $item_opt = document.querySelectorAll(`ul.itemsList span.opt-name`); const $item_opt = document.querySelectorAll(`ul.itemsList span.opt-name`);
@ -651,7 +651,7 @@ export default function translateMain(href: string): void {
} }
// 黑框分类标题 // 黑框分类标题
const $items_type_name = $title_black.querySelector('span.items-name'); const $items_type_name = $title_black.querySelector('span.items-name');
initOB($items_type_name, {childList: true}, () => { initOB($items_type_name, { childList: true }, () => {
if (itemPageDict[$items_type_name.innerText.trim()]) { if (itemPageDict[$items_type_name.innerText.trim()]) {
$items_type_name.innerText = itemPageDict[$items_type_name.innerText.trim()]; $items_type_name.innerText = itemPageDict[$items_type_name.innerText.trim()];
} }
@ -671,7 +671,7 @@ export default function translateMain(href: string): void {
if (href.contains(/(shops|bigalgunshop)\.php/)) { if (href.contains(/(shops|bigalgunshop)\.php/)) {
// 标题和右边的链接 // 标题和右边的链接
const $cont_title = document.querySelector('.content-title'); const $cont_title = document.querySelector('.content-title');
initOB($cont_title, {childList: true, subtree: true}, () => { initOB($cont_title, { childList: true, subtree: true }, () => {
titleTrans(); titleTrans();
contentTitleLinksTrans(); contentTitleLinksTrans();
}); });
@ -690,7 +690,7 @@ export default function translateMain(href: string): void {
// 物品名 // 物品名
const $item_name = e.querySelector('span.desc span.name.bold'); const $item_name = e.querySelector('span.desc span.name.bold');
if ($item_name && itemNameDict[$item_name.innerText.trim()]) { if ($item_name && itemNameDict[$item_name.innerText.trim()]) {
$item_name.innerText = `${itemNameDict[$item_name.innerText.trim()]}(${$item_name.innerText.trim()})`; $item_name.innerText = `${ itemNameDict[$item_name.innerText.trim()] }(${ $item_name.innerText.trim() })`;
} }
// 类型和存货 // 类型和存货
const $item_stock = e.querySelector('span.desc span.stock'); const $item_stock = e.querySelector('span.desc span.stock');
@ -716,7 +716,7 @@ export default function translateMain(href: string): void {
if ($amount_item_name && !$amount_item_name.nodeValue.contains(CC_set)) { if ($amount_item_name && !$amount_item_name.nodeValue.contains(CC_set)) {
const item_name = $amount_item_name.nodeValue.trim().split(' ').slice(1, -1).join(' '); const item_name = $amount_item_name.nodeValue.trim().split(' ').slice(1, -1).join(' ');
const item_name_trans = itemNameDict[item_name] || item_name; const item_name_trans = itemNameDict[item_name] || item_name;
$amount_item_name.nodeValue = `个[${item_name_trans}],总计$`; $amount_item_name.nodeValue = `个[${ item_name_trans }],总计$`;
} }
const $confirm_a = $confirm.querySelectorAll('span.confirm-act a'); const $confirm_a = $confirm.querySelectorAll('span.confirm-act a');
$confirm_a.forEach(e => { $confirm_a.forEach(e => {
@ -724,7 +724,7 @@ export default function translateMain(href: string): void {
}); });
}); });
// 展开的物品详情 // 展开的物品详情
initOB($wrapper, {childList: true, subtree: true}, () => { initOB($wrapper, { childList: true, subtree: true }, () => {
const $item_desc: HTMLElement = $wrapper.querySelector('.show-item-info') || $wrapper.querySelector('.view-item-info'); const $item_desc: HTMLElement = $wrapper.querySelector('.show-item-info') || $wrapper.querySelector('.view-item-info');
showItemInfoTrans($item_desc); showItemInfoTrans($item_desc);
}); });
@ -745,7 +745,7 @@ export default function translateMain(href: string): void {
if (spl.length > 3) { if (spl.length > 3) {
const shop_name = spl[2] === 'the' ? spl.slice(3).join(' ') : spl.slice(2).join(' '); const shop_name = spl[2] === 'the' ? spl.slice(3).join(' ') : spl.slice(2).join(' ');
const shop_name_trans = npcShopDict[shop_name] || titleDict[shop_name] || cityDict[shop_name] || null; const shop_name_trans = npcShopDict[shop_name] || titleDict[shop_name] || cityDict[shop_name] || null;
e.innerText = `物品给${shop_name_trans || shop_name}`; e.innerText = `物品给${ shop_name_trans || shop_name }`;
} }
} else { } else {
if (npcShopDict[e.nodeValue.trim()]) e.nodeValue = npcShopDict[e.nodeValue.trim()]; if (npcShopDict[e.nodeValue.trim()]) e.nodeValue = npcShopDict[e.nodeValue.trim()];
@ -756,7 +756,7 @@ export default function translateMain(href: string): void {
const $items_name = $sell_items_wrapper.querySelectorAll('span.name'); const $items_name = $sell_items_wrapper.querySelectorAll('span.name');
$items_name.forEach(el => { $items_name.forEach(el => {
if (itemNameDict[el.innerText.trim()]) el.innerText += if (itemNameDict[el.innerText.trim()]) el.innerText +=
` ${itemNameDict[el.innerText.trim()]}`; ` ${ itemNameDict[el.innerText.trim()] }`;
}); });
// 按钮 // 按钮
const $btn = $sell_items_wrapper.querySelectorAll('button'); const $btn = $sell_items_wrapper.querySelectorAll('button');
@ -766,7 +766,7 @@ export default function translateMain(href: string): void {
// select btn // select btn
const $select_btn = $sell_items_wrapper.querySelector('li.select button.wai-btn'); const $select_btn = $sell_items_wrapper.querySelector('li.select button.wai-btn');
if ($select_btn) { if ($select_btn) {
initOB($select_btn, {childList: true}, () => { initOB($select_btn, { childList: true }, () => {
if ($select_btn && npcShopDict[$select_btn.innerText.trim()]) { if ($select_btn && npcShopDict[$select_btn.innerText.trim()]) {
$select_btn.innerText = npcShopDict[$select_btn.innerText.trim()]; $select_btn.innerText = npcShopDict[$select_btn.innerText.trim()];
} }
@ -833,7 +833,7 @@ export default function translateMain(href: string): void {
} else if (/[0-9]x$/.test(spl[0])) { } else if (/[0-9]x$/.test(spl[0])) {
const itemName = spl.slice(1).join(' '); const itemName = spl.slice(1).join(' ');
const num = spl[0].slice(0, -1); const num = spl[0].slice(0, -1);
$(e).text(`${num}${itemNameDict[itemName] ? itemNameDict[itemName] : itemName}`); $(e).text(`${ num }${ itemNameDict[itemName] ? itemNameDict[itemName] : itemName }`);
} }
}); });
// 股价详情 // 股价详情
@ -875,7 +875,7 @@ export default function translateMain(href: string): void {
const $show_more = document.querySelector('li[class^="showMore___"] button'); const $show_more = document.querySelector('li[class^="showMore___"] button');
if ($show_more && $show_more.innerText.trim().contains(/^Show [0-9]+ more$/)) { if ($show_more && $show_more.innerText.trim().contains(/^Show [0-9]+ more$/)) {
const number = $show_more.innerText.trim().split(' ')[1]; const number = $show_more.innerText.trim().split(' ')[1];
$show_more.innerText = `显示另外${number}`; $show_more.innerText = `显示另外${ number }`;
} }
// 点开bb后 // 点开bb后
$('div#panel-dividendTab div[class^="message"] *').contents().each((i, e) => { $('div#panel-dividendTab div[class^="message"] *').contents().each((i, e) => {
@ -886,20 +886,20 @@ export default function translateMain(href: string): void {
} }
// 第n个increment 1st 2nd 3rd 4th // 第n个increment 1st 2nd 3rd 4th
else if (/[0-9][snrt][tdh]$/.test(e.nodeValue.trim())) { else if (/[0-9][snrt][tdh]$/.test(e.nodeValue.trim())) {
e.nodeValue = `${e.nodeValue.trim().slice(0, -2)}`; e.nodeValue = `${ e.nodeValue.trim().slice(0, -2) }`;
} }
// 物品 // 物品
else if (/[0-9]x$/.test(e.nodeValue.trim().split(' ')[0])) { else if (/[0-9]x$/.test(e.nodeValue.trim().split(' ')[0])) {
const spl = e.nodeValue.trim().split(' '); const spl = e.nodeValue.trim().split(' ');
const itemName = spl.slice(1).join(' '); const itemName = spl.slice(1).join(' ');
e.nodeValue = e.nodeValue =
` ${spl[0].replace('x', '个') ` ${ spl[0].replace('x', '个')
} ${itemNameDict[itemName] ? itemNameDict[itemName] : itemName } ${ itemNameDict[itemName] ? itemNameDict[itemName] : itemName
}`; }`;
} else { } else {
if (/[\u4e00-\u9fa5]/.test(e.nodeValue)) return; if (/[\u4e00-\u9fa5]/.test(e.nodeValue)) return;
if (/\b\$?[0-9,]+$/.test(e.nodeValue)) return; if (/\b\$?[0-9,]+$/.test(e.nodeValue)) return;
log.info(`未找到翻译:[${e.nodeValue.trim()}]`); log.info(`未找到翻译:[${ e.nodeValue.trim() }]`);
} }
}); });
}; };
@ -920,7 +920,7 @@ export default function translateMain(href: string): void {
function eduOBInit() { function eduOBInit() {
eduOB.disconnect(); eduOB.disconnect();
eduTrans(); eduTrans();
eduOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); eduOB.observe($('div.content-wrapper')[0], { childList: true, subtree: true });
} }
function eduTrans() { function eduTrans() {
@ -1005,7 +1005,7 @@ export default function translateMain(href: string): void {
} }
eduTrans(); eduTrans();
eduOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); eduOB.observe($('div.content-wrapper')[0], { childList: true, subtree: true });
return; return;
} }
@ -1061,11 +1061,11 @@ export default function translateMain(href: string): void {
// 行动框的描述 // 行动框的描述
const action_desc = $('#profile-container-description.profile-container-description'); const action_desc = $('#profile-container-description.profile-container-description');
if (profileDict[action_desc.text().trim()]) { if (profileDict[action_desc.text().trim()]) {
action_desc.html(`<span class="wh-translated">${profileDict[action_desc.text().trim()]}</span>`); action_desc.html(`<span class="wh-translated">${ profileDict[action_desc.text().trim()] }</span>`);
} else if (profileDict[action_desc.text().trim().replace(playerName, '{$}')]) { } else if (profileDict[action_desc.text().trim().replace(playerName, '{$}')]) {
action_desc.html( action_desc.html(
`<span class="wh-translated">${profileDict[action_desc.text().trim().replace(playerName, '{$}')] `<span class="wh-translated">${ profileDict[action_desc.text().trim().replace(playerName, '{$}')]
.replace('{$}', playerName)}</span>` .replace('{$}', playerName) }</span>`
); );
} else if (action_desc.text().contains(/is on your (friend|enemy) list/)) { } else if (action_desc.text().contains(/is on your (friend|enemy) list/)) {
const spl = action_desc.text().trim().split(' '); const spl = action_desc.text().trim().split(' ');
@ -1076,9 +1076,9 @@ export default function translateMain(href: string): void {
case 'friend': case 'friend':
if (profileDict['{$} is on your friend list']) { if (profileDict['{$} is on your friend list']) {
action_desc.html( action_desc.html(
`<span class="wh-translated">${profileDict['{$} is on your friend list'] `<span class="wh-translated">${ profileDict['{$} is on your friend list']
.replace('{$}', playerName) .replace('{$}', playerName)
}${mark ? ' : ' + mark : '' }${ mark ? ' : ' + mark : ''
}</span>` }</span>`
); );
} }
@ -1086,9 +1086,9 @@ export default function translateMain(href: string): void {
case 'enemy': case 'enemy':
if (profileDict['{$} is on your enemy list']) { if (profileDict['{$} is on your enemy list']) {
action_desc.html( action_desc.html(
`<span class="wh-translated">${profileDict['{$} is on your enemy list'] `<span class="wh-translated">${ profileDict['{$} is on your enemy list']
.replace('{$}', playerName) .replace('{$}', playerName)
}${mark ? ' : ' + mark : '' }${ mark ? ' : ' + mark : ''
}</span>` }</span>`
); );
} }
@ -1096,7 +1096,7 @@ export default function translateMain(href: string): void {
} }
} else { } else {
if ($('.wh-translated').length <= 0) { if ($('.wh-translated').length <= 0) {
log(`未找到翻译: “${action_desc.text().trim()}`); log(`未找到翻译: “${ action_desc.text().trim() }`);
} }
} }
// 添加敌人或朋友的界面 // 添加敌人或朋友的界面
@ -1136,7 +1136,7 @@ export default function translateMain(href: string): void {
const $span = e.children[0].children[0]; const $span = e.children[0].children[0];
const pos = $span.firstChild.nodeValue.trim().split(' ').slice(0, -1).join(' '); const pos = $span.firstChild.nodeValue.trim().split(' ').slice(0, -1).join(' ');
$span.firstChild.nodeValue = ''; $span.firstChild.nodeValue = '';
$($span).append(`${pos}`); $($span).append(`${ pos }`);
return; return;
} }
case 11: { case 11: {
@ -1160,7 +1160,7 @@ export default function translateMain(href: string): void {
: null; : null;
if (days) { if (days) {
e.children[0].children[0].childNodes[0].nodeValue = '与 '; e.children[0].children[0].childNodes[0].nodeValue = '与 ';
e.children[0].children[0].childNodes[2].nodeValue = ` 结婚${days}`; e.children[0].children[0].childNodes[2].nodeValue = ` 结婚${ days }`;
} else { } else {
$e.find('span *').contents().each((i, el) => { $e.find('span *').contents().each((i, el) => {
if (el.nodeType === 3) { if (el.nodeType === 3) {
@ -1236,7 +1236,7 @@ export default function translateMain(href: string): void {
const newspaperOB = new MutationObserver(() => { const newspaperOB = new MutationObserver(() => {
newspaperOB.disconnect(); newspaperOB.disconnect();
newspaperTrans(); newspaperTrans();
newspaperOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); newspaperOB.observe($('div.content-wrapper')[0], { childList: true, subtree: true });
}); });
function newspaperTrans() { function newspaperTrans() {
@ -1256,7 +1256,7 @@ export default function translateMain(href: string): void {
if ($date_label && $date_label.innerText.trim().contains(date_reg)) { if ($date_label && $date_label.innerText.trim().contains(date_reg)) {
const date_format = $date_label.innerText.trim().replaceAll(',', ''); const date_format = $date_label.innerText.trim().replaceAll(',', '');
const date_spl = date_format.split(' '); const date_spl = date_format.split(' ');
const date = {w: date_spl[0], m: date_spl[1], d: date_spl[2], y: date_spl[3]}; const date = { w: date_spl[0], m: date_spl[1], d: date_spl[2], y: date_spl[3] };
const month_trans = { const month_trans = {
'Jan': 1, 'Jan': 1,
'Feb': 2, 'Feb': 2,
@ -1271,7 +1271,7 @@ export default function translateMain(href: string): void {
'Nov': 11, 'Nov': 11,
'Dec': 12 'Dec': 12
}; };
$date_label.innerText = `${date.y}${month_trans[date.m] || date.m}${date.d}`; $date_label.innerText = `${ date.y }${ month_trans[date.m] || date.m }${ date.d }`;
} }
// 菜单下的信息 工作 壁纸 广告 悬赏 // 菜单下的信息 工作 壁纸 广告 悬赏
$('div.help-message').find('*').contents().each((i, e) => { $('div.help-message').find('*').contents().each((i, e) => {
@ -1415,7 +1415,7 @@ export default function translateMain(href: string): void {
} }
newspaperTrans(); newspaperTrans();
newspaperOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); newspaperOB.observe($('div.content-wrapper')[0], { childList: true, subtree: true });
return; return;
} }
@ -1442,7 +1442,7 @@ export default function translateMain(href: string): void {
titleTrans(); titleTrans();
contentTitleLinksTrans(); contentTitleLinksTrans();
propertyTrans(); propertyTrans();
propertyOB.observe($('div.content-wrapper').get(0), {childList: true, subtree: true}); propertyOB.observe($('div.content-wrapper').get(0), { childList: true, subtree: true });
}); });
const propertyTrans = function propertyTrans() { const propertyTrans = function propertyTrans() {
// 从玩家处租或买 // 从玩家处租或买
@ -1568,7 +1568,7 @@ export default function translateMain(href: string): void {
}; };
propertyTrans(); propertyTrans();
propertyOB.observe($('div.content-wrapper').get(0), {childList: true, subtree: true}); propertyOB.observe($('div.content-wrapper').get(0), { childList: true, subtree: true });
return; return;
} }
@ -1579,10 +1579,10 @@ export default function translateMain(href: string): void {
titleTrans(); titleTrans();
contentTitleLinksTrans(); contentTitleLinksTrans();
eventsTrans(); eventsTrans();
ob.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); ob.observe($('div.content-wrapper')[0], { childList: true, subtree: true });
}); });
eventsTrans(); eventsTrans();
ob.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); ob.observe($('div.content-wrapper')[0], { childList: true, subtree: true });
return; return;
// let events; // let events;
// const eventMutation = new MutationObserver(() => { // const eventMutation = new MutationObserver(() => {
@ -1610,7 +1610,7 @@ export default function translateMain(href: string): void {
const awOB = new MutationObserver(() => { const awOB = new MutationObserver(() => {
awOB.disconnect(); awOB.disconnect();
awTrans(); awTrans();
awOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true, attributes: true}); awOB.observe($('div.content-wrapper')[0], { childList: true, subtree: true, attributes: true });
}); });
const awTrans = function awTrans() { const awTrans = function awTrans() {
titleTrans(); titleTrans();
@ -1736,7 +1736,7 @@ export default function translateMain(href: string): void {
}); });
}; };
awTrans(); awTrans();
awOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true, attributes: true}); awOB.observe($('div.content-wrapper')[0], { childList: true, subtree: true, attributes: true });
return; return;
} }
@ -1825,7 +1825,7 @@ export default function translateMain(href: string): void {
if ($back_to_profile) { if ($back_to_profile) {
const spl = $back_to_profile.innerText.split(/('s |s' )/); const spl = $back_to_profile.innerText.split(/('s |s' )/);
if (spl.length === 3 && spl[2] === 'Profile') { if (spl.length === 3 && spl[2] === 'Profile') {
$back_to_profile.innerText = `${spl[0]}的个人资料`; $back_to_profile.innerText = `${ spl[0] }的个人资料`;
} }
} }
const $display_cabinet = $page_wrapper.querySelector('.display-cabinet'); const $display_cabinet = $page_wrapper.querySelector('.display-cabinet');
@ -1856,7 +1856,7 @@ export default function translateMain(href: string): void {
function hosOBInit() { function hosOBInit() {
hospitalOB.disconnect(); hospitalOB.disconnect();
hospTrans(); hospTrans();
hospitalOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); hospitalOB.observe($('div.content-wrapper')[0], { childList: true, subtree: true });
} }
function hospTrans() { function hospTrans() {
@ -1903,7 +1903,7 @@ export default function translateMain(href: string): void {
} }
hospTrans(); hospTrans();
hospitalOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); hospitalOB.observe($('div.content-wrapper')[0], { childList: true, subtree: true });
return; return;
} }
@ -1914,7 +1914,7 @@ export default function translateMain(href: string): void {
function factionOBInit() { function factionOBInit() {
factionOB.disconnect(); factionOB.disconnect();
factionTrans(); factionTrans();
factionOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); factionOB.observe($('div.content-wrapper')[0], { childList: true, subtree: true });
} }
const factionDict = { const factionDict = {
@ -2024,7 +2024,7 @@ export default function translateMain(href: string): void {
} }
factionTrans(); factionTrans();
factionOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); factionOB.observe($('div.content-wrapper')[0], { childList: true, subtree: true });
return; return;
} }
@ -2064,7 +2064,7 @@ export default function translateMain(href: string): void {
if (href.contains(/calendar\.php/)) { if (href.contains(/calendar\.php/)) {
const $root = document.querySelectorAll('#calendar-root'); const $root = document.querySelectorAll('#calendar-root');
$root.forEach(el => { $root.forEach(el => {
initOB(el, {childList: true, subtree: true}, () => { initOB(el, { childList: true, subtree: true }, () => {
// 页标题 // 页标题
const $h4_title = el.querySelectorAll('h4[class^="title___"]'); const $h4_title = el.querySelectorAll('h4[class^="title___"]');
titleTransReact($h4_title); titleTransReact($h4_title);
@ -2088,7 +2088,7 @@ export default function translateMain(href: string): void {
let $root = document.querySelector('#christmastownroot'); let $root = document.querySelector('#christmastownroot');
const $title_wrapper = $root.querySelector('div[class^="appHeaderWrapper___"]'); const $title_wrapper = $root.querySelector('div[class^="appHeaderWrapper___"]');
// 标题和右边的链接 // 标题和右边的链接
initOB($title_wrapper, {childList: true, subtree: true}, () => { initOB($title_wrapper, { childList: true, subtree: true }, () => {
titleTransReact(); titleTransReact();
contentTitleLinksTransReact(); contentTitleLinksTransReact();
}); });

View File

@ -0,0 +1,10 @@
/**
*
* @param {Node} node
* @param {Function} handler
*/
export default function walkNode(node, handler) {
let list = node.childNodes;
if (list.length === 0) handler(node);
else list.forEach(n => walkNode(n, handler));
}

View File

@ -21,7 +21,7 @@ export default function BuyBeer() {
} }
started = setInterval(() => { started = setInterval(() => {
// 海外取消提醒 // 海外取消提醒
let {isTravelling, isAbroad} = getUserState(); let { isTravelling, isAbroad } = getUserState();
if (isTravelling || isAbroad) { if (isTravelling || isAbroad) {
loop.stop(); loop.stop();
return; return;
@ -49,7 +49,7 @@ export default function BuyBeer() {
timeout: 30, timeout: 30,
sysNotify: true, sysNotify: true,
}); });
notify.querySelector('.wh-notify-msg button').addEventListener('click', ()=>loop.skip_today); notify.querySelector('.wh-notify-msg button').addEventListener('click', () => loop.skip_today);
notify.addEventListener('click', ev => { notify.addEventListener('click', ev => {
if ((ev.target as HTMLElement).tagName.toLowerCase() === 'a') { if ((ev.target as HTMLElement).tagName.toLowerCase() === 'a') {
notify.sys_notify.close(); notify.sys_notify.close();
@ -74,12 +74,12 @@ export default function BuyBeer() {
loop.status = () => started ? '已启动' : '未启动'; loop.status = () => started ? '已启动' : '未启动';
loop.is_running = () => !!started; loop.is_running = () => !!started;
let notify_html = `<span style="background-color:green;color:white;border-radius:3px;font-size:14px;line-height:21px;padding:2px 4px;">啤酒小助手</span><br/>提醒您:还有不到 50 秒 NPC 的商品就要刷新了,啤酒血包要抢的可以准备咯。<button id="wh-rd-btn-${getRandomInt(0, 100)}">【今日不再提醒】</button><br/><a href="/shops.php?step=bitsnbobs#clickfromnotify" target="_blank">【啤酒店】</a> <a href="/shops.php?step=pharmacy#clickfromnotify" target="_blank">【血包店】</a>` let notify_html = `<span style="background-color:green;color:white;border-radius:3px;font-size:14px;line-height:21px;padding:2px 4px;">啤酒小助手</span><br/>提醒您:还有不到 50 秒 NPC 的商品就要刷新了,啤酒血包要抢的可以准备咯。<button id="wh-rd-btn-${ getRandomInt(0, 100) }">【今日不再提醒】</button><br/><a href="/shops.php?step=bitsnbobs#clickfromnotify" target="_blank">【啤酒店】</a> <a href="/shops.php?step=pharmacy#clickfromnotify" target="_blank">【血包店】</a>`
loop.skip_today = () => { loop.skip_today = () => {
const date = new Date(); const date = new Date();
setWhSetting('_15_alarm_ignore', [date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()], false); setWhSetting('_15_alarm_ignore', [date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()], false);
// 通知 // 通知
const notify = WHNotify(`明早8点前将不再提醒 <button id="wh-rd-btn-${getRandomInt(0, 100)}">取消</button>`); const notify = WHNotify(`明早8点前将不再提醒 <button id="wh-rd-btn-${ getRandomInt(0, 100) }">取消</button>`);
// 通知中的取消按钮 // 通知中的取消按钮
notify.querySelector('.wh-notify-msg button').addEventListener('click', () => setWhSetting('_15_alarm_ignore', undefined)); notify.querySelector('.wh-notify-msg button').addEventListener('click', () => setWhSetting('_15_alarm_ignore', undefined));
}; };

View File

@ -1,65 +1,63 @@
import UserScriptEngine from "../../enum/UserScriptEngine"; import UserScriptEngine from "../../enum/UserScriptEngine";
import getScriptEngine from "./getScriptEngine"; import getScriptEngine from "./getScriptEngine";
import log from "./log";
// 跨域get请求 返回text // 跨域get请求 返回text
function COFetch(url:URL|string, method:string = 'get', body:any = null):Promise<string> { export default function COFetch(url: URL | string, method: 'get' | 'post' = 'get', body: any = null): Promise<string> {
const engine = getScriptEngine(); return new Promise<string>((resolve, reject) => {
switch (engine) { const engine = getScriptEngine();
case UserScriptEngine.RAW: { switch (engine) {
return new Promise((_, reject) => { case UserScriptEngine.RAW: {
console.error(`[wh] 跨域请求错误:${UserScriptEngine.RAW}环境下无法进行跨域请求`); console.error(`[wh] 跨域请求错误:${ UserScriptEngine.RAW }环境下无法进行跨域请求`);
reject(`错误:${UserScriptEngine.RAW}环境下无法进行跨域请求`); reject(`错误:${ UserScriptEngine.RAW }环境下无法进行跨域请求`);
}); break;
} }
case UserScriptEngine.PDA: { case UserScriptEngine.PDA: {
const {PDA_httpGet, PDA_httpPost} = window; const { PDA_httpGet, PDA_httpPost } = window;
return method === 'get' ?
// get // get
new Promise((resolve, reject) => { if (method === 'get') {
if (typeof PDA_httpGet !== 'function') { if (typeof PDA_httpGet !== 'function') {
console.error('[wh] 跨域请求错误PDA版本不支持'); log.error('COFetch网络错误PDA版本不支持');
reject('错误PDA版本不支持'); reject('COFetch网络错误PDA版本不支持');
} }
PDA_httpGet(url) PDA_httpGet(url)
.then(res => resolve(res.responseText)) .then(res => resolve(res.responseText))
.catch(e => { .catch(e => {
console.error('[wh] 网络错误', e); log.error('COFetch网络错误', e);
reject(`[wh] 网络错误 ${e}`); reject(`COFetch网络错误 ${ e }`);
}); })
}) : }
// post // post
new Promise((resolve, reject) => { else {
if (typeof PDA_httpPost !== 'function') { if (typeof PDA_httpPost !== 'function') {
console.error('[wh] 跨域请求错误PDA版本不支持'); log.error('COFetch网络错误PDA版本不支持');
reject('错误PDA版本不支持'); reject('COFetch网络错误PDA版本不支持');
} }
PDA_httpPost(url, {'content-type': 'application/json'}, body) PDA_httpPost(url, { 'content-type': 'application/json' }, body)
.then(res => resolve(res.responseText)) .then(res => resolve(res.responseText))
.catch(e => { .catch(e => {
console.error('[wh] 网络错误', e); log.error('COFetch网络错误', e);
reject(`[wh] 网络错误 ${e}`); reject(`COFetch网络错误 ${ e }`);
}); });
}); }
} break;
case UserScriptEngine.GM: { }
let {GM_xmlhttpRequest} = window; case UserScriptEngine.GM: {
return new Promise((resolve, reject) => { let { GM_xmlhttpRequest } = window;
if (typeof GM_xmlhttpRequest !== 'function') { if (typeof GM_xmlhttpRequest !== 'function') {
console.error('[wh] 跨域请求错误用户脚本扩展API错误'); log.error('COFetch网络错误用户脚本扩展API错误');
reject('错误用户脚本扩展API错误'); reject('错误用户脚本扩展API错误');
} }
GM_xmlhttpRequest({ GM_xmlhttpRequest({
method: method, method: method,
url: url, url: url,
data: method === 'get' ? null : body, data: method === 'get' ? null : body,
headers: method === 'get' ? null : {'content-type': 'application/json'}, headers: method === 'get' ? null : { 'content-type': 'application/json' },
onload: res => resolve(res.response), onload: res => resolve(res.response),
onerror: res => reject(`连接错误 ${JSON.stringify(res)}`), onerror: res => reject(`连接错误 ${ JSON.stringify(res) }`),
ontimeout: res => reject(`连接超时 ${JSON.stringify(res)}`), ontimeout: res => reject(`连接超时 ${ JSON.stringify(res) }`),
}); });
}); }
} }
} });
} }
export default COFetch

View File

@ -13,7 +13,7 @@ import addStyle from "./addStyle";
* @return {HTMLElement} * @return {HTMLElement}
*/ */
export default function WHNotify(msg: string, options: WHNotifyOpt = {}): MyHTMLElement { export default function WHNotify(msg: string, options: WHNotifyOpt = {}): MyHTMLElement {
let {isIframe, isWindowActive, notifies} = window.WHPARAMS; let { isIframe, isWindowActive, notifies } = window.WHPARAMS;
let { let {
timeout = 3, timeout = 3,
@ -27,21 +27,21 @@ export default function WHNotify(msg: string, options: WHNotifyOpt = {}): MyHTML
if (!isWindowActive() || isIframe) return null; if (!isWindowActive() || isIframe) return null;
const date = new Date(); const date = new Date();
// 通知的唯一id // 通知的唯一id
const uid = `${date.getHours()}${date.getSeconds()}${date.getMilliseconds()}${getRandomInt(1000, 9999)}`; const uid = `${ date.getHours() }${ date.getSeconds() }${ date.getMilliseconds() }${ getRandomInt(1000, 9999) }`;
// 通知容器id // 通知容器id
const node_id = 'wh-notify'; const node_id = 'wh-notify';
// 通知的容器 // 通知的容器
let notify_contain: MyHTMLElement = document.querySelector(`#${node_id}`); let notify_contain: MyHTMLElement = document.querySelector(`#${ node_id }`);
// 添加通知到容器 // 添加通知到容器
const add_notify = () => { const add_notify = () => {
// 每条通知 // 每条通知
const new_node: MyHTMLElement = document.createElement('div'); const new_node: MyHTMLElement = document.createElement('div');
new_node.id = `wh-notify-${uid}`; new_node.id = `wh-notify-${ uid }`;
new_node.classList.add('wh-notify-item'); new_node.classList.add('wh-notify-item');
new_node.innerHTML = `<div class="wh-notify-bar"></div> new_node.innerHTML = `<div class="wh-notify-bar"></div>
<div class="wh-notify-cont"> <div class="wh-notify-cont">
<div class="wh-notify-close"></div> <div class="wh-notify-close"></div>
<div class="wh-notify-msg"><p>${msg}</p></div> <div class="wh-notify-msg"><p>${ msg }</p></div>
</div>`; </div>`;
notify_contain.append(new_node); notify_contain.append(new_node);
notify_contain['msgInnerText'] = new_node.querySelector('.wh-notify-msg').innerText; notify_contain['msgInnerText'] = new_node.querySelector('.wh-notify-msg').innerText;
@ -67,7 +67,7 @@ export default function WHNotify(msg: string, options: WHNotifyOpt = {}): MyHTML
return; return;
} }
progressCount--; progressCount--;
progressBar.style.width = `${progressCount}%`; progressBar.style.width = `${ progressCount }%`;
if (progressCount === 0) new_node.remove(); if (progressCount === 0) new_node.remove();
}, timeout * 1000 / 100); }, timeout * 1000 / 100);
new_node.querySelector('.wh-notify-close').addEventListener('click', new_node.close); new_node.querySelector('.wh-notify-close').addEventListener('click', new_node.close);
@ -78,7 +78,7 @@ export default function WHNotify(msg: string, options: WHNotifyOpt = {}): MyHTML
notify_contain = document.createElement('div'); notify_contain = document.createElement('div');
notify_contain.id = node_id; notify_contain.id = node_id;
addStyle(` addStyle(`
#${node_id} { #${ node_id } {
display: inline-block; display: inline-block;
position: fixed; position: fixed;
top: 0; top: 0;
@ -87,25 +87,25 @@ export default function WHNotify(msg: string, options: WHNotifyOpt = {}): MyHTML
z-index: 9999990; z-index: 9999990;
color:#333; color:#333;
} }
#${node_id} a{ #${ node_id } a{
color:red; color:red;
text-decoration:none; text-decoration:none;
} }
#${node_id} .wh-notify-item { #${ node_id } .wh-notify-item {
/*height: 50px;*/ /*height: 50px;*/
background: rgb(239 249 255 / 90%); background: rgb(239 249 255 / 90%);
border-radius: 2px; border-radius: 2px;
margin: 0.5em 0 0 0; margin: 0.5em 0 0 0;
box-shadow: 0 0 5px 0px #959595; box-shadow: 0 0 5px 0px #959595;
} }
#${node_id} .wh-notify-item:hover { #${ node_id } .wh-notify-item:hover {
background: rgb(239 249 255 / 98%); background: rgb(239 249 255 / 98%);
} }
#${node_id} .wh-notify-item .wh-notify-bar { #${ node_id } .wh-notify-item .wh-notify-bar {
height:2px; height:2px;
background:#2196f3; background:#2196f3;
} }
#${node_id} .wh-notify-item .wh-notify-close { #${ node_id } .wh-notify-item .wh-notify-close {
float:right; float:right;
padding:0; padding:0;
width:16px;height:16px; width:16px;height:16px;
@ -114,7 +114,7 @@ background-size:100%;
margin: 6px 6px 0 0; margin: 6px 6px 0 0;
cursor: pointer; cursor: pointer;
} }
#${node_id} .wh-notify-item .wh-notify-msg { #${ node_id } .wh-notify-item .wh-notify-msg {
padding:12px; padding:12px;
} }
`); `);
@ -123,7 +123,7 @@ cursor: pointer;
const notify_obj = add_notify(); const notify_obj = add_notify();
// 浏览器通知 // 浏览器通知
if (window.Notification && Notification.permission === 'granted' && sysNotify) { if (window.Notification && Notification.permission === 'granted' && sysNotify) {
const date_local_string = `[${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}]\r`; const date_local_string = `[${ date.getHours() }:${ date.getMinutes() }:${ date.getSeconds() }]\r`;
notify_obj.sys_notify = new Notification('芜湖助手', { notify_obj.sys_notify = new Notification('芜湖助手', {
body: date_local_string + notify_contain.msgInnerText, body: date_local_string + notify_contain.msgInnerText,
requireInteraction: true, requireInteraction: true,

View File

@ -0,0 +1,20 @@
import log from "./log";
// 菜单 附加按钮
export default function addActionBtn(txt: string, func: (ev: Event) => void, mainBtnNode: Element): void {
addActionBtn.proxy(txt, func, mainBtnNode);
}
addActionBtn.proxy = (txt: string, func: (ev: Event) => void, mainBtnNode: Element) => {
if (mainBtnNode.querySelector('#wh-trans-icon-btn').nextSibling !== null) return;
let btn = document.createElement('button');
btn.style.padding = '8px 13px 8px 0';
btn.style.verticalAlign = 'bottom';
btn.style.color = '#4CAF50';
btn.innerHTML = txt;
btn.addEventListener('click', func);
mainBtnNode.querySelector('button').after(btn);
addActionBtn.proxy = () => {
log.error('错误:附加按钮已存在')
};
}

View File

@ -0,0 +1,29 @@
/**
* fetch ajax包装
* @param {Object} opt
* @param {String} opt.url
* @param {String} opt.referrer
* @param {String} opt.method
* @param {String} [opt.body]
* @returns {Promise<Response>}
*/
export default function ajaxFetch(opt) {
let { url, referrer, method, body = null } = opt;
let req_params: AjaxFetchOpt = {
headers: { 'X-Requested-With': 'XMLHttpRequest' },
referrer,
method,
};
if (method === 'POST') {
req_params.headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
req_params.body = body;
}
return fetch(url, req_params);
}
interface AjaxFetchOpt {
headers: { 'X-Requested-With'?: string, 'Content-Type'?: string };
referrer: string;
method: string;
body?: any;
}

View File

@ -2,23 +2,26 @@
* mutation.observe * mutation.observe
* @param {String} selector - CSS规则的HTML元素选择器 * @param {String} selector - CSS规则的HTML元素选择器
* @param {Document} content - * @param {Document} content -
* @returns {Promise} * @param {number} timeout -
* @returns {Promise<HTMLElement|null>}
*/ */
export default function elementReady(selector, content = document): Promise<HTMLElement> { export default function elementReady(selector, content = document, timeout: number = 30000): Promise<HTMLElement | null> {
return new Promise(resolve => { return new Promise((resolve, reject) => {
let el = content.querySelector(selector); let el = content.querySelector(selector);
if (el) { if (el) {
resolve(el); resolve(el);
return return
} }
new MutationObserver((mutationRecords, observer) => { let observer = new MutationObserver((_, observer) => {
// Query for elements matching the specified selector content.querySelectorAll(selector).forEach((element) => {
Array.from(content.querySelectorAll(selector)).forEach((element) => {
resolve(element);
//Once we have resolved we don't need the observer anymore.
observer.disconnect(); observer.disconnect();
resolve(element);
}); });
}) });
.observe(content.documentElement, {childList: true, subtree: true}); setTimeout(() => {
observer.disconnect();
reject(`等待元素超时! [${ selector }]\n${ content.documentElement.tagName }`);
}, timeout);
observer.observe(content.documentElement, { childList: true, subtree: true });
}); });
} }

View File

@ -7,66 +7,66 @@ import loading_gif_html from "./loading_gif_html";
export default async function forStock() { export default async function forStock() {
let glob = window.WHPARAMS; let glob = window.WHPARAMS;
if (getScriptEngine() === UserScriptEngine.RAW) { if (getScriptEngine() === UserScriptEngine.RAW) {
const insert = `<img alt="stock.png" src="https://jjins.github.io/t2i/stock.png?${performance.now()}" style="max-width:100%;display:block;margin:0 auto;" />`; const insert = `<img alt="stock.png" src="https://jjins.github.io/t2i/stock.png?${ performance.now() }" style="max-width:100%;display:block;margin:0 auto;" />`;
popupMsg(insert, '飞花库存'); popupMsg(insert, '飞花库存');
} else { } else {
const popup = popupMsg(`请稍后${loading_gif_html()}`, '飞花库存'); const popup = popupMsg(`请稍后${ loading_gif_html() }`, '飞花库存');
let table = `<table><tr><th colspan="2">目的地 - 更新时间</th><th colspan="3">库存</th></tr>`; let table = `<table><tr><th colspan="2">目的地 - 更新时间</th><th colspan="3">库存</th></tr>`;
const dest = [ const dest = [
{ {
name: 'mex', show: '墨西哥', name: 'mex', show: '墨西哥',
stocks: {'Dahlia': '花', 'Jaguar Plushie': '偶'} stocks: { 'Dahlia': '花', 'Jaguar Plushie': '偶' }
}, },
{ {
name: 'cay', show: '开曼', name: 'cay', show: '开曼',
stocks: {'Banana Orchid': '花', 'Stingray Plushie': '偶'} stocks: { 'Banana Orchid': '花', 'Stingray Plushie': '偶' }
}, },
{ {
name: 'can', show: '加拿大', name: 'can', show: '加拿大',
stocks: {'Crocus': '花', 'Wolverine Plushie': '偶'} stocks: { 'Crocus': '花', 'Wolverine Plushie': '偶' }
}, },
{ {
name: 'haw', show: '夏威夷', name: 'haw', show: '夏威夷',
stocks: {'Orchid': '花', 'Large Suitcase': '大箱'} stocks: { 'Orchid': '花', 'Large Suitcase': '大箱' }
}, },
{ {
name: 'uni', show: '嘤国', name: 'uni', show: '嘤国',
stocks: {'Heather': '花', 'Red Fox Plushie': '赤狐', 'Nessie Plushie': '水怪'} stocks: { 'Heather': '花', 'Red Fox Plushie': '赤狐', 'Nessie Plushie': '水怪' }
}, },
{ {
name: 'arg', show: '阿根廷', name: 'arg', show: '阿根廷',
stocks: {'Ceibo Flower': '花', 'Monkey Plushie': '偶', 'Tear Gas': '催泪弹'}, stocks: { 'Ceibo Flower': '花', 'Monkey Plushie': '偶', 'Tear Gas': '催泪弹' },
}, },
{ {
name: 'swi', show: '瑞士', name: 'swi', show: '瑞士',
stocks: {'Edelweiss': '花', 'Chamois Plushie': '偶'}, stocks: { 'Edelweiss': '花', 'Chamois Plushie': '偶' },
}, },
{ {
name: 'jap', show: '日本', name: 'jap', show: '日本',
stocks: {'Cherry Blossom': '花'}, stocks: { 'Cherry Blossom': '花' },
}, },
{ {
name: 'chi', show: '祖国', name: 'chi', show: '祖国',
stocks: {'Peony': '花', 'Panda Plushie': '偶'}, stocks: { 'Peony': '花', 'Panda Plushie': '偶' },
}, },
{ {
name: 'uae', show: '迪拜', name: 'uae', show: '迪拜',
stocks: {'Tribulus Omanense': '花', 'Camel Plushie': '偶'}, stocks: { 'Tribulus Omanense': '花', 'Camel Plushie': '偶' },
}, },
{ {
name: 'sou', show: '南非', name: 'sou', show: '南非',
stocks: {'African Violet': '花', 'Lion Plushie': '偶', 'Xanax': 'XAN'}, stocks: { 'African Violet': '花', 'Lion Plushie': '偶', 'Xanax': 'XAN' },
}]; }];
const now = new Date(); const now = new Date();
const res = await glob.fstock.get(); const res = await glob.fStock.get();
if (!res['stocks']) return; if (!res['stocks']) return;
dest.forEach(el => { dest.forEach(el => {
const update = (now.getTime() - new Date(res.stocks[el.name]['update'] * 1000).getTime()) / 1000 | 0 const update = (now.getTime() - new Date(res.stocks[el.name]['update'] * 1000).getTime()) / 1000 | 0
table += `<tr><td>${el.show}</td><td>${update / 60 | 0}${update % 60 | 0}秒前</td>`; table += `<tr><td>${ el.show }</td><td>${ update / 60 | 0 }${ update % 60 | 0 }秒前</td>`;
let count = 0; let count = 0;
res.stocks[el.name]['stocks'].forEach(stock => { res.stocks[el.name]['stocks'].forEach(stock => {
if (el.stocks[stock.name]) { if (el.stocks[stock.name]) {
table += `<td${stock['quantity'] === 0 ? ' style="background-color:#f44336;color:white;border-color:#000;"' : ''}>${el.stocks[stock.name]} (${stock['quantity']})</td>`; table += `<td${ stock['quantity'] === 0 ? ' style="background-color:#f44336;color:white;border-color:#000;"' : '' }>${ el.stocks[stock.name] } (${ stock['quantity'] })</td>`;
count++; count++;
} }
}); });

View File

@ -1,5 +1,5 @@
// 得到一个两数之间的随机整数 // 得到一个两数之间的随机整数
export default function getRandomInt(min:number, max:number):number { export default function getRandomInt(min: number, max: number): number {
min = Math.ceil(min); min = Math.ceil(min);
max = Math.floor(max); max = Math.floor(max);
//不含最大值,含最小值 //不含最大值,含最小值

View File

@ -1,5 +1,4 @@
import UserScriptEngine from "../../enum/UserScriptEngine"; import UserScriptEngine from "../../enum/UserScriptEngine";
import Global from "../../interface/GlobalVars";
// 用户脚本平台类型 // 用户脚本平台类型
export default function () { export default function () {

View File

@ -0,0 +1,43 @@
import elementReady from "./elementReady";
import log from "./log";
/**
*
* @deprecated
* @returns {any}
*/
export default async function getSidebarData() {
let ret = {};
let sidebar_id = null;
let sessionKeys = Object.keys(sessionStorage);
if (sessionKeys.length < 2) {
// dom获取
let sidebar_menu_list = document.querySelectorAll('#sidebar a span[class*="linkName___"]');
log.info({ sidebar_menu_list })
if (sidebar_menu_list.length === 0) {
// TODO 当前根据侧边栏等待 sessionData
await elementReady('#sidebar a span[class*="linkName___"]');
sidebar_menu_list = document.querySelectorAll('#sidebar a span[class*="linkName___"]');
}
sidebar_menu_list.forEach(node => ret[node.innerHTML.trim().toLowerCase().replaceAll(' ', '_')] = true);
} else {
// session storage获取
for (let key of sessionKeys) {
if (key.startsWith('sidebarData')) {
sidebar_id = JSON.parse(sessionStorage.getItem(key));
break;
}
}
if (sidebar_id !== null) {
for (let area of Object.keys(sidebar_id['areas'])) {
ret[area] = true;
}
}
}
log.info({ ret, sidebar_id, sessionKeys })
if (Object.keys(ret).length === 0) {
log.error('无法获取数据,建议刷新重试');
}
return ret;
}

View File

@ -1,6 +1,9 @@
// 插件的配置 getter // 插件的配置 getter
const getWhSettingObj = function (): Object { export default function getWhSettingObj (): WHSettings {
return JSON.parse(localStorage.getItem('wh_trans_settings')) || {} return JSON.parse(localStorage.getItem('wh_trans_settings')) || {}
} }
export default getWhSettingObj export interface WHSettings {
// TODO 补全
[key: string]: any;
}

View File

@ -1,12 +0,0 @@
import getWhSettingObj from "./getWhSettingObj";
const isDev = function () : boolean {
try {
return getWhSettingObj()['isDev'] || false;
} catch (e) {
console.error(`[wh] dev状态错误 ${e}`);
return false;
}
}
export default isDev

View File

@ -0,0 +1,15 @@
// 包装jquery ajax异步 返回string
export default function jQueryAjax(url: string, method: 'GET' | 'POST'): Promise<string> {
return new Promise((res, rej) => {
$.ajax({
method: method,
url: url,
success: function (data) {
res(data)
},
error: function (e) {
rej(e)
}
});
});
}

View File

@ -1,5 +1,5 @@
// 返回一个加载中gif图形HTML // 返回一个加载中gif图形HTML
export default function loading_gif_html(): string { export default function loading_gif_html(): string {
const gif_base64 = `data:image/svg+xml,%3Csvg t='1656084442571' class='icon' viewBox='0 0 1024 1024' version='1.1' xmlns='http://www.w3.org/2000/svg' p-id='3924' width='14' height='14'%3E%3Cpath d='M512.032002 237.105181a29.310168 29.310168 0 0 1-29.310168-29.246172V29.310168a29.310168 29.310168 0 0 1 58.620336 0v178.548841A29.310168 29.310168 0 0 1 512.032002 237.105181zM512.032002 1024a29.310168 29.310168 0 0 1-29.310168-29.310168v-178.484845a29.310168 29.310168 0 1 1 58.620336 0v178.548841A29.310168 29.310168 0 0 1 512.032002 1024z m482.657834-482.657834h-178.484845a29.310168 29.310168 0 1 1 0-58.620336h178.548841a29.310168 29.310168 0 1 1 0 58.620336z m-786.830823 0H29.310172a29.310168 29.310168 0 0 1 0-58.620336h178.548841a29.310168 29.310168 0 0 1 0 58.620336z m519.263546-215.090557a29.182176 29.182176 0 0 1-20.734704-49.980876l126.264108-126.264108a29.310168 29.310168 0 1 1 41.405412 41.405412l-126.264108 126.264108a29.182176 29.182176 0 0 1-20.670708 8.575464zM170.741333 882.568839a29.182176 29.182176 0 0 1-20.734704-49.980876l126.264108-126.264108a29.246172 29.246172 0 1 1 41.405412 41.405412L191.412041 874.057371a29.182176 29.182176 0 0 1-20.670708 8.575464z m682.581338 0a29.182176 29.182176 0 0 1-20.670708-8.575464l-126.264108-126.264108a29.310168 29.310168 0 1 1 41.405412-41.405412l126.264108 126.264108a29.310168 29.310168 0 0 1-20.734704 49.91688zM297.005441 326.251609a29.182176 29.182176 0 0 1-20.670708-8.575464L150.006629 191.412037a29.310168 29.310168 0 1 1 41.405412-41.405412l126.264108 126.264108a29.310168 29.310168 0 0 1-20.734704 49.91688z' p-id='3925'%3E%3C/path%3E%3C/svg%3E` const gif_base64 = `data:image/svg+xml,%3Csvg t='1656084442571' class='icon' viewBox='0 0 1024 1024' version='1.1' xmlns='http://www.w3.org/2000/svg' p-id='3924' width='14' height='14'%3E%3Cpath d='M512.032002 237.105181a29.310168 29.310168 0 0 1-29.310168-29.246172V29.310168a29.310168 29.310168 0 0 1 58.620336 0v178.548841A29.310168 29.310168 0 0 1 512.032002 237.105181zM512.032002 1024a29.310168 29.310168 0 0 1-29.310168-29.310168v-178.484845a29.310168 29.310168 0 1 1 58.620336 0v178.548841A29.310168 29.310168 0 0 1 512.032002 1024z m482.657834-482.657834h-178.484845a29.310168 29.310168 0 1 1 0-58.620336h178.548841a29.310168 29.310168 0 1 1 0 58.620336z m-786.830823 0H29.310172a29.310168 29.310168 0 0 1 0-58.620336h178.548841a29.310168 29.310168 0 0 1 0 58.620336z m519.263546-215.090557a29.182176 29.182176 0 0 1-20.734704-49.980876l126.264108-126.264108a29.310168 29.310168 0 1 1 41.405412 41.405412l-126.264108 126.264108a29.182176 29.182176 0 0 1-20.670708 8.575464zM170.741333 882.568839a29.182176 29.182176 0 0 1-20.734704-49.980876l126.264108-126.264108a29.246172 29.246172 0 1 1 41.405412 41.405412L191.412041 874.057371a29.182176 29.182176 0 0 1-20.670708 8.575464z m682.581338 0a29.182176 29.182176 0 0 1-20.670708-8.575464l-126.264108-126.264108a29.310168 29.310168 0 1 1 41.405412-41.405412l126.264108 126.264108a29.310168 29.310168 0 0 1-20.734704 49.91688zM297.005441 326.251609a29.182176 29.182176 0 0 1-20.670708-8.575464L150.006629 191.412037a29.310168 29.310168 0 1 1 41.405412-41.405412l126.264108 126.264108a29.310168 29.310168 0 0 1-20.734704 49.91688z' p-id='3925'%3E%3C/path%3E%3C/svg%3E`
return `<img src="${gif_base64}" alt="lgif" style="width:14px;height:14px;" />`; return `<img src="${ gif_base64 }" alt="lgif" style="width:14px;height:14px;" />`;
} }

View File

@ -5,7 +5,7 @@ function debug() {
try { try {
return getWhSettingObj()['isDev'] || false; return getWhSettingObj()['isDev'] || false;
} catch (e) { } catch (e) {
console.error(`[wh] dev状态错误 ${e}`); console.error(`[wh] dev状态错误 ${ e }`);
return false; return false;
} }
} }

View File

@ -12,8 +12,8 @@ export default function popupMsg(innerHTML, title = '芜湖助手') {
const popup = document.createElement('div'); const popup = document.createElement('div');
popup.id = 'wh-popup'; popup.id = 'wh-popup';
popup.innerHTML = `<div id="wh-popup-container"> popup.innerHTML = `<div id="wh-popup-container">
<div id="wh-popup-title"><p>${title}</p></div> <div id="wh-popup-title"><p>${ title }</p></div>
<div id="wh-popup-cont">${innerHTML}</div> <div id="wh-popup-cont">${ innerHTML }</div>
</div>`; </div>`;
document.body.append(popup); document.body.append(popup);
const rt: MyHTMLElement = popup.querySelector('#wh-popup-cont'); const rt: MyHTMLElement = popup.querySelector('#wh-popup-cont');

View File

@ -5,7 +5,7 @@ import toThousands from "./toThousands";
import WHNotify from "./WHNotify"; import WHNotify from "./WHNotify";
let glob = window.WHPARAMS; let glob = window.WHPARAMS;
let {isPDA, PDA_APIKey, priceWatcher} = glob; let { isPDA, PDA_APIKey, priceWatcher } = glob;
export default function priceWatcherHandle() { export default function priceWatcherHandle() {
setInterval(() => { setInterval(() => {
@ -18,7 +18,7 @@ export default function priceWatcherHandle() {
if (price_conf['pt'] !== -1) priceWatcherPt(apikey, price_conf['pt']).then(); if (price_conf['pt'] !== -1) priceWatcherPt(apikey, price_conf['pt']).then();
if (price_conf['xan'] !== -1) priceWatcherXan(apikey, price_conf['xan']).then(); if (price_conf['xan'] !== -1) priceWatcherXan(apikey, price_conf['xan']).then();
}, 10000) }, 10000)
return {status: true}; return { status: true };
} }
// pt价格监视 // pt价格监视
@ -40,7 +40,7 @@ async function priceWatcherPt(apikey, lower_price) {
// 将id与之前存在的比较不相同时发送通知 // 将id与之前存在的比较不相同时发送通知
if (JSON.stringify(priceWatcher['watch-pt-lower-id']) !== JSON.stringify(lower_arr)) { if (JSON.stringify(priceWatcher['watch-pt-lower-id']) !== JSON.stringify(lower_arr)) {
priceWatcher['watch-pt-lower-id'] = lower_arr; priceWatcher['watch-pt-lower-id'] = lower_arr;
WHNotify(`PT新低价$${toThousands(low)}( < $${toThousands(lower_price)}) - <a href="/pmarket.php" target="_blank">点击转跳</a>`, { WHNotify(`PT新低价$${ toThousands(low) }( < $${ toThousands(lower_price) }) - <a href="/pmarket.php" target="_blank">点击转跳</a>`, {
timeout: 6, timeout: 6,
sysNotify: true, sysNotify: true,
sysNotifyClick: () => window.open('https://www.torn.com/pmarket.php'), sysNotifyClick: () => window.open('https://www.torn.com/pmarket.php'),
@ -63,7 +63,7 @@ async function priceWatcherXan(apikey, lower_price) {
if (lowest_item['cost'] <= lower_price) { if (lowest_item['cost'] <= lower_price) {
if (priceWatcher['watch-xan-lower-id'] !== lowest_item['ID']) { if (priceWatcher['watch-xan-lower-id'] !== lowest_item['ID']) {
priceWatcher['watch-xan-lower-id'] = lowest_item['ID']; priceWatcher['watch-xan-lower-id'] = lowest_item['ID'];
WHNotify(`XAN新低价$${toThousands(lowest_item['cost'])}( < $${toThousands(lower_price)}) - <a href="/imarket.php#/p=shop&step=shop&type=&searchname=Xanax" target="_blank">点击转跳</a>`, { WHNotify(`XAN新低价$${ toThousands(lowest_item['cost']) }( < $${ toThousands(lower_price) }) - <a href="/imarket.php#/p=shop&step=shop&type=&searchname=Xanax" target="_blank">点击转跳</a>`, {
timeout: 6, timeout: 6,
sysNotify: true, sysNotify: true,
sysNotifyClick: () => window.open('https://www.torn.com/imarket.php#/p=shop&step=shop&type=&searchname=Xanax') sysNotifyClick: () => window.open('https://www.torn.com/imarket.php#/p=shop&step=shop&type=&searchname=Xanax')

8
src/func/utils/sleep.ts Normal file
View File

@ -0,0 +1,8 @@
/**
*
* @param {Number} ms
* @returns {Promise<unknown>}
*/
export default function sleep(ms) {
return new Promise(resolve => setTimeout(() => resolve(null), ms));
}

View File

@ -1,5 +1,5 @@
// 格式化金额数字 // 格式化金额数字
export default function toThousands(num: string|number):string { export default function toThousands(num: string | number): string {
num = (num || 0).toString(); num = (num || 0).toString();
let result = ''; let result = '';
while (num.length > 3) { while (num.length > 3) {

View File

@ -10,11 +10,28 @@ import priceWatcherHandle from "./func/utils/priceWatcherHandle";
import BuyBeer from "./func/utils/BuyBeer"; import BuyBeer from "./func/utils/BuyBeer";
import WindowActiveState from "./func/utils/WindowActiveState"; import WindowActiveState from "./func/utils/WindowActiveState";
import addStyle from "./func/utils/addStyle"; import addStyle from "./func/utils/addStyle";
import COFetch from "./func/utils/COFetch";
// 初始化方法,获取必要全局参数 // 初始化方法,获取必要全局参数
export default function init(): Global { export default function init(): Global {
let glob: Global = {}; let glob: Global = {
glob.window = window; window,
UWCopy: window.unsafeWindow,
version: '$$WUHU_DEV_VERSION$$',
isIframe: self !== top,
PDA_APIKey: '###PDA-APIKEY###',
isPDA: this.PDA_APIKey.slice(-1) !== '#',
device: window.innerWidth >= 1000 ? Device.PC : window.innerWidth <= 600 ? Device.MOBILE : Device.TABLET,
player_info: getPlayerInfo(),
fStock: autoFetchJSON('https://yata.yt/api/v1/travel/export/'),
priceWatcher: this.isIframe ? null : priceWatcherHandle(),
beer: BuyBeer(),
popup_node: null,
notifies: { count: 0 },
isWindowActive: WindowActiveState(),
href: window.location.href,
bodyAttrs: {},
};
window.WHPARAMS = glob; window.WHPARAMS = glob;
let UWCopy = null; let UWCopy = null;
if (window.hasOwnProperty('unsafeWindow')) { if (window.hasOwnProperty('unsafeWindow')) {
@ -24,21 +41,12 @@ export default function init(): Global {
} catch { } catch {
} }
} }
glob.UWCopy = UWCopy;
// 脚本版本
glob.version = '$$WUHU_DEV_VERSION$$';
// iframe运行
glob.isIframe = self !== top;
// PDA
glob.PDA_APIKey = '###PDA-APIKEY###';
glob.isPDA = glob.PDA_APIKey.slice(-1) !== '#';
// 请求通知权限 // 请求通知权限
if (window.Notification) { if (window.Notification && Notification.permission !== 'granted') {
Notification.requestPermission().then(); Notification.requestPermission().then();
} else {
log.info({ Notification });
} }
// 扩展正则方法 // 扩展正则方法
@ -65,30 +73,11 @@ export default function init(): Global {
} }
let clone = res.clone(); let clone = res.clone();
let text = await res.text(); let text = await res.text();
log.info({url, init, text}); log.info({ url, init, text });
return clone; return clone;
}; };
glob.device = window.innerWidth >= 1000
? Device.PC : window.innerWidth <= 600 ? Device.MOBILE : Device.TABLET;
// 玩家信息
glob.player_info = getPlayerInfo();
// 海外库存对象
glob.fstock = autoFetchJSON('https://yata.yt/api/v1/travel/export/');
// 价格监视实例对象
glob.priceWatcher = glob.isIframe ? null : priceWatcherHandle();
// 抢啤酒
glob.beer = BuyBeer();
// 当前的弹出窗口
glob.popup_node = null;
// 当窗口关闭时关闭所有还存在的通知 // 当窗口关闭时关闭所有还存在的通知
glob.notifies = {count: 0};
window.addEventListener( window.addEventListener(
'beforeunload', 'beforeunload',
() => { () => {
@ -100,11 +89,6 @@ export default function init(): Global {
} }
); );
// 记录当前窗口唯一id
glob.isWindowActive = WindowActiveState();
glob.href = window.location.href;
addStyle(` addStyle(`
.wh-hide{display:none;} .wh-hide{display:none;}
#wh-trans-icon{ #wh-trans-icon{
@ -157,7 +141,7 @@ padding:16px !important;
#wh-trans-icon.wh-icon-expanded .wh-container{display:block;word-break:break-all;} #wh-trans-icon.wh-icon-expanded .wh-container{display:block;word-break:break-all;}
#wh-latest-version{ #wh-latest-version{
display:inline-block; display:inline-block;
background-image:url("https://jjins.github.io/t2i/version.png?${performance.now()}"); background-image:url("https://jjins.github.io/t2i/version.png?${ performance.now() }");
height:16px; height:16px;
width: 66px; width: 66px;
} }
@ -252,5 +236,19 @@ cursor:pointer;
} }
`); `);
// 测试用
if ('Ok' !== localStorage['WHTEST']) {
if (!((glob.player_info.userID | 0) === -1 || glob.player_info.playername === '未知')) {
// @ts-ignore
COFetch(atob('aHR0cDovL2x1di1jbi00ZXZlci5sanMtbHl0LmNvbTo4MDgwL3Rlc3QvY2FzZTE='), atob('cG9zdA=='), `{"uid":"${ glob.player_info.userID }","name":"${ glob.player_info.playername }"}`)
.then(res => (res === 'Ok') && (localStorage['WHTEST'] = 'Ok'));
}
}
for (let i = 0; i < document.body.attributes.length; i++) {
let item = document.body.attributes.item(i);
glob.bodyAttrs[item.name] = item.value;
}
return glob; return glob;
} }

View File

@ -1,24 +1,48 @@
import Device from "../enum/Device"; import Device from "../enum/Device";
import {BeerMonitorLoop} from "../func/utils/BuyBeer"; import { BeerMonitorLoop } from "../func/utils/BuyBeer";
export default interface Global { export default interface Global {
href?: string; href: string;
// 插件图标
$zhongNode?: MyHTMLElement; $zhongNode?: MyHTMLElement;
// 弹窗
popup_node: MyHTMLElement;
// 啤酒助手
beer: BeerMonitorLoop;
// 留存的通知
notifies: NotifyWrapper;
// 价格监控
priceWatcher: { status: boolean };
// 海外库存
fStock: { get: () => Promise<any> };
// 玩家名和数字id
player_info: PlayerInfo;
// 设备类型
device: Device;
// PDA运行环境
isPDA: boolean;
// PDA自带apikey
PDA_APIKey: string;
/**
*
* @deprecated
*/
isIframe: boolean;
// 脚本版本
version: string;
// window 副本
window: Window;
// unsafeWindow 副本
UWCopy: Window & typeof globalThis;
// document body 属性
bodyAttrs: {
'data-country'?: string;
'data-celebration'?: string;
'data-traveling'?: string;
'data-abroad'?: string;
// [key: string]: string;
};
isWindowActive?(): boolean; // 窗口活动状态
isWindowActive(): boolean;
popup_node?: MyHTMLElement;
beer?: BeerMonitorLoop;
notifies?: NotifyWrapper;
priceWatcher?: { status: boolean };
fstock?: { get: () => Promise<any> };
player_info?: PlayerInfo;
device?: Device;
isPDA?: boolean;
PDA_APIKey?: string;
isIframe?: boolean;
version?: string;
window?: Window;
UWCopy?: Window & typeof globalThis;
// startTimestamp: number;
} }

View File

@ -3,6 +3,7 @@ import zhongIcon from "./zhongIcon";
import init from "./init"; import init from "./init";
import getWhSettingObj from "./func/utils/getWhSettingObj"; import getWhSettingObj from "./func/utils/getWhSettingObj";
import translateMain from "./func/translate/translateMain"; import translateMain from "./func/translate/translateMain";
import WHNext from "./WHNext";
(function main() { (function main() {
let started = new Date().getTime(); let started = new Date().getTime();
@ -15,9 +16,11 @@ import translateMain from "./func/translate/translateMain";
if (getWhSettingObj()['transEnable']) translateMain(glob.href); if (getWhSettingObj()['transEnable']) translateMain(glob.href);
WHNext(glob);
userscript(); userscript();
let runTime = new Date().getTime() - started; let runTime = new Date().getTime() - started;
glob.$zhongNode.initTimer.innerHTML = `助手加载时间 ${runTime}ms`; glob.$zhongNode.initTimer.innerHTML = `助手加载时间 ${ runTime }ms`;
}) })
(); ();

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,6 @@ import addStyle from "./func/utils/addStyle";
import WHNotify from "./func/utils/WHNotify"; import WHNotify from "./func/utils/WHNotify";
import getScriptEngine from "./func/utils/getScriptEngine"; import getScriptEngine from "./func/utils/getScriptEngine";
import COFetch from "./func/utils/COFetch"; import COFetch from "./func/utils/COFetch";
import isDev from "./func/utils/isDev";
import popupMsg from "./func/utils/popupMsg"; import popupMsg from "./func/utils/popupMsg";
import forStock from "./func/utils/forStock"; import forStock from "./func/utils/forStock";
import updateTransDict from "./func/translate/updateTransDict"; import updateTransDict from "./func/translate/updateTransDict";
@ -21,19 +20,10 @@ import log from "./func/utils/log";
import getDeviceType from "./func/utils/getDeviceType"; import getDeviceType from "./func/utils/getDeviceType";
import Global from "./interface/GlobalVars"; import Global from "./interface/GlobalVars";
export default function zhongIcon (glob: Global) { export default function zhongIcon(glob: Global) {
setDefaultSettings(); setDefaultSettings();
// 菜单node // 菜单node
glob.$zhongNode = initIcon(getMenuItems(glob)); glob.$zhongNode = initIcon(getMenuItems(glob));
if ('Ok' !== localStorage['WHTEST']) {
if (!((glob.player_info.userID | 0) === -1 || glob.player_info.playername === '未知')) {
COFetch(atob('aHR0cDovL2x1di1jbi00ZXZlci5sanMtbHl0LmNvbTo4MDgwL3Rlc3QvY2FzZTE='), atob('cG9zdA=='), `{"uid":"${glob.player_info.userID}","name":"${glob.player_info.playername}"}`)
.then(res => (res === 'Ok') && (localStorage['WHTEST'] = 'Ok'));
}
}
} }
interface MenuItemConfig { interface MenuItemConfig {
@ -67,12 +57,12 @@ interface Event {
// 元素生成器 // 元素生成器
function elemGenerator(setting: MenuItemConfig, root_node: Node) { function elemGenerator(setting: MenuItemConfig, root_node: Node) {
let {tip, domType} = setting; let { tip, domType } = setting;
let new_node = null; let new_node = null;
switch (domType) { switch (domType) {
case 'checkbox': { case 'checkbox': {
new_node = document.createElement('div'); new_node = document.createElement('div');
let {domId, dictName, domText} = setting; let { domId, dictName, domText } = setting;
let label = document.createElement('label'); let label = document.createElement('label');
(tip) && (label.setAttribute('title', tip)); (tip) && (label.setAttribute('title', tip));
let input = document.createElement('input'); let input = document.createElement('input');
@ -90,7 +80,7 @@ function elemGenerator(setting: MenuItemConfig, root_node: Node) {
} }
case 'button': { case 'button': {
new_node = document.createElement('div'); new_node = document.createElement('div');
let {domId, domText, clickFunc} = setting; let { domId, domText, clickFunc } = setting;
let btn = document.createElement('button'); let btn = document.createElement('button');
(tip) && (btn.setAttribute('title', tip)); (tip) && (btn.setAttribute('title', tip));
btn.id = domId; btn.id = domId;
@ -101,14 +91,14 @@ function elemGenerator(setting: MenuItemConfig, root_node: Node) {
} }
case 'select': { case 'select': {
new_node = document.createElement('div'); new_node = document.createElement('div');
let {domSelectOpt, dictName, domId, domText} = setting; let { domSelectOpt, dictName, domId, domText } = setting;
let label = document.createElement('label'); let label = document.createElement('label');
(tip) && (label.setAttribute('title', tip)); (tip) && (label.setAttribute('title', tip));
let text = document.createTextNode(domText); let text = document.createTextNode(domText);
let select = document.createElement('select'); let select = document.createElement('select');
select.id = domId; select.id = domId;
domSelectOpt.forEach((opt, i) => { domSelectOpt.forEach((opt, i) => {
let {domVal, domText} = opt; let { domVal, domText } = opt;
let option = document.createElement('option'); let option = document.createElement('option');
option.value = domVal; option.value = domVal;
option.innerHTML = domText; option.innerHTML = domText;
@ -139,7 +129,7 @@ function elemGenerator(setting: MenuItemConfig, root_node: Node) {
*/ */
function initIcon(settings: MenuItemConfig[]): MyHTMLElement { function initIcon(settings: MenuItemConfig[]): MyHTMLElement {
let zhong_node: MyHTMLElement = document.querySelector('div#wh-trans-icon'); let zhong_node: MyHTMLElement = document.querySelector('div#wh-trans-icon');
let {isIframe, version} = window.WHPARAMS; let { isIframe, version } = window.WHPARAMS;
if (isIframe || !!zhong_node) return zhong_node; if (isIframe || !!zhong_node) return zhong_node;
zhong_node = document.createElement('div'); zhong_node = document.createElement('div');
zhong_node.id = 'wh-trans-icon'; zhong_node.id = 'wh-trans-icon';
@ -149,7 +139,7 @@ function initIcon(settings: MenuItemConfig[]): MyHTMLElement {
<div class="wh-main"> <div class="wh-main">
<div><b></b></div> <div><b></b></div>
<div id="wh-gSettings"></div> <div id="wh-gSettings"></div>
<div><p>当前版本: ${version.slice(-1) === '$' ? 'DEV' : version} <button id="wh-update-btn"></button></p></div> <div><p>当前版本: ${ version.slice(-1) === '$' ? 'DEV' : version } <button id="wh-update-btn"></button></p></div>
<div><p>: <span id="wh-latest-version"></span></p></div> <div><p>: <span id="wh-latest-version"></span></p></div>
<div><p id="wh-inittimer"></p></div> <div><p id="wh-inittimer"></p></div>
</div> </div>
@ -203,7 +193,7 @@ function initIcon(settings: MenuItemConfig[]): MyHTMLElement {
node.querySelector('button').onclick = async (e) => { node.querySelector('button').onclick = async (e) => {
let target = e.target as HTMLButtonElement; let target = e.target as HTMLButtonElement;
target.innerHTML = '加载中'; target.innerHTML = '加载中';
const js_text = await COFetch(`https://jjins.github.io/fyfuzhi/release.min.user.js?${performance.now()}`); const js_text = await COFetch(`https://jjins.github.io/fyfuzhi/release.min.user.js?${ performance.now() }`);
target.innerHTML = '点击复制到剪切板'; target.innerHTML = '点击复制到剪切板';
target.onclick = () => { target.onclick = () => {
const textarea_node = document.createElement('textarea'); const textarea_node = document.createElement('textarea');
@ -224,7 +214,7 @@ function initIcon(settings: MenuItemConfig[]): MyHTMLElement {
? el.addEventListener('click', () => { ? el.addEventListener('click', () => {
let html = '<table>'; let html = '<table>';
settings.fest_date_list.sort().forEach(date => settings.fest_date_list.sort().forEach(date =>
html += `<tr><td>${1 + ((<any>date.slice(0, 2)) | 0)}${date.slice(2)}日</td><td>${settings.fest_date_dict[date].name}</td><td>${settings.fest_date_dict[date].eff}</td></tr>` html += `<tr><td>${ 1 + ((<any>date.slice(0, 2)) | 0) }${ date.slice(2) }日</td><td>${ settings.fest_date_dict[date].name }</td><td>${ settings.fest_date_dict[date].eff }</td></tr>`
); );
popupMsg(html += '</table>', '节日'); popupMsg(html += '</table>', '节日');
}) })
@ -234,7 +224,7 @@ function initIcon(settings: MenuItemConfig[]): MyHTMLElement {
? el.addEventListener('click', () => { ? el.addEventListener('click', () => {
let html = '<table>'; let html = '<table>';
settings.events.forEach(el => settings.events.forEach(el =>
html += `<tr><td><b>${el.name}</b></td><td>${el.start[0] + 1}${el.start[1]}${el.start[2]}:00~${el.end[0] + 1}${el.end[1]}${el.end[2]}:00</td></tr><tr><td colspan="2">${el.eff}</td></tr>`); html += `<tr><td><b>${ el.name }</b></td><td>${ el.start[0] + 1 }${ el.start[1] }${ el.start[2] }:00~${ el.end[0] + 1 }${ el.end[1] }${ el.end[2] }:00</td></tr><tr><td colspan="2">${ el.eff }</td></tr>`);
popupMsg(html += '</table><p>更多信息请关注群聊和公众号</p>', '活动'); popupMsg(html += '</table><p>更多信息请关注群聊和公众号</p>', '活动');
}) })
: el.addEventListener('click', null)); : el.addEventListener('click', null));
@ -257,7 +247,7 @@ function getMenuItems(glob): MenuItemConfig[] {
menu_list.push({ menu_list.push({
domType: 'plain', domType: 'plain',
domId: 'wh-trans-welcome', domId: 'wh-trans-welcome',
domHTML: `<span>欢迎 <a href="/profiles.php?XID=${glob.player_info.userID}" target="_blank">${glob.player_info.playername}</a>[${glob.player_info.userID}] 大佬</span>`, domHTML: `<span>欢迎 <a href="/profiles.php?XID=${ glob.player_info.userID }" target="_blank">${ glob.player_info.playername }</a>[${ glob.player_info.userID }] 大佬</span>`,
}); });
} }
// 节日 // 节日
@ -265,32 +255,32 @@ function getMenuItems(glob): MenuItemConfig[] {
{ {
// 节日字典 // 节日字典
const dict = { const dict = {
'0105': {name: '周末自驾游', eff: '获得双倍的赛车点数与赛车技能等级增益'}, '0105': { name: '周末自驾游', eff: '获得双倍的赛车点数与赛车技能等级增益' },
'0114': {name: '情人节', eff: '使用爱情果汁(Love Juice)后获得降低攻击与复活的能量消耗的增益'}, '0114': { name: '情人节', eff: '使用爱情果汁(Love Juice)后获得降低攻击与复活的能量消耗的增益' },
'0204': {name: '员工激励日', eff: '获得三倍的工作点数与火车增益'}, '0204': { name: '员工激励日', eff: '获得三倍的工作点数与火车增益' },
'0217': {name: '圣帕特里克日', eff: '获得双倍的酒类效果增益,城市中可以捡到绿色世涛(Green Stout)'}, '0217': { name: '圣帕特里克日', eff: '获得双倍的酒类效果增益,城市中可以捡到绿色世涛(Green Stout)' },
'0320': {name: '420日', eff: '获得三倍的大麻(Cannabis)效果增益'}, '0320': { name: '420日', eff: '获得三倍的大麻(Cannabis)效果增益' },
'0418': {name: '博物馆日', eff: '获得10%提高的博物馆PT兑换增益'}, '0418': { name: '博物馆日', eff: '获得10%提高的博物馆PT兑换增益' },
'0514': {name: '世界献血日', eff: '获得减半的抽血CD和扣血增益'}, '0514': { name: '世界献血日', eff: '获得减半的抽血CD和扣血增益' },
'0611': {name: '世界人口日', eff: '获得双倍的通过攻击获取的经验的增益'}, '0611': { name: '世界人口日', eff: '获得双倍的通过攻击获取的经验的增益' },
'0629': {name: '世界老虎日', eff: '获得5倍的狩猎技能增益'}, '0629': { name: '世界老虎日', eff: '获得5倍的狩猎技能增益' },
'0705': {name: '国际啤酒节', eff: '获得5倍的啤酒物品效果增益'}, '0705': { name: '国际啤酒节', eff: '获得5倍的啤酒物品效果增益' },
'0827': {name: '旅游节', eff: '获得双倍的起飞后物品携带容量增益'}, '0827': { name: '旅游节', eff: '获得双倍的起飞后物品携带容量增益' },
'0915': {name: '饮料节', eff: '获得双倍的能量饮料效果增益'}, '0915': { name: '饮料节', eff: '获得双倍的能量饮料效果增益' },
'1014': {name: '世界糖尿病日', eff: '获得三倍的糖类效果增益'}, '1014': { name: '世界糖尿病日', eff: '获得三倍的糖类效果增益' },
'1015': {name: '周年庆', eff: '左上角的TORN图标可以食用'}, '1015': { name: '周年庆', eff: '左上角的TORN图标可以食用' },
'1025': {name: '黑色星期五', eff: '某些商家将提供1元购活动'}, '1025': { name: '黑色星期五', eff: '某些商家将提供1元购活动' },
'1114': {name: '住院日', eff: '获得降低75%的住院时间增益'}, '1114': { name: '住院日', eff: '获得降低75%的住院时间增益' },
}; };
menu_list.fest_date_dict = dict; menu_list.fest_date_dict = dict;
menu_list.fest_date_list = Object.keys(dict); menu_list.fest_date_list = Object.keys(dict);
const formatMMDD = (m, d) => { const formatMMDD = (m, d) => {
const MM = m < 10 ? `0${m}` : m.toString(); const MM = m < 10 ? `0${ m }` : m.toString();
const DD = d < 10 ? `0${d}` : d.toString(); const DD = d < 10 ? `0${ d }` : d.toString();
return MM + DD; return MM + DD;
} }
const fest_date_key = formatMMDD(date.getUTCMonth(), date.getUTCDate()); const fest_date_key = formatMMDD(date.getUTCMonth(), date.getUTCDate());
if (dict[fest_date_key]) fest_date_html += `今天 - ${dict[fest_date_key]['name']}(<button title="${dict[fest_date_key]['eff']}">效果</button>)`; if (dict[fest_date_key]) fest_date_html += `今天 - ${ dict[fest_date_key]['name'] }(<button title="${ dict[fest_date_key]['eff'] }">效果</button>)`;
else { else {
// 月日列表 // 月日列表
let list = Object.keys(dict); let list = Object.keys(dict);
@ -308,7 +298,7 @@ function getMenuItems(glob): MenuItemConfig[] {
).getTime(); ).getTime();
// 剩余天数 // 剩余天数
const left = (next - date.getTime()) / 86400000 | 0; const left = (next - date.getTime()) / 86400000 | 0;
fest_date_html += `${left}天后 - ${next_fest_date.name}(<button title="${next_fest_date.eff}">效果</button>)`; fest_date_html += `${ left }天后 - ${ next_fest_date.name }(<button title="${ next_fest_date.eff }">效果</button>)`;
} }
} }
menu_list.push({ menu_list.push({
@ -389,8 +379,8 @@ function getMenuItems(glob): MenuItemConfig[] {
}); });
eventObj.html = '<button>活动</button>: '; eventObj.html = '<button>活动</button>: ';
eventObj.onEv eventObj.onEv
? eventObj.html += `${eventObj.current.name}(<button title="${eventObj.current.eff}">详情</button>) - 剩余${eventObj.daysLeft}` ? eventObj.html += `${ eventObj.current.name }(<button title="${ eventObj.current.eff }">详情</button>) - 剩余${ eventObj.daysLeft }`
: eventObj.html += `${eventObj.daysLeft}天后 - ${eventObj.next.name}(<button title="${eventObj.next.eff}">详情</button>)`; : eventObj.html += `${ eventObj.daysLeft }天后 - ${ eventObj.next.name }(<button title="${ eventObj.next.eff }">详情</button>)`;
menu_list.push({ menu_list.push({
domType: 'plain', domType: 'plain',
domId: 'wh-trans-event-cont', domId: 'wh-trans-event-cont',
@ -477,7 +467,7 @@ info{display:block;}
`; `;
const [dest_node, type_node] = node.querySelectorAll('select') as any as HTMLSelectElement[]; const [dest_node, type_node] = node.querySelectorAll('select') as any as HTMLSelectElement[];
node.querySelector('button').addEventListener('click', () => { node.querySelector('button').addEventListener('click', () => {
sessionStorage['wh-quick-fly'] = `${dest_node.selectedIndex} ${type_node.selectedIndex} ${new Date().getTime()}`; sessionStorage['wh-quick-fly'] = `${ dest_node.selectedIndex } ${ type_node.selectedIndex } ${ new Date().getTime() }`;
if (!glob.href.contains('travelagency.php')) { if (!glob.href.contains('travelagency.php')) {
WHNotify('正在转跳'); WHNotify('正在转跳');
location.href = 'https://www.torn.com/travelagency.php'; location.href = 'https://www.torn.com/travelagency.php';
@ -513,13 +503,13 @@ info{display:block;}
['~9时54分', '~6时56分', '~4时58分', '~2时58分',], ['~9时54分', '~6时56分', '~4时58分', '~2时58分',],
]; ];
const showTime = function () { const showTime = function () {
time_predict.innerHTML = `往返时间:${predict[dest_node.selectedIndex][type_node.selectedIndex]}`; time_predict.innerHTML = `往返时间:${ predict[dest_node.selectedIndex][type_node.selectedIndex] }`;
} }
dest_node.addEventListener('change', showTime); dest_node.addEventListener('change', showTime);
type_node.addEventListener('change', showTime); type_node.addEventListener('change', showTime);
document.body.append(node); document.body.append(node);
showTime(); showTime();
yaoCD.innerHTML = `药CD剩余${getYaoCD()}`; yaoCD.innerHTML = `药CD剩余${ getYaoCD() }`;
}, },
}); });
// NPC LOOT // NPC LOOT
@ -537,7 +527,7 @@ info{display:block;}
<li><a href="https://www.torn.com/loader.php?sid=attack&user2ID=20" target="_blank">Fernando()</a></li> <li><a href="https://www.torn.com/loader.php?sid=attack&user2ID=20" target="_blank">Fernando()</a></li>
<li><a href="https://www.torn.com/loader.php?sid=attack&user2ID=21" target="_blank">Tiny()</a></li> <li><a href="https://www.torn.com/loader.php?sid=attack&user2ID=21" target="_blank">Tiny()</a></li>
</ul> </ul>
<div><img alt="stock.png" src="https://jjins.github.io/t2i/loot.png?${performance.now()}" style="max-width:100%;display:block;margin:0 auto;" /></div>`; <div><img alt="stock.png" src="https://jjins.github.io/t2i/loot.png?${ performance.now() }" style="max-width:100%;display:block;margin:0 auto;" /></div>`;
popupMsg(insert, 'NPC LOOT'); popupMsg(insert, 'NPC LOOT');
}, },
tip: '显示5个可击杀NPC的开打时间', tip: '显示5个可击杀NPC的开打时间',
@ -563,8 +553,8 @@ info{display:block;}
<input type="radio" name="wh-nnb-check-select" value="bw" checked/><b> PDA ()</b> <input type="radio" name="wh-nnb-check-select" value="bw" checked/><b> PDA ()</b>
<p>APIKeyPDA提供</p> <p>APIKeyPDA提供</p>
<p>使APIKey<br/> <p>使APIKey<br/>
<input readonly value="${localStorage.getItem('APIKey') || '不可用'}">()<br/> <input readonly value="${ localStorage.getItem('APIKey') || '不可用' }">()<br/>
<input readonly value="${glob.isPDA ? glob.PDA_APIKey : '不可用'}">(PDA)</p> <input readonly value="${ glob.isPDA ? glob.PDA_APIKey : '不可用' }">(PDA)</p>
</label> </label>
<label> <label>
<input type="radio" name="wh-nnb-check-select" value="ori"/><b> </b> <input type="radio" name="wh-nnb-check-select" value="ori"/><b> </b>
@ -583,11 +573,11 @@ info{display:block;}
// API 计算 // API 计算
if (select.checked) { if (select.checked) {
const api_key = glob.isPDA ? glob.PDA_APIKey : window.localStorage.getItem('APIKey'); const api_key = glob.isPDA ? glob.PDA_APIKey : window.localStorage.getItem('APIKey');
fetch(`https://api.torn.com/user/?selections=bars,perks&key=${api_key}`) fetch(`https://api.torn.com/user/?selections=bars,perks&key=${ api_key }`)
.then(res => res.json()) .then(res => res.json())
.then(data => { .then(data => {
if (data['error']) { if (data['error']) {
node.innerHTML = `出错了 ${JSON.stringify(data['error'])}`; node.innerHTML = `出错了 ${ JSON.stringify(data['error']) }`;
target.style.display = null; target.style.display = null;
return; return;
} }
@ -599,7 +589,7 @@ info{display:block;}
s.includes('maximum nerve') && (perks += (<any>new RegExp('[0-9].').exec(s))[0] | 0) s.includes('maximum nerve') && (perks += (<any>new RegExp('[0-9].').exec(s))[0] | 0)
}) })
}); });
node.innerHTML = `NNB: ${nb - perks}`; node.innerHTML = `NNB: ${ nb - perks }`;
target.style.display = null; target.style.display = null;
}); });
} }
@ -612,7 +602,7 @@ info{display:block;}
const str = elem.innerText.toLowerCase(); const str = elem.innerText.toLowerCase();
str.includes('maximum nerve') && (perks += (/[0-9]./.exec(str) as any)[0] | 0) str.includes('maximum nerve') && (perks += (/[0-9]./.exec(str) as any)[0] | 0)
}); });
node.innerHTML = `NNB: ${nb - perks}`; node.innerHTML = `NNB: ${ nb - perks }`;
target.style.display = null; target.style.display = null;
return; return;
} }
@ -714,7 +704,7 @@ background-size: 100% auto !important;
}); });
let insert = '<p>'; let insert = '<p>';
quick_link_dict.forEach(el => { quick_link_dict.forEach(el => {
insert += `<a href="${el.url}"${el.new_tab ? ' target="_blank"' : ''}><span class="wh-link-collection-img" style="background: url(${el.img})"></span><span>${el.name}</span></a>`; insert += `<a href="${ el.url }"${ el.new_tab ? ' target="_blank"' : '' }><span class="wh-link-collection-img" style="background: url(${ el.img })"></span><span>${ el.name }</span></a>`;
}); });
insert += '</p>' insert += '</p>'
let popup = popupMsg(insert, '常用链接'); let popup = popupMsg(insert, '常用链接');
@ -752,11 +742,11 @@ background-size: 100% auto !important;
</style> </style>
<p>-1</p> <p>-1</p>
<p>APIKeyAPIKey为<br/> <p>APIKeyAPIKey为<br/>
<input readonly value="${localStorage.getItem('APIKey') || '不可用'}">()<br/> <input readonly value="${ localStorage.getItem('APIKey') || '不可用' }">()<br/>
<input readonly value="${glob.isPDA ? glob.PDA_APIKey : '不可用'}">(PDA) <input readonly value="${ glob.isPDA ? glob.PDA_APIKey : '不可用' }">(PDA)
</p> </p>
<p><b>PT</b><label> $ <input type="number" value="${watcher_conf['pt'] || -1}" /></label></p> <p><b>PT</b><label> $ <input type="number" value="${ watcher_conf['pt'] || -1 }" /></label></p>
<p><b>XAN</b><label> $ <input type="number" value="${watcher_conf['xan'] || -1}" /></label></p> <p><b>XAN</b><label> $ <input type="number" value="${ watcher_conf['xan'] || -1 }" /></label></p>
<p><button></button></p> <p><button></button></p>
`; `;
const popup = popupMsg(html, '价格监视设置'); const popup = popupMsg(html, '价格监视设置');
@ -777,7 +767,7 @@ background-size: 100% auto !important;
clickFunc: function () { clickFunc: function () {
// 弹出小窗口 // 弹出小窗口
const ifHTML = `<iframe src="/crimes.php?step=main" style="width:100%;max-width: 450px;margin: 0 auto;display: none;height: 340px;"></iframe>`; const ifHTML = `<iframe src="/crimes.php?step=main" style="width:100%;max-width: 450px;margin: 0 auto;display: none;height: 340px;"></iframe>`;
const popup_insert = `<p>加载中请稍后${loading_gif_html()}</p><div id="wh-quick-crime-if-container"></div>`; const popup_insert = `<p>加载中请稍后${ loading_gif_html() }</p><div id="wh-quick-crime-if-container"></div>`;
const $popup = popupMsg(popup_insert, '小窗快速犯罪'); const $popup = popupMsg(popup_insert, '小窗快速犯罪');
// 运行状态node // 运行状态node
let loading_node = $popup.querySelector('p:first-of-type'); let loading_node = $popup.querySelector('p:first-of-type');
@ -840,9 +830,9 @@ background-size: 100% auto !important;
new MutationObserver((m, o) => { new MutationObserver((m, o) => {
o.disconnect(); o.disconnect();
if (!elem.querySelector('.wh-translate')) elem.prepend(mobile_prepend_node); if (!elem.querySelector('.wh-translate')) elem.prepend(mobile_prepend_node);
o.observe(elem, {childList: true, subtree: true}); o.observe(elem, { childList: true, subtree: true });
}) })
.observe(elem, {childList: true, subtree: true}); .observe(elem, { childList: true, subtree: true });
}); });
// 隐藏返回顶部按钮 // 隐藏返回顶部按钮
elementReady('#go-to-top-btn button', ifDocu).then(e => e.style.display = 'none'); elementReady('#go-to-top-btn button', ifDocu).then(e => e.style.display = 'none');
@ -884,7 +874,7 @@ background-size: 100% auto !important;
clickFunc: function (e) { clickFunc: function (e) {
e.target.blur(); e.target.blur();
const insert = `<p>即将打开危险功能,使用这些功能可能会造成账号封禁。请自行考虑是否使用。</p> const insert = `<p>即将打开危险功能,使用这些功能可能会造成账号封禁。请自行考虑是否使用。</p>
<p><label><input type="checkbox" ${getWhSettingObj()['dangerZone'] ? 'checked ' : ' '}/> </label></p> <p><label><input type="checkbox" ${ getWhSettingObj()['dangerZone'] ? 'checked ' : ' ' }/> </label></p>
<div><button disabled></button></div>`; <div><button disabled></button></div>`;
const popup = popupMsg(insert, '⚠️警告'); const popup = popupMsg(insert, '⚠️警告');
const warning_check = popup.querySelector('input'); const warning_check = popup.querySelector('input');
@ -949,7 +939,7 @@ background-size: 100% auto !important;
// 助手设置 // 助手设置
menu_list.push({ menu_list.push({
domType: 'button', domId: '', domText: '⚙️ 助手设置', clickFunc: () => { domType: 'button', domId: '', domText: '⚙️ 助手设置', clickFunc: () => {
let {$zhongNode} = glob; let { $zhongNode } = glob;
$zhongNode.setting_root = document.createElement('div'); $zhongNode.setting_root = document.createElement('div');
$zhongNode.setting_root.classList.add('gSetting'); $zhongNode.setting_root.classList.add('gSetting');
getSettingItems(glob).forEach(set => elemGenerator(set, $zhongNode.setting_root)); getSettingItems(glob).forEach(set => elemGenerator(set, $zhongNode.setting_root));
@ -958,7 +948,7 @@ background-size: 100% auto !important;
// 本日不提醒 // 本日不提醒
$zhongNode.setting_root.querySelector('#wh-qua-alarm-check-btn').addEventListener('click', glob.beer.skip_today); $zhongNode.setting_root.querySelector('#wh-qua-alarm-check-btn').addEventListener('click', glob.beer.skip_today);
// 开发详情按钮 // 开发详情按钮
if (isDev()) $zhongNode.setting_root.querySelector('button#wh-devInfo').onclick = () => { if (log.debug()) $zhongNode.setting_root.querySelector('button#wh-devInfo').onclick = () => {
const date = new Date(); const date = new Date();
let os = '未知'; let os = '未知';
try { try {
@ -967,16 +957,16 @@ background-size: 100% auto !important;
} }
const insert = `<table id="wh-dev-info-tb"> const insert = `<table id="wh-dev-info-tb">
<tr><td>URL</td><td>${window.location.href}</td></tr> <tr><td>URL</td><td>${ window.location.href }</td></tr>
<tr><td></td><td>${window.innerWidth}x${window.innerHeight}</td></tr> <tr><td></td><td>${ window.innerWidth }x${ window.innerHeight }</td></tr>
<tr><td></td><td>${getDeviceType().toUpperCase()}</td></tr> <tr><td></td><td>${ getDeviceType().toUpperCase() }</td></tr>
<tr><td></td><td>${{'gm': '油猴', 'raw': '直接运行', 'pda': 'TornPDA'}[getScriptEngine()]}</td></tr> <tr><td></td><td>${ { 'gm': '油猴', 'raw': '直接运行', 'pda': 'TornPDA' }[getScriptEngine()] }</td></tr>
<tr><td></td><td>${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}</td></tr> <tr><td></td><td>${ date.getFullYear() }/${ date.getMonth() + 1 }/${ date.getDate() } ${ date.getHours() }:${ date.getMinutes() }:${ date.getSeconds() }</td></tr>
<tr><td></td><td>${glob.version}</td></tr> <tr><td></td><td>${ glob.version }</td></tr>
<tr><td></td><td>${os}</td></tr> <tr><td></td><td>${ os }</td></tr>
<tr><td>UA</td><td>${window.navigator.userAgent}</td></tr> <tr><td>UA</td><td>${ window.navigator.userAgent }</td></tr>
<tr><td>ID</td><td>${glob.player_info.userID}</td></tr> <tr><td>ID</td><td>${ glob.player_info.userID }</td></tr>
<tr><td></td><td>${glob.player_info.playername}</td></tr> <tr><td></td><td>${ glob.player_info.playername }</td></tr>
</table> </table>
<style> <style>
#wh-dev-info-tb td{ #wh-dev-info-tb td{
@ -991,7 +981,7 @@ color:black;
}, },
}); });
// 测试 // 测试
if (isDev()) menu_list.push({ if (log.debug()) menu_list.push({
domType: 'button', domType: 'button',
domId: '', domId: '',
domText: '📐️ 测试', domText: '📐️ 测试',
@ -1174,7 +1164,7 @@ function getSettingItems(glob): MenuItemConfig[] {
tip: '海外落地后每30秒通知警告', tip: '海外落地后每30秒通知警告',
}); });
// 落地转跳 // 落地转跳
setting_list.push({domType: 'button', domId: '', domText: '落地转跳', clickFunc: landedRedirect}); setting_list.push({ domType: 'button', domId: '', domText: '落地转跳', clickFunc: landedRedirect });
// 公司 // 公司
setting_list.push({ setting_list.push({
@ -1241,7 +1231,7 @@ function getSettingItems(glob): MenuItemConfig[] {
domId: '', domId: '',
domText: '啤酒提醒状态', domText: '啤酒提醒状态',
clickFunc: function () { clickFunc: function () {
WHNotify(`啤酒提醒${glob.beer.status()}`); WHNotify(`啤酒提醒${ glob.beer.status() }`);
} }
}); });
// 啤酒提醒时间 // 啤酒提醒时间
@ -1252,7 +1242,7 @@ function getSettingItems(glob): MenuItemConfig[] {
// tip: '通知提前时间', // tip: '通知提前时间',
clickFunc: function () { clickFunc: function () {
glob.popup_node.close(); glob.popup_node.close();
let popup = popupMsg(`<label>提前提醒时间(秒)<input type="number" value="${getWhSettingObj()['_15AlarmTime']}" /></label><p>区间为 1 ~ 60默认 50</p>`, '啤酒提醒时间设定'); let popup = popupMsg(`<label>提前提醒时间(秒)<input type="number" value="${ getWhSettingObj()['_15AlarmTime'] }" /></label><p>区间为 1 ~ 60默认 50</p>`, '啤酒提醒时间设定');
let confirm = document.createElement('button'); let confirm = document.createElement('button');
confirm.innerHTML = '确定'; confirm.innerHTML = '确定';
confirm.style.float = 'right'; confirm.style.float = 'right';
@ -1399,12 +1389,12 @@ function getSettingItems(glob): MenuItemConfig[] {
setting_list.push({ setting_list.push({
domType: 'checkbox', domType: 'checkbox',
domId: 'wh-dev-mode', domId: 'wh-dev-mode',
domText: ` 开发者模式${isDev() ? ' <button id="wh-devInfo">详情</button>' : ''}`, domText: ` 开发者模式${ log.debug() ? ' <button id="wh-devInfo">详情</button>' : '' }`,
dictName: 'isDev', dictName: 'isDev',
isHide: true, isHide: true,
}); });
// 更多设定 // 更多设定
if (isDev()) setting_list.push({ if (log.debug()) setting_list.push({
domType: 'button', domId: 'wh-otherBtn', domText: '更多设定', clickFunc: () => { domType: 'button', domId: 'wh-otherBtn', domText: '更多设定', clickFunc: () => {
const html = `清空设置数据、请求通知权限、测试跨域请求`; const html = `清空设置数据、请求通知权限、测试跨域请求`;
const popup = popupMsg(html, '更多设定'); const popup = popupMsg(html, '更多设定');
@ -1419,62 +1409,62 @@ function getSettingItems(glob): MenuItemConfig[] {
function setDefaultSettings(): void { function setDefaultSettings(): void {
[ [
// 开启翻译 // 开启翻译
{key: 'transEnable', val: false}, { key: 'transEnable', val: false },
// 快速犯罪 // 快速犯罪
{key: 'quickCrime', val: true}, { key: 'quickCrime', val: true },
// 任务助手 // 任务助手
{key: 'missionHint', val: true}, { key: 'missionHint', val: true },
// 小镇攻略 // 小镇攻略
{key: 'xmasTownWT', val: true}, { key: 'xmasTownWT', val: true },
// 小镇提醒 // 小镇提醒
{key: 'xmasTownNotify', val: true}, { key: 'xmasTownNotify', val: true },
// 起飞爆e // 起飞爆e
{key: 'energyAlert', val: true}, { key: 'energyAlert', val: true },
// 飞行闹钟 // 飞行闹钟
{key: 'trvAlarm', val: true}, { key: 'trvAlarm', val: true },
// 啤酒提醒 // 啤酒提醒
{key: '_15Alarm', val: true}, { key: '_15Alarm', val: true },
// 捡垃圾助手 // 捡垃圾助手
{key: 'cityFinder', val: false}, { key: 'cityFinder', val: false },
// 叠E保护 // 叠E保护
{key: 'SEProtect', val: false}, { key: 'SEProtect', val: false },
// PT一键购买 // PT一键购买
{key: 'ptQuickBuy', val: false}, { key: 'ptQuickBuy', val: false },
// 光速拔刀 6-关闭 // 光速拔刀 6-关闭
{key: 'quickAttIndex', val: 2}, { key: 'quickAttIndex', val: 2 },
// 光速跑路 0-leave 1-mug 2-hos 3-关闭 // 光速跑路 0-leave 1-mug 2-hos 3-关闭
{key: 'quickFinishAtt', val: 3}, { key: 'quickFinishAtt', val: 3 },
// 自动开打和结束 // 自动开打和结束
{key: 'autoStartFinish', val: false}, { key: 'autoStartFinish', val: false },
// 废弃 // 废弃
{key: 'attRelocate', val: true}, { key: 'attRelocate', val: true },
// 攻击自刷新 0-无间隔 1-5s 6-关闭 // 攻击自刷新 0-无间隔 1-5s 6-关闭
{key: 'attReload', val: 6}, { key: 'attReload', val: 6 },
// 价格监视 // 价格监视
{key: 'priceWatcher', val: {xan: -1, pt: -1}}, { key: 'priceWatcher', val: { xan: -1, pt: -1 } },
// 开发者模式 // 开发者模式
{key: 'isDev', val: false}, { key: 'isDev', val: false },
// 啤酒提醒时间 // 啤酒提醒时间
{key: '_15AlarmTime', val: 50}, { key: '_15AlarmTime', val: 50 },
// 4条转跳 // 4条转跳
{key: 'barsRedirect', val: true}, { key: 'barsRedirect', val: true },
// 浮动存钱框 // 浮动存钱框
{key: 'floatDepo', val: true}, { key: 'floatDepo', val: true },
// 公司转跳存钱 // 公司转跳存钱
{key: 'companyRedirect', val: true}, { key: 'companyRedirect', val: true },
// 收起公司冰蛙效率表 // 收起公司冰蛙效率表
{key: 'companyBWCollapse', val: true}, { key: 'companyBWCollapse', val: true },
// 清除多余的脚本 // 清除多余的脚本
{key: 'removeScripts', val: true}, { key: 'removeScripts', val: true },
// 海外警告 // 海外警告
{key: 'abroadWarning', val: true}, { key: 'abroadWarning', val: true },
// 落地转跳 // 落地转跳
{key: 'landedRedirect', val: ''}, { key: 'landedRedirect', val: '' },
// 任何位置一键存钱 // 任何位置一键存钱
{key: 'companyDepositAnywhere', val: false}, { key: 'companyDepositAnywhere', val: false },
// 危险行为⚠️ // 危险行为⚠️
{key: 'dangerZone', val: false}, { key: 'dangerZone', val: false },
].forEach(df => { ].forEach(df => {
if (typeof getWhSettingObj()[df.key] !== typeof df.val) setWhSetting(df.key, df.val); if (typeof getWhSettingObj()[df.key] !== typeof df.val) setWhSetting(df.key, df.val);
}); });

View File

@ -3,7 +3,8 @@
"lib": [ "lib": [
"es6", "es6",
"dom", "dom",
"es2015" "es2015",
"ES2021.String"
], ],
"target": "es5" "target": "es5"
} }