This commit is contained in:
Liwanyi 2023-01-09 18:07:20 +08:00
parent 82c01b18de
commit 6a0d0e064a
19 changed files with 416 additions and 53 deletions

View File

@ -4,6 +4,15 @@
# CHANGE
## 0.7.9
2023年01月09日
### 修改
- 优化了迷你选项卡的汉化效果
- 更新节日数据
## 0.7.8
2022年12月20日

View File

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

File diff suppressed because one or more lines are too long

View File

@ -1,11 +1,13 @@
import miniprofTrans from "../func/translate/miniprofTrans";
import CommonUtils from "./utils/CommonUtils";
import WuhuBase from "./WuhuBase";
import TravelItem from "./action/TravelItem";
import Global from "./Global";
import Log from "./Log";
import WuhuConfig from "./WuhuConfig";
import COMMON_CSS from "../static/css/common.css";
import Timer from "./utils/Timer";
import Translate from "./action/Translate";
import globVars from "../globVars";
import FetchEventCallback from "./action/FetchEventCallback";
/**
*
@ -44,36 +46,46 @@ export default class WuHuTornHelper extends WuhuBase {
};
// 监听fetch
let ori_fetch = window.fetch;
let ori_fetch = fetch || window.fetch;
// 引用解决与其他脚本接管fetch方法引起的兼容性问题
if (Global.getInstance().unsafeWindow) {
ori_fetch = Global.getInstance().unsafeWindow.fetch;
}
let fetchHandle: (string, RequestInit) => Promise<Response> = (url: string, init: RequestInit) => {
let startTime = performance.now();
Log.info('FETCH调用[' + url + '], init:', init);
let startTime = new Timer();
Log.info({ info: 'fetching', init, url });
return new Promise(resolve => {
if (url.contains('newsTickers')) {
if (url.includes('newsTickers')) {
Log.info('阻止获取新闻横幅');
resolve(new Response('{}'));
resolve(new Response('{}', init));
return;
}
if (url.includes('google')) {
Log.info('阻止google相关请求');
resolve(new Response('{}'));
resolve(new Response('{}', init));
return;
}
ori_fetch(url, init)
.then(res => {
// mini profile 翻译
if (url.includes('profiles.php?step=getUserNameContextMenu') && WuhuConfig.get('transEnable')) {
window.setTimeout(() => miniprofTrans(), 200);
}
let clone = res.clone();
res.text().then(text => Log.info('FETCH响应耗时' + ((performance.now() - startTime) | 0) + 'ms', { response: text }));
resolve(clone);
clone.text().then(text => {
let jsonObj = {};
try {
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;
});
})
.catch(error => Log.error('监听到fetch获取错误', error));
.catch(error => Log.error('fetch错误', error.stack || error.message));
})
};
if (Global.getInstance().unsafeWindow) {

View File

@ -133,8 +133,8 @@ export default class ZhongIcon extends WuhuBase {
? el.addEventListener('click', () => {
let html = '<table>';
// TODO 动态节日数据
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>`
Object.keys(FEST.val).sort().forEach(date =>
html += `<tr><td>${ 1 + ((<any>date.slice(0, 2)) | 0) }${ date.slice(2) }日</td><td>${ FEST.val[date].name }</td><td>${ FEST.val[date].eff }</td></tr>`
);
new Popup(html += '</table>', '节日');
})
@ -144,7 +144,7 @@ export default class ZhongIcon extends WuhuBase {
? el.addEventListener('click', () => {
let html = '<table>';
// TODO 动态节日数据
settings.events.forEach(el =>
EVENTS.default.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>`);
new Popup(html += '</table><p>更多信息请关注群聊和公众号</p>', '活动');
})
@ -239,8 +239,8 @@ export default class ZhongIcon extends WuhuBase {
{
// 节日字典
const dict = FEST.val;
list.fest_date_dict = dict;
list.fest_date_list = Object.keys(dict);
// list.fest_date_dict = dict;
// list.fest_date_list = Object.keys(dict);
const formatMMDD = (m, d) => {
const MM = m < 10 ? `0${ m }` : m.toString();
const DD = d < 10 ? `0${ d }` : d.toString();
@ -279,7 +279,7 @@ export default class ZhongIcon extends WuhuBase {
daysLeft: Infinity,
events: EVENTS.default,
};
list.events = eventObj.events;
list.events = EVENTS.default;
eventObj.events.forEach((obj, index) => {
if (eventObj.onEv) return;
// 当前年份

View File

@ -26,7 +26,6 @@ export default class CompanyHelper extends WuhuBase {
*
*
* TODO URL判断
* @private
*/
private async trainsDetect(test: boolean = false): Promise<null> {
// 通过用户的icon判断公司老板

View File

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

View File

@ -2,6 +2,7 @@ import WuhuBase from "../WuhuBase";
import { chatDict, eventsDict, headerDict, propertyDict, sidebarDict } from "../../dictionary/translation";
import Log from "../Log";
import Timer from "../utils/Timer";
import { Button, MiniProfile } from "../../interface/responseType/MiniProfile";
export default class Translate extends WuhuBase {
className = 'Translate';
@ -290,4 +291,226 @@ export default class Translate extends WuhuBase {
observer.observe(document.body, opt);
}).observe(document.body, opt);
}
public static responseHandler(body: string, url: string): unknown {
let ret: unknown = null;
try {
// Mini Profile
if (url.includes('profiles.php?step=getUserNameContextMenu')) {
let jsonObj: MiniProfile = JSON.parse(body);
Log.info('翻译mini profile返回内容');
// TODO 字典抽取
let map = {
iconMap: {
'Online': { title: "在线" },
'Level 100': { title: "100 级" },
'Jail': {
title: "坐牢", description: {
map: {
'Being questioned for suspicious online activity.': '因可疑的网上活动而被盘问。',
'Suspect of a presidential assassination': '刺杀总统的嫌疑人',
}
}
},
'Federal jail': {
title: "联邦监狱(FJ)", description: {
map: {
'Account marked for deletion': '账号标记删除',
}
}
},
'Idle': { title: "暂离" },
'Offline': { title: "离线" },
'Enby': { title: "中性" },
'Male': { title: "男性" },
'Female': { title: "女性" },
'Donator': { title: "DP捐助者" },
'Subscriber': { title: "蓝星订阅者" },
'Traveling': { title: "旅行中" },
'Hospital': {
title: "已入院",
description: {
map: {
'Fell from a two story building while on a hitman mission': '在执行刺杀任务时从二楼摔下',
'Overdosed on Xanax': '吃 Xan 后 OD',
'Mauled by a guard dog': '被看门狗咬',
},
replace: [/(Hospitalized|Mugged|Attacked|Defeated) by (someone|<a.+\/a>)(.+Early discharge available.+)?/, '被 $2 $1$3'],
attachedMap: [
{
'Hospitalized': '强制住院',
'Mugged': '抢劫',
'Attacked': '攻击',
'Defeated': '击败',
},
{ 'someone': '某人' },
{ '<br><i>Early discharge available</i>': '<br><i>提前出院(ED)可用</i>' },
],
}
},
'Bounty': {
title: "被悬赏",
description: { replace: [/On this person's head for (\$[,0-9]+)( : .+)?/, '$1 悬赏此人$2'] }
},
'Married': {
title: "已婚", description: { replace: [/To/, '和'] }
},
'Company': {
title: "公司",
description: {
replace: [/([a-zA-Z ]+)( of )(.+) \(([aA-zZ ]+)\)$/, "【$3】$4的$1"],
attachedMap: [
{
'Director': '老板',
'Salesperson': '销售员',
},
{}, {},
{
'Private Security Firm': '安保公司 (PSF)',
'Lingerie Store': '内衣店 (LS)',
'Adult Novelties': '成人用品店 (AN)',
}
]
}
},
'Faction': {
title: "帮派",
description: { replace: [/([aA-zZ ]+)( of )(.+)/, "[$3] 帮派的 [$1]"] }
},
'Bazaar': {
title: "摊位",
description: {
map: {
'This person has items in their bazaar for sale':
'此人在摊位上有物品出售'
}
}
},
},
buttonMap: {
message: {
'Add $0 to your enemy list': '添加 $0 到敌人列表',
'Add $0 to your friend list': '添加 $0 到好友列表',
'You are currently traveling': '你在天上',
'Initiate a chat with $0': '与 $0 私聊',
'You are not in Torn': '你不在城内',
"View $0's personal statistics": '查看 $0 的个人统计数据',
"Place a bounty on $0": '对 $0 发起悬赏',
"Report $0 to staff": '向工作人员举报 $0',
"Send $0 a message": '发邮件给 $0',
"View $0's display case": '查看 $0 的展柜',
"$0 is currently in hospital": '$0 正在住院',
"$0 has not been online in the last 6 hours": '$0 超 6 小时未在线',
"Give some money to $0": '给 $0 一些钱',
"$0's bazaar is closed": '$0 的摊位已关闭',
"View $0's bazaar": '查看 $0 的摊位',
"Initiate a trade with $0": '与 $0 交易',
"$0 has no items in their bazaar": '$0 的摊位是空的',
"$0 is currently in jail": '$0 目前在坐牢',
"Pay $0's bail": '支付 $0 的保释金',
"Bust $0 out of jail": '把 $0 从监狱里踢出来',
"$0 is currently in federal jail": '$0 目前在联邦监狱(FJ)',
"NPC's cannot be bountied": 'NPC 不能被悬赏',
"$0 is hiding out abroad": '$0 正在海外躲藏',
"$0 has no items in their display cabinet": '$0 的展柜是空的',
},
},
destinationMap: {
'Mexico': '墨西哥',
'Cayman Islands': '开曼群岛',
'Canada': '加拿大',
'Hawaii': '夏威夷',
'United Kingdom': '英国',
'Argentina': '阿根廷',
'Switzerland': '瑞士',
'Japan': '日本',
'China': '中国',
'UAE': '阿联酋(UAE)',
'South Africa': '南非',
}
};
// 状态图标
jsonObj.icons.forEach(icon => {
let iconMap = map.iconMap;
let oriTitle = icon.title;
if (iconMap[oriTitle]) {
icon.title = iconMap[oriTitle].title;
let desc = iconMap[oriTitle].description;
let oriDesc = icon.description;
if (icon.description && desc) {
if (desc.map && desc.map[oriDesc]) {
icon.description = desc.map[oriDesc];
} else if (desc.replace) {
icon.description = oriDesc.replace(new RegExp(desc.replace[0]), desc.replace[1]);
if (desc.attachedMap) {
desc.attachedMap.forEach((item, index) => {
let factor = oriDesc.replace(new RegExp(desc.replace[0]), '$' + (index + 1));
Log.info({ factor });
let cn = item[factor];
cn && (icon.description = icon.description.replace(factor, cn));
});
}
}
}
}
});
// 离线转钱警告
if (jsonObj.user.sendMoneyWarning) {
let daysMatch = jsonObj.user.sendMoneyWarning.match(/[0-9]+/);
if (daysMatch.length !== 0)
jsonObj.user.sendMoneyWarning = `警告:此人已离线 ${ daysMatch[0] }`;
}
// 按钮
let buttons = jsonObj.profileButtons.buttons;
let buttonKeyList = Object.keys(buttons);
let username = jsonObj.user.playerName;
let msgMap = map.buttonMap.message;
buttonKeyList.forEach(buttonKey => {
if (buttons[buttonKey].state === 'hidden') return;
let button: Button = buttons[buttonKey];
let oriMsg = button.message.replace(username, '$0');
if (msgMap[oriMsg]) {
button.message = msgMap[oriMsg].replace('$0', username);
}
});
// TODO 称号
// 用户状态
let status = jsonObj.userStatus.status.type;
switch (status) {
case 'traveling-to': {
let origin = jsonObj.userStatus.status.to.simpleName;
let cn = map.destinationMap[origin]
cn && (jsonObj.userStatus.status.to.simpleName = cn);
break;
}
case 'traveling-from': {
let origin = jsonObj.userStatus.status.from.simpleName;
let cn = map.destinationMap[origin]
cn && (jsonObj.userStatus.status.from.simpleName = cn);
break;
}
case 'abroad': {
let origin = jsonObj.userStatus.status.in.simpleName;
let cn = map.destinationMap[origin]
cn && (jsonObj.userStatus.status.in.simpleName = cn);
break;
}
case 'jail': {
let origin = jsonObj.userStatus.status.description;
let cn = map.iconMap.Jail.description.map[origin];
cn && (jsonObj.userStatus.status.description = cn);
break;
}
}
Log.info({ 'localized': jsonObj });
ret = jsonObj;
}
// TODO 边栏
} catch (e) {
Log.error('responseHandler', e.stack || e.message);
}
return ret;
}
}

View File

@ -16,9 +16,9 @@ export default class TravelItem extends WuhuBase {
super();
window.setInterval(async () => {
if (!WindowActiveState.getInstance().get()) return;
Log.info('fetching ', this.apiUrl);
Log.info('COFetch ', this.apiUrl);
this.foreignStockInfo = JSON.parse(await CommonUtils.COFetch(this.apiUrl));
Log.info({ 'fetch returned': this.foreignStockInfo });
Log.info({ info: 'TravelItem 跨域返回', 'returned': this.foreignStockInfo });
}, 30 * 1000);
}

View File

@ -20,8 +20,8 @@ export default class CommonUtils extends WuhuBase {
}
static COFetch(url: URL | string, method: 'get' | 'post' = 'get', body: any = null): Promise<string> {
let start = new Timer();
const engine = this.getScriptEngine();
let start = performance.now();
Log.info('跨域获取数据开始, 脚本引擎: ' + engine);
return new Promise<string>((resolve, reject) => {
switch (engine) {
@ -40,7 +40,7 @@ export default class CommonUtils extends WuhuBase {
}
PDA_httpGet(url)
.then(res => {
Log.info('跨域获取数据成功, 耗时' + (performance.now() - start | 0) + 'ms');
Log.info('跨域获取数据成功, 耗时' + start.getTimeMs());
resolve(res.responseText);
})
.catch(e => {
@ -75,7 +75,7 @@ export default class CommonUtils extends WuhuBase {
data: method === 'get' ? null : body,
headers: method === 'get' ? null : { 'content-type': 'application/json' },
onload: res => {
Log.info('跨域获取数据成功,耗时' + (performance.now() - start | 0) + 'ms');
Log.info('跨域获取数据成功,耗时' + start.getTimeMs());
resolve(res.response);
},
onerror: res => reject(`连接错误 ${ JSON.stringify(res) }`),
@ -361,4 +361,28 @@ export default class CommonUtils extends WuhuBase {
if (match.length > 0) ret = match[0];
return ret;
}
public secondsFormat(s: number): string {
let gap = '日 时 分 秒'.split(' ');
let last = s;
let formatDate = [];
let days = last / 86400 | 0;
formatDate.push(days);
last -= days * 86400;
let hours = last / 3600 | 0;
formatDate.push(hours);
last -= hours * 3600;
let mins = last / 60 | 0;
formatDate.push(mins);
last -= mins * 60;
formatDate.push(last);
let ret = '';
formatDate.forEach((num, i) => {
if (num > 0) {
let twoDig = i === 0 ? num : ('0' + num).slice(-2);
ret += twoDig + gap[i];
}
});
return ret;
}
}

View File

@ -1,12 +1,16 @@
/**
* performance.now()
*/
export default class Timer {
private readonly startTime: number;
constructor() {
public constructor() {
this.startTime = performance.now();
}
/**
* ms结束
* ms结束
*
* `'99ms'`
*/
public getTimeMs(): string {

View File

@ -160,11 +160,11 @@ export const statusDict = {
'In Canada': '在加拿大',
'In Hawaii': '在夏威夷',
'In United Kingdom': '在英国',
'In United Argentina': '在阿根廷',
'In United Switzerland': '在瑞士',
'In United Japan': '在日本',
'In United China': '在中国',
'In United UAE': '在 UAE',
'In Argentina': '在阿根廷',
'In Switzerland': '在瑞士',
'In Japan': '在日本',
'In China': '在中国',
'In UAE': '在 UAE',
'In South Africa': '在南非',
}
// const miniProfileDict = {}

5
src/ts/globVars.ts Normal file
View File

@ -0,0 +1,5 @@
export default {
// 监听到的fetch数据
WH_FETCH_LOG: [] as { body: unknown | string, url: string }[],
map: {} as { [key: string]: unknown },
};

View File

@ -0,0 +1,52 @@
/**
* Mini Profile
*/
export interface MiniProfile {
icons: { id: number, type: string, title: string, description?: string }[];
profileButtons: {
buttons: {
addToEnemyList: Button,
addToFriendList: Button,
attack: Button,
bail: Button,
bust: Button,
initiateChat: Button,
initiateTrade: Button,
personalStats: Button,
placeBounty: Button,
report: Button,
revive: Button,
sendMessage: Button,
sendMoney: Button,
viewBazaar: Button,
viewDisplayCabinet: Button,
}
};
user: {
lastAction: {
seconds: number
};
rank: {
userRank: string,
userTitle: string
},
sendMoneyWarning: string,
playerName: string,
};
userStatus: {
status: {
from: { simpleName: string },
to: { simpleName: string },
in: { simpleName: string, relatedName: string },
type: 'ok' | 'traveling-to' | 'traveling-from' | 'abroad' | 'abroad-hospital' | 'jail',
description: string,
}
};
}
export interface Button {
actionDescription: string,
link: string,
state: "hidden" | "active" | "disabled",
message: string,
}

View File

@ -13,7 +13,7 @@
<option>瑞士 (解毒)</option>
<option>立本</option>
<option>祖国</option>
<option>迪拜</option>
<option>阿联酋 (UAE)</option>
<option>南非</option>
</select></label>
<label>飞机:<select>

View File

@ -2,12 +2,12 @@
{
"start": [
0,
17,
16,
8
],
"end": [
0,
24,
22,
8
],
"name": "捡垃圾周",
@ -86,7 +86,7 @@
{
"start": [
11,
14,
19,
20
],
"end": [

View File

@ -1,6 +1,6 @@
{
"val": {
"0105": {
"0104": {
"name": "周末自驾游",
"eff": "获得双倍的赛车点数与赛车技能等级增益"
},
@ -8,7 +8,7 @@
"name": "情人节",
"eff": "使用爱情果汁(Love Juice)后获得降低攻击与复活的能量消耗的增益"
},
"0204": {
"0203": {
"name": "员工激励日",
"eff": "获得三倍的工作点数与火车增益"
},
@ -36,7 +36,7 @@
"name": "世界老虎日",
"eff": "获得5倍的狩猎技能增益"
},
"0705": {
"0704": {
"name": "国际啤酒节",
"eff": "获得5倍的啤酒物品效果增益"
},
@ -56,11 +56,11 @@
"name": "周年庆",
"eff": "左上角的TORN图标可以食用"
},
"1025": {
"1024": {
"name": "黑色星期五",
"eff": "某些商家将提供1元购活动"
},
"1114": {
"1113": {
"name": "住院日",
"eff": "获得降低75%的住院时间增益"
}

View File

@ -74,7 +74,7 @@
},
{
"name": "uae",
"show": "迪拜",
"show": "阿联酋 (UAE)",
"stocks": {
"Tribulus Omanense": "花",
"Camel Plushie": "偶"

View File

@ -3,6 +3,7 @@ import Log from "../class/Log";
import CommonUtils from "../class/utils/CommonUtils";
import Popup from "../class/utils/Popup";
import CompanyHelper from "../class/action/CompanyHelper";
import globVars from "../globVars";
export default class Test extends WuhuBase {
className = 'Test';
@ -10,10 +11,11 @@ export default class Test extends WuhuBase {
public test(): void {
let popup = new Popup(CommonUtils.getInstance().getTravelStage().toString());
popup.getElement()['__POOL__'] = Test.getPool();
Log.info({ WH_FETCH_LOG: globVars.WH_FETCH_LOG });
// this.case1()
// this.case2()
this.case3().then();
// this.case3().then();
}
private case1() {