This commit is contained in:
Liwanyi 2023-01-18 11:29:11 +08:00
parent 6a0d0e064a
commit 1e151060f3
16 changed files with 429 additions and 214 deletions

View File

@ -4,6 +4,14 @@
# CHANGE # CHANGE
## 0.8.0
2023年01月16日
### 修改
- 完善新的翻译部分
## 0.7.9 ## 0.7.9
2023年01月09日 2023年01月09日

View File

@ -1,6 +1,6 @@
{ {
"name": "wuhu-torn-helper", "name": "wuhu-torn-helper",
"version": "0.7.9", "version": "0.8.0",
"description": "芜湖助手", "description": "芜湖助手",
"dependencies": {}, "dependencies": {},
"scripts": { "scripts": {

File diff suppressed because one or more lines are too long

View File

@ -11,6 +11,9 @@ import Log from "./Log";
import FetchUtils from "./utils/FetchUtils"; import FetchUtils from "./utils/FetchUtils";
import ZhongIcon from "./ZhongIcon"; import ZhongIcon from "./ZhongIcon";
import Alert from "./utils/Alert"; import Alert from "./utils/Alert";
import FetchEventCallback from "./action/FetchEventCallback";
import globVars from "../globVars";
import Translate from "./action/Translate";
/** /**
* *
@ -62,6 +65,11 @@ export class Common extends WuhuBase {
}); });
} }
// fetch方法处理
FetchEventCallback.getInstance();
// fetch方法处理-翻译
globVars.responseHandlers.push(Translate.responseHandler);
// 存钱相关 // 存钱相关
depoHelper(); depoHelper();

View File

@ -21,6 +21,7 @@ import ProfileHelper from "./action/ProfileHelper";
import SearchHelper from "./action/SearchHelper"; import SearchHelper from "./action/SearchHelper";
import TornStyleSwitch from "./utils/TornStyleSwitch"; import TornStyleSwitch from "./utils/TornStyleSwitch";
import SlotsHelper from "./action/SlotsHelper"; import SlotsHelper from "./action/SlotsHelper";
import globVars from "../globVars";
/** /**
* *
@ -97,15 +98,16 @@ export default class UrlPattern extends WuhuBase {
}); });
// 监听啤酒购买 // 监听啤酒购买
$(document).ajaxComplete((_, xhr, settings) => { let buyBeerResultMonitor = (url, body, opt) => {
Log.info({ xhr, settings }); if (url.includes('shops.php') && opt.method === 'POST') {
let { data } = settings, { responseText } = xhr; let req = opt.requestBody;
let response = JSON.parse(responseText); if (req && req.includes('step=buyShopItem') && req.includes('ID=180') && body.json && body.json['success']) {
if (data.includes('step=buyShopItem') && data.includes('ID=180') && response['success']) { new Alert('检测到已成功购买啤酒');
new Alert('已检测成功购买啤酒');
BuyBeerHelper.getInstance().skip_today(); BuyBeerHelper.getInstance().skip_today();
} }
}); }
};
globVars.responseHandlers.push(buyBeerResultMonitor);
} }
// 快速crime TODO 重构、与翻译解藕 // 快速crime TODO 重构、与翻译解藕

View File

@ -43,6 +43,7 @@ export default class WuhuConfig extends WuhuBase {
[ [
// 开启翻译 // 开启翻译
{ key: 'transEnable', val: false }, { key: 'transEnable', val: false },
{ key: 'transNew', val: true },
// 快速犯罪 // 快速犯罪
{ key: 'quickCrime', val: true }, { key: 'quickCrime', val: true },
// 任务助手 // 任务助手

View File

@ -4,10 +4,7 @@ import TravelItem from "./action/TravelItem";
import Global from "./Global"; import Global from "./Global";
import Log from "./Log"; import Log from "./Log";
import COMMON_CSS from "../static/css/common.css"; import COMMON_CSS from "../static/css/common.css";
import Timer from "./utils/Timer";
import Translate from "./action/Translate";
import globVars from "../globVars"; import globVars from "../globVars";
import FetchEventCallback from "./action/FetchEventCallback";
/** /**
* *
@ -45,15 +42,49 @@ export default class WuHuTornHelper extends WuhuBase {
} }
}; };
/**
* xhrfetch
* @param data
* @param url
* @param method
* @param requestBody
* @param {'fetch'|'xhr'}from
* @return {string|unknown}
*/
const intercept = (data: string, url: string, method: 'GET' | 'POST' | string, requestBody: string | unknown, from: 'fetch' | 'xhr') => {
let origin = data;
let ret = { json: null, text: null, isModified: false };
try {
ret.json = JSON.parse(<string>data);
} catch {
Log.warn('JSON.parse 错误', { data });
ret.text = data;
}
Log.info('[' + from + ']响应', { url, method, ret, requestBody });
globVars.WH_NET_LOG.push({ url, method, ret, requestBody, from });
globVars.responseHandlers.forEach(handler => {
try {
handler(url, ret, { method, requestBody });
} catch (e) {
Log.error(e.stack || e.message);
}
});
if (ret.isModified) {
return ret.json ? JSON.stringify(ret.json) : ret.text;
} else {
return origin;
}
};
// 监听fetch // 监听fetch
let ori_fetch = fetch || window.fetch; (function (fetch0, window) {
let originFetch = fetch0;
// 引用解决与其他脚本接管fetch方法引起的兼容性问题 // 引用解决与其他脚本接管fetch方法引起的兼容性问题
if (Global.getInstance().unsafeWindow) { if (Global.getInstance().unsafeWindow) {
ori_fetch = Global.getInstance().unsafeWindow.fetch; originFetch = Global.getInstance().unsafeWindow.fetch;
} }
let fetchHandle: (string, RequestInit) => Promise<Response> = (url: string, init: RequestInit) => { let fetchHandle: (string, RequestInit) => Promise<Response> = (url: string, init: RequestInit) => {
let startTime = new Timer(); if (!init) init = { method: 'GET' };
Log.info({ info: 'fetching', init, url });
return new Promise(resolve => { return new Promise(resolve => {
if (url.includes('newsTickers')) { if (url.includes('newsTickers')) {
Log.info('阻止获取新闻横幅'); Log.info('阻止获取新闻横幅');
@ -65,33 +96,53 @@ export default class WuHuTornHelper extends WuhuBase {
resolve(new Response('{}', init)); resolve(new Response('{}', init));
return; return;
} }
ori_fetch(url, init) originFetch(url, init)
.then(res => { .then(res => {
let clone = res.clone(); let clone = res.clone();
clone.text().then(text => { clone.text().then(text => {
let jsonObj = {}; let modified = intercept(text, url, init.method, init.body, 'fetch');
try { resolve(new Response(modified, init));
jsonObj = JSON.parse(text);
} catch {
}
globVars.WH_FETCH_LOG.push({ body: Object.keys(jsonObj).length ? jsonObj : text, url });
Log.info({
info: 'fetch响应耗时' + startTime.getTimeMs(),
response: { text, res, jsonObj }
});
let localized = Translate.responseHandler(text, url);
FetchEventCallback.getInstance().handler(text, url);
resolve(new Response(localized ? JSON.stringify(localized) : text, init));
return; return;
}); });
}) })
.catch(error => Log.error('fetch错误', error.stack || error.message)); .catch(error => Log.error('fetch错误', error.stack || error.message));
}) })
}; };
if (Global.getInstance().unsafeWindow) {
Global.getInstance().unsafeWindow.fetch = fetchHandle;
}
window.fetch = fetchHandle; window.fetch = fetchHandle;
// @ts-ignore
fetch = fetchHandle;
})(fetch || window.fetch, Global.getInstance().unsafeWindow || window);
// 监听xhr
(function (xhr) {
let originOpen = xhr.open;
let originSend = xhr.send;
let modifyResponse = (response: { responseText: string, response: string }, after: string) => {
Object.defineProperty(response, 'responseText', { writable: true });
Object.defineProperty(response, 'response', { writable: true });
response.responseText = after;
response.response = after;
};
XMLHttpRequest.prototype.open = function (method, url, async?, u?, p?) {
this.addEventListener('readystatechange', function () {
if (this.readyState !== 4) return;
let response = this.responseText || this.response;
let reqBody = this['reqBody'];
Log.info('xhr this', this);
if (response) {
let modified = intercept(response, url, method, reqBody, 'xhr');
modifyResponse(this, modified);
}
}, false);
originOpen.call(this, method, url, async, u, p);
};
XMLHttpRequest.prototype.send = function (body?) {
this['reqBody'] = body;
originSend.call(this, body);
}
})(XMLHttpRequest.prototype);
CommonUtils.addStyle(COMMON_CSS.replace('{{}}', performance.now().toString())); CommonUtils.addStyle(COMMON_CSS.replace('{{}}', performance.now().toString()));

View File

@ -1,6 +1,7 @@
import WuhuBase from "../WuhuBase"; import WuhuBase from "../WuhuBase";
import { MiniProfile } from "../../interface/responseType/MiniProfile"; import { MiniProfile } from "../../interface/responseType/MiniProfile";
import CommonUtils from "../utils/CommonUtils"; import CommonUtils from "../utils/CommonUtils";
import globVars from "../../globVars";
/** /**
* fetch * fetch
@ -10,24 +11,26 @@ export default class FetchEventCallback extends WuhuBase {
constructor() { constructor() {
super(); super();
globVars.responseHandlers.push((url, response) => this.handler(response, url))
} }
public handler(response: string, url: string): void { /**
window.setTimeout(async () => { * fetch
* @param response
* @param url
*/
public handler(response, url: string) {
// mini profile 中添加上次动作
if (url.includes('profiles.php?step=getUserNameContextMenu')) { if (url.includes('profiles.php?step=getUserNameContextMenu')) {
window.setTimeout(async () => {
let cont = await CommonUtils.querySelector('[class*=profile-mini-_userProfileWrapper___]'); let cont = await CommonUtils.querySelector('[class*=profile-mini-_userProfileWrapper___]');
let resp: MiniProfile = null; let resp: MiniProfile = response.json as MiniProfile;
try {
resp = JSON.parse(response);
} catch (e) {
throw e;
}
let newNode = document.createElement('div'); let newNode = document.createElement('div');
let formatted = CommonUtils.getInstance().secondsFormat(resp.user.lastAction.seconds); let formatted = CommonUtils.getInstance().secondsFormat(resp.user.lastAction.seconds);
newNode.innerText = '上次动作: ' + formatted; newNode.innerText = '上次动作: ' + formatted;
cont.append(newNode); cont.append(newNode);
}
}, 0); }, 0);
} }
}
} }

