This commit is contained in:
Liwanyi 2022-10-24 17:31:28 +08:00
parent a7bd4bc838
commit acc995c4a2
32 changed files with 1451 additions and 1145 deletions

29
global.d.ts vendored
View File

@ -18,10 +18,14 @@ declare interface Window {
// 插件运行标识
WHTRANS?: number;
Vue?: Function;
/* 油猴脚本引擎自带 */
/**
*
*/
unsafeWindow?: Window & typeof globalThis;
GM: any;
/**
* google
*/
_gaUserPrefs?: unknown;
GM_xmlhttpRequest(init: GM_RequestParams): void;
@ -29,26 +33,25 @@ declare interface Window {
GM_setValue(k: string, v: any): void;
// google不跟踪标识
_gaUserPrefs?: unknown;
/**
* TORN自带
*/
ReactDOM?: any;
dataLayer?: unknown;
eval(exc: string): void;
/* TORN自带 */
ReactDOM?: any;
addRFC(url: URL | string): string;
// initMiniProf(selector: string): void;
getAction(opt: TornGetActionParams): void;
initializeTooltip(selector: string, elemId: string): void;
renderMiniProfile(node: Element, props: any): never;
/* PDA自带 */
/**
* PDA自带
*/
PDA_httpGet(url: URL | string): Promise<PDA_Response>;
PDA_httpPost(url: URL | string, init: any, body: any): Promise<PDA_Response>;
@ -114,4 +117,6 @@ declare module "*.css" {
export default value;
}
declare function GM_xmlhttpRequest(init: any): void;
declare function GM_xmlhttpRequest(init: any): void;
declare var unsafeWindow: Window & typeof globalThis;

View File

@ -10,12 +10,14 @@ import BuyBeerHelper from "./action/BuyBeerHelper";
*/
export default class Global extends WuhuBase implements IGlobal {
className = 'Global';
GM_xmlhttpRequest: Function = null;
GM_xmlhttpRequest: Function = null;
href: string = window.location.href;
// 弹窗
popup_node: MyHTMLElement = null;
// 啤酒助手
/**
* @deprecated 使getInstance替代
*/
beer = null;
// 留存的通知
notifies: NotifyWrapper = null;
@ -45,11 +47,18 @@ export default class Global extends WuhuBase implements IGlobal {
constructor() {
Log.info('WH脚本参数[Global]初始化');
super();
this.unsafeWindow = window.unsafeWindow || null;
try {
// 上层调用如果使用eval此处GM_xmlhttpRequest可能不存在与window中
if (typeof unsafeWindow !== 'undefined') {
Log.info('存在unsafeWindow, 引入');
this.unsafeWindow = unsafeWindow || null;
window.addRFC = this.unsafeWindow.addRFC;
window.getAction = this.unsafeWindow.getAction;
window.initializeTooltip = this.unsafeWindow.initializeTooltip;
window.renderMiniProfile = this.unsafeWindow.renderMiniProfile;
window.ReactDOM = this.unsafeWindow.ReactDOM;
}
if (typeof GM_xmlhttpRequest === 'function') {
// 上层调用如果使用eval此处GM_xmlhttpRequest可能不存在于window中
this.GM_xmlhttpRequest = window.GM_xmlhttpRequest || GM_xmlhttpRequest || null;
} catch {
}
this.version = '$$WUHU_DEV_VERSION$$';
this.PDA_APIKey = '###PDA-APIKEY###';
@ -62,15 +71,6 @@ export default class Global extends WuhuBase implements IGlobal {
this.href = window.location.href;
this.bodyAttrs = {};
if (this.unsafeWindow) {
Log.info('存在unsafeWindow, 引入部分torn公共方法');
window.addRFC = this.unsafeWindow.addRFC;
window.getAction = this.unsafeWindow.getAction;
window.initializeTooltip = this.unsafeWindow.initializeTooltip;
window.renderMiniProfile = this.unsafeWindow.renderMiniProfile;
window.ReactDOM = this.unsafeWindow.ReactDOM;
}
for (let i = 0; i < document.body.attributes.length; i++) {
let item = document.body.attributes.item(i);
this.bodyAttrs[item.name] = item.value;

View File

@ -61,7 +61,7 @@ export default class Log {
if (typeof item === 'string') this.logs += item;
else if (item !== null && item !== undefined) {
let json = '{}';
let name = 'UNKNOWN_OBJECT'
let name = item.toString ? item.toString() : 'UNKNOWN_OBJECT';
try {
json = JSON.stringify(item);
name = Object.getPrototypeOf(item).constructor.name;

View File

@ -63,11 +63,9 @@ export default class UrlPattern extends WuhuBase {
beer.innerHTML = SHOP_BEER_STATIC_ITEM_HTML;
if (clear_node) clear_node.before(beer);
else node.append(beer);
// (<MyHTMLElement>e.target).remove();
(<HTMLInputElement>e.target).disabled = true;
msg_node.innerHTML = '添加成功';
});
// });
// 监听啤酒购买
$(document).ajaxComplete((_, xhr, settings) => {
@ -76,7 +74,6 @@ export default class UrlPattern extends WuhuBase {
let response = JSON.parse(responseText);
if (data.includes('step=buyShopItem') && data.includes('ID=180') && response['success']) {
new Alert('已检测成功购买啤酒');
// Global.getInstance().beer.skip_today();
BuyBeerHelper.getInstance().skip_today();
}
});
@ -84,6 +81,7 @@ export default class UrlPattern extends WuhuBase {
// 快速crime TODO 重构、与翻译解藕
if (href.contains(/crimes\.php/) && WuhuConfig.get('quickCrime')) {
// iframe
if (self !== top) {
const isValidate = document.querySelector('h4#skip-to-content').innerText.toLowerCase().includes('validate');
CommonUtils.elementReady('#header-root').then(e => e.style.display = 'none');
@ -112,13 +110,14 @@ export default class UrlPattern extends WuhuBase {
});
const trans = () => {
const dom = QUICK_CRIMES_HTML;
const is_wh_translate = element.querySelector('.wh-translate') !== null;
const is_captcha = element.querySelector('div#tab-menu.captcha') !== null;
const $title = $('div.content-title');
const $info = $('.info-msg-cont');
if (!is_wh_translate && !is_captcha) {
if ($title.length > 0) $title.before(dom);
else if ($info.length > 0) $info.before(dom);
const hasInserted = element.querySelector('.wh-translate') !== null;
// const is_captcha = element.querySelector('div#tab-menu.captcha') !== null;
const $title = document.querySelector('div.content-title');
const $info = document.querySelector('.info-msg-cont');
// if (!hasInserted && !is_captcha) {
if (!hasInserted) {
if ($title) $title.insertAdjacentHTML('beforebegin', dom);
else if ($info) $info.insertAdjacentHTML('beforebegin', dom);
}
};
trans();
@ -132,13 +131,13 @@ export default class UrlPattern extends WuhuBase {
// 任务助手 TODO 重构、与翻译解藕
if (href.contains(/loader\.php\?sid=missions/) && WuhuConfig.get('missionHint')) {
const $$ = $('.content-wrapper');
const anchor = document.querySelector('.content-wrapper');
const OB = new MutationObserver(() => {
OB.disconnect();
// titleTrans();
// contentTitleLinksTrans();
trans();
OB.observe($$.get(0), {
OB.observe(anchor, {
characterData: true,
attributes: true,
subtree: true,
@ -148,16 +147,18 @@ export default class UrlPattern extends WuhuBase {
const taskList = {};
const trans = () => {
$('ul#giver-tabs a.ui-tabs-anchor').each((i, e) => {
if ($(e).children().hasClass('mission-complete-icon')) {
let $e = $(e);
if ($e.children().hasClass('mission-complete-icon')) {
taskList[i] = e.innerText.trim();
} else {
taskList[i] = $(e).clone().children().remove().end().text().trim();
taskList[i] = $e.clone().children().remove().end().text().trim();
}
});
// 助手注入
$('div.max-height-fix.info').each((i, e) => {
if ($(e).find('.wh-translated').length !== 0) return;
$(e).append(`<div class="wh-translated"><h6 style="color:green"><b>任务助手</b></h6><p>${ getTaskHint(taskList[i]) }</p></div>`);
let $e = $(e);
if ($e.find('.wh-translated').length !== 0) return;
$e.append(`<div class="wh-translated"><h6 style="color:green"><b>任务助手</b></h6><p>${ getTaskHint(taskList[i]) }</p></div>`);
});
// 任务目标
$('ul.tasks-list span.title-wrap').contents().each((i, e) => {
@ -169,7 +170,7 @@ export default class UrlPattern extends WuhuBase {
});
};
trans();
OB.observe($$.get(0), {
OB.observe(anchor, {
characterData: true,
attributes: true,
subtree: true,

View File

@ -38,8 +38,8 @@ export default class WuHuTornHelper extends WuhuBase {
};
// 监听fetch
const ori_fetch = window.fetch;
window.fetch = (url: string, init: RequestInit) => {
let ori_fetch = window.fetch;
let fetchHandle: (string, RequestInit) => Promise<Response> = (url: string, init: RequestInit) => {
let startTime = performance.now();
Log.info('FETCH调用[' + url + '], init:', init);
return new Promise(resolve => {
@ -66,6 +66,10 @@ export default class WuHuTornHelper extends WuhuBase {
.catch(error => Log.error('监听到fetch获取错误', error));
})
};
if (Global.getInstance().unsafeWindow) {
Global.getInstance().unsafeWindow.fetch = fetchHandle;
}
window.fetch = fetchHandle;
CommonUtils.addStyle(COMMON_CSS.replace('{{}}', performance.now().toString()));

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,7 @@ import Alert from "../utils/Alert";
import MathUtils from "../utils/MathUtils";
import NOTIFY_HTML from "../../static/html/buyBeer/notify.html";
import CommonUtils from "../utils/CommonUtils";
import Popup from "../utils/Popup";
export default class BuyBeerHelper extends WuhuBase implements BeerMonitorLoop {
className = 'BuyBeerHelper';
@ -98,6 +99,26 @@ export default class BuyBeerHelper extends WuhuBase implements BeerMonitorLoop {
// 通知中的取消按钮
notify.getElement().querySelector('.wh-notify-msg button').addEventListener('click', () => WuhuConfig.set('_15_alarm_ignore', undefined, true));
}
public setTimeHandler(): void {
let popup = new Popup(`<label>提前提醒时间(秒)<input type="number" value="${ WuhuConfig.get('_15AlarmTime') }" /></label><p>区间为 1 ~ 60默认 50</p>`, '啤酒提醒时间设定');
let confirm = document.createElement('button');
confirm.innerHTML = '确定';
confirm.style.float = 'right';
confirm.addEventListener('click', () => {
let input: HTMLInputElement = popup.getElement().querySelector('input');
let num = (input.value as any) | 0;
if (num === WuhuConfig.get('_15AlarmTime')) return;
if (num < 1 || num > 60) num = 50;
input.value = num.toString();
WuhuConfig.set('_15AlarmTime', num);
this.set_time(num);
// 之前的运行状态
if (this.is_running()) this.start();
popup.close();
});
popup.getElement().appendChild(confirm);
}
}
export interface BeerMonitorLoop {

View File

@ -4,6 +4,7 @@ import InfoUtils from "../utils/InfoUtils";
import MathUtils from "../utils/MathUtils";
import CommonUtils from "../utils/CommonUtils";
import TornStyleBlock from "../utils/TornStyleBlock";
import Timer from "../utils/Timer";
export default class LotteryHelper extends WuhuBase {
className = 'LotteryHelper';
@ -22,7 +23,7 @@ export default class LotteryHelper extends WuhuBase {
private readonly mathUtils = MathUtils.getInstance();
public init() {
let startTime = performance.now();
let startTime = new Timer();
Log.info('彩票助手初始化开始');
let radioLabelDaily = document.createElement('label');
@ -99,11 +100,11 @@ export default class LotteryHelper extends WuhuBase {
progressBarBg, progressBar, status, desc).insert2Dom();
// document.querySelector('#websocketConnectionData').after(container);
Log.info('彩票助手初始化结束,耗时:' + (performance.now() - startTime) + 'ms');
Log.info('彩票助手初始化结束,耗时:' + startTime.getTimeMs());
}
private async start() {
let startTime = performance.now();
let startTime = new Timer();
this.loopFlag = true;
this.stopBtn.disabled = false;
this.startBtn.disabled = true;
@ -151,7 +152,7 @@ export default class LotteryHelper extends WuhuBase {
rsMsg = '输入有误';
}
this.desc.innerHTML = '结束: ' + (rsMsg ? rsMsg + `<br/>耗时:${ (performance.now() - startTime) | 0 }ms` : '出错了');
this.desc.innerHTML = '结束: ' + (rsMsg ? rsMsg + '<br/>耗时:' + startTime.getTimeMs() : '出错了');
this.stopBtn.disabled = true;
this.startBtn.disabled = false;

View File

@ -0,0 +1,27 @@
import WuhuBase from "../WuhuBase";
import Popup from "../utils/Popup";
import Alert from "../utils/Alert";
export default class AdditionalSettingsHandler extends WuhuBase {
className = 'AdditionalSettingsHandler';
public handle(): void {
let pop = new Popup('', '更多设定');
let insertHtml = '<p><button class="torn-btn">清空设置</button></p><p><button class="torn-btn">通知权限</button></p><p><button class="torn-btn">外部数据权限</button></p>';
pop.getElement().insertAdjacentHTML('beforeend', insertHtml);
let [btn1, btn2, btn3] = Array.from(pop.getElement().querySelectorAll('button'));
btn1.addEventListener('click', () => {
localStorage.removeItem('wh_trv_alarm');
localStorage.removeItem('wh_trans_settings');
localStorage.removeItem('whuuid');
localStorage.removeItem('wh-gs-storage');
localStorage.removeItem('WHTEST');
new Alert('已清空,刷新页面');
window.location.reload();
});
btn2.addEventListener('click', () => {
});
btn3.addEventListener('click', () => {
});
}
}

View File

@ -0,0 +1,49 @@
import WuhuBase from "../WuhuBase";
import Popup from "../utils/Popup";
import CommonUtils from "../utils/CommonUtils";
import MDUtils from "../utils/MDUtils";
import Log from "../Log";
export default class ChangeLogHandler extends WuhuBase {
className = 'ChangeLogHandler';
public handle(): void {
let popup = new Popup(
'更新历史:<br/><a target="_blank" href="https://gitlab.com/JJins/wuhu-torn-helper/-/blob/dev/CHANGELOG.md">https://gitlab.com/JJins/wuhu-torn-helper/-/blob/dev/CHANGELOG.md</a><br/>',
'更新历史'
).getElement();
popup.classList.add('wh-changeLog');
let progressBar = document.createElement('div');
progressBar.style.height = '2px';
progressBar.style.width = '1%';
progressBar.style.backgroundColor = 'red';
let progressText = document.createElement('p');
progressText.innerText = '加载更新文件……';
progressText.style.textAlign = 'center';
let style = document.createElement('style');
style.innerHTML = `.wh-changeLog h2,.wh-changeLog h3,.wh-changeLog h4 {margin:8px 0;}.wh-changeLog li{list-style: inside;}`;
popup.append(progressBar, progressText, style);
CommonUtils
.COFetch('https://gitlab.com/JJins/wuhu-torn-helper/-/raw/dev/CHANGELOG.md?' + performance.now())
.then(update => {
progressBar.style.width = '60%';
progressText.innerText = '解析中……';
let md = MDUtils.getInstance().parse(update);
popup.append(md);
progressBar.style.width = '100%';
progressText.innerText = '加载完成';
window.setTimeout(() => {
progressBar.remove();
progressText.remove()
}, 3000);
})
.catch(e => {
Log.error(e);
progressBar.remove();
progressText.innerText = '无法加载';
});
}
}

View File

@ -0,0 +1,95 @@
import WuhuBase from "../WuhuBase";
import CommonUtils from "../utils/CommonUtils";
import Popup from "../utils/Popup";
import QUICK_CRIMES_HTML from "../../static/html/quick_crimes.html";
export default class IFrameCrimeHandler extends WuhuBase {
className = 'IFrameCrimeHandler';
public handle(): void {
// 弹出小窗口
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>加载中请稍后${ CommonUtils.loading_gif_html() }</p><div id="wh-quick-crime-if-container"></div>`;
const $popup = new Popup(popup_insert, '小窗快速犯罪').getElement();
// 运行状态node
let loading_node = $popup.querySelector('p:first-of-type');
// if容器
const if_cont = $popup.querySelector('#wh-quick-crime-if-container');
if_cont.innerHTML = ifHTML;
// if内未加载脚本时插入的快捷crime node
const mobile_prepend_node = document.createElement('div');
mobile_prepend_node.classList.add('wh-translate');
mobile_prepend_node.innerHTML = QUICK_CRIMES_HTML;
// if对象加载后运行
let cIframe = $popup.querySelector('iframe');
// 加载状态
const if_onload_func = () => {
// if内部文档对象
const ifDocu = cIframe.contentWindow.document;
// 内部插件运行flag
const ifWH = cIframe.contentWindow.WHTRANS;
// 文档加载完成后移除
if (!!loading_node) loading_node.remove();
// 文档加载完成后才显示if
cIframe.style.display = 'block';
// 验证码flag
const isValidate = ifDocu.querySelector('h4#skip-to-content').innerText.toLowerCase().includes('validate');
// 如果iframe内部未运行脚本
if (ifWH === undefined) {
// 隐藏顶部
CommonUtils.elementReady('#header-root', ifDocu).then(e => e.style.display = 'none');
// 隐藏4条
CommonUtils.elementReady('#sidebarroot', ifDocu).then(e => e.style.display = 'none');
// 隐藏聊天
CommonUtils.elementReady('#chatRoot', ifDocu).then(e => e.style.display = 'none');
// 非验证码页面隐藏滚动条
if (!isValidate) ifDocu.body.style.overflow = 'hidden';
// 调整容器位置
CommonUtils.elementReady('.content-wrapper', ifDocu).then(elem => {
// 加入
elem.prepend(mobile_prepend_node);
elem.style.margin = '0px';
elem.style.position = 'absolute';
elem.style.top = '-35px';
new MutationObserver((m, o) => {
o.disconnect();
if (!elem.querySelector('.wh-translate')) elem.prepend(mobile_prepend_node);
o.observe(elem, { childList: true, subtree: true });
})
.observe(elem, { childList: true, subtree: true });
});
// 隐藏返回顶部按钮
CommonUtils.elementReady('#go-to-top-btn button', ifDocu).then(e => e.style.display = 'none');
}
};
cIframe.onload = if_onload_func;
// 超时判断
let time_counter = 0;
let time_out_id = window.setInterval(() => {
loading_node = $popup.querySelector('p:first-of-type');
if (!loading_node) {
clearInterval(time_out_id);
time_out_id = undefined;
return;
}
time_counter++;
if (time_counter > 0 && !loading_node.querySelector('button')) {
const reload_btn = document.createElement('button');
reload_btn.innerHTML = '重新加载';
reload_btn.onclick = () => {
reload_btn.remove();
time_counter = 0;
if_cont.innerHTML = null;
if_cont.innerHTML = ifHTML;
cIframe = $popup.querySelector('iframe');
cIframe.onload = if_onload_func;
};
loading_node.append(reload_btn);
}
}, 1000);
}
}

View File

@ -0,0 +1,27 @@
import WuhuBase from "../WuhuBase";
import WuhuConfig from "../WuhuConfig";
import PRICE_WATCHER_HTML from "../../static/html/price_watcher.html";
import Popup from "../utils/Popup";
import Global from "../Global";
export default class ItemPriceWatcherHandler extends WuhuBase {
className = 'ItemPriceWatcherHandler';
public handle(): void {
const watcher_conf = WuhuConfig.get('priceWatcher');
const pre_str = JSON.stringify(watcher_conf);
const html = PRICE_WATCHER_HTML
.replace('{{}}', localStorage.getItem('APIKey') || '不可用')
.replace('{{}}', Global.getInstance().isPDA ? Global.getInstance().PDA_APIKey : '不可用')
.replace('{{}}', watcher_conf['pt'] || -1)
.replace('{{}}', watcher_conf['xan'] || -1);
const popup = new Popup(html, '价格监视设置');
popup.getElement().querySelector('button').onclick = () => {
const [pt_node, xan_node] = Array.from(<NodeListOf<HTMLInputElement>>popup.getElement().querySelectorAll('input[type="number"]'));
watcher_conf.pt = (pt_node.value as any) | 0;
watcher_conf.xan = (xan_node.value as any) | 0;
if (JSON.stringify(watcher_conf) !== pre_str) WuhuConfig.set('priceWatcher', watcher_conf);
popup.close();
};
}
}

62
src/class/handler/NNB.ts Normal file
View File

@ -0,0 +1,62 @@
import WuhuBase from "../WuhuBase";
import NNB_INFO_HTML from "../../static/html/nnb_info.html";
import Popup from "../utils/Popup";
import Global from "../Global";
export default class NNB extends WuhuBase {
className = 'NNB';
public handle(): void {
let { isPDA, PDA_APIKey } = Global.getInstance();
const insert = NNB_INFO_HTML
.replace('{{}}', localStorage.getItem('APIKey') || '不可用')
.replace('{{}}', isPDA ? PDA_APIKey : '不可用');
const popup = new Popup(insert, '查看NNB').getElement();
const select = popup.querySelector('input');
const node = popup.querySelector('p');
popup.querySelector('button').addEventListener('click', ev => {
let target = ev.target as HTMLInputElement;
target.style.display = 'none';
node.innerHTML = '加载中';
// API 计算
if (select.checked) {
const api_key = isPDA ? PDA_APIKey : window.localStorage.getItem('APIKey');
window.fetch(`https://api.torn.com/user/?selections=bars,perks&key=${ api_key }`)
.then(res => res.json())
.then(data => {
if (data['error']) {
node.innerHTML = `出错了 ${ JSON.stringify(data['error']) }`;
target.style.display = null;
return;
}
let nb = data['nerve']['maximum'];
let perks = 0;
Object.values(data).forEach(val => {
(val instanceof Array) && val.forEach(s => {
s = s.toLowerCase();
s.includes('maximum nerve') && (perks += (<any>new RegExp('[0-9].').exec(s))[0] | 0)
})
});
node.innerHTML = `NNB: ${ nb - perks }`;
target.style.display = null;
});
}
// 主页计算
else {
if (window.location.href.includes('index.php') && document.title.includes('Home')) {
let nb = (<any>document.querySelector('#barNerve p[class^="bar-value___"]').innerText.split('/')[1]) | 0;
let perks = 0;
document.querySelectorAll('#personal-perks li').forEach(elem => {
const str = elem.innerText.toLowerCase();
str.includes('maximum nerve') && (perks += (/[0-9]./.exec(str) as any)[0] | 0)
});
node.innerHTML = `NNB: ${ nb - perks }`;
target.style.display = null;
return;
}
node.innerHTML = '不在主页面,<a href="/index.php">点击前往</a>';
target.style.display = null;
}
});
}
}

View File

@ -0,0 +1,107 @@
import WuhuBase from "../WuhuBase";
import CommonUtils from "../utils/CommonUtils";
import QUICK_FLY_CSS from "../../static/css/quick_fly.css";
import QUICK_FLY_HTML from "../../static/html/quick_fly.html";
import Alert from "../utils/Alert";
import TravelItem from "../action/TravelItem";
export default class QuickFlyBtnHandler extends WuhuBase {
className = 'QuickFlyBtnHandler';
public static doQuickFly(): void {
// [id: dest, _type: (1...4), ts: timestamp]
const [_id, _type, ts] = sessionStorage['wh-quick-fly'].trim().split(' ');
if (new Date().getTime() - ts > 20000) {
new Alert('超时,一键起飞计划已取消');
return;
}
const keyNode = document.querySelector('div[data-id][data-key]');
if (!keyNode) {
new Alert('出错了,无法起飞,已取消');
return;
}
const _key = keyNode.getAttribute('data-key');
window.getAction({
type: 'post',
data: {
step: 'travel',
id: QuickFlyBtnHandler.getDestId(_id),
key: _key,
type: ['standard', 'airstrip', 'private', 'business'][_type]
},
success: function (str) {
new Alert(str)
if (str.includes('err')) {
new Alert('起飞出错了');
return;
}
window.location.href = 'https://www.torn.com/index.php'
},
before: function () {
}
});
delete sessionStorage['wh-quick-fly'];
}
// 起飞目的地id
private static getDestId(dest): number {
// 墨、开、加、夏、英、阿、瑞s、立本、祖、迪、南
return [2, 12, 9, 3, 10, 7, 8, 5, 6, 11, 4][dest];
}
public handle(): void {
if (window.hasWHQuickFlyOpt) return;
window.hasWHQuickFlyOpt = true;
// TODO
CommonUtils.addStyle(QUICK_FLY_CSS);
const node = document.createElement('div');
node.id = 'wh-quick-fly-opt';
node.innerHTML = QUICK_FLY_HTML;
const [dest_node, type_node] = node.querySelectorAll('select') as any as HTMLSelectElement[];
node.querySelector('button').addEventListener('click', () => {
sessionStorage['wh-quick-fly'] = `${ dest_node.selectedIndex } ${ type_node.selectedIndex } ${ new Date().getTime() }`;
if (!window.location.href.contains('travelagency.php')) {
new Alert('正在转跳');
location.href = 'https://www.torn.com/travelagency.php';
} else {
QuickFlyBtnHandler.doQuickFly();
}
});
node.querySelector('a').addEventListener('click', (e) => {
e.preventDefault();
// forStock();
TravelItem.getInstance().clickHandler();
});
node.querySelector('input').addEventListener('click', (e) => {
node.classList.toggle('wh-quick-fly-opt-hide');
const el = e.target as HTMLInputElement;
el.value = el.value === ' - ' ? ' + ' : ' - ';
});
const info_node = node.querySelector('info');
const time_predict = document.createElement('p');
const yaoCD = document.createElement('p');
info_node.append(time_predict);
info_node.append(yaoCD);
const predict = [
['~54分', '~36分', '~26分', '~16分',],
['~1时10分', '~50分', '~36分', '~22分',],
['~1时22分', '~58分', '~40分', '~24分',],
['~4时28分', '~3时8分', '~2时14分', '~1时20分',],
['~5时18分', '~3时42分', '~2时40分', '~1时36分',],
['~5时34分', '~3时54分', '~2时46分', '~1时40分',],
['~5时50分', '~4时6分', '~2时56分', '~1时46分',],
['~7时30分', '~5时16分', '~3时46分', '~2时16分',],
['~8时4分', '~5时38分', '~4时2分', '~2时24分',],
['~9时2分', '~6时20分', '~4时30分', '~2时42分',],
['~9时54分', '~6时56分', '~4时58分', '~2时58分',],
];
const showTime = function () {
time_predict.innerHTML = `往返时间:${ predict[dest_node.selectedIndex][type_node.selectedIndex] }`;
}
dest_node.addEventListener('change', showTime);
type_node.addEventListener('change', showTime);
document.body.append(node);
showTime();
yaoCD.innerHTML = `药CD剩余${ CommonUtils.getYaoCD() }`;
}
}

View File

@ -0,0 +1,93 @@
import WuhuBase from "../WuhuBase";
import CommonUtils from "../utils/CommonUtils";
import QUICK_LINK_CSS from "../../static/css/quick_link.css";
import Popup from "../utils/Popup";
export default class QuickLinksHandler extends WuhuBase {
className = 'QuickLinksHandler';
private styleAdded: boolean = false;
private list = [];
constructor() {
super();
let list = this.list;
// 生存手册
list.push({
name: '生存手册',
url: 'https://docs.qq.com/doc/DTVpmV2ZaRnB0RG56',
new_tab: true,
img: 'https://www.torn.com/images/items/293/medium.png',
});
// 买啤酒
list.push({
name: '抢啤酒',
url: 'https://www.torn.com/shops.php?step=bitsnbobs',
new_tab: true,
img: 'https://www.torn.com/images/items/180/medium.png',
});
// 买XAN
list.push({
name: '买XAN',
url: 'https://www.torn.com/imarket.php#/p=shop&step=shop&type=&searchname=Xanax',
new_tab: true,
img: 'https://www.torn.com/images/items/206/medium.png',
});
// 起飞
list.push({
name: '起飞',
url: 'https://www.torn.com/travelagency.php',
new_tab: true,
img: 'https://www.torn.com/images/items/396/medium.png',
});
// 买PT
list.push({
name: '买PT',
url: 'https://www.torn.com/pmarket.php',
new_tab: true,
img: 'https://www.torn.com/images/items/722/medium.png',
});
// 租PI
list.push({
name: '租PI',
url: 'https://www.torn.com/properties.php?step=rentalmarket#/property=13',
new_tab: false,
img: 'https://www.torn.com/images/v2/properties/350x230/350x230_default_private_island.png',
});
// 找工作
list.push({
name: '找工作',
url: 'https://www.torn.com/joblist.php#!p=main',
new_tab: false,
img: 'https://www.torn.com/images/items/421/medium.png',
});
// 下悬赏
list.push({
name: '下悬赏',
url: 'https://www.torn.com/bounties.php#/p=add',
new_tab: false,
img: 'https://www.torn.com/images/items/431/medium.png',
});
}
public handle(): void {
if (!this.styleAdded) {
CommonUtils.addStyle(QUICK_LINK_CSS);
this.styleAdded = true;
}
const list = this.list;
let insert = '<p>';
list.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 += '</p>'
let popup = new Popup(insert, '常用链接');
popup.getElement().classList.add('wh-link-collection-cont');
popup.getElement().addEventListener('click', ev => {
let target = ev.target as HTMLElement;
if (target.tagName.toLowerCase() === 'a' || target.tagName.toLowerCase() === 'span') {
popup.close();
}
});
}
}

View File

@ -0,0 +1,448 @@
import WuhuBase from "../WuhuBase";
import { MenuItemConfig } from "../ZhongIcon";
import Log from "../Log";
import Timer from "../utils/Timer";
import BuyBeerHelper from "../action/BuyBeerHelper";
import UpdateTranslateDict from "./UpdateTranslateDict";
import landedRedirect from "../../func/module/landedRedirect";
import Alert from "../utils/Alert";
import WuhuConfig from "../WuhuConfig";
import ViewLogsHandler from "./ViewLogsHandler";
import AdditionalSettingsHandler from "./AdditionalSettingsHandler";
import Popup from "../utils/Popup";
import CommonUtils from "../utils/CommonUtils";
export default class SettingsHandler extends WuhuBase {
className = 'SettingsHandler';
private list: MenuItemConfig[] = [];
constructor() {
super();
this.constructWuhuSettingList();
}
public handler(): void {
let startTime = new Timer();
Log.info('构造设置开始');
let pop = new Popup(CommonUtils.loading_gif_html(), '芜湖助手设置');
let tmp = document.createElement('div');
tmp.classList.add('gSetting');
this.list.forEach(set => CommonUtils.getInstance().elemGenerator(set, tmp));
pop.getElement().innerHTML = '';
pop.getElement().appendChild(tmp);
// 本日不提醒
pop.getElement().querySelector('#wh-qua-alarm-check-btn')
.addEventListener('click', () => BuyBeerHelper.getInstance().skip_today());
(window.initializeTooltip) && (window.initializeTooltip('#wh-popup-cont', 'white-tooltip'));
Log.info('构造设置结束 ' + startTime.getTimeMs());
}
// 设置
private constructWuhuSettingList(): SettingsHandler {
let timer = new Timer();
Log.info('构造设置列表开始');
const date = new Date();
let beer = BuyBeerHelper.getInstance();
let list = this.list;
// 12月时加入圣诞小镇选项
if (date.getMonth() === 11) {
list.push({
domType: 'plain',
domId: '',
domHTML: '圣诞小镇',
tagName: 'h4',
})
list.push({
domType: 'checkbox',
domId: 'wh-xmastown-wt',
domText: ' 圣诞小镇攻略',
dictName: 'xmasTownWT',
isHide: true,
});
list.push({
domType: 'checkbox',
domId: 'wh-xmastown-notify',
domText: ' 圣诞小镇物品提示',
dictName: 'xmasTownNotify',
isHide: true,
});
}
// 翻译
list.push({
domType: 'plain',
domId: '',
domHTML: '翻译',
tagName: 'h4',
});
// 开启翻译
list.push({
domType: 'checkbox',
domId: 'wh-trans-enable',
domText: ' 开启翻译',
dictName: 'transEnable',
isHide: true,
});
// 更新翻译词库
list.push({
domType: 'button',
domId: '',
domText: '更新翻译词库',
clickFunc: () => UpdateTranslateDict.getInstance().handle()
});
// 战斗优化
list.push({
domType: 'plain',
domId: '',
domHTML: '战斗优化',
tagName: 'h4',
});
// 光速拔刀
list.push({
domType: 'select',
domId: 'wh-quick-attack-index',
domText: '光速拔刀 ',
domSelectOpt: [
{
domVal: 'pri',
domText: '主手',
},
{
domVal: 'sec',
domText: '副手',
},
{
domVal: 'wea',
domText: '近战',
},
{
domVal: 'gre',
domText: '手雷',
},
{
domVal: 'fis',
domText: '拳头',
},
{
domVal: 'kic',
domText: '脚踢',
},
{
domVal: 'none',
domText: '关闭',
},
],
dictName: 'quickAttIndex',
isHide: true,
tip: '将Start Fight按钮移动到指定格子上',
});
// 光速跑路
list.push({
domType: 'select',
domId: 'wh-quick-mug',
domText: '光速跑路 ',
domSelectOpt: [
{
domVal: 'leave',
domText: '跑路(LEAVE)',
},
{
domVal: 'mug',
domText: '打劫(MUG)',
},
{
domVal: 'hosp',
domText: '住院(HOSP)',
},
{
domVal: 'none',
domText: '关闭',
},
],
dictName: 'quickFinishAtt',
isHide: true,
tip: '<del>将结束后指定按钮移动到上面指定的格子上</del>暂时关闭',
});
// 攻击链接转跳
list.push({
domType: 'checkbox',
domId: 'wh-attack-relocate',
domText: ' 真·攻击界面转跳',
dictName: 'attRelocate',
tip: '在无法打开攻击界面的情况下依然可以转跳到正确的攻击页面',
isHide: true,
});
// 危险行为⚠️
if (WuhuConfig.get('dangerZone') === true) {
// 攻击界面自刷新
list.push({
domType: 'select',
domId: 'wh-attack-reload',
domText: '⚠️攻击界面自动刷新 ',
dictName: 'attReload',
domSelectOpt: [
{
domVal: 'none',
domText: '无间隔',
},
{
domVal: '1',
domText: '约1s',
},
{
domVal: '2',
domText: '约2s',
},
{
domVal: '3',
domText: '约3s',
},
{
domVal: '4',
domText: '约4s',
},
{
domVal: '5',
domText: '约5s',
},
{
domVal: 'disabled',
domText: '关闭',
},
],
isHide: true,
tip: '危险功能:接机时常用,将自动刷新页面直到目标落地',
});
// 自动开打和结束
list.push({
domType: 'checkbox',
domId: 'wh-auto-start-finish',
domText: ' ⚠️自动开打和结束',
dictName: 'autoStartFinish',
tip: '脚本将会自动按下战斗和结束按钮',
isHide: true,
});
} else {
WuhuConfig.set('autoStartFinish', false)
WuhuConfig.set('attReload', 6)
}
// 飞行
list.push({
domType: 'plain',
domId: '',
domHTML: '飞行',
tagName: 'h4',
});
// 起飞警告
list.push({
domType: 'checkbox',
domId: 'wh-energy-alert',
domText: ' 起飞爆E警告',
dictName: 'energyAlert',
tip: '起飞前计算来回是否会爆体,红字警告',
isHide: true,
});
// 飞行闹钟
list.push({
domType: 'checkbox',
domId: 'wh-trv-alarm-check',
domText: ' 飞行闹钟',
dictName: 'trvAlarm',
tip: '(仅PC) 飞行页面将显示一个内建的闹钟,落地前声音提醒,需要打开浏览器声音权限',
isHide: true,
});
// 海外警告
list.push({
domType: 'checkbox',
domId: '',
domText: ' 海外警告',
dictName: 'abroadWarning',
tip: '海外落地后每30秒通知警告',
});
// 落地转跳
list.push({ domType: 'button', domId: '', domText: '落地转跳', clickFunc: landedRedirect });
// 公司
list.push({
domType: 'plain',
domId: '',
domHTML: '公司',
tagName: 'h4',
});
// 浮动存钱框
list.push({
domType: 'checkbox',
domId: '',
domText: ' 浮动存钱框',
dictName: 'floatDepo',
tip: '打开公司或帮派的存钱页面后存钱框将浮动显示',
});
// 公司转跳存钱
list.push({
domType: 'checkbox',
domId: '',
domText: ' 公司转跳存钱',
dictName: 'companyRedirect',
tip: '打开公司页面时自动打开存钱选项卡',
});
// 收起公司冰蛙效率表
list.push({
domType: 'checkbox',
domId: '',
domText: ' 收起公司冰蛙效率表',
dictName: 'companyBWCollapse',
tip: '开启后可手动显示隐藏冰蛙公司表格',
});
// 任何位置一键存钱
list.push({
domType: 'checkbox',
domId: '',
domText: ' 任何位置一键存钱',
dictName: 'companyDepositAnywhere',
tip: '在所有页面显示一键存钱按钮Torn OK状态下可用此功能未完全测试无害使用请慎重',
});
// 火车检测开关
list.push({
domType: 'checkbox',
domId: null,
domText: '火车检测',
dictName: 'CHTrainsDetectSwitch',
tip: '检测明日火车是否会超出上限,需要系统通知权限'
});
// 啤酒
list.push({
domType: 'plain',
domId: '',
domHTML: '啤酒',
tagName: 'h4',
});
// 啤酒提醒
list.push({
domType: 'checkbox',
domId: 'wh-qua-alarm-check',
domText: '<span> 啤酒提醒 </span><button id="wh-qua-alarm-check-btn">今日不提醒</button>',
dictName: '_15Alarm',
tip: '每小时的整15分钟的倍数时通知提醒抢啤酒或者血包',
isHide: true,
changeEv: function (ev) {
ev.target.checked ? beer.start() : beer.stop();
},
});
// 啤酒提醒状态
list.push({
domType: 'button',
domId: '',
domText: '啤酒提醒状态',
clickFunc: function () {
new Alert(`啤酒提醒${ beer.status() }`);
}
});
// 啤酒提醒时间
list.push({
domType: 'button',
domId: '',
domText: '啤酒提醒时间设定',
// tip: '通知提前时间',
clickFunc: () => BuyBeerHelper.getInstance().setTimeHandler()
});
// 其他
list.push({
domType: 'plain',
domId: '',
domHTML: '其他',
tagName: 'h4',
});
// 任务助手
list.push({
domType: 'checkbox',
domId: 'wh-mission-lint',
domText: ' 任务助手',
dictName: 'missionHint',
tip: 'Duke任务的一些中文小提示',
isHide: true,
});
// 捡垃圾助手
list.push({
domType: 'checkbox',
domId: 'wh-city-finder',
domText: ' 捡垃圾助手',
dictName: 'cityFinder',
tip: '城市地图中放大显示物品并且估计价值',
isHide: true,
});
// 快速crime
list.push({
domType: 'checkbox',
domId: 'wh-quick-crime',
domText: ' 快速犯罪',
dictName: 'quickCrime',
tip: '显示快捷操作按钮,目前不支持自定义',
isHide: true,
});
// 叠E保护
list.push({
domType: 'checkbox',
domId: 'wh-SEProtect-check',
domText: ' 叠E保护',
dictName: 'SEProtect',
tip: '隐藏健身房的锻炼按钮,防止误操作',
isHide: true,
});
// PT一键购买
list.push({
domType: 'checkbox',
domId: 'wh-ptQuickBuy-check',
domText: ' PT一键购买',
dictName: 'ptQuickBuy',
tip: 'PT市场页面购买时跳过确认',
isHide: true,
});
// 4条转跳
list.push({
domType: 'checkbox',
domId: '',
domText: ' 4条转跳',
dictName: 'barsRedirect',
tip: '点击4条时转跳对应页面',
});
// 清除多余的脚本
list.push({
domType: 'checkbox',
domId: '',
domText: ' 清除多余的脚本',
dictName: 'removeScripts',
tip: '清除Google相关脚本、顶部横幅等',
});
// dev
list.push({
domType: 'checkbox',
domId: 'wh-dev-mode',
domText: '开发模式',
dictName: 'isDev',
isHide: true,
});
// 查看logs
list.push({
domType: 'button',
domId: null,
domText: '查看日志',
clickFunc: () => ViewLogsHandler.getInstance().handle()
});
// 更多设定
list.push({
domType: 'button', domId: 'wh-otherBtn', domText: '更多设定',
clickFunc: () => AdditionalSettingsHandler.getInstance().handle()
});
Log.info('构造设置列表结束' + timer.getTimeMs());
return this;
}
}

View File

@ -0,0 +1,10 @@
import WuhuBase from "../WuhuBase";
import Alert from "../utils/Alert";
export default class UpdateTranslateDict extends WuhuBase {
className = 'UpdateTranslateDict';
public handle(): void {
new Alert('计划中');
}
}

View File

@ -0,0 +1,19 @@
import WuhuBase from "../WuhuBase";
import Log from "../Log";
import Popup from "../utils/Popup";
export default class ViewLogsHandler extends WuhuBase {
className = 'ViewLogsHandler';
public handle(): void {
let logCounter = Log.getCounter();
let pop = new Popup('<textarea readonly style="width:100%;height:340px;"></textarea>', '查看日志');
let text = pop.getElement().querySelector('textarea');
text.innerHTML = Log.getLogs();
text.onclick = () => text.select();
pop.getElement().insertAdjacentHTML(
'afterbegin',
`<p>${ logCounter.info }信息 ${ logCounter.warning }警告 ${ logCounter.error }错误</p>`
);
}
}

View File

@ -3,10 +3,12 @@ import WuhuBase from "../WuhuBase";
import Log from "../Log";
import Device from "../../enum/Device";
import AjaxFetchOption from "../../interface/AjaxFetchOption";
import Alert from "./Alert";
import LOADING_IMG_HTML from "../../static/html/loading_img.html";
import Timer from "./Timer";
import FetchUtils from "./FetchUtils";
import TornStyleSwitch from "./TornStyleSwitch";
import WuhuConfig from "../WuhuConfig";
import { MenuItemConfig } from "../ZhongIcon";
export default class CommonUtils extends WuhuBase {
className = 'CommonUtils';
@ -84,22 +86,22 @@ export default class CommonUtils extends WuhuBase {
});
}
/**
* { playername: string, userID: number }
* @return {PlayerInfo} rs
*/
static getPlayerInfo(): PlayerInfo {
const node = document.querySelector('script[uid]');
if (node) {
return {
playername: node.getAttribute('name'),
userID: node.getAttribute('uid') as unknown as number,
}
} else {
new Alert('严重错误:芜湖助手无法获取用户数据,已退出');
throw '芜湖助手无法获取用户数据';
}
}
// /**
// * 返回玩家信息的对象 { playername: string, userID: number }
// * @return {PlayerInfo} rs
// */
// static getPlayerInfo(): PlayerInfo {
// const node = document.querySelector('script[uid]');
// if (node) {
// return {
// playername: node.getAttribute('name'),
// userID: node.getAttribute('uid') as unknown as number,
// }
// } else {
// new Alert('严重错误:芜湖助手无法获取用户数据,已退出');
// throw '芜湖助手无法获取用户数据';
// }
// }
// 用户设备类型 对应PC MOBILE TABLET
public static getDeviceType(): Device {
@ -171,6 +173,12 @@ export default class CommonUtils extends WuhuBase {
});
}
/**
* mutation.observe
* @param selectors
* @param content
* @param timeout
*/
public static querySelector(selectors: string, content: Document = document, timeout: number = 30000): Promise<HTMLElement> {
return CommonUtils.elementReady(selectors, content, timeout);
}
@ -247,4 +255,70 @@ export default class CommonUtils extends WuhuBase {
let time = Math.max(ms, 10);
return new Promise(resolve => setTimeout(() => resolve(null), time));
}
}
public elemGenerator(setting: MenuItemConfig, root_node: Element): HTMLElement {
let { tip, domType } = setting;
let new_node = null;
switch (domType) {
case 'checkbox': {
new_node = document.createElement('div');
let { domId, dictName, domText, changeEv } = setting;
let switcher = new TornStyleSwitch(domText);
let _input = switcher.getInput();
switcher.getBase().id = domId;
(tip) && (switcher.getBase().setAttribute('title', tip));
_input.checked = WuhuConfig.get(dictName);
_input.onchange = e => {
WuhuConfig.set(dictName, _input.checked, true);
if (changeEv) changeEv(e);
};
new_node.appendChild(switcher.getBase());
break;
}
case 'button': {
new_node = document.createElement('div');
let { domId, domText, clickFunc } = setting;
let btn = document.createElement('button');
(tip) && (btn.setAttribute('title', tip));
btn.id = domId;
btn.innerHTML = domText;
btn.addEventListener('click', clickFunc);
new_node.appendChild(btn);
break;
}
case 'select': {
new_node = document.createElement('div');
let { domSelectOpt, dictName, domId, domText } = setting;
let label = document.createElement('label');
(tip) && (label.setAttribute('title', tip));
let text = document.createTextNode(domText);
let select = document.createElement('select');
select.id = domId;
domSelectOpt.forEach((opt, i) => {
let { domVal, domText } = opt;
let option = document.createElement('option');
option.value = domVal;
option.innerHTML = domText;
option.selected = i === WuhuConfig.get(dictName);
option.innerHTML = domText;
select.appendChild(option);
});
select.onchange = e => WuhuConfig.set(dictName, (<HTMLSelectElement>e.target).selectedIndex);
label.appendChild(text);
label.appendChild(select);
new_node.appendChild(label);
break;
}
case 'plain': {
let tag = setting.tagName || 'div';
new_node = document.createElement(tag);
if (setting.domId) new_node.id = setting.domId;
new_node.innerHTML += setting['domHTML'];
break;
}
}
// 移动节点
return root_node.appendChild(new_node);
}
}

View File

@ -0,0 +1,53 @@
import Log from "../Log";
import DIALOG_MSG_BOX_HTML from "../../static/html/dialog_msg_box.html";
export default class DialogMsgBox {
private static existed = false;
private readonly container: HTMLElement;
constructor(msg: string, opt: DialogMsgBoxOptions) {
Log.info('创建DialogMsgBox', { msg, opt });
let { title = '提示', callback } = opt;
if (!callback) {
Log.error('无callback');
throw new Error('无callback');
}
if (DialogMsgBox.existed) {
Log.error('无法创建DialogMsgBox已存在');
throw new Error('无法创建DialogMsgBox已存在');
}
this.container = document.createElement('div');
this.container.id = 'wh-dialog';
this.container.innerHTML = DIALOG_MSG_BOX_HTML.replace('{{}}', title).replace('{{}}', msg);
let [confirm, cancel] = Array.from(this.container.querySelectorAll('button'));
confirm.addEventListener('click', () => {
callback(this.container);
this.destroy();
});
cancel.addEventListener('click', () => {
this.destroy();
});
document.body.append(this.container);
// this.hideChat();
DialogMsgBox.existed = true;
}
// private hideChat() {
// document.querySelector('#chatRoot').classList.add('wh-hide');
// }
//
// private showChat() {
// document.querySelector('#chatRoot').classList.remove('wh-hide');
// }
private destroy() {
this.container.remove();
// this.showChat();
DialogMsgBox.existed = false;
}
}
interface DialogMsgBoxOptions {
title?: string;
callback: Function;
}

View File

@ -1,5 +1,5 @@
export default class Timer {
private startTime: number;
private readonly startTime: number;
constructor() {
this.startTime = performance.now();

View File

@ -4,11 +4,11 @@ export default class TornStyleSwitch {
private readonly baseElement;
private readonly randomId;
constructor(label: string) {
constructor(label: string, checked: boolean = false) {
this.randomId = MathUtils.getInstance().getRandomInt(100, 2000);
this.baseElement = document.createElement('span');
this.baseElement.id = 'WHSwitch' + this.randomId;
this.baseElement.innerHTML = `<input class="checkbox-css" type="checkbox" id="WHCheck${ this.randomId }">
this.baseElement.innerHTML = `<input class="checkbox-css" type="checkbox" id="WHCheck${ this.randomId }" ${ checked ? 'checked' : '' }/>
<label for="WHCheck${ this.randomId }" class="non-selection marker-css">${ label }</label>`;
}
@ -19,4 +19,8 @@ export default class TornStyleSwitch {
public getInput(): HTMLInputElement {
return this.baseElement.querySelector('input');
}
public getHtml(): string {
return this.baseElement.innerHTML;
}
}

View File

@ -1,43 +1,43 @@
import Alert from "../../class/utils/Alert";
// 一键起飞
export default function doQuickFly() {
// [id: dest, _type: (1...4), ts: timestamp]
const [_id, _type, ts] = sessionStorage['wh-quick-fly'].trim().split(' ');
if (new Date().getTime() - ts > 20000) {
new Alert('超时,一键起飞计划已取消');
return;
}
const keynode = document.querySelector('div[data-id][data-key]');
if (!keynode) {
new Alert('出错了,无法起飞,已取消');
return;
}
const _key = keynode.getAttribute('data-key');
window.getAction({
type: 'post',
data: {
step: 'travel',
id: getDestId(_id),
key: _key,
type: ['standard', 'airstrip', 'private', 'business'][_type]
},
success: function (str) {
new Alert(str)
if (str.includes('err')) {
new Alert('起飞出错了');
return;
}
window.location.href = 'https://www.torn.com/index.php'
},
before: function () {
}
});
delete sessionStorage['wh-quick-fly'];
}
// 起飞目的地id
function getDestId(dest) {
// 墨、开、加、夏、英、阿、瑞s、立本、祖、迪、南
return [2, 12, 9, 3, 10, 7, 8, 5, 6, 11, 4][dest];
}
// import Alert from "../../class/utils/Alert";
//
// // 一键起飞
// export default function doQuickFly() {
// // [id: dest, _type: (1...4), ts: timestamp]
// const [_id, _type, ts] = sessionStorage['wh-quick-fly'].trim().split(' ');
// if (new Date().getTime() - ts > 20000) {
// new Alert('超时,一键起飞计划已取消');
// return;
// }
// const keynode = document.querySelector('div[data-id][data-key]');
// if (!keynode) {
// new Alert('出错了,无法起飞,已取消');
// return;
// }
// const _key = keynode.getAttribute('data-key');
// window.getAction({
// type: 'post',
// data: {
// step: 'travel',
// id: getDestId(_id),
// key: _key,
// type: ['standard', 'airstrip', 'private', 'business'][_type]
// },
// success: function (str) {
// new Alert(str)
// if (str.includes('err')) {
// new Alert('起飞出错了');
// return;
// }
// window.location.href = 'https://www.torn.com/index.php'
// },
// before: function () {
// }
// });
// delete sessionStorage['wh-quick-fly'];
// }
//
// // 起飞目的地id
// function getDestId(dest) {
// // 墨、开、加、夏、英、阿、瑞s、立本、祖、迪、南
// return [2, 12, 9, 3, 10, 7, 8, 5, 6, 11, 4][dest];
// }

View File

@ -1,5 +1,3 @@
import getWhSettingObj from "../utils/@deprecated/getWhSettingObj";
import log from "../utils/@deprecated/log";
import toThousands from "../utils/toThousands";
import Log from "../../class/Log";
import Alert from "../../class/utils/Alert";
@ -12,7 +10,7 @@ export default function priceWatcherHandle(isPDA: boolean, PDA_APIKey: string) {
const price_conf = WuhuConfig.get('priceWatcher');
const apikey = isPDA ? PDA_APIKey : localStorage.getItem('APIKey');
if (!apikey || (price_conf['pt'] === -1 && price_conf['xan'] === -1)) {
Log.error('价格监视失败无apikey');
Log.warn('价格监视关闭无apikey或设置未打开');
window.clearInterval(intervalId);
return;
}

View File

@ -1,7 +1,6 @@
import titleTrans from "../translate/titleTrans";
import contentTitleLinksTrans from "../translate/contentTitleLinksTrans";
import Device from "../../enum/Device";
import doQuickFly from "./doQuickFly";
import WuhuBase from "../../class/WuhuBase";
import Alert from "../../class/utils/Alert";
import ActionButtonUtils from "../../class/utils/ActionButtonUtils";
@ -10,6 +9,7 @@ import CommonUtils from "../../class/utils/CommonUtils";
import TRAVEL_ALARM_CSS from "../../static/css/travel_alarm.css";
import TRAVEL_ALARM_HTML from "../../static/html/travel_alarm.html";
import TornStyleBlock from "../../class/utils/TornStyleBlock";
import QuickFlyBtnHandler from "../../class/handler/QuickFlyBtnHandler";
export default async function travelHelper(): Promise<null> {
let { href, bodyAttrs, device } = WuhuBase.glob;
@ -29,7 +29,7 @@ export default async function travelHelper(): Promise<null> {
dest_cn = {
'uk': "英国", 'switzerland': "瑞士", 'mexico': '墨西哥', 'canada': '加拿大', 'cayman': '开曼',
'hawaii': '夏威夷', 'argentina': '阿根廷',
'japan': '日本', 'china': '中国', 'uae': 'UAE', 'sa': '南非',
'japan': '日本', 'china': '中国', 'uae': 'UAE', 'south-africa': '南非',
}[country] || country;
}
@ -286,7 +286,7 @@ export default async function travelHelper(): Promise<null> {
}
// 一键起飞
if (sessionStorage['wh-quick-fly']) {
doQuickFly();
QuickFlyBtnHandler.doQuickFly();
}
}
}

View File

@ -37,6 +37,7 @@ import showItemInfoTrans from "./showItemInfoTrans";
import log from "../utils/@deprecated/log";
import contentTitleLinksTransReact from "./contentTitleLinksTransReact";
import titleTransReact from "./titleTransReact";
import Log from "../../class/Log";
export default function translateMain(href: string): void {
// 时分秒转换
@ -123,12 +124,14 @@ export default function translateMain(href: string): void {
const headerTrans = function headerTrans() {
// 搜索内容下拉框中的文字 已选中
if (headerDict[$('div.find button.toggler.down').text()])
$('div.find button.toggler.down').text(headerDict[$('div.find button.toggler.down').text()]);
let $toggle = $('div.find button.toggler.down');
if (headerDict[$toggle.text()])
$toggle.text(headerDict[$toggle.text()]);
// pc端 搜索下拉框点击后的搜索类型文字
$('div.find li.item').each((i, e) => {
if (headerDict[$(e).text()])
$(e).text(headerDict[$(e).text()]);
let $e = $(e);
if (headerDict[$e.text()])
$e.text(headerDict[$e.text()]);
});
// 手机端 搜索下拉框点击后的搜索类型文字
$('li[class^="search-type-"] label').each((i, e) => {
@ -136,46 +139,54 @@ export default function translateMain(href: string): void {
$(e).text(headerDict[$(e).text()]);
});
// 搜索框placeholder
if (headerDict[$('input[class^="searchInput"]').attr('placeholder')])
$('input[class^="searchInput"]').attr('placeholder',
headerDict[$('input[class^="searchInput"]').attr('placeholder')]);
let $searchInput = $('input[class^="searchInput"]');
if (headerDict[$searchInput.attr('placeholder')])
$searchInput.attr('placeholder',
headerDict[$searchInput.attr('placeholder')]);
// 高级搜索框 search by
if (headerDict[document.querySelector('div#header-root legend.title').innerText])
$('div#header-root legend.title').text(headerDict[$('div#header-root legend.title').text()]);
if (headerDict[document.querySelector('div#header-root legend.title').innerText]) {
let $title = $('div#header-root legend.title');
$title.text(headerDict[$title.text()]);
}
// 高级搜索框的条件 左 键
$('ul.advancedSearchFormBody label.label').each((i, e) => {
if (headerDict[$(e).text()])
$(e).text(headerDict[$(e).text()]);
let $e = $(e);
if (headerDict[$e.text()])
$e.text(headerDict[$e.text()]);
});
// 高级搜索框的已选中
$('ul.advancedSearchFormBody div.select-wrapper button.toggler.down').each((i, e) => {
// log($(e).text())
if (headerDict[$(e).text().trim()])
$(e).text(headerDict[$(e).text().trim()]);
else if (propertyDict[$(e).text().trim()])
$(e).text(propertyDict[$(e).text().trim()]);
let $e = $(e);
if (headerDict[$e.text().trim()])
$e.text(headerDict[$e.text().trim()]);
else if (propertyDict[$e.text().trim()])
$e.text(propertyDict[$e.text().trim()]);
});
// 高级搜索的下拉选项
$('ul.advancedSearchFormBody li.item').each((i, e) => {
if (headerDict[$(e).text()])
$(e).text(headerDict[$(e).text()]);
else if (propertyDict[$(e).text()])
$(e).text(propertyDict[$(e).text()]);
let $e = $(e);
if (headerDict[$e.text()])
$e.text(headerDict[$e.text()]);
else if (propertyDict[$e.text()])
$e.text(propertyDict[$e.text()]);
});
// 高级搜索的"Not"
$('ul.advancedSearchFormBody label.search-condition-not').each((i, e) => {
if (headerDict[$(e).text()])
$(e).text(headerDict[$(e).text()]);
let $e = $(e);
if (headerDict[$e.text()])
$e.text(headerDict[$e.text()]);
});
// 高级搜索的"to"
$('ul.advancedSearchFormBody label[for*="To"]').each((i, e) => {
if (headerDict[$(e).text()])
$(e).text(headerDict[$(e).text()]);
let $e = $(e);
if (headerDict[$e.text()])
$e.text(headerDict[$e.text()]);
});
// 高级搜索的reset search按钮
$('form.form-search-extend div.bottom button').each((i, e) => {
if (headerDict[$(e).text()])
$(e).text(headerDict[$(e).text()]);
let $e = $(e);
if (headerDict[$e.text()])
$e.text(headerDict[$e.text()]);
});
// log按钮“view log”
const $view_log = $('div.recentHistory a[class^="link"] span[class^="text"]')
@ -184,8 +195,9 @@ export default function translateMain(href: string): void {
.text(headerDict[$view_log.text().trim()]);
// 点击头像打开的菜单
$('ul.settings-menu span').each((i, e) => {
if (headerDict[$(e).text()] && e.childNodes.length === 1)
$(e).text(headerDict[$(e).text()]);
let $e = $(e);
if (headerDict[$e.text()] && e.childNodes.length === 1)
$e.text(headerDict[$e.text()]);
else if (e.childNodes.length === 3)
if (headerDict[e.firstChild.nodeValue])
e.firstChild.nodeValue = headerDict[e.firstChild.nodeValue];
@ -205,20 +217,22 @@ export default function translateMain(href: string): void {
const chatTrans = function chatTrans() {
// 聊天框的标题
$('div#chatRoot div[class^="chat-box-title"] span[class^="name"]').each((i, e) => {
if (chatDict[$(e).text().trim()])
$(e).text(chatDict[$(e).text().trim()]);
let $e = $(e);
if (chatDict[$e.text().trim()])
$e.text(chatDict[$e.text().trim()]);
});
// 聊天设置的左边label
$('div[class^="chat-settings-opts"] div[class*="label"]').each((i, e) => {
if ($(e).next().children('div.rc-slider').length > 0) {
let $e = $(e);
if ($e.next().children('div.rc-slider').length > 0) {
// 高度和宽度有响应式的%
if (chatDict[$(e).text().split(' ')[0]]) {
$(e).text($(e).text().replace($(e).text().split(' ')[0], chatDict[$(e).text().split(' ')[0]]));
if (chatDict[$e.text().split(' ')[0]]) {
$e.text($e.text().replace($e.text().split(' ')[0], chatDict[$e.text().split(' ')[0]]));
}
return;
}
if (chatDict[$(e).text().trim()])
$(e).text(chatDict[$(e).text().trim()]);
if (chatDict[$e.text().trim()])
$e.text(chatDict[$e.text().trim()]);
});
// 选项下拉栏
$('div[class^="dropdown-root"]').find('*').contents().each((i, e) => {
@ -228,29 +242,30 @@ export default function translateMain(href: string): void {
});
// 设置的两个选项
$('label[class^="privacy-label"]').each((i, e) => {
if (chatDict[$(e).text().trim()])
$(e).text(chatDict[$(e).text().trim()]);
let $e = $(e);
if (chatDict[$e.text().trim()])
$e.text(chatDict[$e.text().trim()]);
});
// people中的5个分类 faction friend...
$('ul[class^="type-list"] li a').each((i, e) => {
if (chatDict[$(e).text().trim()])
$(e).text(chatDict[$(e).text().trim()]);
let $e = $(e);
if (chatDict[$e.text().trim()])
$e.text(chatDict[$e.text().trim()]);
});
// people中的列表添加框placeholder
$('div.ac-wrapper input.ac-search').each((i, e) => {
if (chatDict[$(e).attr('placeholder')])
$(e).attr('placeholder', chatDict[$(e).attr('placeholder')]);
let $e = $(e);
if (chatDict[$e.attr('placeholder')])
$e.attr('placeholder', chatDict[$e.attr('placeholder')]);
});
//
if (eventsDict[$('div#chatRoot div[class^="overview"] > div > div:nth-child(2)').text().trim()]) {
$('div#chatRoot div[class^="overview"] > div > div:nth-child(2)')
.text(
eventsDict[document.querySelector('div#chatRoot div[class^="overview"] > div > div:nth-child(2)').innerText.trim()]
);
let $chatRootOverview = document.querySelector('div#chatRoot div[class^="overview"] > div > div:nth-child(2)');
if (eventsDict[$chatRootOverview.innerText.trim()]) {
$chatRootOverview.innerText = eventsDict[$chatRootOverview.innerText.trim()];
}
};
chatTrans();
chatOB.observe($('div#chatRoot').get(0), { childList: true, subtree: true, attributes: true });
chatOB.observe(document.querySelector('div#chatRoot'), { childList: true, subtree: true, attributes: true });
}
// 搜索玩家的4个分类按钮
@ -327,18 +342,18 @@ export default function translateMain(href: string): void {
// 翻译最近5个攻击
else if (e.firstChild.nodeValue === 'Latest Attacks') {
$(e).parent().next().find('span').each(function () {
let nodes = $(this)[0].childNodes;
let $this = $(this);
let nodes = $this[0].childNodes;
nodes.forEach((v, i) => {
if (v.nodeValue !== null) {
let waitToTsf = v.nodeValue.toString().indexOf(" ");
// let waitToTsf = v.nodeValue.toString().indexOf(" ");
let words = v.nodeValue.replace("\n", "").toString().split(" ");
words.forEach((word, j) => {
if (attackDict.hasOwnProperty(word)) {
if (word === "Someone") {
$(this)[0].childNodes[i].nodeValue = $(this)[0].childNodes[i].nodeValue.replace(" ", "");
$this[0].childNodes[i].nodeValue = $(this)[0].childNodes[i].nodeValue.replace(" ", "");
}
let change = $(this)[0].childNodes[i].nodeValue.replace(word, attackDict[word]);
$(this)[0].childNodes[i].nodeValue = change;
$this[0].childNodes[i].nodeValue = $this[0].childNodes[i].nodeValue.replace(word, attackDict[word]);
}
})
@ -373,13 +388,13 @@ export default function translateMain(href: string): void {
});
// 标志建筑 标题
if (cityDict[$('div.title-black').text()])
$('div.title-black').text(cityDict[$('div.title-black').text()]);
let $divTitleBlack = document.querySelector('div.title-black');
if (cityDict[$divTitleBlack.innerText])
$divTitleBlack.innerText = cityDict[$divTitleBlack.innerText];
// 标志建筑 6个分类
$('ul.map-symbols span').each((i, e) => {
if (cityDict[$(e).text()])
$(e).text(cityDict[$(e).text()]);
if (cityDict[e.innerText]) e.innerText = cityDict[e.innerText];
});
// 地图显示模式
@ -388,13 +403,13 @@ export default function translateMain(href: string): void {
// 完全显示 文字
$('span.active-mode').text(cityDict['active-mode']);
// 开关
$('div.on-label').text('已开启');
$('div.off-label').text('已关闭');
document.querySelector('div.on-label').innerText = '已开启';
document.querySelector('div.off-label').innerText = '已关闭';
// 快速链接中的分类标题
$('li.title').each((i, e) => {
if (cityDict[$(e).text()])
$(e).text(cityDict[$(e).text()]);
if (cityDict[e.innerText])
e.innerText = cityDict[e.innerText];
});
// 快速链接中的区域
@ -1235,9 +1250,10 @@ export default function translateMain(href: string): void {
let newspaperTrans = function newspaperTrans() {
titleTrans();
contentTitleLinksTrans();
if ($('a.newspaper-link').length === 0) return;
let $newspaperLink = $('a.newspaper-link');
if ($newspaperLink.length === 0) return;
// 导航菜单
$('a.newspaper-link').contents().each((i, e) => {
$newspaperLink.contents().each((i, e) => {
if (newspaperDict[e.nodeValue])
e.nodeValue = newspaperDict[e.nodeValue];
});
@ -1284,8 +1300,9 @@ export default function translateMain(href: string): void {
});
// 底部链接
// Why not visit our sponsor?
if (newspaperDict[$('div.link-left').text().trim()])
$('div.link-left').text(newspaperDict[$('div.link-left').text().trim()]);
let $linkLeft = document.querySelector('div.link-left');
if (newspaperDict[$linkLeft.innerText.trim()])
$linkLeft.innerText = newspaperDict[$linkLeft.innerText.trim()];
// View all | Advertise here
$('div.link-right a').contents().each((i, e) => {
if (newspaperDict[e.nodeValue.trim()])
@ -1306,8 +1323,9 @@ export default function translateMain(href: string): void {
}
// 漫画
if (window.location.href.contains(/freebies/)) {
if (newspaperDict[$('div.bonus-wrap a').text().trim()])
$('div.bonus-wrap a').text(newspaperDict[$('div.bonus-wrap a').text().trim()]);
let $bonusWrapA = document.querySelector('div.bonus-wrap a');
if (newspaperDict[$bonusWrapA.innerText.trim()])
$bonusWrapA.innerText = newspaperDict[$bonusWrapA.innerText.trim()];
}
// 悬赏
if (window.location.href.contains(/bounties/)) {
@ -1960,39 +1978,42 @@ export default function translateMain(href: string): void {
//攻击链盒
$('div[class^="chain-box"]').contents().each((i, e) => {
if (factionDict[$(e).text().trim()]) {
$(e).text(factionDict[$(e).text().trim()]);
let $e = $(e);
if (factionDict[$e.text().trim()]) {
$e.text(factionDict[$e.text().trim()]);
}
})
//帮派消息类别
$('div[class^="newsHeader"]').contents().each((i, e) => {
if (factionDict[$(e).text().trim()]) {
$(e).text(factionDict[$(e).text().trim()]);
let $e = $(e);
if (factionDict[$e.text().trim()]) {
$e.text(factionDict[$e.text().trim()]);
}
})
//帮派主要消息日志
$('button[class^="tab"] ').each((i, e) => {
if ($(e).attr('class').indexOf("active") >= 0) {
log.info($(e).text());
switch ($(e).text().trim()) {
if (e.classList.contains('active')) {
Log.info(e.innerText);
let $newListInfo = $('ul[class^="news-list"] span[class^="info"]');
switch (e.innerText.trim()) {
case "主要消息":
$('ul[class^="news-list"] span[class^="info"]').contents().each((i, u) => {
$newListInfo.contents().each((i, u) => {
if (factionDict[$(u).text().trim()]) {
u.nodeValue = u.nodeValue.replace($(u).text().trim(), factionDict[$(u).text().trim()]);
}
})
break;
case "攻击":
$('ul[class^="news-list"] span[class^="info"]').find('*').contents().each((i, u) => {
log.info($(u).text().trim())
$newListInfo.find('*').contents().each((i, u) => {
Log.info($(u).text().trim());
if (factionDict[$(u).text().trim()]) {
u.nodeValue = factionDict[$(u).text().trim()];
}
})
break;
case "资金流动":
$('ul[class^="news-list"] span[class^="info"]').contents().each((i, u) => {
$newListInfo.contents().each((i, u) => {
if (u.nodeValue) {
u.nodeValue = u.nodeValue.replace("deposited", "存放了");
}

View File

@ -1,6 +1,6 @@
import Alert from "../../class/utils/Alert";
// 更新词库
export default function updateTransDict() {
new Alert('计划中');
}
// import Alert from "../../class/utils/Alert";
//
// // 更新词库
// export default function updateTransDict() {
// new Alert('计划中');
// }

View File

@ -1,5 +1,4 @@
export default interface ISidebarData {
// TODO 补全
statusIcons?: StatusIcons;
user?: {
userID: number,

View File

@ -114,10 +114,7 @@ div#wh-popup::after {
#wh-popup-container {
max-width: 568px;
margin: 5em auto 0;
/*background: #d7d7d7;*/
/*min-height: 120px;*/
box-shadow: 0 0 5px 1px #898989;
/*border-radius: 4px;*/
/*box-shadow: 0 0 5px 1px #898989;*/
}
#wh-popup-title p {

View File

@ -0,0 +1,54 @@
<style>
html {
overflow: hidden !important;
}
#chatRoot {
display: none !important;
}
#wh-dialog {
position: absolute;
/*width: 100%;*/
/*height: 100%;*/
background: #00000066;
flex-direction: column;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 290001;
}
#wh-dialog .top-round {
text-align: center;
}
#wh-dialog div.wh-content {
padding: 1em;
}
#wh-dialog .border-round {
margin: auto;
max-width: 400px;
position: fixed;
top: 100px;
left: 0;
right: 0;
}
#wh-dialog .pin-bottom {
text-align: center;
padding: 8px 0;
}
</style>
<div class="border-round">
<div class="title-black top-round">{{}}</div>
<div class="cont-gray bottom-round">
<div class="wh-content">{{}}</div>
<div class="non-selection pin-bottom">
<button class="torn-btn">确定</button>
<button class="torn-btn">取消</button>
</div>
</div>
</div>

View File

@ -2,7 +2,7 @@
<div id="deadman_header" style="margin:10px 0px; border:1px solid darkgray; text-align:center;">
<button class="torn-btn" id="deadman-start-btn" style="margin:5px;">开始寻找木桩</button>
</div>
<div id="deadman_tips" style="text-align:center; margin-bottom: 3px; font-size: 4px;">未开始</div>
<div id="deadman_tips" style="text-align:center; margin-bottom: 3px; font-size: 16px;">未开始</div>
<div id="deadman_wrapper"
style="min-height:700px;margin:10px 0px; border:1px solid darkgray; text-align:center;overflow:hidden;">
<table cellspacing="0" id="watchlist-table" style="width:100%; background-color: white; font-size:12px;">

View File

@ -1,15 +1,13 @@
import WuhuBase from "../class/WuhuBase";
import Log from "../class/Log";
import Popup from "../class/utils/Popup";
import WuhuConfig from "../class/WuhuConfig";
import Alert from "../class/utils/Alert";
import DialogMsgBox from "../class/utils/DialogMsgBox";
export default class Test extends WuhuBase {
className = 'Test';
public test(): void {
let popup = new Popup('');
popup.getElement()['__POOL__'] = Test.getPool();
// let popup = new Popup('');
// popup.getElement()['__POOL__'] = Test.getPool();
// this.case1()
// this.case2()
@ -25,6 +23,10 @@ export default class Test extends WuhuBase {
temp.append(...document.body.childNodes);
// @ts-ignore
temp2.append(...document.head.childNodes);
temp2.querySelectorAll('script[src*="google"]').forEach(item => item.remove());
temp2.querySelectorAll('#gtm_tag').forEach(item => item.remove());
temp2.querySelectorAll('script[src*="chat/gonline"]').forEach(item => item.remove());
temp2.querySelectorAll('script[nonce]').forEach(item => item.remove());
window.stop();
@ -35,7 +37,8 @@ export default class Test extends WuhuBase {
// @ts-ignore
document.body.append(...temp.childNodes);
// @ts-ignore
document.head.append(...temp2.childNodes);
// document.head.append(...temp2.childNodes);
document.body.insertAdjacentHTML('afterbegin', temp2.innerHTML);
}
private case2() {
@ -47,11 +50,6 @@ export default class Test extends WuhuBase {
}
private async case3() {
WuhuConfig.set('CHTrainsDetect', 0);
new Alert(`公司助手<br/>火车检测:火车明日将溢出!有${ 1 }个可用火车`, {
timeout: 15,
force: true,
sysNotify: true
});
new DialogMsgBox('123', { callback: () => alert(1) })
}
}