View File

@ -7,6 +7,9 @@ import TornStyleBlock from "../utils/TornStyleBlock";
import Timer from "../utils/Timer"; import Timer from "../utils/Timer";
import FetchUtils from "../utils/FetchUtils"; import FetchUtils from "../utils/FetchUtils";
/**
*
*/
export default class LotteryHelper extends WuhuBase { export default class LotteryHelper extends WuhuBase {
className = 'LotteryHelper'; className = 'LotteryHelper';
private loopFlag = true; private loopFlag = true;

View File

@ -7,7 +7,7 @@ import CommonUtils from "../utils/CommonUtils";
import MathUtils from "../utils/MathUtils"; import MathUtils from "../utils/MathUtils";
/** /**
* *
*/ */
export default class SlotsHelper extends WuhuBase { export default class SlotsHelper extends WuhuBase {
className = "SlotsHelper"; className = "SlotsHelper";

View File

@ -3,6 +3,8 @@ import { chatDict, eventsDict, headerDict, propertyDict, sidebarDict } from "../
import Log from "../Log"; import Log from "../Log";
import Timer from "../utils/Timer"; import Timer from "../utils/Timer";
import { Button, MiniProfile } from "../../interface/responseType/MiniProfile"; import { Button, MiniProfile } from "../../interface/responseType/MiniProfile";
import WuhuConfig from "../WuhuConfig";
import Sidebar from "../../interface/responseType/Sidebar";
export default class Translate extends WuhuBase { export default class Translate extends WuhuBase {
className = 'Translate'; className = 'Translate';
@ -292,13 +294,13 @@ export default class Translate extends WuhuBase {
}).observe(document.body, opt); }).observe(document.body, opt);
} }
public static responseHandler(body: string, url: string): unknown { /**
let ret: unknown = null; * fetch xhr
try { * @param url
// Mini Profile * @param body
if (url.includes('profiles.php?step=getUserNameContextMenu')) { */
let jsonObj: MiniProfile = JSON.parse(body); public static responseHandler(url: string, body: { json: unknown, text: string, isModified: boolean }): void {
Log.info('翻译mini profile返回内容'); if (!WuhuConfig.get('transNew')) return;
// TODO 字典抽取 // TODO 字典抽取
let map = { let map = {
iconMap: { iconMap: {
@ -373,6 +375,21 @@ export default class Translate extends WuhuBase {
] ]
} }
}, },
'Job': {
title: "系统公司",
description: {
replace: [/([a-zA-Z ]+) (in|at) (.+)$/, "$3的$1"],
attachedMap: [
{
'Manager': '经理',
},
{},
{
'a Grocery Store': '杂货店',
}
]
}
},
'Faction': { 'Faction': {
title: "帮派", title: "帮派",
description: { replace: [/([aA-zZ ]+)( of )(.+)/, "[$3] 帮派的 [$1]"] } description: { replace: [/([aA-zZ ]+)( of )(.+)/, "[$3] 帮派的 [$1]"] }
@ -413,6 +430,8 @@ export default class Translate extends WuhuBase {
"NPC's cannot be bountied": 'NPC 不能被悬赏', "NPC's cannot be bountied": 'NPC 不能被悬赏',
"$0 is hiding out abroad": '$0 正在海外躲藏', "$0 is hiding out abroad": '$0 正在海外躲藏',
"$0 has no items in their display cabinet": '$0 的展柜是空的', "$0 has no items in their display cabinet": '$0 的展柜是空的',
"You do not have enough energy to attack $0": '你没有足够的能量攻击 $0',
"You have not met this person recently or they have blocked you": '最近你没有遇见此人,或已被屏蔽',
}, },
}, },
destinationMap: { destinationMap: {
@ -427,8 +446,46 @@ export default class Translate extends WuhuBase {
'China': '中国', 'China': '中国',
'UAE': '阿联酋(UAE)', 'UAE': '阿联酋(UAE)',
'South Africa': '南非', 'South Africa': '南非',
},
barMap: {
'Chain': { name: '连击' },
'Energy': { name: '能量' },
'Happy': { name: '快乐' },
'Life': { name: '血量' },
'Nerve': { name: '犯罪' },
},
areaMap: {
calendar: { name: '日历', shortName: '日历' },
traveling: { name: '飞行中', shortName: '飞行' },
casino: { name: '赌场' },
city: { name: '城市' },
crimes: { name: '犯罪' },
education: { name: '教育', shortName: '教育' },
forums: { name: '论坛' },
gym: { name: '健身房' },
hall_of_fame: { name: '名人堂', shortName: '排名' },
home: { name: '主页', shortName: '主页' },
hospital: { name: '医院' },
items: { name: '物品' },
jail: { name: '监狱' },
job: { name: '工作', shortName: '工作' },
missions: { name: '任务' },
my_faction: { name: '帮派', shortName: '帮派' },
newspaper: { name: '报纸', shortName: '报纸' },
properties: { name: '住宅', shortName: '住宅' },
recruit_citizens: { name: '招募玩家', shortName: '招募' },
},
accountMap: {
awards: { name: '奖章' },
events: { name: '通知' },
messages: { name: '邮件' }
} }
}; };
try {
// Mini Profile
if (url.includes('profiles.php?step=getUserNameContextMenu')) {
let jsonObj: MiniProfile = body.json as MiniProfile;
Log.info('翻译mini profile返回内容');
// 状态图标 // 状态图标
jsonObj.icons.forEach(icon => { jsonObj.icons.forEach(icon => {
let iconMap = map.iconMap; let iconMap = map.iconMap;
@ -502,15 +559,31 @@ export default class Translate extends WuhuBase {
break; break;
} }
} }
body.isModified = true;
Log.info({ 'localized': jsonObj }); Log.info({ 'localized': jsonObj });
ret = jsonObj;
} }
// TODO 边栏 // TODO 边栏
else if (url.includes('sidebarAjaxAction.php?q=sync')) {
let response = body.json as Sidebar;
type target = { [k: string]: { name: string, shortName?: string } };
let nameMapReplace = (target: target, _map: target) => {
Object.keys(target).forEach(key => {
if (target[key] && _map[key]) {
target[key].name = _map[key].name;
if (target[key].shortName && _map[key].shortName) {
target[key].shortName = _map[key].shortName;
}
}
});
};
nameMapReplace(response.areas, map.areaMap);
nameMapReplace(response.account, map.accountMap);
body.isModified = true;
}
} catch (e) { } catch (e) {
Log.error('responseHandler', e.stack || e.message); Log.error('responseHandler', e.stack || e.message);
} }
return ret;
} }
} }

View File

@ -89,6 +89,13 @@ export default class SettingsHandler extends WuhuBase {
dictName: 'transEnable', dictName: 'transEnable',
isHide: true, isHide: true,
}); });
list.push({
domType: 'checkbox',
domId: '',
domText: ' 新翻译',
dictName: 'transNew',
tip: '改进后的翻译,更好的性能',
});
// 更新翻译词库 // 更新翻译词库
list.push({ list.push({
domType: 'button', domType: 'button',

View File

@ -362,6 +362,12 @@ export default class CommonUtils extends WuhuBase {
return ret; return ret;
} }
/**
*
*
* `日 时 分 秒`
* @param s
*/
public secondsFormat(s: number): string { public secondsFormat(s: number): string {
let gap = '日 时 分 秒'.split(' '); let gap = '日 时 分 秒'.split(' ');
let last = s; let last = s;

View File

@ -1,5 +1,15 @@
/**
*
*/
export default { export default {
// 监听到的fetch数据 // 监听到的fetch数据
WH_FETCH_LOG: [] as { body: unknown | string, url: string }[], WH_NET_LOG: [],
map: {} as { [key: string]: unknown }, map: {},
}; responseHandlers: [],
} as IGlobVars;
interface IGlobVars {
WH_NET_LOG: unknown[],
map: { [key: string]: unknown },
responseHandlers: ((url: string, responseBody: { json: unknown, text: string, isModified: boolean }, opt: { method: string, requestBody: unknown }) => void)[],
}

View File

@ -0,0 +1,43 @@
export default interface Sidebar {
account: {
awards: Area,
events: Area,
messages: Area,
},
areas: {
calendar: Area,
casino: Area,
city: Area,
crimes: Area,
education: Area,
forums: Area,
gym: Area,
hall_of_fame: Area,
home: Area,
hospital: Area,
items: Area,
jail: Area,
job: Area,
missions: Area,
my_faction: Area,
newspaper: Area,
properties: Area,
recruit_citizens: Area,
},
bars: {
chain: Bar,
energy: Bar,
happy: Bar,
life: Bar,
nerve: Bar,
},
}
interface Bar {
name: string
}
interface Area {
name: string,
shortName?: string,
}

View File

@ -11,7 +11,7 @@ export default class Test extends WuhuBase {
public test(): void { public test(): void {
let popup = new Popup(CommonUtils.getInstance().getTravelStage().toString()); let popup = new Popup(CommonUtils.getInstance().getTravelStage().toString());
popup.getElement()['__POOL__'] = Test.getPool(); popup.getElement()['__POOL__'] = Test.getPool();
Log.info({ WH_FETCH_LOG: globVars.WH_FETCH_LOG }); Log.info({ NET: globVars.WH_NET_LOG });
// this.case1() // this.case1()
// this.case2() // this.case2()