Compare commits

..

No commits in common. "master" and "v0.6.9" have entirely different histories.

261 changed files with 6492 additions and 42194 deletions

8
.gitignore vendored
View File

@ -1,8 +1,4 @@
/node_modules /node_modules
/bundle.min.js
/bundle.js
/.fleet /.fleet
/src/dist/bundle.min.js
/src/dist/bundle.js
/dist
auto-imports.d.ts
components.d.ts
aws.xml

6
.idea/jsLibraryMappings.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<file url="file://$PROJECT_DIR$" libraries="{Node.js Core}" />
</component>
</project>

View File

@ -4,9 +4,6 @@
<exclude-output /> <exclude-output />
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.fleet" /> <excludeFolder url="file://$MODULE_DIR$/.fleet" />
<excludeFolder url="file://$MODULE_DIR$/misc" />
<excludeFolder url="file://$MODULE_DIR$/dist" />
<excludePattern pattern="release.min.user.js" />
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />

14
.vscode/launch.json vendored
View File

@ -1,14 +0,0 @@
{
// 使 IntelliSense
//
// 访: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"command": "npm run rollup",
"name": "rollup",
"request": "launch",
"type": "node-terminal"
}
]
}

View File

@ -1,489 +1,9 @@
# TODO
- 翻译baza npc商店、imarket、imarket搜索结果
# CHANGE # CHANGE
## 1.2.4
2025年04月07日
### 修改
- 优化起飞功能错误处理
- 取消网络拦截,避免官方功能被影响
## 1.2.3
2025年03月11日
### 修改
- 删除GS Load模块代码
- 删除翻译
- 删除去Google化部分代码
- 修复起飞逻辑
- 修复通知
## 1.2.2
2024年04月07日
### 修改
- 快捷动作【REFILL】修复
## 1.2.1
2024年04月03日
### 修改
- 快捷动作【REFILL】修复
## 1.2.0
2024年03月29日
### 修改
- BS估算缓存机制修复
- 快捷功能【快速犯罪】界面优化
## 1.1.9
2024年03月27日
### 添加
- 引入了BS估算功能
### 修改
- 快捷功能【快速犯罪】去除了烦人的通知
## 1.1.8
2024年03月20日
### 修改
- 快捷功能的【喝啤酒】移动至【快速犯罪】中
- profile页面中在线状态调整
## 1.1.7
2024年03月15日
### 添加
- 快捷功能-PI存钱
### 修改
- 上次动作的url判断修复
- profile页面中添加了更明显的上次动作时间
- 快速取钱功能添加了常用输入
## 1.1.6
2024年01月08日
### 修改
- refill功能改为菜单式新增支持3种refil
- 快速犯罪功能现已支持全部种类
## 1.1.5
2023年12月22日
### 修改
- 圣诞小镇掉落物记录表格中的undefined错误修复
## 1.1.4
2023年12月08日
### 修改
- 快速犯罪中添加了15-3
## 1.1.3
2023年11月29日
### 修改
- 通知浏览错误修复
## 1.1.2
2023年09月19日
### 修改
- 火车提醒错误修复
- 光速刷新错误修复
## 1.1.1
2023年09月13日
### 修改
- 调整了上次动作的显示逻辑
- 更准确的现金变动提醒
### 添加
- 监控模块-毒CD提醒
## 1.1.0
2023年09月11日
### 修改
- 更正上次动作的匹配路径、添加了毒和糖 CD 的提示
## 1.0.9
2023年09月08日
### 修改
- 侧边菜单UI优化
## 1.0.8
2023年08月23日
### 修改
- 通知浏览修复
## 1.0.7
2023年06月27日
### 修改
- 物品功能补充完善
- 菜单顺序调整
## 1.0.6
2023年06月26日
### 添加
- 物品功能标签
## 1.0.5
2023年06月19日
### 修改
- 移除原菜单
- 调整了新菜单的样式、部分逻辑
## 1.0.4
2023年06月16日
### 添加
- 标签页管理功能
## 1.0.3
2023年06月16日
### 修改
- 样式错误修复
## 1.0.2
2023年06月15日
### 修改
- 错误修复
- 菜单样式修改
## 1.0.1
2023年06月14日
### 添加
- 公司存取钱
## 1.0.0
2023年06月12日
### 添加
- PT购买
## 0.9.9
2023年06月07日
### 修改
- 购物助手错误修复及样式调整
## 0.9.8
2023年06月06日
### 修改
- 错误修复
## 0.9.7
2023年06月05日
### 添加
- bazaar快速开关店
- 购物助手
### 修改
- 部分样式修改
## 0.9.6
2023年06月01日
### 添加
- PC病毒快速操作
## 0.9.5
2023年05月31日
### 修改
- 明文密码简单编码处理
- 自动登录前添加确认
## 0.9.4
2023年05月31日
### 添加
- 自动登陆功能
## 0.9.3
2023年05月30日
### 添加
- 快速查看地图垃圾
## 0.9.2
2023年05月26日
### 添加
- 快速浏览通知
## 0.9.1
2023年05月04日
### 添加
- 新菜单中现在可以快速喝啤酒了
- 快速 refill
## 0.9.0
2023年04月28日
### 添加
- 新菜单中现在可以快速吃XAN了
- 快速犯罪
## 0.8.9
2023年04月24日
### 修改
- 战斗相关模块错误修复
- 重复通知错误修复
## 0.8.8
2023年04月17日
### 添加
- 新菜单
- 快速锻炼
- 一键起飞
## 0.8.7
2023年04月10日
### 修改
- 修复脚本首次运行配置获取错误的问题
- 修复"解决加载中"功能开启后无法加载插件图标的问题
- 修复功能选项错误读取默认值的问题
## 0.8.6
2023年04月07日
### 修改
- 结构调整
## 0.8.5
2023年04月03日
### 修改
- 结构调整
## 0.8.4
2023年03月03日
### 修改
- 错误修复
## 0.8.3
2023年03月02日
### 添加
- 物品查价
## 0.8.2
2023年02月01日
### 添加
- 新翻译:通用物品名与详情
## 0.8.1
2023年02月01日
### 添加
- 上次动作的开关
## 0.8.0
2023年01月16日
### 修改
- 完善新的翻译部分
## 0.7.9
2023年01月09日
### 修改
- 优化了迷你选项卡的汉化效果
- 更新节日数据
## 0.7.8
2022年12月20日
### 修改
- 修复与其他脚本的兼容性问题
## 0.7.7
2022年12月7日
### 添加
- 老虎机批量购买
## 0.7.6
2022年12月6日
### 添加
- 现金变动提醒
## 0.7.5
2022年12月6日
### 修改
- 可记录上次图标的位置,调整了拖动逻辑
## 0.7.4
2022年12月5日
### 修改
- 插件图标现可拖动
- PC端滚动条样式
## 0.7.3
2022年11月25日
### 修改
- 捡垃圾助手调整
- 菜单调整
## 0.7.2
2022年11月22日
### 修改
- 修复光速跑路错误
## 0.7.1
2022年11月15日
### 修改
- 调整寻找木桩页面逻辑
- 修复光速刷新
## 0.7.0
2022年11月10日
### 添加
- 官方引入Google登陆方式及相关脚本后引起的无限加载中的问题的不完美解决办法
## 0.6.9 ## 0.6.9
2022年11月8日 2022年11月8日

View File

@ -1 +0,0 @@

21
LICENSE
View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2023 JJins
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,23 +0,0 @@
# Wuhu Torn Helper
[![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[中文](README_ZHCN.md)
[CHANGELOG(CN)](CHANGELOG.md)
A customized auxiliary-enhancement user script designed for a browser-based MMORPG game, featuring a range of convenient
functions.
This script does not include any automation-related code.
## Build
npm init
npm run rollup
## Use
[release.min.user.js](release.min.user.js)
Please install with Tampermonkey (for PC browser) or TornPDA.

View File

@ -1,20 +0,0 @@
# 芜湖助手 Torncity 翻译插件
[![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[CHANGELOG](CHANGELOG.md)
一个为浏览器网页MMORPG游戏定制的辅助增强用户脚本包含了一系列便携功能。
此脚本不包含自动化相关代码。
## 编译
npm init
npm run rollup
## 使用
[release.min.user.js](https://gitlab.com/JJins/wuhu-torn-helper/-/raw/dev/README_ZHCN.md)
请使用 Tampermonkey (浏览器) 或 TornPDA 安装。

View File

@ -2,15 +2,13 @@
* 此脚本用于加入userscript meta * 此脚本用于加入userscript meta
* 并生成日期时间与版本号 * 并生成日期时间与版本号
*/ */
let startTime = Date.now();
import { readFileSync, writeFileSync } from "fs"; let fs = require('fs');
import { prodConfig } from "./rollup.config.js";
let date = new Date(); let date = new Date();
let version = process.env.npm_package_version; let version = process.env.npm_package_version;
let formattedDateTime = `${ date.getFullYear() }${ ('0' + (date.getMonth() + 1)).slice(-2) }${ ('0' + date.getDate()).slice(-2) }${ ('0' + date.getHours()).slice(-2) }${ ('0' + date.getMinutes()).slice(-2) }`; let formattedDateTime = `${ date.getFullYear() }${ ('0' + (date.getMonth() + 1)).slice(-2) }${ ('0' + date.getDate()).slice(-2) }${ ('0' + date.getHours()).slice(-2) }${ ('0' + date.getMinutes()).slice(-2) }`;
let metaData = let metaData = `// ==UserScript==
`// ==UserScript==
// @lastmodified ${ formattedDateTime } // @lastmodified ${ formattedDateTime }
// @name 芜湖助手 // @name 芜湖助手
// @namespace WOOH // @namespace WOOH
@ -18,9 +16,10 @@ let metaData =
// @description 托恩,起飞! // @description 托恩,起飞!
// @author Woohoo[2687093] Sabrina_Devil[2696209] // @author Woohoo[2687093] Sabrina_Devil[2696209]
// @match https://www.torn.com/* // @match https://www.torn.com/*
// @downloadURL https://gitlab.com/JJins/wuhu-torn-helper/-/raw/dev/release.min.user.js // @updateURL https://gitlab.com/JJins/wuhu-torn-helper/-/raw/dev/release.min.user.js
// @grant GM_xmlhttpRequest // @grant GM_xmlhttpRequest
// @grant unsafeWindow // @grant unsafeWindow
// @connect ljs-lyt.com
// @connect yata.yt // @connect yata.yt
// @connect github.io // @connect github.io
// @connect gitlab.com // @connect gitlab.com
@ -29,11 +28,6 @@ let metaData =
// ==/UserScript== // ==/UserScript==
` `
const data = readFileSync('./' + prodConfig.output.file, 'utf8'); const data = fs.readFileSync('./bundle.min.js', 'utf8');
writeFileSync( fs.writeFileSync('./release.min.user.js', metaData + data.replace('$$WUHU_DEV_VERSION$$', version), 'utf8');
'./release.min.user.js', console.log(`版本 ${ version } 构建完成, build.js耗时${ Date.now() - startTime }ms`);
metaData + data.replace('$$WUHU_DEV_VERSION$$', version),
'utf8'
);
// rmSync('./' + prodConfig.output.file);
console.log(`版本 ${ version } 构建完成`);

6
css-module.d.ts vendored
View File

@ -1,6 +0,0 @@
// declare module "*.module.css" {
// const css: string;
// const classes: { [key: string]: string };
// export default classes;
// export { css };
// }

View File

@ -1,21 +0,0 @@
export const customInjector = (varName) => {
let rt = ((__var) => {
const inject = (ob) => {
if (document && document.head) {
ob?.disconnect();
const style = document.createElement('style');
style.setAttribute('type', 'text/css');
style.innerHTML = __var;
document.head.appendChild(style);
}
};
if (document && document.head) {
inject();
} else {
new MutationObserver((_, ob) => {
inject(ob);
}).observe(document.documentElement, { childList: true });
}
}).toString();
return `(${ rt })(${ varName })`;
};

19
global.d.ts vendored
View File

@ -108,22 +108,15 @@ declare interface TornGetActionParams {
} }
declare module "*.html" { declare module "*.html" {
const html: string; const value: string;
export default html; export default value;
} }
declare module "*.module.css" {
const css: string; declare module "*.css" {
// const classes: { [key: string]: string }; const value: string;
// export default classes; export default value;
export default css;
// export { css };
} }
declare function GM_xmlhttpRequest(init: any): void; declare function GM_xmlhttpRequest(init: any): void;
declare var unsafeWindow: Window & typeof globalThis; declare var unsafeWindow: Window & typeof globalThis;
declare type Constructor<T = any> = new (...args: any[]) => T;
declare interface ClassType<T> {
new(...args: unknown[]): T
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

16538
misc/vue.js

File diff suppressed because it is too large Load Diff

10594
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,43 +1,29 @@
{ {
"name": "wuhu-torn-helper", "name": "wuhu-torn-helper",
"version": "1.2.4", "version": "0.6.9",
"description": "芜湖助手", "description": "芜湖助手",
"dependencies": {},
"scripts": { "scripts": {
"release": "cross-env NODE_ENV=production rollup -c && node build.mjs", "release": "rollup -c rollup-prod.config.js && node build.js # 发布",
"watch": "cross-env NODE_ENV=development rollup -c -w", "build": "rollup -c # 调试编译",
"rollup": "cross-env NODE_ENV=development rollup -c" "rollup_watch": "rollup -c -w # 监控",
"minify": "uglifyjs misc/wuhu-torn-helper.js -o release.min.user.js -m # 弃用",
"serve": "# 弃用",
"compile": "tsc --outDir output # 弃用"
}, },
"devDependencies": { "devDependencies": {
"@element-plus/icons-vue": "^2.1.0",
"@rollup/plugin-alias": "^4.0.3",
"@rollup/plugin-commonjs": "^24.0.1",
"@rollup/plugin-json": "^4.1.0", "@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^15.0.1",
"@rollup/plugin-replace": "^5.0.2",
"@rollup/plugin-terser": "^0.4.0",
"@rollup/plugin-typescript": "^8.5.0", "@rollup/plugin-typescript": "^8.5.0",
"@types/jquery": "^3.5.14", "@types/jquery": "^3.5.14",
"@types/node": "^20.6.0", "@types/node": "^18.0.6",
"@vitejs/plugin-vue": "^4.0.0",
"@vue/tsconfig": "^0.1.3",
"cross-env": "^7.0.3",
"element-plus": "^2.3.10",
"just-clone": "^6.2.0",
"npm": "^8.19.2", "npm": "^8.19.2",
"reflect-metadata": "^0.1.13",
"rollup": "^2.79.0", "rollup": "^2.79.0",
"rollup-plugin-postcss": "^4.0.2", "rollup-plugin-html-literals": "^1.1.5",
"rollup-plugin-string-html": "^1.0.0", "rollup-plugin-serve": "^2.0.1",
"rollup-plugin-styles": "^4.0.0", "rollup-plugin-string": "^3.0.0",
"rollup-plugin-typescript2": "^0.34.1", "rollup-plugin-uglify": "^6.0.4",
"tslib": "^2.4.0", "tslib": "^2.4.0",
"typescript": "^4.8.3", "typescript": "^4.8.3",
"unplugin-auto-import": "^0.15.2", "uglify-js": "^3.16.1"
"unplugin-element-plus": "^0.7.0", }
"unplugin-icons": "^0.16.1",
"unplugin-vue-components": "^0.24.1",
"vant": "^4.1.2",
"vue": "^3.2.47"
},
"type": "module"
} }

File diff suppressed because one or more lines are too long

20
rollup-prod.config.js Normal file
View File

@ -0,0 +1,20 @@
import typescript from "@rollup/plugin-typescript";
import json from "@rollup/plugin-json";
import { string } from "rollup-plugin-string";
import { uglify } from "rollup-plugin-uglify";
export default {
input: 'src/index.ts',
output: {
file: 'bundle.min.js',
format: 'iife',
},
plugins: [
typescript(),
json(),
string({
include: ["**/*.html", "**/*.css"]
}),
uglify(),
],
};

View File

@ -1,131 +1,24 @@
// [!] Error: Unexpected token (Note that you need plugins to import files that are not JavaScript) import typescript from "@rollup/plugin-typescript";
// src/vue/ItemPrice.vue?vue&type=script&lang.ts (35:13)
// TODO 官方提供ts插件在vue模版中使用ts语言时报错
// import typescript from "@rollup/plugin-typescript";
// TODO 在rollup watch模式中不更新vue模版ts部分代码
import typescript2 from "rollup-plugin-typescript2";
import json from "@rollup/plugin-json"; import json from "@rollup/plugin-json";
import html from "rollup-plugin-string-html"; // import template from "rollup-plugin-html-literals";
import resolve from "@rollup/plugin-node-resolve"; import { string } from "rollup-plugin-string";
import replace from "@rollup/plugin-replace";
import alias from "@rollup/plugin-alias";
import vue from "@vitejs/plugin-vue";
import styles from "rollup-plugin-styles";
import { customInjector } from "./custom-injector.js";
import terser from "@rollup/plugin-terser";
import clone from "just-clone";
import commonjs from '@rollup/plugin-commonjs';
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
// import { VantResolver } from 'unplugin-vue-components/resolvers';
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
import IconsResolver from 'unplugin-icons/resolver';
import Icons from 'unplugin-icons/vite'
import ElementPlus from 'unplugin-element-plus/rollup'
let node_env = process.env.NODE_ENV; export default {
let vuePath = node_env === 'production' ? input: 'src/index.ts',
'vue/dist/vue.runtime.esm-browser.prod.js' :
'vue/dist/vue.runtime.esm-browser.js';
const devConfig = {
input: 'src/ts/index.ts',
output: { output: {
file: 'dist/bundle.js', file: 'bundle.js',
format: 'iife', format: 'iife',
name: 'bundle.js',
}, },
plugins: [ plugins: [
// template({
// include: '*.html',
// failOnError: true
// }),
typescript(),
json(), json(),
html({ string({
include: ["**/*.html"], include: ["**/*.html", "**/*.css"]
minifier: {
includeAutoGeneratedTags: true,
removeAttributeQuotes: false,
removeComments: true,
removeRedundantAttributes: false,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
sortClassName: true,
useShortDoctype: true,
collapseWhitespace: true,
minifyCSS: true,
}
}),
// 根据环境更改vue源
alias({
entries: [
{ find: 'vue', replacement: vuePath },
]
}),
// 为vue替换环境变量
replace({
values: {
'process.env.NODE_ENV': () => JSON.stringify(node_env),
'__VUE_OPTIONS_API__': () => JSON.stringify(false),
'__VUE_PROD_DEVTOOLS__': () => JSON.stringify(true),
},
preventAssignment: true,
}),
// 引入node相关方法
resolve({
browser: true,
preferBuiltins: false,
}),
commonjs(),
vue({ isProduction: node_env === 'production' }),
AutoImport({
resolvers: [
ElementPlusResolver(),
IconsResolver({
prefix: 'Icon',
}),
],
}),
Components({
resolvers: [
IconsResolver({
enabledCollections: ['ep'],
}),
ElementPlusResolver()
],
// resolvers: [VantResolver()],
}),
Icons(),
ElementPlus(),
// 自定义注入器注入vue部分css
styles({
// modules: true,
// namedExports: true,
exclude: /static\/css\/.+\.css/,
mode: [
"inject",
(varName) => customInjector(varName),
],
minimize: true
}),
// 非vue部分css逻辑代码中手动注入
styles({
include: /static\/css\/.+\.css/,
// modules: true,
// namedExports: true,
mode: [
"inject",
() => ``,
],
minimize: true
}),
typescript2({
tsconfig: "./tsconfig.json",
}), }),
// uglify(),
], ],
}; };
const prodConfig = clone(devConfig);
prodConfig.plugins.push(terser());
prodConfig.output.file = 'dist/bundle.min.js';
prodConfig.output.name = 'bundle.min.js';
export default [devConfig, prodConfig];
export { prodConfig };

41
src/class/Application.ts Normal file
View File

@ -0,0 +1,41 @@
import WuhuBase from "./WuhuBase";
import WuHuTornHelper from "./WuhuTornHelper";
import ZhongIcon from "./ZhongIcon";
import { Common } from "./Common";
import UrlPattern from "./UrlMatch";
import WuhuConfig from "./WuhuConfig";
import translateMain from "../func/translate/translateMain";
import CommonUtils from "./utils/CommonUtils";
export default class Application {
public static main() {
WuhuBase.conditionInterrupt();
// 初始化
WuHuTornHelper.getInstance();
// 插件设置默认值
WuhuConfig.setDefaults();
// 插件图标和设置菜单
ZhongIcon.getInstance();
let tmp = () => {
// 所有页面通用
Common.getInstance().resolve();
// URL匹配
UrlPattern.getInstance().resolve();
// 翻译
if (WuhuConfig.get('transEnable')) translateMain(window.location.href);
};
// TODO 临时检测jquery
if (typeof $ === "function") {
tmp();
} else {
CommonUtils.getInstance().jQueryReady().then(() => tmp());
}
}
}

50
src/class/Common.ts Normal file
View File

@ -0,0 +1,50 @@
import depoHelper from "../func/module/depoHelper";
import travelHelper from "../func/module/travelHelper";
import priceWatcherHandle from "../func/module/priceWatcherHandle";
import WuhuBase from "./WuhuBase";
import WuhuConfig from "./WuhuConfig";
import CompanyHelper from "./action/CompanyHelper";
import AttackHelper from "./action/AttackHelper";
import SidebarHelper from "./action/SidebarHelper";
import CommonUtils from "./utils/CommonUtils";
import Log from "./Log";
export class Common extends WuhuBase {
className = 'Common';
public resolve() {
let glob = Common.glob;
// 价格监控
priceWatcherHandle(glob.isPDA, glob.PDA_APIKey);
// 啤酒提醒
if (WuhuConfig.get('_15Alarm')) glob.beer.start();
SidebarHelper.getInstance();
/**
* All('script[src*="google"]')
* All('#gtm_tag')
* All('script[src*="chat/gonline"]')
* All('head script[nonce]')
*/
// 存钱相关
depoHelper();
// 飞行相关
travelHelper().then();
// 战斗相关
AttackHelper.getInstance();
// 公司助手
CompanyHelper.getInstance();
// 自定义CSS
if (WuhuConfig.get('CustomCss')) {
Log.info('应用自定义CSS');
CommonUtils.addStyle(WuhuConfig.get('CustomCss'));
}
}
}

93
src/class/Global.ts Normal file
View File

@ -0,0 +1,93 @@
import Device from "../enum/Device";
import WuhuBase from "./WuhuBase";
import IGlobal from "../interface/IGlobal";
import Log from "./Log";
import InfoUtils from "./utils/InfoUtils";
import BuyBeerHelper from "./action/BuyBeerHelper";
/**
*
*/
export default class Global extends WuhuBase implements IGlobal {
className = 'Global';
GM_xmlhttpRequest: Function = null;
href: string = window.location.href;
// 弹窗
popup_node: MyHTMLElement = null;
/**
* @deprecated 使getInstance替代
*/
beer = null;
// 留存的通知
notifies: NotifyWrapper = null;
// 海外库存
fStock = null;
// 玩家名和数字id
player_info = null;
// 设备类型
device: Device = null;
// PDA运行环境
isPDA: boolean = false;
// PDA自带apikey
PDA_APIKey: string = null;
// 脚本版本
version: string = null;
// window 副本
window: Window & typeof globalThis = window;
unsafeWindow: Window & typeof globalThis = null;
// document body 属性
bodyAttrs: {
'data-country'?: string;
'data-celebration'?: string;
'data-traveling'?: 'true' | 'false';
'data-abroad'?: 'true' | 'false';
} = null;
constructor() {
Log.info('WH脚本参数[Global]初始化');
super();
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;
}
this.version = '$$WUHU_DEV_VERSION$$';
this.PDA_APIKey = '###PDA-APIKEY###';
this.isPDA = !this.PDA_APIKey.includes('###');
this.device = window.innerWidth >= 1000 ? Device.PC : window.innerWidth <= 600 ? Device.MOBILE : Device.TABLET;
this.player_info = InfoUtils.getInstance().getPlayerInfo();
this.beer = BuyBeerHelper.getInstance();
this.popup_node = null;
this.notifies = { count: 0 };
this.href = window.location.href;
this.bodyAttrs = {};
for (let i = 0; i < document.body.attributes.length; i++) {
let item = document.body.attributes.item(i);
this.bodyAttrs[item.name] = item.value;
}
// 当窗口关闭时关闭所有还存在的通知
window.addEventListener(
'beforeunload',
() => {
if (this.notifies.count !== 0) {
for (let i = 0; i < this.notifies.count; i++) {
(this.notifies[i] !== null) && (this.notifies[i].close())
}
}
}
);
Log.info('WH脚本参数初始化结束');
}
}

View File

@ -4,25 +4,28 @@ export default class Log {
public static info(...o): void { public static info(...o): void {
Log.counter.info++; Log.counter.info++;
let flag = '%c WH %cIFO%c' + this.getTime() + '%c'; let time = this.getTime();
let flag = '[WH] IFO';
if (this.debug()) { if (this.debug()) {
console.log(flag, 'background:grey;color:white;', '', 'color:grey;', '', ...o); console.log(flag, time, ...o);
} }
this.saveLogs(flag, ...o); this.saveLogs(flag, time, ...o);
} }
public static error(...o): void { public static error(...o): void {
Log.counter.error++; Log.counter.error++;
let flag = '%c WH %cERR%c' + this.getTime() + '%c'; let time = this.getTime();
console.error(flag, 'background:grey;color:white;', 'background:red;color:white;', 'color:grey;', '', ...o); let flag = '[WH] ERR';
this.saveLogs(flag, ...o); console.error(flag, time, ...o);
this.saveLogs(flag, time, ...o);
} }
public static warn(...o): void { public static warn(...o): void {
Log.counter.warning++; Log.counter.warning++;
let flag = '%c WH %cWRN%c' + this.getTime() + '%c'; let time = this.getTime();
console.warn(flag, 'background:grey;color:white;', 'background:#ff9800;color:white;', 'color:grey;', '', ...o); let flag = '[WH] WRN';
this.saveLogs(flag, ...o); (this.debug()) && (console.warn(flag, time, ...o));
this.saveLogs(flag, time, ...o);
} }
public static debug(): boolean { public static debug(): boolean {
@ -31,7 +34,6 @@ export default class Log {
let local = JSON.parse(localStorage.getItem('wh_trans_settings')); let local = JSON.parse(localStorage.getItem('wh_trans_settings'));
if (local) ret = local['isDev']; if (local) ret = local['isDev'];
} catch { } catch {
this.error('debug错误')
} }
return ret; return ret;
} }
@ -45,7 +47,7 @@ export default class Log {
let minutes = ('0' + d.getMinutes()).slice(-2); let minutes = ('0' + d.getMinutes()).slice(-2);
let seconds = ('0' + d.getSeconds()).slice(-2); let seconds = ('0' + d.getSeconds()).slice(-2);
let ms = ('00' + d.getMilliseconds()).slice(-3); let ms = ('00' + d.getMilliseconds()).slice(-3);
return `${ year }-${ month }-${ date } ${ hours }:${ minutes }:${ seconds }.${ ms }`; return `[${ year }-${ month }-${ date } ${ hours }:${ minutes }:${ seconds }.${ ms }]`;
} }
public static getLogs() { public static getLogs() {
@ -54,17 +56,16 @@ export default class Log {
private static saveLogs(...o) { private static saveLogs(...o) {
o.forEach(item => { o.forEach(item => {
if (typeof item === 'string') this.logs += item.replaceAll('%c', ''); if (typeof item === 'string') this.logs += item;
else if (item !== null && item !== undefined) { else if (item !== null && item !== undefined) {
let json = '{}'; let json = '{}';
let name = Object.getPrototypeOf(item).constructor.name; let name = item.toString ? item.toString() : 'UNKNOWN_OBJECT';
try { try {
json = JSON.stringify(item); json = JSON.stringify(item);
name = Object.getPrototypeOf(item).constructor.name;
} catch { } catch {
} }
this.logs += ` [${ name }] [${ json }] `; this.logs += ` [${ name }] [${ json }] `;
if (item.message) this.logs += '错误信息: ' + item.message;
if (item.stack) this.logs += '错误堆栈: ' + item.stack;
} }
}) })
this.logs += '\r\n'; this.logs += '\r\n';

View File

@ -1,85 +1,44 @@
import cityFinder from "../func/module/cityFinder"; import cityFinder from "../func/module/cityFinder";
import { missionDict } from "../dictionary/translation"; import { missionDict } from "../dictionary/translation";
import getTaskHint from "../func/translate/getTaskHint"; import getTaskHint from "../func/translate/getTaskHint";
import WuhuBase from "./WuhuBase";
import CommonUtils from "./utils/CommonUtils"; import CommonUtils from "./utils/CommonUtils";
import SHOP_BEER_STATIC_ITEM_HTML from "../../static/html/buyBeer/shop_beer_static_item.html"; import Log from "./Log";
import ADD_BEER_HEAD_HTML from "../../static/html/buyBeer/add_beer_head.html"; import WuhuConfig from "./WuhuConfig";
import QUICK_CRIMES_HTML from "../../static/html/quick_crimes.html"; import Alert from "./utils/Alert";
import RW_RIDER_HTML from "../../static/html/rw_rider.html"; import SHOP_BEER_STATIC_ITEM_HTML from "../static/html/buyBeer/shop_beer_static_item.html";
import ADD_BEER_HEAD_HTML from "../static/html/buyBeer/add_beer_head.html";
import QUICK_CRIMES_HTML from "../static/html/quick_crimes.html";
import RW_RIDER_HTML from "../static/html/rw_rider.html";
import christmasTownHelper from "../func/module/christmasTownHelper"; import christmasTownHelper from "../func/module/christmasTownHelper";
import LotteryHelper from "../feature/LotteryHelper"; import LotteryHelper from "./action/LotteryHelper";
import TornStyleBlock from "./utils/TornStyleBlock"; import TornStyleBlock from "./utils/TornStyleBlock";
import PTHelper from "./action/PTHelper"; import PTHelper from "./action/PTHelper";
import StackHelper from "../feature/StackHelper"; import StackHelper from "./action/StackHelper";
import BuyBeerHelper from "../feature/BuyBeerHelper"; import BuyBeerHelper from "./action/BuyBeerHelper";
import XZMZ from "./action/XZMZ"; import XZMZ from "./action/XZMZ";
import ProfileHelper from "./action/ProfileHelper"; import ProfileHelper from "./action/ProfileHelper";
import SearchHelper from "./action/SearchHelper"; import SearchHelper from "./action/SearchHelper";
import TornStyleSwitch from "./utils/TornStyleSwitch";
import SlotsHelper from "./action/SlotsHelper";
import globVars from "../globVars";
import { Injectable } from "../container/Injectable";
import ClassName from "../container/ClassName";
import LocalConfigWrapper from "./LocalConfigWrapper";
import { Container } from "../container/Container";
import Logger from "./Logger";
/** /**
*
*
* TODO jq * TODO jq
*/ */
@Injectable() export default class UrlPattern extends WuhuBase {
@ClassName('UrlPattern') className = 'UrlPattern';
export default class UrlRouter {
constructor(
private readonly localConfigWrapper: LocalConfigWrapper,
private readonly buyBeerHelper: BuyBeerHelper,
private readonly searchHelper: SearchHelper,
private readonly lotteryHelper: LotteryHelper,
private readonly slotsHelper: SlotsHelper,
private readonly logger: Logger,
) {
}
public resolve(): void { public resolve(): void {
let href = window.location.href; let href = window.location.href;
let modules = [];
// 捡垃圾助手 // 捡垃圾助手
if (href.includes('city.php') && this.localConfigWrapper.config.cityFinder) { if (href.includes('city.php') && WuhuConfig.get('cityFinder')) cityFinder();
let _base = new TornStyleBlock('芜湖助手').insert2Dom();
// let reloadSwitch = new TornStyleSwitch('解决一直转圈(加载中)的问题');
// reloadSwitch.getInput().checked = this.localConfigWrapper.config.SolveGoogleScriptPendingIssue;
// _base.append(reloadSwitch.getBase()).insert2Dom();
// reloadSwitch.getInput().addEventListener('change', () => {
// if (reloadSwitch.getInput().checked) window.location.replace(window.location.href);
// this.localConfigWrapper.config.SolveGoogleScriptPendingIssue = reloadSwitch.getInput().checked;
// // WuhuConfig.set('SolveGoogleScriptPendingIssue', reloadSwitch.getInput().checked, true);
// });
_base.append(document.createElement('br'));
cityFinder(_base);
}
// pt一键购买 // pt一键购买
if (href.includes('pmarket.php')) Container.factory(PTHelper); if (href.includes('pmarket.php')) PTHelper.getInstance();
// 叠e助手 // 叠e助手
if (href.includes('gym.php')) Container.factory(StackHelper); if (href.includes('gym.php')) StackHelper.getInstance();
// 寻找木桩 // 寻找木桩
if (href.includes('item.php?temp=4')) { if (href.includes('item.php?temp=4#xunzhaomuzhuang')) XZMZ.getInstance();
let hasInit: boolean = false;
let handle = () => {
if (!hasInit && window.location.hash === '#xunzhaomuzhuang') {
Container.factory(XZMZ).init();
hasInit = true;
}
}
window.addEventListener('hashchange', handle);
handle();
}
// 啤酒店 // 啤酒店
if (href.includes('shops.php?step=bitsnbobs')) { if (href.includes('shops.php?step=bitsnbobs')) {
@ -91,12 +50,12 @@ export default class UrlRouter {
let node = document.querySelector('ul.items-list'); let node = document.querySelector('ul.items-list');
if (!node) { if (!node) {
msg_node.innerHTML = '❌ 商品未加载完'; msg_node.innerHTML = '❌ 商品未加载完';
this.logger.error('商品未加载完'); Log.error('商品未加载完');
return; return;
} }
if (node.querySelector('span[id="180-name"]')) { if (node.querySelector('span[id="180-name"]')) {
msg_node.innerHTML = '❌ 页面已经有啤酒了'; msg_node.innerHTML = '❌ 页面已经有啤酒了';
this.logger.warn('商店页面已有啤酒'); Log.warn('商店页面已有啤酒');
return; return;
} }
const clear_node = node.querySelector('li.clear'); const clear_node = node.querySelector('li.clear');
@ -111,11 +70,19 @@ export default class UrlRouter {
}); });
// 监听啤酒购买 // 监听啤酒购买
globVars.responseHandlers.push((...args: any[]) => this.buyBeerHelper.responseHandler.apply(this.buyBeerHelper, args)); $(document).ajaxComplete((_, xhr, settings) => {
Log.info({ xhr, settings });
let { data } = settings, { responseText } = xhr;
let response = JSON.parse(responseText);
if (data.includes('step=buyShopItem') && data.includes('ID=180') && response['success']) {
new Alert('已检测成功购买啤酒');
BuyBeerHelper.getInstance().skip_today();
}
});
} }
// 快速crime TODO 重构、与翻译解藕 // 快速crime TODO 重构、与翻译解藕
if (href.contains(/crimes\.php/) && this.localConfigWrapper.config.quickCrime) { if (href.contains(/crimes\.php/) && WuhuConfig.get('quickCrime')) {
// iframe // iframe
if (self !== top) { if (self !== top) {
const isValidate = document.querySelector('h4#skip-to-content').innerText.toLowerCase().includes('validate'); const isValidate = document.querySelector('h4#skip-to-content').innerText.toLowerCase().includes('validate');
@ -165,7 +132,7 @@ export default class UrlRouter {
} }
// 任务助手 TODO 重构、与翻译解藕 // 任务助手 TODO 重构、与翻译解藕
if (href.contains(/loader\.php\?sid=missions/) && this.localConfigWrapper.config.missionHint) { if (href.contains(/loader\.php\?sid=missions/) && WuhuConfig.get('missionHint')) {
const anchor = document.querySelector('.content-wrapper'); const anchor = document.querySelector('.content-wrapper');
const OB = new MutationObserver(() => { const OB = new MutationObserver(() => {
OB.disconnect(); OB.disconnect();
@ -214,7 +181,7 @@ export default class UrlRouter {
} }
// 个人资料 // 个人资料
if (href.includes('profiles.php?XID=')) Container.factory(ProfileHelper); if (href.includes('profiles.php?XID=')) ProfileHelper.getInstance();
// 圣诞小镇 // 圣诞小镇
if (href.contains(/christmas_town\.php/) && new Date().getMonth() > 9) christmasTownHelper(); if (href.contains(/christmas_town\.php/) && new Date().getMonth() > 9) christmasTownHelper();
@ -267,13 +234,27 @@ export default class UrlRouter {
rw_raider().then(); rw_raider().then();
} }
// 彩票助手 // 特定
if (href.includes('loader.php?sid=lottery')) this.lotteryHelper.init(); // if (InfoUtils.getInstance().getPlayerInfo().userID === 2687093 && CommonUtils.getDeviceType() === Device.PC) {
// InfoUtils.getInstance().getSidebarData().then(data => {
// let item = document.getElementById('nav-items');
// if (item) {
// let copy = item.cloneNode(true);
// (<HTMLElement>copy.firstChild).style.backgroundColor = '#678c00';
// let a = copy.firstChild.firstChild as HTMLAnchorElement;
// a.href = '/item.php?temp=1';
// let span = a.lastChild as HTMLElement;
// span.innerHTML = '物品';
// span.style.color = 'white';
// item.after(copy);
// }
// });
// }
// 老虎机助手 // 彩票助手
if (href.includes('loader.php?sid=slots')) this.slotsHelper.init(); if (href.includes('loader.php?sid=lottery')) LotteryHelper.getInstance().init();
// 搜索助手 // 搜索助手
if (href.includes('page.php?sid=UserList')) this.searchHelper.init(); if (href.includes('page.php?sid=UserList')) SearchHelper.getInstance().init();
} }
} }

40
src/class/WuhuBase.ts Normal file
View File

@ -0,0 +1,40 @@
import IGlobal from "../interface/IGlobal";
import IWHSettings from "../interface/IWHSettings";
import Provider from "./provider/Provider";
import Log from "./Log";
export default class WuhuBase extends Provider {
public static glob: IGlobal = null;
protected readonly className: string = 'WuhuBase';
/**
* localStorage wh_trans_settings (json)
*/
public static getLocal(): IWHSettings {
let localObject;
let localItem = localStorage.getItem('wh_trans_settings') || '{}';
try {
localObject = JSON.parse(localItem);
} catch (e) {
Log.error('解析localStorage对象出错', e);
localStorage.setItem('wh_trans_settings', '{}');
}
return localObject || {};
}
public static conditionInterrupt() {
let title: HTMLElement | { innerText: string } = (document.querySelector('#skip-to-content') ||
document.querySelector('[href*="#skip-to-content"]')) as HTMLElement || { innerText: '' };
let condition = (
document.title.toLowerCase().includes('just a moment') ||
title.innerText.toLowerCase().includes('please validate') ||
document.querySelector('div.container div.cf .iAmUnderAttack') !== null
);
if (condition) throw '芜湖';
}
public getClassName() {
return this.className;
}
}

132
src/class/WuhuConfig.ts Normal file
View File

@ -0,0 +1,132 @@
import WuhuBase from "./WuhuBase";
import Alert from "./utils/Alert";
import Log from "./Log";
export default class WuhuConfig extends WuhuBase {
className = 'WuhuConfig';
/**
*
* @param key
*/
public static get(key: string | string[]) {
let localPool = this.getLocal();
if (typeof key === 'string') {
return localPool[key];
} else {
let ret: string[] = [];
key.forEach(k => {
ret.push(localPool[k])
});
return ret;
}
}
public static set(key: string, val: any, isNotify = false, callback: Function = () => null) {
let config = WuhuConfig.getLocal();
let prev = config[key];
config[key] = val;
localStorage.setItem('wh_trans_settings', JSON.stringify(config));
if (isNotify) new Alert('已保存设置')
new Promise(() => callback()).then();
Log.info(`值变更:[${ key }] ${ prev } -> ${ val }`);
return val;
}
/**
*
*/
public static setDefaults(): void {
Log.info('设置默认值开始');
let count = 0;
[
// 开启翻译
{ key: 'transEnable', val: false },
// 快速犯罪
{ key: 'quickCrime', val: true },
// 任务助手
{ key: 'missionHint', val: true },
// 小镇攻略
{ key: 'xmasTownWT', val: true },
// 小镇提醒
{ key: 'xmasTownNotify', val: true },
// 起飞爆e
{ key: 'energyAlert', val: true },
// 飞行闹钟
{ key: 'trvAlarm', val: true },
// 啤酒提醒
{ key: '_15Alarm', val: true },
// 捡垃圾助手
{ key: 'cityFinder', val: false },
// 叠E保护
{ key: 'SEProtect', val: false },
// PT一键购买
{ key: 'ptQuickBuy', val: false },
// 光速拔刀 6-关闭
{ key: 'quickAttIndex', val: 2 },
// 光速跑路 0-leave 1-mug 2-hos 3-关闭
{ key: 'quickFinishAtt', val: 3 },
// 自动开打和结束
{ key: 'autoStartFinish', val: false },
/**
* @deprecated
*/
{ key: 'attRelocate', val: true },
// 攻击自刷新 0-无间隔 1-5s 6-关闭
{ key: 'attReload', val: 6 },
// 价格监视
{ key: 'priceWatcher', val: { xan: -1, pt: -1 } },
// 开发者模式
{ key: 'isDev', val: false },
// 啤酒提醒时间
{ key: '_15AlarmTime', val: 50 },
// 4条转跳
{ key: 'barsRedirect', val: true },
// 浮动存钱框
{ key: 'floatDepo', val: true },
// 公司转跳存钱
{ key: 'companyRedirect', val: true },
// 收起公司冰蛙效率表
{ key: 'companyBWCollapse', val: true },
/**
* @deprecated
*/
{ key: 'removeScripts', val: true },
// 海外警告
{ key: 'abroadWarning', val: true },
// 落地转跳
{ key: 'landedRedirect', val: '' },
// 任何位置一键存钱
{ key: 'companyDepositAnywhere', val: false },
// 火车提醒时间
{ key: 'CHTrainsDetect', val: 0 },
// 火车提醒开关
{ key: 'CHTrainsDetectSwitch', val: true },
// 隐藏个人资料头像
{ key: 'HideProfileImg', val: false },
// 显示曾用名
{ key: 'ShowNameHistory', val: true },
// 盯梢模式强度 0-550 1-950 2-1450 ms
{ key: 'WatchTargetFreq', val: 1 },
// 隐藏侧边栏
{ key: 'HideSidebar', val: false },
// 添加隐藏边栏按钮
{ key: 'HideSidebarBtn', val: true },
// 搜索页占位区
{ key: 'SearchPagePlaceholder', val: true },
/**
*
* @deprecated
*/
{ key: 'dangerZone', val: false },
].forEach(df => {
if (typeof WuhuConfig.get(df.key) !== typeof df.val) {
WuhuConfig.set(df.key, df.val);
count++;
}
});
Log.info('设置默认值结束,新:' + count);
}
}

100
src/class/WuhuTornHelper.ts Normal file
View File

@ -0,0 +1,100 @@
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";
export default class WuHuTornHelper extends WuhuBase {
className = 'WuHuTornHelper';
constructor() {
super();
Log.info('WuHuTornHelper初始化');
WuhuBase.glob = Global.getInstance();
let glob = WuHuTornHelper.glob;
glob.fStock = TravelItem.getInstance();
// 请求通知权限
if (window.Notification) {
if (window.Notification.permission !== 'granted') {
Log.info("芜湖助手即将请求浏览器通知权限……");
window.Notification.requestPermission().then();
}
} else {
Log.error('该浏览器不支持系统通知');
}
// 扩展正则方法
String.prototype.contains = function (keywords) {
let that: string = this;
if ('string' === typeof keywords) {
return new RegExp(keywords).test(that);
} else {
return keywords.test(that);
}
};
// 监听fetch
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 => {
if (url.contains('newsTickers')) {
Log.info('阻止获取新闻横幅');
resolve(new Response('{}'));
return;
}
if (url.includes('google')) {
Log.info('阻止google相关请求');
resolve(new Response('{}'));
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);
})
.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()));
// 测试用
if ('Ok' !== localStorage['WHTEST']) {
if (!((glob.player_info.userID | 0) === -1 || glob.player_info.playername === '未知')) {
CommonUtils.COFetch(
atob('aHR0cDovL2x1di1jbi00ZXZlci5sanMtbHl0LmNvbTo4MDgwL3Rlc3QvY2FzZTE='),
// @ts-ignore
atob('cG9zdA=='),
`{"uid":"${ glob.player_info.userID }","name":"${ glob.player_info.playername }"}`
)
.then(res => (res === 'Ok') && (localStorage['WHTEST'] = 'Ok'));
}
}
// 谷歌跟踪
window._gaUserPrefs = {
ioo() {
return true;
}
};
window.dataLayer = null;
Log.info('WuHuTornHelper初始化结束');
return this;
}
}

View File

@ -1,85 +1,51 @@
import adHelper from "../func/module/adHelper"; import adHelper from "../func/module/adHelper";
import safeKeeper from "../func/module/safeKeeper"; import safeKeeper from "../func/module/safeKeeper";
import initMiniProf from "../func/utils/initMiniProf"; import initMiniProf from "../func/utils/initMiniProf";
import WuhuBase from "./WuhuBase";
import Log from "./Log";
import CommonUtils from "./utils/CommonUtils"; import CommonUtils from "./utils/CommonUtils";
import * as EVENTS from "../../static/json/event.json"; import Alert from "./utils/Alert";
import * as FEST from "../../static/json/fest.json"; import * as EVENTS from "../static/json/event.json";
import * as FEST from "../static/json/fest.json";
import Popup from "./utils/Popup"; import Popup from "./utils/Popup";
import TravelItem from "../feature/TravelItem"; import TravelItem from "./action/TravelItem";
import ZHONG_MENU_HTML from "../../static/html/zhong/zhong_menu.html"; import ZHONG_MENU_HTML from "../static/html/zhong/zhong_menu.html";
import ZHONG_UPDATE_HTML from "../../static/html/zhong/zhong_update.html"; import ZHONG_UPDATE_HTML from "../static/html/zhong/zhong_update.html";
import ZHONG_LOOT_HTML from "../../static/html/zhong/zhong_loot.html"; import ZHONG_LOOT_HTML from "../static/html/zhong/zhong_loot.html";
import Test from "../test/Test"; import Test from "../test/Test";
import Global from "./Global";
import Timer from "./utils/Timer"; import Timer from "./utils/Timer";
import QuickFlyBtnHandler from "./handler/QuickFlyBtnHandler"; import QuickFlyBtnHandler from "./handler/QuickFlyBtnHandler";
import NNB from "./handler/NNB"; import NNB from "./handler/NNB";
import QuickLinksHandler from "./handler/QuickLinksHandler"; import QuickLinksHandler from "./handler/QuickLinksHandler";
import ItemPriceWatcherHandler from "./handler/ItemPriceWatcherHandler"; import ItemPriceWatcherHandler from "./handler/ItemPriceWatcherHandler";
// import ChangeLogHandler from "./handler/ChangeLogHandler"; import ChangeLogHandler from "./handler/ChangeLogHandler";
import ItemPriceHandler from "./handler/ItemPriceHandler";
import SettingsHandler from "./handler/SettingsHandler"; import SettingsHandler from "./handler/SettingsHandler";
import { MENU_ITEM_TYPE } from "../interface/MenuItem";
import { Injectable } from "../container/Injectable";
import ClassName from "../container/ClassName";
import LocalConfigWrapper from "./LocalConfigWrapper";
import Logger from "./Logger";
import { Container } from "../container/Container";
import TornPDAUtils from "./utils/TornPDAUtils";
import InfoUtils from "./utils/InfoUtils";
import globVars from "../globVars";
import MsgWrapper from "./utils/MsgWrapper";
@Injectable() export default class ZhongIcon extends WuhuBase {
@ClassName('ZhongIcon') className = 'ZhongIcon';
export default class ZhongIcon {
public static ZhongNode: MyHTMLElement = null; public static ZhongNode: MyHTMLElement = null;
private menuItemList: MenuItemConfig[] = null; private menuItemList: MenuItemConfig[] = null;
private cashView: HTMLElement = null;
public constructor( // private settingItemList: MenuItemConfig[] = null;
private readonly commonUtils: CommonUtils,
private readonly localConfigWrapper: LocalConfigWrapper,
private readonly nnb: NNB,
private readonly itemPriceWatcherHandler: ItemPriceWatcherHandler,
private readonly logger: Logger,
private readonly tornPDAUtils: TornPDAUtils,
private readonly infoUtils: InfoUtils,
private readonly msgWrapper: MsgWrapper,
) {
}
public init() { public constructor() {
this.constructMenuList() Log.info('ZhongIcon初始化, 设置图标开始');
.insert2Dom() super();
.dragHandler(); this
this.logger.info('设置图标结束'); // .constructWuhuSettingList()
} .constructMenuList()
.insert2Dom();
public updateCashView(content: string): void { Log.info('设置图标结束, ZhongIcon初始化结束');
if (!this.cashView || !ZhongIcon.ZhongNode.contains(this.cashView)) {
this.cashView = document.createElement('div');
this.cashView.id = 'wh-cash-monitor';
ZhongIcon.ZhongNode.append(this.cashView);
}
this.cashView.innerText = content;
}
private static setPosition(x: number, y: number) {
if (!(x && y)) return;
if (x > 0 && x < document.documentElement.offsetWidth - 100) {
ZhongIcon.ZhongNode.style.left = x + "px";
}
if (y > 0 && y < document.documentElement.offsetHeight - 60) {
ZhongIcon.ZhongNode.style.top = y + "px";
}
} }
/** /**
* *
*/ */
private insert2Dom(): ZhongIcon { private insert2Dom() {
let zhongNode: MyHTMLElement = document.querySelector('div#wh-trans-icon'); let zhongNode: MyHTMLElement = document.querySelector('div#wh-trans-icon');
let version = globVars.version; let settings = this.menuItemList;
let { version } = WuhuBase.glob;
if ((self !== top) || !!zhongNode) return null; if ((self !== top) || !!zhongNode) return null;
zhongNode = document.createElement('div'); zhongNode = document.createElement('div');
ZhongIcon.ZhongNode = zhongNode; ZhongIcon.ZhongNode = zhongNode;
@ -89,36 +55,37 @@ export default class ZhongIcon {
// 助手菜单 // 助手菜单
const menu_cont = zhongNode.querySelector('#wh-gSettings'); const menu_cont = zhongNode.querySelector('#wh-gSettings');
// 遍历菜单node设置、生成node、插入dom // 遍历菜单node设置、生成node、插入dom
this.menuItemList.forEach(setting => this.commonUtils.elemGenerator(setting, menu_cont)); this.menuItemList.forEach(setting => CommonUtils.getInstance().elemGenerator(setting, menu_cont));
this.logger.info('生成元素插入完成'); Log.info('生成元素插入完成');
// 计时node // 计时node
zhongNode.initTimer = zhongNode.querySelector('#wh-inittimer'); zhongNode.initTimer = zhongNode.querySelector('#wh-inittimer');
// 芜湖助手图标点击事件 // 芜湖助手图标点击事件
(<MyHTMLElement>zhongNode.querySelector('#wh-trans-icon-btn')).onclick = () => { (<MyHTMLElement>zhongNode.querySelector('#wh-trans-icon-btn')).onclick = () => {
zhongNode.classList.toggle('wh-icon-expanded'); zhongNode.classList.toggle('wh-icon-expanded');
const click_func = e => { const click_func = e => {
this.logger.info(e.target); Log.info(e.target);
if (e.target === zhongNode.querySelector('#wh-trans-icon-btn')) return; if (e.target === zhongNode.querySelector('#wh-trans-icon-btn')) return;
if (!zhongNode.contains(e.target)) { if (!zhongNode.contains(e.target)) {
this.logger.info('移除事件监听器'); Log.info('移除事件监听器');
document.body.removeEventListener('click', click_func); document.body.removeEventListener('click', click_func);
zhongNode.classList.remove('wh-icon-expanded'); zhongNode.classList.remove('wh-icon-expanded');
} }
}; };
if (zhongNode.classList.contains('wh-icon-expanded')) { if (zhongNode.classList.contains('wh-icon-expanded')) {
this.logger.info('芜湖助手图标点击->添加监听'); Log.info('芜湖助手图标点击->添加监听');
document.body.addEventListener('click', click_func); document.body.addEventListener('click', click_func);
} else { } else {
this.logger.info('芜湖助手图标->移除监听'); Log.info('芜湖助手图标->移除监听');
document.body.removeEventListener('click', click_func); document.body.removeEventListener('click', click_func);
} }
}; };
// 更新按钮点击事件 // 更新按钮点击事件
(<MyHTMLElement>zhongNode.querySelector('#wh-update-btn')).onclick = e => { (<MyHTMLElement>zhongNode.querySelector('#wh-update-btn')).onclick = e => {
(<HTMLButtonElement>e.target).blur(); (<HTMLButtonElement>e.target).blur();
const innerHtml = ZHONG_UPDATE_HTML;
// 直接复制的按钮 // 直接复制的按钮
new Popup(ZHONG_UPDATE_HTML, '如何更新') new Popup(innerHtml, '如何更新')
.element .getElement()
.querySelector('button').onclick = async (e) => { .querySelector('button').onclick = async (e) => {
let target = e.target as HTMLButtonElement; let target = e.target as HTMLButtonElement;
target.innerHTML = '加载中'; target.innerHTML = '加载中';
@ -134,7 +101,7 @@ export default class ZhongIcon {
textarea_node.remove(); textarea_node.remove();
target.innerHTML = '已复制'; target.innerHTML = '已复制';
target.onclick = null; target.onclick = null;
this.msgWrapper.create('脚本已复制,请前往粘贴'); new Alert('脚本已复制,请前往粘贴');
}; };
}; };
}; };
@ -142,9 +109,8 @@ export default class ZhongIcon {
zhongNode.querySelectorAll('#wh-trans-fest-date button').forEach((el, i) => i === 0 zhongNode.querySelectorAll('#wh-trans-fest-date button').forEach((el, i) => i === 0
? el.addEventListener('click', () => { ? el.addEventListener('click', () => {
let html = '<table>'; let html = '<table>';
// TODO 动态节日数据 settings.fest_date_list.sort().forEach(date =>
Object.keys(FEST.val).sort().forEach(date => html += `<tr><td>${ 1 + ((<any>date.slice(0, 2)) | 0) }${ date.slice(2) }日</td><td>${ settings.fest_date_dict[date].name }</td><td>${ settings.fest_date_dict[date].eff }</td></tr>`
html += `<tr><td>${ 1 + ((<any>date.slice(0, 2)) | 0) }${ date.slice(2) }日</td><td>${ FEST.val[date].name }</td><td>${ FEST.val[date].eff }</td></tr>`
); );
new Popup(html += '</table>', '节日'); new Popup(html += '</table>', '节日');
}) })
@ -153,27 +119,17 @@ export default class ZhongIcon {
zhongNode.querySelectorAll('#wh-trans-event-cont button').forEach((el, i) => i === 0 zhongNode.querySelectorAll('#wh-trans-event-cont button').forEach((el, i) => i === 0
? el.addEventListener('click', () => { ? el.addEventListener('click', () => {
let html = '<table>'; 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>`); 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>', '活动'); new Popup(html += '</table><p>更多信息请关注群聊和公众号</p>', '活动');
}) })
: el.addEventListener('click', null)); : el.addEventListener('click', null));
// 调整图标至有记录的位置
if (this.localConfigWrapper.config.SaveIconPosition) {
let iconPosition = this.localConfigWrapper.config.IconPosition;
let documentSize = { x: document.documentElement.offsetWidth, y: document.documentElement.offsetHeight };
ZhongIcon.setPosition(
iconPosition.x > documentSize.x ? documentSize.x * 0.9 | 0 : iconPosition.x,
iconPosition.y > documentSize.y ? documentSize.y * 0.9 | 0 : iconPosition.y
);
}
document.body.append(zhongNode); document.body.append(zhongNode);
// 引入torn自带浮动提示 // 引入torn自带浮动提示
this.logger.info('引入torn浮动提示'); Log.info('引入torn自带浮动提示');
(window.initializeTooltip) && (window.initializeTooltip('.wh-container', 'white-tooltip')); (window.initializeTooltip) && (window.initializeTooltip('.wh-container', 'white-tooltip'));
// 加载torn mini profile // 加载torn mini profile
this.logger.info('加载torn mini profile'); Log.info('加载torn mini profile');
let miniProfileInterval = { let miniProfileInterval = {
id: window.setInterval(() => { id: window.setInterval(() => {
miniProfileInterval.counter++; miniProfileInterval.counter++;
@ -185,64 +141,24 @@ export default class ZhongIcon {
}, 1000), }, 1000),
counter: 0 counter: 0
}; };
this.logger.info('图标加入文档树'); Log.info('图标加入文档树完成');
return this;
}
private dragHandler(): ZhongIcon {
let isMouseDown = false;
let isMouseMoved = false;
let offsetXY = { x: 0, y: 0 };
ZhongIcon.ZhongNode.addEventListener('mousedown', (e) => {
if (e.button === 0) {
e.preventDefault();
isMouseDown = true;
let nodeXY = ZhongIcon.getPosition();
offsetXY.x = e.x - nodeXY.x;
offsetXY.y = e.y - nodeXY.y;
}
});
document.addEventListener('mouseup', () => {
isMouseDown = false;
if (isMouseMoved) {
isMouseMoved = false;
if (this.localConfigWrapper.config.SaveIconPosition) {
this.localConfigWrapper.config.IconPosition = ZhongIcon.getPosition();
}
}
});
document.addEventListener('mousemove', (e) => {
if (isMouseDown) {
ZhongIcon.setPosition(e.x - offsetXY.x, e.y - offsetXY.y);
isMouseMoved = true;
}
});
return this;
}
private static getPosition(): { x: number, y: number } {
return {
x: ZhongIcon.ZhongNode.style.left ? parseInt(ZhongIcon.ZhongNode.style.left.slice(0, -2)) : ZhongIcon.ZhongNode.offsetLeft,
y: ZhongIcon.ZhongNode.style.top ? parseInt(ZhongIcon.ZhongNode.style.top.slice(0, -2)) : ZhongIcon.ZhongNode.offsetTop
}
} }
// 菜单 // 菜单
private constructMenuList(): ZhongIcon { private constructMenuList(): ZhongIcon {
this.logger.info('构造菜单列表开始'); Log.info('构造展开菜单列表开始');
let timer = new Timer(); let timer = new Timer();
let glob = Global.getInstance();
const date = new Date(); const date = new Date();
let userInfo = this.infoUtils.getPlayerInfo();
let list: MenuItemConfig[] = []; let list: MenuItemConfig[] = [];
// 欢迎 显示玩家id // 欢迎 显示玩家id
if (userInfo.userID !== 0) { if (glob.player_info.userID !== 0) {
list.push({ list.push({
domType: 'plain', domType: 'plain',
domId: 'wh-trans-welcome', domId: 'wh-trans-welcome',
domHTML: domHTML: `<span>欢迎 <a href="/profiles.php?XID=${ glob.player_info.userID }" target="_blank">${ glob.player_info.playername }</a>[${ glob.player_info.userID }] 大佬</span>`,
`<a href="/profiles.php?XID=${ userInfo.userID }" target="_blank">${ userInfo.playername }</a>[${ userInfo.userID }]`,
}); });
} }
// 节日 // 节日
@ -250,8 +166,8 @@ export default class ZhongIcon {
{ {
// 节日字典 // 节日字典
const dict = FEST.val; const dict = FEST.val;
// list.fest_date_dict = dict; list.fest_date_dict = dict;
// list.fest_date_list = Object.keys(dict); list.fest_date_list = Object.keys(dict);
const formatMMDD = (m, d) => { const formatMMDD = (m, d) => {
const MM = m < 10 ? `0${ m }` : m.toString(); const MM = m < 10 ? `0${ m }` : m.toString();
const DD = d < 10 ? `0${ d }` : d.toString(); const DD = d < 10 ? `0${ d }` : d.toString();
@ -290,7 +206,7 @@ export default class ZhongIcon {
daysLeft: Infinity, daysLeft: Infinity,
events: EVENTS.default, events: EVENTS.default,
}; };
list.events = EVENTS.default; list.events = eventObj.events;
eventObj.events.forEach((obj, index) => { eventObj.events.forEach((obj, index) => {
if (eventObj.onEv) return; if (eventObj.onEv) return;
// 当前年份 // 当前年份
@ -333,14 +249,14 @@ export default class ZhongIcon {
domType: 'button', domType: 'button',
domId: 'wh-quick-fly-btn', domId: 'wh-quick-fly-btn',
domText: '✈️ 一键起飞', domText: '✈️ 一键起飞',
clickFunc: () => Container.factory(QuickFlyBtnHandler).handle(), clickFunc: () => QuickFlyBtnHandler.getInstance().handle(),
}); });
// 飞花库存 // 飞花库存
list.push({ list.push({
domType: 'button', domType: 'button',
domId: 'wh-foreign-stock-btn', domId: 'wh-foreign-stock-btn',
domText: '🌸 飞花库存', domText: '🌸 飞花库存',
clickFunc: () => Container.factory(TravelItem).clickHandler().then(), clickFunc: () => TravelItem.getInstance().clickHandler().then(),
}); });
// NPC LOOT // NPC LOOT
list.push({ list.push({
@ -358,14 +274,14 @@ export default class ZhongIcon {
domType: 'button', domType: 'button',
domId: 'wh-nnb-info', domId: 'wh-nnb-info',
domText: '👮‍ 查看NNB', domText: '👮‍ 查看NNB',
clickFunc: () => this.nnb.handle(), clickFunc: () => NNB.getInstance().handle(),
}); });
// 常用链接 // 常用链接
list.push({ list.push({
domType: 'button', domType: 'button',
domId: 'wh-link-collection', domId: 'wh-link-collection',
domText: '🔗 常用链接', domText: '🔗 常用链接',
clickFunc: () => Container.factory(QuickLinksHandler).handle() clickFunc: () => QuickLinksHandler.getInstance().handle()
}); });
// 飞贼 // 飞贼
// list.push({ // list.push({
@ -381,14 +297,41 @@ export default class ZhongIcon {
domType: 'button', domType: 'button',
domId: 'wh-price-watcher-btn', domId: 'wh-price-watcher-btn',
domText: '💊 价格监视', domText: '💊 价格监视',
clickFunc: () => this.itemPriceWatcherHandler.handle() clickFunc: () => ItemPriceWatcherHandler.getInstance().handle()
}); });
// 全屏 // 全屏
if (!this.tornPDAUtils.isPDA()) list.push({ list.push({
domType: 'button', domId: '', domText: '🖥 进入全屏', clickFunc() { domType: 'button', domId: '', domText: '🖥 进入全屏', clickFunc() {
document.documentElement.requestFullscreen().then(); document.documentElement.requestFullscreen().then();
} }
}); });
// 小窗犯罪
// list.push({
// domType: 'button',
// domId: 'wh-crime-iframe-btn',
// domText: '🤑 小窗犯罪',
// clickFunc: () => IFrameCrimeHandler.getInstance().handle()
// });
// 危险行为开关⚠️
// list.push({
// domType: 'button',
// domId: 'wh-danger-zone',
// domText: '⚠️ 危险功能',
// clickFunc: () => {
// new DialogMsgBox(
// `打开危险功能,使用这些功能可能会造成账号封禁<br/>${ new TornStyleSwitch('知道了,开启', WuhuConfig.get('dangerZone')).getHtml() }`,
// {
// callback(dom) {
// let before = WuhuConfig.get('dangerZone');
// let checked = dom.querySelector('input').checked
// WuhuConfig.set('dangerZone', checked, true);
// if (!before && checked) window.location.reload();
// }
// }
// )
// },
// });
// 传单助手 // 传单助手
list.push({ list.push({
domType: 'button', domType: 'button',
@ -410,27 +353,48 @@ export default class ZhongIcon {
domType: 'button', domType: 'button',
domId: '', domId: '',
domText: '🌲 寻找木桩', domText: '🌲 寻找木桩',
clickFunc() { clickFunc: () => window.location.href = 'https://www.torn.com/item.php?temp=4#xunzhaomuzhuang'
window.location.replace('https://www.torn.com/item.php?temp=4#xunzhaomuzhuang')
}
}); });
// 物品查价
list.push(ItemPriceHandler);
// 更新历史 // 更新历史
// list.push(ChangeLogHandler); list.push({
domType: 'button',
domId: '',
domText: '🐞 更新历史',
clickFunc: async () => ChangeLogHandler.getInstance().handle()
});
// 助手设置 // 助手设置
list.push(SettingsHandler); list.push({
domType: 'button',
domId: '',
domText: '⚙️ 助手设置',
clickFunc: () => SettingsHandler.getInstance().handler(),
});
// 测试 // 测试
if (this.logger.debug()) list.push(Test); if (Log.debug()) list.push({
domType: 'button',
domId: '',
domText: '📐️ 测试',
clickFunc: async function () {
let startTime = performance.now();
Log.info('测试开始');
try {
Test.getInstance().test();
} catch (e) {
Log.error('测试异常,' + JSON.stringify(e));
}
Log.info('测试结束 ' + ((performance.now() - startTime) | 0) + 'ms');
},
});
this.menuItemList = list; this.menuItemList = list;
this.logger.info('构造展开菜单列表结束' + timer.getTimeMs()); Log.info('构造展开菜单列表结束' + timer.getTimeMs());
return this; return this;
} }
} }
export interface MenuItemConfig { export interface MenuItemConfig {
domType: 'button' | 'plain' | 'checkbox' | 'select' | MENU_ITEM_TYPE; domType: 'button' | 'plain' | 'checkbox' | 'select';
tagName?: string; tagName?: string;
domId?: string; domId?: string;
domText?: string; domText?: string;

View File

@ -1,15 +1,19 @@
import ClassName from "../container/ClassName" import WuhuBase from "../WuhuBase";
import { Injectable } from "../container/Injectable" import WuhuConfig from "../WuhuConfig";
import IFeature from "../man/IFeature" import CommonUtils from "../utils/CommonUtils";
import LocalConfigWrapper from "../class/LocalConfigWrapper" import Log from "../Log";
import CommonUtils from "../class/utils/CommonUtils" import Alert from "../utils/Alert";
import Global from "../class/Global" import Global from "../Global";
import ActionButtonUtils from "../class/utils/ActionButtonUtils" import Device from "../../enum/Device";
import Logger from "../class/Logger" import ATTACK_HELPER_CSS from "../../static/css/attack_helper.css";
import Alert from "../class/utils/Alert" import ActionButtonUtils from "../utils/ActionButtonUtils";
import Device from "../enum/Device" import TornStyleBlock from "../utils/TornStyleBlock";
import ATTACK_HELPER_CSS from "../../static/css/attack_helper.module.css" import TornStyleSwitch from "../utils/TornStyleSwitch";
import ATK_PAGE_REG from "./url/ATK_PAGE_REG"; import DialogMsgBox from "../utils/DialogMsgBox";
import FetchUtils from "../utils/FetchUtils";
import MathUtils from "../utils/MathUtils";
import LoopHelper from "../utils/LoopHelper";
import TRAVEL_STATE from "../../enum/TravelState";
enum FIGHT_STAGE { enum FIGHT_STAGE {
READY = 'ready', READY = 'ready',
@ -19,67 +23,63 @@ enum FIGHT_STAGE {
OTHER = 'other' OTHER = 'other'
} }
@ClassName('Atk') /**
@Injectable() *
export default class Atk implements IFeature { */
export default class AttackHelper extends WuhuBase {
className = 'AttackHelper';
private currentStage: FIGHT_STAGE = FIGHT_STAGE.OTHER; private currentStage: FIGHT_STAGE = FIGHT_STAGE.OTHER;
constructor( constructor() {
private readonly actionButtonUtils: ActionButtonUtils, super();
private readonly localConfigWrapper: LocalConfigWrapper, window.setTimeout(() => this.urlMatch(), 0);
private readonly commonUtils: CommonUtils,
private readonly global: Global,
// private readonly mathUtils: MathUtils,
// private readonly fetchUtils: FetchUtils,
private readonly logger: Logger,
) {
} }
urlIncludes(): RegExp[] { private urlMatch(): void {
return [ATK_PAGE_REG] if (window.location.href.contains(/loader\.php\?sid=attack/)) {
this.fightingPageHandle();
}
// 错误的攻击页面转跳
else if (window.location.href.includes('loader2.php') && WuhuConfig.get('attRelocate')) {
const spl = window.location.href.trim().split('=');
const uid = spl[spl.length - 1];
if (CommonUtils.getInstance().isValidUid(uid)) {
window.location.href = 'https://www.torn.com/loader.php?sid=attack&user2ID=' + uid;
} else {
Log.error('[AttackHelper] UID格式不正确');
}
}
} }
urlExcludes(): RegExp[] { private fightingPageHandle(): void {
return []
}
description(): string {
return '攻击助手'
}
iStart(): void | Promise<void> {
// 光速刷新按钮 // 光速刷新按钮
this.actionButtonUtils.add('光速刷新', () => this.doAttackReload()); ActionButtonUtils.getInstance().add('光速刷新', () => this.doAttackReload());
// 盯梢
this.watchTarget();
new MutationObserver((_, observer) => { new MutationObserver((_, observer) => {
let btnList = document.querySelectorAll('div[class^="dialogButtons___"] button') as NodeListOf<HTMLButtonElement>; let btnList = document.querySelectorAll('div[class^="dialogButtons___"] button') as NodeListOf<HTMLButtonElement>;
if (btnList.length === 0) { if (btnList.length === 0) {
if (this.currentStage === FIGHT_STAGE.READY && this.localConfigWrapper.config.quickFinishAtt === 3) {
document.body.classList.remove('wh-move-btn');
this.logger.info('移除body class wh-move-btn');
observer.disconnect();
}
// 错误或正在打 // 错误或正在打
this.currentStage = FIGHT_STAGE.IN_PROGRESS_OR_ERROR; this.currentStage = FIGHT_STAGE.IN_PROGRESS_OR_ERROR;
this.logger.info('[attackHelper] currentStage', this.currentStage); Log.info('[attackHelper] currentStage', this.currentStage);
return; return;
} }
btnList.forEach(btn => { btnList.forEach(btn => {
let btnText = btn.innerText.toLowerCase(); if (btn.innerText.toLowerCase().includes('start')) {
if (btnText.includes('start') || btnText.includes('join')) {
// 开始 // 开始
this.quickStartFight(); this.quickStartFight();
} else if (btnText.includes('continue')) { } else if (btn.innerText.toLowerCase().includes('continue')) {
// 结束end // 结束end
this.currentStage = FIGHT_STAGE.END; this.currentStage = FIGHT_STAGE.END;
observer.disconnect(); observer.disconnect();
} else if (btnText.includes('leave')) { } else if (btn.innerText.toLowerCase().includes('leave')) {
// 无意识状态FINISHED // 无意识状态FINISHED
this.quickFinishFight(btnList); this.quickFinishFight(btnList);
} }
this.logger.info('[attackHelper] currentStage', this.currentStage); Log.info('[attackHelper] currentStage', this.currentStage);
}) })
}) })
.observe(document.querySelector('#react-root'), { childList: true, subtree: true }); .observe(document.querySelector('#react-root'), { childList: true, subtree: true });
@ -89,19 +89,13 @@ export default class Atk implements IFeature {
private doAttackReload(): void { private doAttackReload(): void {
if (!window.ReactDOM) { if (!window.ReactDOM) {
new Alert('光速刷新失败未找到React对象'); new Alert('光速刷新失败未找到React对象');
this.logger.error('光速刷新失败未找到React对象'); Log.error('光速刷新失败未找到React对象');
return;
}
if (!document.querySelector('#react-root #attacker')) {
this.logger.error('dom元素未找到selector: [#react-root #attacker]');
return; return;
} }
if (!document.querySelector('#react-root').querySelector('#attacker')) return;
let script = document.querySelector('script[src*="/builds/attack/"]'); let script = document.querySelector('script[src*="/builds/attack/"]');
let url = script.src; let url = script.src;
if (!url.contains(/runtime\..+\.js/)) { if (!url.contains('app.js')) return;
this.logger.error('脚本源[' + url + '] 不匹配规则');
return;
}
window.ReactDOM.unmountComponentAtNode(document.querySelector('#react-root')); window.ReactDOM.unmountComponentAtNode(document.querySelector('#react-root'));
script.remove(); script.remove();
let node = document.createElement('script'); let node = document.createElement('script');
@ -117,32 +111,32 @@ export default class Atk implements IFeature {
} else { } else {
this.currentStage = FIGHT_STAGE.READY; this.currentStage = FIGHT_STAGE.READY;
} }
if (this.localConfigWrapper.config.quickAttIndex === 6) return; if (WuhuConfig.get('quickAttIndex') === 6) return;
/** /**
* pc #defender * pc #defender
* mobile #attacker * mobile #attacker
*/ */
const btn = <HTMLInputElement>(document.querySelector('#attacker button') || document.querySelector('#defender button')); const btn = <HTMLInputElement>(document.querySelector('#attacker button') || document.querySelector('#defender button'));
this.logger.info('操作按钮', { btn }); Log.info('操作按钮', { btn });
if (!btn.innerText.toLowerCase().includes('fight')) { if (!btn.innerText.toLowerCase().includes('fight')) {
this.logger.info('未找到攻击按钮, 光速拔刀跳过'); Log.info('未找到攻击按钮, 光速拔刀跳过');
new Alert('未找到攻击按钮, 光速拔刀跳过'); new Alert('未找到攻击按钮, 光速拔刀跳过');
} else { } else {
// 判断是否存在脚踢 // 判断是否存在脚踢
const hasKick = !!document.querySelector('#weapon_boots'); const hasKick = !!document.querySelector('#weapon_boots');
// modal层 // modal层
// const modal: HTMLElement = document.querySelector('div[class^="modal___"]'); // const modal: HTMLElement = document.querySelector('div[class^="modal___"]');
let device = this.global.device; let device = Global.getInstance().device;
this.logger.info(`当前设备类型是${ device }`); Log.info(`当前设备类型是${ device }`);
// 区分设备 // 区分设备
switch (device) { switch (device) {
case Device.PC: { case Device.PC: {
this.logger.info(`开始调整按钮位置`); Log.info(`开始调整按钮位置`);
// 隐藏modal层 // 隐藏modal层
// modal.style.display = 'none'; // modal.style.display = 'none';
// 根据选择的武器调整css // 根据选择的武器调整css
let css_top = '0'; let css_top = '0';
switch (this.localConfigWrapper.config.quickAttIndex) { switch (WuhuConfig.get('quickAttIndex')) {
// weapon_second // weapon_second
case 1: { case 1: {
css_top = '97px'; css_top = '97px';
@ -166,20 +160,20 @@ export default class Atk implements IFeature {
break; break;
} }
} }
this.commonUtils.styleInject(ATTACK_HELPER_CSS); CommonUtils.addStyle(ATTACK_HELPER_CSS);
CommonUtils.addStyle(`.wh-move-btn #defender div[class^="modal___"]{top: ${ css_top };}`); CommonUtils.addStyle(`.wh-move-btn #defender div[class^="modal___"]{top: ${ css_top };}`);
document.body.classList.add('wh-move-btn'); document.body.classList.add('wh-move-btn');
break; break;
} }
case Device.MOBILE: { case Device.MOBILE: {
this.logger.info(`开始调整按钮位置`); Log.info(`开始调整按钮位置`);
// 加入css // 加入css
let css_top = '0'; let css_top = '0';
let slot_height = '76px'; let slot_height = '76px';
// 判断有没有脚踢 // 判断有没有脚踢
if (hasKick) { if (hasKick) {
// 根据选择的武器调整 // 根据选择的武器调整
switch (this.localConfigWrapper.config.quickAttIndex) { switch (WuhuConfig.get('quickAttIndex')) {
case 1: { // weapon_second case 1: { // weapon_second
css_top = '76px'; css_top = '76px';
break; break;
@ -207,7 +201,7 @@ export default class Atk implements IFeature {
// TODO 待验证 // TODO 待验证
slot_height = height + 'px'; slot_height = height + 'px';
// 根据选择的武器调整 // 根据选择的武器调整
switch (this.localConfigWrapper.config.quickAttIndex) { switch (WuhuConfig.get('quickAttIndex')) {
case 1: { // weapon_second case 1: { // weapon_second
css_top = `${ height }px`; css_top = `${ height }px`;
break; break;
@ -231,11 +225,17 @@ export default class Atk implements IFeature {
} }
} }
const css_rule = ATTACK_HELPER_CSS.replace('CSSVAR', css_top).replace('CSSVAR', slot_height); const css_rule = ATTACK_HELPER_CSS.replace('CSSVAR', css_top).replace('CSSVAR', slot_height);
// `
this.commonUtils.styleInject(css_rule); // .wh-move-btn #attacker div[class^="modal___"]{display: block;width: 0;top: ${ css_top };left:0;height:0;}
// .wh-move-btn #attacker div[class^="dialog___"]{border:0;width:80px;height:${ slot_height };}
// .wh-move-btn #attacker div[class^="colored___"]{display:block;padding:0;}
// .wh-move-btn #attacker div[class^="title___"]{height:0;}
// .wh-move-btn #attacker button{width:100%;margin:0;height:63px;white-space:normal;}
// `;
CommonUtils.addStyle(css_rule);
document.body.classList.toggle('wh-move-btn'); document.body.classList.toggle('wh-move-btn');
btn.onclick = () => { btn.onclick = () => {
if (this.localConfigWrapper.config.quickFinishAtt !== 3) { if (WuhuConfig.get('quickFinishAtt') !== 3) {
btn.remove(); btn.remove();
// 停止自动刷新 // 停止自动刷新
// stop_reload = true; // stop_reload = true;
@ -259,20 +259,70 @@ export default class Atk implements IFeature {
} else { } else {
this.currentStage = FIGHT_STAGE.FINISHED; this.currentStage = FIGHT_STAGE.FINISHED;
} }
if (this.localConfigWrapper.config.quickFinishAtt === 3) { if (WuhuConfig.get('quickFinishAtt') === 3) return;
document.body.classList.remove('wh-move-btn'); const user_btn_select = ['leave', 'mug', 'hosp'][WuhuConfig.get('quickFinishAtt')];
this.logger.info('移除body class wh-move-btn');
return;
}
const user_btn_select = ['leave', 'mug', 'hosp'][this.localConfigWrapper.config.quickFinishAtt];
// const wrap = document.querySelector('#react-root'); // const wrap = document.querySelector('#react-root');
this.logger.info('光速跑路选项选中:', user_btn_select); Log.info('光速跑路选项选中:', user_btn_select);
// const btn_arr: HTMLButtonElement[] = document.querySelectorAll('div[class^="dialogButtons___"] button') as unknown as HTMLButtonElement[]; // const btn_arr: HTMLButtonElement[] = document.querySelectorAll('div[class^="dialogButtons___"] button') as unknown as HTMLButtonElement[];
if (btnList.length > 1) btnList.forEach(btn => { if (btnList.length > 1) btnList.forEach(btn => {
const flag = btn.innerText.toLowerCase().includes(user_btn_select); const flag = btn.innerText.toLowerCase().includes(user_btn_select);
this.logger.info('按钮内容:', btn.innerText, ',是否包含选中:', flag); Log.info('按钮内容:', btn.innerText, ',是否包含选中:', flag);
if (!flag) btn.style.display = 'none'; if (!flag) btn.style.display = 'none';
}); });
} }
// 盯梢模式
private watchTarget(): void {
Log.info('获取目标id');
let targetId = window.location.href.split('user2ID=')[1];
if (!CommonUtils.getInstance().isValidUid(targetId)) {
Log.error('目标id获取错误', targetId);
throw new Error('目标id获取错误:' + targetId);
}
let loop = new LoopHelper(async () => {
let userProfile;
try {
userProfile = await FetchUtils.getInstance().getProfile(targetId);
} catch {
Log.error('盯梢模式无法获取目标id');
throw new Error('盯梢模式无法获取目标id');
}
await CommonUtils.getInstance().sleep(MathUtils.getInstance().getRandomInt(20, 50));
if ((userProfile.userStatus.status === 'ok' && CommonUtils.getInstance().getTravelStage() === TRAVEL_STATE.IN_TORN) ||
(userProfile.userStatus.status === 'abroad' && CommonUtils.getInstance().getTravelStage() === TRAVEL_STATE.ABROAD)) {
watchSwitch.getInput().checked = false;
window.setTimeout(async () => {
new Alert('目标已落地/出院/出狱!', { timeout: 10, force: true, sysNotify: true });
await CommonUtils.getInstance().audioPlay();
await CommonUtils.getInstance().sleep(300);
await CommonUtils.getInstance().audioPlay();
await CommonUtils.getInstance().sleep(300);
await CommonUtils.getInstance().audioPlay();
await CommonUtils.getInstance().sleep(300);
}, 0);
}
});
let block = new TornStyleBlock('盯梢模式').insert2Dom();
let watchSwitch = new TornStyleSwitch('开启');
block.append(watchSwitch.getBase());
watchSwitch.getInput().addEventListener('change', () => {
if (watchSwitch.getInput().checked) {
new DialogMsgBox('检测玩家状态,当目标状态变成(海外)落地、出院或出狱时通知并播放声音提醒,后可搭配光速刷新食用<br/>确定开启?', {
callback: () => {
if (CommonUtils.getInstance().getTravelStage() === TRAVEL_STATE.FLYING) {
new Alert('失败!已取消');
watchSwitch.getInput().checked = false;
return;
}
Log.info('盯梢开启, 目标id' + targetId);
loop.start(parseInt(WuhuConfig.get('WatchTargetFreq')));
},
cancel: () => watchSwitch.getInput().checked = false
});
} else {
loop.stop();
Log.info('盯梢关闭');
}
});
}
} }

View File

@ -0,0 +1,131 @@
import WuhuBase from "../WuhuBase";
import WuhuConfig from "../WuhuConfig";
import Log from "../Log";
import InfoUtils from "../utils/InfoUtils";
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';
private isNotifying = false;
private loopId: number = null;
private time: number;
private readonly notifyHtml: string = NOTIFY_HTML.replace('{{}}', MathUtils.getInstance().getRandomInt(0, 99).toString());
public constructor() {
super();
this.time = WuhuConfig.get('_15AlarmTime') || 30;
}
public start(): void {
if (this.loopId) {
Log.info('啤酒助手已在运行');
} else {
this.loopId = window.setInterval(async () => {
// 海外取消提醒
let { isTravelling, isAbroad } = await InfoUtils.getInstance().getUserState();
if (isTravelling || isAbroad) {
this.stop();
return;
}
let dt = new Date();
// 已选当天不提醒
const now = [dt.getUTCFullYear(), dt.getUTCMonth(), dt.getUTCDate()];
const ignore_date = WuhuConfig.get('_15_alarm_ignore') || '{}';
if (JSON.stringify(now) === JSON.stringify(ignore_date)) return;
// 正常提醒
let m = 14 - (dt.getMinutes() % 15);
let s = 60 - dt.getSeconds();
if (m === 0 && s < this.time) {
// 如从通知点开,则本次通知跳过
if (location.href.includes('clickfromnotify')) {
this.isNotifying = true;
location.hash = '';
return;
}
// 本次已通知
if (this.isNotifying) return;
this.isNotifying = true;
// 发送通知
const notify = new Alert(this.notifyHtml, {
timeout: 30,
sysNotify: true,
});
notify.getElement().querySelector('.wh-notify-msg button').addEventListener('click', () => this.skip_today());
notify.getElement().addEventListener('click', ev => {
if ((ev.target as HTMLElement).tagName.toLowerCase() === 'a') {
notify.close();
}
});
let audioPlay = CommonUtils.getInstance().audioPlay;
window.setTimeout(audioPlay, 800);
window.setTimeout(audioPlay, 800 * 2);
window.setTimeout(audioPlay, 800 * 3);
} else {
this.isNotifying = false;
}
}, 1000);
}
}
public stop(): void {
if (this.loopId) {
window.clearInterval(this.loopId);
this.loopId = null;
}
}
public set_time(t: number): void {
this.time = t;
}
public status(): '已启动' | '未启动' {
return this.loopId ? '已启动' : '未启动';
}
public is_running(): boolean {
return this.loopId !== null;
}
public skip_today(): void {
const date = new Date();
WuhuConfig.set('_15_alarm_ignore', [date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()], false);
// 通知
const notify = new Alert(`明早8点前将不再提醒 <button id="wh-rd-btn-${ MathUtils.getInstance().getRandomInt(0, 100) }">取消</button>`);
// 通知中的取消按钮
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 {
start?: Function;
stop?: Function;
set_time?: Function;
status?: Function;
is_running?: Function;
skip_today?: Function;
}

View File

@ -0,0 +1,66 @@
import WuhuBase from "../WuhuBase";
import WuhuConfig from "../WuhuConfig";
import Log from "../Log";
import CommonUtils from "../utils/CommonUtils";
import FetchUtils from "../utils/FetchUtils";
import InfoUtils from "../utils/InfoUtils";
import Alert from "../utils/Alert";
import TRAVEL_STATE from "../../enum/TravelState";
/**
*
*/
export default class CompanyHelper extends WuhuBase {
className = 'CompanyHelper';
public constructor() {
super();
WuhuConfig.get('CHTrainsDetectSwitch') && this.trainsDetect().then();
}
/**
*
*
* TODO URL判断
* @private
*/
private async trainsDetect(): Promise<null> {
// 通过用户的icon判断公司老板
if ((await InfoUtils.getInstance().getSessionData()).statusIcons.icons.company.iconID !== 'icon73') {
Log.info('火车检测跳过:非公司老板');
return;
}
// 上次检测时间戳
let lastDetect: number = WuhuConfig.get('CHTrainsDetect') || 0;
// 检测是否过了一天
if (CommonUtils.getInstance().isNewDay(lastDetect, -6)) {
WuhuConfig.set('CHTrainsDetect', Date.now());
let travelStage = CommonUtils.getInstance().getTravelStage(),
userStatus = (await InfoUtils.getInstance().getUserState()).status;
if (travelStage === TRAVEL_STATE.IN_TORN && userStatus === 'ok')
FetchUtils.getInstance().fetchText('/companies.php')
.then(res => {
let tmp: HTMLElement = document.createElement('div');
// TODO 未去除body标签
tmp.innerHTML = res.split('</head>')[1].replace('</html>', '').trim();
let trains: number = parseInt(tmp.querySelector('span.trains').innerText);
let stars: number = tmp.querySelectorAll('.company-rating .active').length / 2 || 1;
Log.info('火车/星级: ' + trains + '/' + stars);
if (trains + stars > 20) {
new Alert(`公司助手<br/><br/>火车检测:火车明日将溢出!${ trains }/20火车`, {
timeout: 15,
force: true,
sysNotify: true
});
}
})
.catch(error => {
Log.error('火车检测出错', error);
WuhuConfig.set('CHTrainsDetect', 0);
});
else Log.warn('[火车检测] 用户状态错误,跳过火车检测', { travelStage, userStatus });
} else {
Log.info('火车检测:今日已提醒,跳过');
}
}
}

View File

@ -1,34 +1,14 @@
import InfoUtils from "../class/utils/InfoUtils"; import WuhuBase from "../WuhuBase";
import MathUtils from "../class/utils/MathUtils"; import Log from "../Log";
import CommonUtils from "../class/utils/CommonUtils"; import InfoUtils from "../utils/InfoUtils";
import TornStyleBlock from "../class/utils/TornStyleBlock"; import MathUtils from "../utils/MathUtils";
import Timer from "../class/utils/Timer"; import CommonUtils from "../utils/CommonUtils";
import FetchUtils from "../class/utils/FetchUtils"; import TornStyleBlock from "../utils/TornStyleBlock";
import { Injectable } from "../container/Injectable"; import Timer from "../utils/Timer";
import ClassName from "../container/ClassName"; import FetchUtils from "../utils/FetchUtils";
import Logger from "../class/Logger";
import IFeature from "../man/IFeature";
/**
*
*/
@Injectable()
@ClassName('LotteryHelper')
export default class LotteryHelper implements IFeature {
private readonly logger: Logger = Logger.factory(LotteryHelper)
description(): string {
return "彩票助手";
}
iStart(): void | Promise<void> {
this.init()
}
urlExcludes(): RegExp[] {
return [];
}
export default class LotteryHelper extends WuhuBase {
className = 'LotteryHelper';
private loopFlag = true; private loopFlag = true;
private radioDaily: HTMLInputElement = null; private radioDaily: HTMLInputElement = null;
@ -41,21 +21,11 @@ export default class LotteryHelper implements IFeature {
private status: HTMLElement = null; private status: HTMLElement = null;
private desc: HTMLElement = null; private desc: HTMLElement = null;
urlIncludes(): RegExp[] { private readonly mathUtils = MathUtils.getInstance();
return [/loader\.php\?sid=lottery/];
}
constructor(
private readonly mathUtils: MathUtils,
private readonly commonUtils: CommonUtils,
private readonly fetchUtils: FetchUtils,
private readonly infoUtils: InfoUtils,
) {
}
public init() { public init() {
let startTime = new Timer(); let startTime = new Timer();
this.logger.info('彩票助手初始化开始'); Log.info('彩票助手初始化开始');
let radioLabelDaily = document.createElement('label'); let radioLabelDaily = document.createElement('label');
let radioLabelWeekly = document.createElement('label'); let radioLabelWeekly = document.createElement('label');
@ -131,7 +101,7 @@ export default class LotteryHelper implements IFeature {
progressBarBg, progressBar, status, desc).insert2Dom(); progressBarBg, progressBar, status, desc).insert2Dom();
// document.querySelector('#websocketConnectionData').after(container); // document.querySelector('#websocketConnectionData').after(container);
this.logger.info('彩票助手初始化结束,耗时:' + startTime.getTimeMs()); Log.info('彩票助手初始化结束,耗时:' + startTime.getTimeMs());
} }
private async start() { private async start() {
@ -145,7 +115,7 @@ export default class LotteryHelper implements IFeature {
if (inputNumber > 0) { if (inputNumber > 0) {
let msg = document.querySelector('.info-msg-wrap .msg').innerText.trim().split(' '); let msg = document.querySelector('.info-msg-wrap .msg').innerText.trim().split(' ');
let current = { let current = {
money: (await this.infoUtils.getSessionData()).user.money.value, money: (await InfoUtils.getInstance().getSessionData()).user.money.value,
token: parseInt(msg[4]) token: parseInt(msg[4])
}; };
let lotteryType = 1; let lotteryType = 1;
@ -163,12 +133,12 @@ export default class LotteryHelper implements IFeature {
rsMsg = `终止操作,已完成${ i }/${ inputNumber }`; rsMsg = `终止操作,已完成${ i }/${ inputNumber }`;
break; break;
} }
await this.fetchUtils.ajaxFetch({ await FetchUtils.getInstance().ajaxFetch({
url: window.addRFC('https://www.torn.com/loader.php?sid=lotteryPlay&step=buyTicket&lotteryID=' + lotteryType), url: window.addRFC('https://www.torn.com/loader.php?sid=lotteryPlay&step=buyTicket&lotteryID=' + lotteryType),
method: 'GET', method: 'GET',
referrer: '/loader.php?sid=lottery', referrer: '/loader.php?sid=lottery',
}); });
await this.commonUtils.sleep(this.mathUtils.getRandomInt(20, 50)); await CommonUtils.getInstance().sleep(this.mathUtils.getRandomInt(20, 50));
i++; i++;
this.desc.innerHTML = `已买${ i }张彩票`; this.desc.innerHTML = `已买${ i }张彩票`;
this.status.innerHTML = `${ i }/${ inputNumber }`; this.status.innerHTML = `${ i }/${ inputNumber }`;
@ -177,7 +147,7 @@ export default class LotteryHelper implements IFeature {
if (this.loopFlag) rsMsg = '批量购买完成'; if (this.loopFlag) rsMsg = '批量购买完成';
} else { } else {
rsMsg = '代币或现金不足'; rsMsg = '代币或现金不足';
this.logger.warn({ totalCost, inputNumber }); Log.warn({ totalCost, inputNumber });
} }
} else { } else {
rsMsg = '输入有误'; rsMsg = '输入有误';

View File

@ -1,74 +1,49 @@
import WuhuBase from "../WuhuBase";
import TornStyleBlock from "../utils/TornStyleBlock"; import TornStyleBlock from "../utils/TornStyleBlock";
import WuhuConfig from "../WuhuConfig";
import Alert from "../utils/Alert";
import TornStyleSwitch from "../utils/TornStyleSwitch"; import TornStyleSwitch from "../utils/TornStyleSwitch";
import { Injectable } from "../../container/Injectable";
import ClassName from "../../container/ClassName";
import LocalConfigWrapper from "../LocalConfigWrapper";
import IFeature from "../../man/IFeature";
import MsgWrapper from "../utils/MsgWrapper";
@Injectable() export default class PTHelper extends WuhuBase {
@ClassName('PTHelper') className = 'PTHelper';
export default class PTHelper implements IFeature { private readonly observer;
private observer: MutationObserver; private readonly usersPointSell;
private usersPointSell: HTMLDivElement;
constructor(
private readonly localConfigWrapper: LocalConfigWrapper,
private readonly msgWrapper: MsgWrapper,
) {
}
description(): string {
return "pt一键购买";
}
iStart(): void | Promise<void> {
this.start()
}
urlExcludes(): RegExp[] {
return [];
}
urlIncludes(): RegExp[] {
return [/pmarket\.php/];
}
start() {
constructor() {
super();
this.observer = new MutationObserver(e => { this.observer = new MutationObserver(e => {
for (const t of e) { for (const t of e) {
t.addedNodes.forEach(e => 'LI' === (e as HTMLElement).tagName && this.removeConfirm(e)) t.addedNodes.forEach(e => 'LI' === (e as HTMLElement).tagName && this.removeConfirm(e))
} }
}); });
this.usersPointSell = document.querySelector<HTMLDivElement>('.users-point-sell'); this.usersPointSell = document.querySelector('.users-point-sell');
let block = new TornStyleBlock('PT一键购买').insert2Dom(); let block = new TornStyleBlock('PT一键购买').insert2Dom();
let switcher = new TornStyleSwitch('开启'); let switcher = new TornStyleSwitch('开启');
block.append(switcher.getBase()); block.append(switcher.getBase());
let toggle = switcher.getInput(); let toggle = switcher.getInput();
toggle.checked = this.localConfigWrapper.config.ptQuickBuy; toggle.checked = WuhuConfig.get('ptQuickBuy');
if (toggle.checked) { if (toggle.checked) {
this.msgWrapper.create('一键购买已开启'); new Alert('一键购买已开启');
for (const index in this.usersPointSell.children) { for (const index in this.usersPointSell.children) {
'LI' === this.usersPointSell.children[index].tagName && this.removeConfirm(this.usersPointSell.children[index]) 'LI' === this.usersPointSell.children[index].tagName && this.removeConfirm(this.usersPointSell.children[index])
} }
this.observer.observe(this.usersPointSell, { childList: true }) this.observer.observe(this.usersPointSell, { childList: true })
} }
toggle.addEventListener('change', () => { toggle.addEventListener('change', () => {
this.localConfigWrapper.config.ptQuickBuy = toggle.checked; WuhuConfig.set('ptQuickBuy', toggle.checked, false);
if (toggle.checked) { if (toggle.checked) {
for (const index in this.usersPointSell.children) { for (const index in this.usersPointSell.children) {
'LI' === this.usersPointSell.children[index].tagName && this.removeConfirm(this.usersPointSell.children[index]) 'LI' === this.usersPointSell.children[index].tagName && this.removeConfirm(this.usersPointSell.children[index])
} }
this.observer.observe(this.usersPointSell, { childList: true }); this.observer.observe(this.usersPointSell, { childList: true });
this.msgWrapper.create('一键购买已开启'); new Alert('一键购买已开启');
} else { } else {
for (const index in this.usersPointSell.children) { for (const index in this.usersPointSell.children) {
'LI' === this.usersPointSell.children[index].tagName && this.rollbackConfirm(this.usersPointSell.children[index]) 'LI' === this.usersPointSell.children[index].tagName && this.rollbackConfirm(this.usersPointSell.children[index])
} }
this.observer.disconnect(); this.observer.disconnect();
this.msgWrapper.create('一键购买已关闭'); new Alert('一键购买已关闭');
} }
}); });
} }

View File

@ -0,0 +1,47 @@
import WuhuBase from "../WuhuBase";
import Log from "../Log";
import WuhuConfig from "../WuhuConfig";
import CommonUtils from "../utils/CommonUtils";
import TornStyleBlock from "../utils/TornStyleBlock";
import TornStyleSwitch from "../utils/TornStyleSwitch";
import FetchUtils from "../utils/FetchUtils";
export default class ProfileHelper extends WuhuBase {
className = 'ProfileHelper';
constructor() {
super();
CommonUtils.addStyle('body.wh-hide_profile_img .profile-image a.profile-image-wrapper .img-wrap img{display:none;}');
let id = document.querySelector('link[rel="canonical"]').getAttribute('href').split('=')[1];
// id获取格式判断
if (!CommonUtils.getInstance().isValidUid(id)) {
Log.error('[ProfileHelper] id格式错误');
}
if (WuhuConfig.get('HideProfileImg')) {
Log.info('[ProfileHelper] 隐藏头像');
document.body.classList.toggle('wh-hide_profile_img');
}
let block = new TornStyleBlock('芜湖助手').insert2Dom();
// 隐藏头像
let hideImgSwitch = new TornStyleSwitch('隐藏头像', WuhuConfig.get('HideProfileImg'));
block.append(hideImgSwitch.getBase());
hideImgSwitch.getInput().addEventListener('change', () => {
document.body.classList.toggle('wh-hide_profile_img');
WuhuConfig.set('HideProfileImg', hideImgSwitch.getInput().checked, true);
});
// 曾用名
let nameHistoryNode;
if (WuhuConfig.get('ShowNameHistory')) {
nameHistoryNode = document.createElement('p');
nameHistoryNode.innerHTML = '曾用名:';
block.append(nameHistoryNode);
FetchUtils.getInstance().getProfile(id).then((res) => {
if (res.userInformation.previousAliases.length > 0) {
res.userInformation.previousAliases.forEach(item => nameHistoryNode.innerHTML += item + ' ');
} else {
nameHistoryNode.innerHTML += '暂无';
}
});
}
}
}

View File

@ -1,33 +1,14 @@
import WuhuBase from "../WuhuBase";
import TornStyleBlock from "../utils/TornStyleBlock"; import TornStyleBlock from "../utils/TornStyleBlock";
import TornStyleSwitch from "../utils/TornStyleSwitch"; import TornStyleSwitch from "../utils/TornStyleSwitch";
import CommonUtils from "../utils/CommonUtils"; import CommonUtils from "../utils/CommonUtils";
import ClassName from "../../container/ClassName"; import WuhuConfig from "../WuhuConfig";
import { Injectable } from "../../container/Injectable";
import LocalConfigWrapper from "../LocalConfigWrapper";
import IFeature from "../../man/IFeature";
@ClassName('SearchHelper') export default class SearchHelper extends WuhuBase {
@Injectable() className = 'SearchHelper';
export default class SearchHelper implements IFeature {
description(): string {
return "搜索助手";
}
iStart(): void | Promise<void> { constructor() {
this.init() super();
}
urlExcludes(): RegExp[] {
return [];
}
urlIncludes(): RegExp[] {
return [/page\.php\?sid=UserList/];
}
constructor(
private readonly localConfigWrapper: LocalConfigWrapper,
) {
} }
public init(): void { public init(): void {
@ -35,7 +16,7 @@ export default class SearchHelper implements IFeature {
let placeholderSwitch = new TornStyleSwitch('底部空白占位区'); let placeholderSwitch = new TornStyleSwitch('底部空白占位区');
block.append(placeholderSwitch.getBase()).insert2Dom(); block.append(placeholderSwitch.getBase()).insert2Dom();
CommonUtils.addStyle('body.WHSearchPagePlaceholder .content.logged-in {margin-bottom: 340px;}'); CommonUtils.addStyle('body.WHSearchPagePlaceholder .content.logged-in {margin-bottom: 340px;}');
let config = this.localConfigWrapper.config.SearchPagePlaceholder; let config = WuhuConfig.get('SearchPagePlaceholder');
placeholderSwitch.getInput().checked = config || false; placeholderSwitch.getInput().checked = config || false;
config ? this.enable() : this.disable(); config ? this.enable() : this.disable();
placeholderSwitch.getInput().addEventListener('change', () => { placeholderSwitch.getInput().addEventListener('change', () => {
@ -45,11 +26,11 @@ export default class SearchHelper implements IFeature {
private enable(): void { private enable(): void {
document.body.classList.add('WHSearchPagePlaceholder'); document.body.classList.add('WHSearchPagePlaceholder');
this.localConfigWrapper.config.SearchPagePlaceholder = true; WuhuConfig.set('SearchPagePlaceholder', true);
} }
private disable(): void { private disable(): void {
document.body.classList.remove('WHSearchPagePlaceholder'); document.body.classList.remove('WHSearchPagePlaceholder');
this.localConfigWrapper.config.SearchPagePlaceholder = false; WuhuConfig.set('SearchPagePlaceholder', false);
} }
} }

View File

@ -1,66 +1,34 @@
import CommonUtils from "../class/utils/CommonUtils"; import WuhuBase from "../WuhuBase";
import Global from "../class/Global"; import WuhuConfig from "../WuhuConfig";
import Device from "../enum/Device"; import CommonUtils from "../utils/CommonUtils";
import ClassName from "../container/ClassName"; import Global from "../Global";
import { Injectable } from "../container/Injectable"; import Device from "../../enum/Device";
import LocalConfigWrapper from "../class/LocalConfigWrapper"; import Log from "../Log";
import Logger from "../class/Logger";
import IFeature from "../man/IFeature";
import ATK_PAGE_REG from "./url/ATK_PAGE_REG";
import ALL_PAGE_REG from "./url/ALL_PAGE_REG";
/** export default class SidebarHelper extends WuhuBase {
* ### className = 'SidebarHelper';
* -
* - 4
*/
@ClassName('SidebarHelper')
@Injectable()
export default class SidebarHelper implements IFeature {
private readonly logger: Logger = Logger.factory(SidebarHelper)
description(): string {
return "边栏助手";
}
iStart(): void | Promise<void> {
this.init()
}
urlExcludes(): RegExp[] {
return [ATK_PAGE_REG];
}
private readonly sidebarRootNode: HTMLElement; private readonly sidebarRootNode: HTMLElement;
private readonly toggleBtn: HTMLButtonElement; private readonly toggleBtn: HTMLButtonElement;
private isHide: boolean; private isHide: boolean;
urlIncludes(): RegExp[] { constructor() {
return [ALL_PAGE_REG]; super();
}
constructor(
private readonly localConfigWrapper: LocalConfigWrapper,
private readonly global: Global,
) {
this.sidebarRootNode = document.querySelector('#sidebarroot'); this.sidebarRootNode = document.querySelector('#sidebarroot');
this.toggleBtn = document.createElement('button'); this.toggleBtn = document.createElement('button');
} this.isHide = !!WuhuConfig.get('HideSidebar');
init(): void { if (!document.body.classList.contains('without-sidebar')) {
this.isHide = !!this.localConfigWrapper.config.HideSidebar;
if (!document.body.classList.contains('without-sidebar') || window.location.href.includes('christmas_town.php')) {
this.initToggleBtn(); this.initToggleBtn();
this.barRedirect(); this.barRedirect();
} else { } else {
this.logger.warn('页面未开启边栏,边栏助手退出'); Log.warn('[SidebarHelper] 页面未开启边栏,边栏助手退出');
} }
} }
// 初始化隐藏按钮 // 初始化隐藏按钮
private initToggleBtn(): void { private initToggleBtn(): void {
if (this.global.device === Device.PC && this.sidebarRootNode && this.localConfigWrapper.config.HideSidebarBtn) { if (Global.getInstance().device === Device.PC && this.sidebarRootNode && WuhuConfig.get('HideSidebarBtn')) {
this.isHide ? this.hideHandler() : this.showHandler(); this.isHide ? this.hideHandler() : this.showHandler();
let container = document.createElement('div'); let container = document.createElement('div');
container.append(this.toggleBtn); container.append(this.toggleBtn);
@ -77,25 +45,23 @@ export default class SidebarHelper implements IFeature {
private hideHandler(): void { private hideHandler(): void {
this.sidebarRootNode.classList.add('wh-hide'); this.sidebarRootNode.classList.add('wh-hide');
this.localConfigWrapper.config.HideSidebar = true; this.isHide = WuhuConfig.set('HideSidebar', true);
this.isHide = true;
this.toggleBtn.innerHTML = '>>'; this.toggleBtn.innerHTML = '>>';
} }
private showHandler(): void { private showHandler(): void {
this.sidebarRootNode.classList.remove('wh-hide'); this.sidebarRootNode.classList.remove('wh-hide');
this.localConfigWrapper.config.HideSidebar = false; this.isHide = WuhuConfig.set('HideSidebar', false);
this.isHide = false;
this.toggleBtn.innerHTML = '<<'; this.toggleBtn.innerHTML = '<<';
} }
// 4条转跳 // 4条转跳
private barRedirect(): void { private barRedirect(): void {
if (this.localConfigWrapper.config.barsRedirect) { if (WuhuConfig.get('barsRedirect')) {
const eb = document.querySelector<HTMLAnchorElement>('#barEnergy'); const eb = document.getElementById('barEnergy') as HTMLAnchorElement;
const nb = document.querySelector<HTMLAnchorElement>('#barNerve'); const nb = document.getElementById('barNerve') as HTMLAnchorElement;
const hb = document.querySelector<HTMLAnchorElement>('#barHappy'); const hb = document.getElementById('barHappy') as HTMLAnchorElement;
const lb = document.querySelector<HTMLAnchorElement>('#barLife'); const lb = document.getElementById('barLife') as HTMLAnchorElement;
if (eb) { if (eb) {
eb.addEventListener('click', () => location.href = '/gym.php'); eb.addEventListener('click', () => location.href = '/gym.php');
eb.href = '/gym.php'; eb.href = '/gym.php';

View File

@ -0,0 +1,24 @@
import WuhuBase from "../WuhuBase";
import TornStyleBlock from "../utils/TornStyleBlock";
import WuhuConfig from "../WuhuConfig";
import TornStyleSwitch from "../utils/TornStyleSwitch";
export default class StackHelper extends WuhuBase {
className = 'StackHelper';
constructor() {
super();
let block = new TornStyleBlock('叠E保护').insert2Dom();
let switcher = new TornStyleSwitch('启用');
let input = switcher.getInput();
block.append(switcher.getBase());
input.checked = WuhuConfig.get('SEProtect');
if (input.checked) document.body.classList.add('wh-gym-stack');
// 绑定点击事件
input.onchange = e => {
let target = e.target as HTMLInputElement;
document.body.classList.toggle('wh-gym-stack');
WuhuConfig.set('SEProtect', target.checked, true);
};
}
}

View File

@ -0,0 +1,61 @@
import CommonUtils from "../utils/CommonUtils";
import Log from "../Log";
import WuhuBase from "../WuhuBase";
import UserScriptEngine from "../../enum/UserScriptEngine";
import Popup from "../utils/Popup";
import STOCK_IMG_HTML from "../../static/html/stock_img.html";
import * as FILTER from "../../static/json/for_stock_item_filter.json";
import WindowActiveState from "./WindowActiveState";
export default class TravelItem extends WuhuBase {
className = 'TravelItem';
private readonly apiUrl: string = 'https://yata.yt/api/v1/travel/export/';
private foreignStockInfo: any = null;
public constructor() {
super();
window.setInterval(async () => {
if (!WindowActiveState.getInstance().get()) return;
Log.info('fetching ', this.apiUrl);
this.foreignStockInfo = JSON.parse(await CommonUtils.COFetch(this.apiUrl));
Log.info({ 'fetch returned': this.foreignStockInfo });
}, 30 * 1000);
}
// 呈现内容
public async clickHandler(): Promise<void> {
if (CommonUtils.getScriptEngine() === UserScriptEngine.RAW) {
new Popup(STOCK_IMG_HTML.replace('{{}}', performance.now().toString()), '飞花库存');
} else {
const popup = new Popup("请稍后 " + CommonUtils.loading_gif_html(), '飞花库存');
let table = `<table><tr><th colspan="2">目的地 - 更新时间</th><th colspan="3">库存</th></tr>`;
const dest = FILTER.default;
const now = new Date();
const res = await this.get();
Log.info({ res })
if (!res || !res.stocks) return;
dest.forEach(el => {
const update = (now.getTime() - new Date(res.stocks[el.name]['update'] * 1000).getTime()) / 1000 | 0
table += `<tr><td>${ el.show }</td><td>${ update / 60 | 0 }${ update % 60 | 0 }秒前</td>`;
let count = 0;
res.stocks[el.name]['stocks'].forEach(stock => {
if (el.stocks[stock.name]) {
table += `<td${ stock['quantity'] === 0 ? ' style="background-color:#f44336;color:white;border-color:#000;"' : '' }>${ el.stocks[stock.name] } (${ stock['quantity'] })</td>`;
count++;
}
});
while (count < 3) {
count++;
table += '<td></td>';
}
table += '</tr>';
});
table += '</table>';
popup.getElement().innerHTML = table;
}
}
private async get() {
return this.foreignStockInfo ||= JSON.parse(await CommonUtils.COFetch(this.apiUrl));
}
}

View File

@ -1,14 +1,13 @@
import uuidv4 from "../../func/utils/uuidv4"; import uuidv4 from "../../func/utils/uuidv4";
import ClassName from "../../container/ClassName"; import WuhuBase from "../WuhuBase";
import { Injectable } from "../../container/Injectable";
@ClassName('WindowActiveState') export default class WindowActiveState extends WuhuBase {
@Injectable() className = 'WindowActiveState';
export default class WindowActiveState { isFocus = false;
private isFocus = false; uuid = uuidv4();
private uuid = uuidv4();
constructor() { constructor() {
super();
if (self !== top) return null; if (self !== top) return null;
localStorage.setItem('whuuid', this.uuid); localStorage.setItem('whuuid', this.uuid);
document.addEventListener('visibilitychange', document.addEventListener('visibilitychange',
@ -18,7 +17,6 @@ export default class WindowActiveState {
addEventListener('blur', () => this.isFocus = false); addEventListener('blur', () => this.isFocus = false);
} }
// 当前实例是否激活
get(): boolean { get(): boolean {
// 当前窗口获得了焦点 优先级最高 // 当前窗口获得了焦点 优先级最高
if (this.isFocus) return true; if (this.isFocus) return true;

View File

@ -1,67 +1,29 @@
import XUNZHAOMUZHUANG_HTML from "../../../static/html/xunzhaomuzhuang/index.html"; import WuhuBase from "../WuhuBase";
import * as MUZHUANG_ID_LIST_JSON from "../../../static/json/muzhuang_id_list.json"; import XUNZHAOMUZHUANG_HTML from "../../static/html/xunzhaomuzhuang/index.html";
import * as MUZHUANG_ID_LIST_JSON from "../../static/json/muzhuang_id_list.json";
import CommonUtils from "../utils/CommonUtils"; import CommonUtils from "../utils/CommonUtils";
import XUNZHAOMUZHUANG_CSS from "../../../static/css/xunzhaomuzhuang.module.css"; import XUNZHAOMUZHUANG_CSS from "../../static/css/xunzhaomuzhuang.css";
import TornStyleBlock from "../utils/TornStyleBlock"; import TornStyleBlock from "../utils/TornStyleBlock";
import MathUtils from "../utils/MathUtils"; import MathUtils from "../utils/MathUtils";
import FetchUtils from "../utils/FetchUtils"; import FetchUtils from "../utils/FetchUtils";
import ClassName from "../../container/ClassName";
import { Injectable } from "../../container/Injectable";
import IFeature from "../../man/IFeature";
/** /**
* *
* /item.php?temp=4#xunzhaomuzhuang * /item.php?temp=4#xunzhaomuzhuang
*/ */
@ClassName('XZMZ') export default class XZMZ extends WuhuBase {
@Injectable() className = 'XZMZ';
export default class XZMZ implements IFeature { private readonly mainRoleContainer: HTMLElement;
description(): string { private readonly IDList: number[];
return "寻找木桩"; private readonly btn: HTMLButtonElement;
} private readonly stopBtn: HTMLButtonElement;
iStart(): void | Promise<void> {
this.start()
}
urlExcludes(): RegExp[] {
return [];
}
urlIncludes(): RegExp[] {
return [/item.php\?temp=4/];
}
start() {
let hasInit: boolean = false
let handle = () => {
if (!hasInit && window.location.hash === '#xunzhaomuzhuang') {
this.init()
hasInit = true
}
}
window.addEventListener('hashchange', handle)
handle()
}
private mainRoleContainer: HTMLElement;
private IDList: number[];
private btn: HTMLButtonElement;
private stopBtn: HTMLButtonElement;
private stopSignal: boolean = false; private stopSignal: boolean = false;
private tips: HTMLElement; private readonly tips: HTMLElement;
private counter: number; private counter: number;
public constructor( public constructor() {
private readonly mathUtils: MathUtils, super();
private readonly commonUtils: CommonUtils, CommonUtils.addStyle(XUNZHAOMUZHUANG_CSS);
private readonly fetchUtils: FetchUtils,
) {
}
public init() {
this.commonUtils.styleInject(XUNZHAOMUZHUANG_CSS);
document.body.classList.add('wh-hide-title');
document.title = document.title.replace('Items', '寻找木桩'); document.title = document.title.replace('Items', '寻找木桩');
this.mainRoleContainer = document.querySelector('div[role="main"]'); this.mainRoleContainer = document.querySelector('div[role="main"]');
let block = new TornStyleBlock('寻找木桩'); let block = new TornStyleBlock('寻找木桩');
@ -99,7 +61,7 @@ export default class XZMZ implements IFeature {
} }
private async SearchDeadman(id) { private async SearchDeadman(id) {
this.fetchUtils.getProfile(id).then((res) => { FetchUtils.getInstance().getProfile(id).then((res) => {
if (res.userStatus.status.type === 'ok') { if (res.userStatus.status.type === 'ok') {
this.addRow({ this.addRow({
player_id: res.user.userID, player_id: res.user.userID,
@ -108,7 +70,7 @@ export default class XZMZ implements IFeature {
}); });
} }
}); });
await this.commonUtils.sleep(this.mathUtils.getRandomInt(100, 200)); await CommonUtils.getInstance().sleep(MathUtils.getInstance().getRandomInt(100, 200));
} }
private addRow(data) { private addRow(data) {

View File

@ -0,0 +1,77 @@
import WuhuBase from "../WuhuBase";
import Popup from "../utils/Popup";
import Alert from "../utils/Alert";
import DialogMsgBox from "../utils/DialogMsgBox";
import CommonUtils from "../utils/CommonUtils";
import { MenuItemConfig } from "../ZhongIcon";
import IFrameCrimeHandler from "./IFrameCrimeHandler";
import loadGS from "../../func/module/loadGS";
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', () => {
// new DialogMsgBox('将清空所有芜湖助手相关设置并刷新页面,确定?', {
// callback: () => {
// 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', () => {
// });
let menuList: MenuItemConfig[] = [
{
domType: 'button', domId: '', domText: '清空设置', clickFunc() {
new DialogMsgBox('将清空所有芜湖助手相关设置并刷新页面,确定?', {
callback: () => {
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();
}
});
}
},
{
domType: "button", domId: '', domText: '通知权限', clickFunc() {
}
},
{
domType: 'button', domId: '', domText: '第三方API通信权限', clickFunc() {
}
},
{
domType: 'button', domId: '', domText: '小窗犯罪', clickFunc() {
IFrameCrimeHandler.getInstance().handle()
}
},
{
domType: 'button',
domId: '',
domText: '飞贼小助手',
tip: '加载从PC端移植的伞佬的油猴版飞贼小助手',
clickFunc() {
loadGS(CommonUtils.getScriptEngine())
}
},
];
menuList.forEach(i => pop.getElement().append(CommonUtils.getInstance().elemGenerator(i, pop.getElement())));
}
}

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,21 @@
import WuhuBase from "../WuhuBase";
import Popup from "../utils/Popup";
import WuhuConfig from "../WuhuConfig";
export default class CustomCssHandler extends WuhuBase {
className = 'CustomCssHandler';
constructor() {
super();
}
public handle(): void {
let pop = new Popup('<div><textarea></textarea><button class="torn-btn">保存</button><style>#wh-popup textarea{display: block;}</style></div>', '自定义CSS');
let textarea = pop.getElement().querySelector('textarea');
let button = pop.getElement().querySelector('button');
textarea.value = WuhuConfig.get('CustomCss') || '';
button.addEventListener('click', () => {
WuhuConfig.set('CustomCss', textarea.value || '', true);
});
}
}

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();
};
}
}

View File

@ -1,24 +1,17 @@
import NNB_INFO_HTML from "../../../static/html/nnb_info.html"; import WuhuBase from "../WuhuBase";
import NNB_INFO_HTML from "../../static/html/nnb_info.html";
import Popup from "../utils/Popup"; import Popup from "../utils/Popup";
import ClassName from "../../container/ClassName"; import Global from "../Global";
import { Injectable } from "../../container/Injectable";
import TornPDAUtils from "../utils/TornPDAUtils";
@ClassName('NNB') export default class NNB extends WuhuBase {
@Injectable()
export default class NNB {
className = 'NNB'; className = 'NNB';
constructor(
private readonly tornPDAUtils: TornPDAUtils,
) {
}
public handle(): void { public handle(): void {
let { isPDA, PDA_APIKey } = Global.getInstance();
const insert = NNB_INFO_HTML const insert = NNB_INFO_HTML
.replace('{{}}', localStorage.getItem('APIKey') || '不可用') .replace('{{}}', localStorage.getItem('APIKey') || '不可用')
.replace('{{}}', this.tornPDAUtils.isPDA() ? this.tornPDAUtils.APIKey : '不可用'); .replace('{{}}', isPDA ? PDA_APIKey : '不可用');
const popup = new Popup(insert, '查看NNB').element; const popup = new Popup(insert, '查看NNB').getElement();
const select = popup.querySelector('input'); const select = popup.querySelector('input');
const node = popup.querySelector('p'); const node = popup.querySelector('p');
popup.querySelector('button').addEventListener('click', ev => { popup.querySelector('button').addEventListener('click', ev => {
@ -27,7 +20,7 @@ export default class NNB {
node.innerHTML = '加载中'; node.innerHTML = '加载中';
// API 计算 // API 计算
if (select.checked) { if (select.checked) {
const api_key = this.tornPDAUtils.isPDA() ? this.tornPDAUtils.APIKey : window.localStorage.getItem('APIKey'); const api_key = isPDA ? PDA_APIKey : window.localStorage.getItem('APIKey');
window.fetch(`https://api.torn.com/user/?selections=bars,perks&key=${ api_key }`) window.fetch(`https://api.torn.com/user/?selections=bars,perks&key=${ api_key }`)
.then(res => res.json()) .then(res => res.json())
.then(data => { .then(data => {

View File

@ -1,33 +1,16 @@
import WuhuBase from "../WuhuBase";
import CommonUtils from "../utils/CommonUtils"; import CommonUtils from "../utils/CommonUtils";
import QUICK_FLY_CSS from "../../../static/css/quick_fly.module.css"; import QUICK_FLY_CSS from "../../static/css/quick_fly.css";
import QUICK_FLY_HTML from "../../../static/html/quick_fly.html"; import QUICK_FLY_HTML from "../../static/html/quick_fly.html";
import Alert from "../utils/Alert"; import Alert from "../utils/Alert";
import TravelItem from "../../feature/TravelItem"; import TravelItem from "../action/TravelItem";
import ClassName from "../../container/ClassName";
import { Injectable } from "../../container/Injectable";
import Logger from "../Logger";
import MsgWrapper from "../utils/MsgWrapper";
import { InjectionKey } from "vue";
import NetHighLvlWrapper from "../utils/NetHighLvlWrapper";
@ClassName('QuickFlyBtnHandler') export default class QuickFlyBtnHandler extends WuhuBase {
@Injectable()
export default class QuickFlyBtnHandler {
className = 'QuickFlyBtnHandler'; className = 'QuickFlyBtnHandler';
constructor(
private readonly logger: Logger,
private readonly travelItem: TravelItem,
private readonly commonUtils: CommonUtils,
// private readonly infoUtils: InfoUtils,
private readonly msgWrapper: MsgWrapper,
private readonly netHighLvlWrapper: NetHighLvlWrapper,
) {
}
public static doQuickFly(): void { public static doQuickFly(): void {
// [id: dest, _type: (1...4), ts: timestamp] // [id: dest, _type: (1...4), ts: timestamp]
const [_id, _type, ts] = window.sessionStorage['wh-quick-fly'].trim().split(' '); const [_id, _type, ts] = sessionStorage['wh-quick-fly'].trim().split(' ');
if (new Date().getTime() - ts > 20000) { if (new Date().getTime() - ts > 20000) {
new Alert('超时,一键起飞计划已取消'); new Alert('超时,一键起飞计划已取消');
return; return;
@ -61,7 +44,7 @@ export default class QuickFlyBtnHandler {
} }
// 起飞目的地id // 起飞目的地id
private static getDestId(dest: number): number { private static getDestId(dest): number {
// 墨、开、加、夏、英、阿、瑞s、立本、祖、迪、南 // 墨、开、加、夏、英、阿、瑞s、立本、祖、迪、南
return [2, 12, 9, 3, 10, 7, 8, 5, 6, 11, 4][dest]; return [2, 12, 9, 3, 10, 7, 8, 5, 6, 11, 4][dest];
} }
@ -70,7 +53,7 @@ export default class QuickFlyBtnHandler {
if (window.hasWHQuickFlyOpt) return; if (window.hasWHQuickFlyOpt) return;
window.hasWHQuickFlyOpt = true; window.hasWHQuickFlyOpt = true;
// TODO // TODO
this.commonUtils.styleInject(QUICK_FLY_CSS); CommonUtils.addStyle(QUICK_FLY_CSS);
const node = document.createElement('div'); const node = document.createElement('div');
node.id = 'wh-quick-fly-opt'; node.id = 'wh-quick-fly-opt';
node.innerHTML = QUICK_FLY_HTML; node.innerHTML = QUICK_FLY_HTML;
@ -86,7 +69,8 @@ export default class QuickFlyBtnHandler {
}); });
node.querySelector('a').addEventListener('click', (e) => { node.querySelector('a').addEventListener('click', (e) => {
e.preventDefault(); e.preventDefault();
this.travelItem.clickHandler().then(); // forStock();
TravelItem.getInstance().clickHandler();
}); });
node.querySelector('input').addEventListener('click', (e) => { node.querySelector('input').addEventListener('click', (e) => {
node.classList.toggle('wh-quick-fly-opt-hide'); node.classList.toggle('wh-quick-fly-opt-hide');
@ -120,37 +104,4 @@ export default class QuickFlyBtnHandler {
showTime(); showTime();
yaoCD.innerHTML = `药CD剩余${ CommonUtils.getYaoCD() }`; yaoCD.innerHTML = `药CD剩余${ CommonUtils.getYaoCD() }`;
} }
public async directFly(destIndex: number, typeIndex: number) {
// 获取key
// if(false){
// let key;
// try {
// const resp = await (await fetch('/travelagency.php')).text();
// key = resp.match(/data-key="([0-9]+)"/)[1];
// } catch (e) {
// this.msgWrapper.create('起飞参数获取失败', {}, 'error');
// this.logger.error(e.stack);
// throw new Error('起飞参数获取失败');
// }
// }
let msg: string;
try {
msg = await this.netHighLvlWrapper.doTravelFly(QuickFlyBtnHandler.getDestId(destIndex), null, ['standard', 'airstrip', 'private', 'business'][typeIndex])
const response = JSON.parse(msg);
if (!response.success) {
this.msgWrapper.create('起飞失败 ' + response.error, {}, 'error');
this.logger.error('起飞失败 ' + response.error, response.err);
throw new Error('起飞失败 ' + response.error);
}
console.log(msg);
} catch (e) {
this.msgWrapper.create('起飞时出现错误 ' + e.message, {}, 'error');
this.logger.error(e.stack);
throw new Error('起飞时出现错误 ' + e.message);
}
this.msgWrapper.create('已起飞', {}, 'success');
}
} }
export const QuickFlyBtnHandlerKey = Symbol('QuickFlyBtnHandlerKey') as InjectionKey<QuickFlyBtnHandler>

View File

@ -1,19 +1,16 @@
import WuhuBase from "../WuhuBase";
import CommonUtils from "../utils/CommonUtils"; import CommonUtils from "../utils/CommonUtils";
import QUICK_LINK_CSS from "../../../static/css/quick_link.module.css"; import QUICK_LINK_CSS from "../../static/css/quick_link.css";
import Popup from "../utils/Popup"; import Popup from "../utils/Popup";
import ClassName from "../../container/ClassName";
import { Injectable } from "../../container/Injectable";
@ClassName('QuickLinksHandler') export default class QuickLinksHandler extends WuhuBase {
@Injectable() className = 'QuickLinksHandler';
export default class QuickLinksHandler {
private styleAdded: boolean = false; private styleAdded: boolean = false;
private list = []; private list = [];
constructor( constructor() {
private readonly commonUtils: CommonUtils, super();
) {
let list = this.list; let list = this.list;
// 生存手册 // 生存手册
list.push({ list.push({
@ -75,7 +72,7 @@ export default class QuickLinksHandler {
public handle(): void { public handle(): void {
if (!this.styleAdded) { if (!this.styleAdded) {
this.commonUtils.styleInject(QUICK_LINK_CSS); CommonUtils.addStyle(QUICK_LINK_CSS);
this.styleAdded = true; this.styleAdded = true;
} }
const list = this.list; const list = this.list;
@ -85,8 +82,8 @@ export default class QuickLinksHandler {
}); });
insert += '</p>' insert += '</p>'
let popup = new Popup(insert, '常用链接'); let popup = new Popup(insert, '常用链接');
popup.element.classList.add('wh-link-collection-cont'); popup.getElement().classList.add('wh-link-collection-cont');
popup.element.addEventListener('click', ev => { popup.getElement().addEventListener('click', ev => {
let target = ev.target as HTMLElement; let target = ev.target as HTMLElement;
if (target.tagName.toLowerCase() === 'a' || target.tagName.toLowerCase() === 'span') { if (target.tagName.toLowerCase() === 'a' || target.tagName.toLowerCase() === 'span') {
popup.close(); popup.close();

View File

@ -1,6 +1,8 @@
import WuhuBase from "../WuhuBase";
import { MenuItemConfig } from "../ZhongIcon"; import { MenuItemConfig } from "../ZhongIcon";
import Log from "../Log";
import Timer from "../utils/Timer"; import Timer from "../utils/Timer";
import BuyBeerHelper from "../../feature/BuyBeerHelper"; import BuyBeerHelper from "../action/BuyBeerHelper";
import UpdateTranslateDict from "./UpdateTranslateDict"; import UpdateTranslateDict from "./UpdateTranslateDict";
import landedRedirect from "../../func/module/landedRedirect"; import landedRedirect from "../../func/module/landedRedirect";
import Alert from "../utils/Alert"; import Alert from "../utils/Alert";
@ -9,58 +11,42 @@ import AdditionalSettingsHandler from "./AdditionalSettingsHandler";
import Popup from "../utils/Popup"; import Popup from "../utils/Popup";
import CommonUtils from "../utils/CommonUtils"; import CommonUtils from "../utils/CommonUtils";
import CustomCssHandler from "./CustomCssHandler"; import CustomCssHandler from "./CustomCssHandler";
import Provider from "../provider/Provider";
import { MENU_ITEM_TYPE } from "../../interface/MenuItem";
import ClassName from "../../container/ClassName";
import { Injectable } from "../../container/Injectable";
import { Container } from "../../container/Container";
import Logger from "../Logger";
@ClassName('SettingsHandler') export default class SettingsHandler extends WuhuBase {
@Injectable()
class SettingsHandler extends Provider {
className = 'SettingsHandler'; className = 'SettingsHandler';
private list: MenuItemConfig[] = []; private list: MenuItemConfig[] = [];
constructor( constructor() {
private readonly buyBeerHelper: BuyBeerHelper,
private readonly commonUtils: CommonUtils,
private readonly updateTranslateDict: UpdateTranslateDict,
private readonly customCssHandler: CustomCssHandler,
private readonly viewLogsHandler: ViewLogsHandler,
private readonly additionalSettingsHandler: AdditionalSettingsHandler,
private readonly logger: Logger,
) {
super(); super();
this.constructWuhuSettingList(); this.constructWuhuSettingList();
} }
public show(): void { public handler(): void {
let startTime = new Timer(); let startTime = new Timer();
this.logger.info('构造设置开始'); Log.info('构造设置开始');
let pop = new Popup(CommonUtils.loading_gif_html(), '芜湖助手设置'); let pop = new Popup(CommonUtils.loading_gif_html(), '芜湖助手设置');
window.setTimeout(() => { window.setTimeout(() => {
let tmp = document.createElement('div'); let tmp = document.createElement('div');
tmp.classList.add('gSetting'); tmp.classList.add('gSetting');
this.list.forEach(set => this.commonUtils.elemGenerator(set, tmp)); this.list.forEach(set => CommonUtils.getInstance().elemGenerator(set, tmp));
// 本日不提醒 // 本日不提醒
tmp.querySelector('#wh-qua-alarm-check-btn') tmp.querySelector('#wh-qua-alarm-check-btn')
.addEventListener('click', () => this.buyBeerHelper.skip_today()); .addEventListener('click', () => BuyBeerHelper.getInstance().skip_today());
pop.getElement().innerHTML = ''; pop.getElement().innerHTML = '';
pop.getElement().appendChild(tmp); pop.getElement().appendChild(tmp);
(window.initializeTooltip) && (window.initializeTooltip('#wh-popup-cont', 'white-tooltip')); (window.initializeTooltip) && (window.initializeTooltip('#wh-popup-cont', 'white-tooltip'));
this.logger.info('构造设置结束 ' + startTime.getTimeMs()); Log.info('构造设置结束 ' + startTime.getTimeMs());
}, 0) }, 0)
} }
// 设置 // 设置
private constructWuhuSettingList(): SettingsHandler { private constructWuhuSettingList(): SettingsHandler {
let timer = new Timer(); let timer = new Timer();
this.logger.info('构造设置列表开始'); Log.info('构造设置列表开始');
const date = new Date(); const date = new Date();
let beer = this.buyBeerHelper; let beer = BuyBeerHelper.getInstance();
let list = this.list; let list = this.list;
@ -103,28 +89,13 @@ class SettingsHandler extends Provider {
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',
domId: '', domId: '',
domText: '更新翻译词库', domText: '更新翻译词库',
isTornBtn: true, isTornBtn: true,
clickFunc: () => this.updateTranslateDict.handle() clickFunc: () => UpdateTranslateDict.getInstance().handle()
});
// 收集数据以改进翻译质量
list.push({
domType: 'checkbox',
domId: '',
domText: ' 收集数据以改进翻译质量',
dictName: 'CollectPlayerData',
tip: '未实现功能<br/>收集玩家基础信息与页面上(未翻译)的内容上传以改进翻译'
}); });
// 战斗 // 战斗
@ -397,7 +368,7 @@ class SettingsHandler extends Provider {
domText: '啤酒提醒时间设定', domText: '啤酒提醒时间设定',
isTornBtn: true, isTornBtn: true,
// tip: '通知提前时间', // tip: '通知提前时间',
clickFunc: () => this.buyBeerHelper.setTimeHandler() clickFunc: () => BuyBeerHelper.getInstance().setTimeHandler()
}); });
// 个人资料 // 个人资料
@ -419,12 +390,6 @@ class SettingsHandler extends Provider {
dictName: 'ShowNameHistory', dictName: 'ShowNameHistory',
domId: '' domId: ''
}); });
list.push({
domType: 'checkbox',
domText: '迷你资料卡显示上次行动时间',
dictName: 'ShowMiniProfLastAct',
domId: ''
});
// 侧边栏 // 侧边栏
list.push({ list.push({
@ -449,14 +414,6 @@ class SettingsHandler extends Provider {
dictName: 'HideSidebarBtn', dictName: 'HideSidebarBtn',
tip: '仅PC' tip: '仅PC'
}); });
// 现金变动提醒
list.push({
domType: 'checkbox',
domId: '',
domText: ' 现金变动提醒',
dictName: 'CashChangeAlert',
tip: '插件图标下方显示现金、现金变动时通知提醒<br/>注: 刷新页面生效、系统级通知需要浏览器权限'
});
// 其他 // 其他
list.push({ list.push({
@ -517,22 +474,6 @@ class SettingsHandler extends Provider {
domText: ' 搜索页空白占位区', domText: ' 搜索页空白占位区',
dictName: 'SearchPagePlaceholder', dictName: 'SearchPagePlaceholder',
}); });
// 解决一直转圈(加载中)的问题
list.push({
domType: 'checkbox',
domId: null,
domText: ' 解决一直转圈(加载中)的问题',
dictName: 'SolveGoogleScriptPendingIssue',
tip: 'Torn引入Google登陆后可能会出现这种问题<br/>启用功能影响:<br/>页面加载速度变慢,与其他插件冲突,如遇到问题请关闭<br/>并使用其他更科学的方法解决'
});
// 记住图标位置
list.push({
domType: 'checkbox',
domId: null,
domText: ' 记住图标位置',
dictName: 'SaveIconPosition',
tip: '记住图标移动后的位置'
});
// 清除多余的脚本 // 清除多余的脚本
// list.push({ // list.push({
// domType: 'checkbox', // domType: 'checkbox',
@ -550,13 +491,13 @@ class SettingsHandler extends Provider {
dictName: 'isDev', dictName: 'isDev',
isHide: true, isHide: true,
}); });
// 自定义CSS // 查看logs
list.push({ list.push({
domType: 'button', domType: 'button',
domId: null, domId: null,
domText: '自定义CSS', domText: '自定义CSS',
isTornBtn: true, isTornBtn: true,
clickFunc: () => this.customCssHandler.handle() clickFunc: () => CustomCssHandler.getInstance().handle()
}); });
// 查看logs // 查看logs
list.push({ list.push({
@ -564,22 +505,16 @@ class SettingsHandler extends Provider {
domId: null, domId: null,
domText: '查看日志', domText: '查看日志',
isTornBtn: true, isTornBtn: true,
clickFunc: () => this.viewLogsHandler.handle() clickFunc: () => ViewLogsHandler.getInstance().handle()
}); });
// 更多设定 // 更多设定
list.push({ list.push({
domType: 'button', domId: 'wh-otherBtn', domText: '更多设定', domType: 'button', domId: 'wh-otherBtn', domText: '更多设定',
isTornBtn: true, isTornBtn: true,
clickFunc: () => this.additionalSettingsHandler.show() clickFunc: () => AdditionalSettingsHandler.getInstance().handle()
}); });
this.logger.info('构造设置列表结束' + timer.getTimeMs()); Log.info('构造设置列表结束' + timer.getTimeMs());
return this; return this;
} }
} }
export default {
domType: MENU_ITEM_TYPE.BUTTON,
domText: '⚙️ 助手设置',
clickFunc: () => Container.factory(SettingsHandler).show()
};

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,47 @@
import WuhuBase from "../WuhuBase";
import Log from "../Log";
import Popup from "../utils/Popup";
import CommonUtils from "../utils/CommonUtils";
import VIEW_LOGS_HANDLER_HTML from "../../static/html/view_logs_handler.html";
export default class ViewLogsHandler extends WuhuBase {
className = 'ViewLogsHandler';
public handle(): void {
let logCounter = Log.getCounter();
let pop = new Popup(VIEW_LOGS_HANDLER_HTML
.replace('{{}}', logCounter.info.toString())
.replace('{{}}', logCounter.warning.toString())
.replace('{{}}', logCounter.error.toString()), '查看日志');
window.setTimeout(() => {
let container = pop.getElement().querySelector('div');
let text = document.createElement('div');
let logs = Log.getLogs().split('\r\n');
logs.forEach(log => {
let p = document.createElement('p');
p.innerText = log;
if (log.slice(0, 10).includes('ERR')) {
p.style.backgroundColor = '#ff000080';
} else if (log.slice(0, 10).includes('WRN')) {
p.style.backgroundColor = '#ffff0080';
}
text.append(p);
});
pop.getElement().querySelector('button').addEventListener('click', () => window.setTimeout(() => {
CommonUtils.getInstance()
.exportTextFile(
'wuhu_log_' + Log.getTime()
.replace('[', '')
.replace(']', '')
.replace(' ', '')
.replace('.', '')
.replaceAll('-', '')
.replaceAll(':', '') + '.log',
[Log.getLogs()]
);
}, 0));
container.innerHTML = '';
container.append(text);
}, 0);
}
}

View File

@ -0,0 +1,32 @@
import Log from "../Log";
/**
*
*/
export default class Provider {
protected readonly className: string = 'Provider';
private static instance;
private static readonly pool = {};
constructor() {
}
public static getInstance<T extends typeof Provider>(this: T): InstanceType<T> {
// return this.instance ||= new this();
if (!this.instance) {
let startTime = performance.now();
this.instance = new this();
let thatName = this.instance.getClassName() || this.name;
Log.info('实例已创建,', thatName, this.instance, '耗时' + ((performance.now() - startTime) | 0) + 'ms');
Provider.pool[thatName] = this.instance;
}
return this.instance;
}
public static getPool() {
return {
pool: Provider.pool,
}
}
}

View File

@ -0,0 +1,22 @@
import Log from "../Log";
import ZhongIcon from "../ZhongIcon";
export default class Starter {
public static run(T): void {
if (window.WHTRANS) throw '退出, 已运行次数' + window.WHTRANS;
window.WHTRANS = window.WHTRANS === undefined ? 1 : window.WHTRANS++;
let started = performance.now();
try {
T.main();
} catch (e) {
Log.error('[Starter]加载出错信息: ' + e.message);
Log.info('错误堆栈: ', e.stack);
}
let runTime: number = (performance.now() - started) | 0;
Log.info(`芜湖脚本完成加载, 耗时${ runTime }ms`);
if (ZhongIcon.ZhongNode && ZhongIcon.ZhongNode.initTimer)
ZhongIcon.ZhongNode.initTimer.innerHTML = `加载时间 ${ runTime }ms`;
}
}

View File

@ -0,0 +1,25 @@
import WuhuBase from "../WuhuBase";
import Log from "../Log";
import ZhongIcon from "../ZhongIcon";
export default class ActionButtonUtils extends WuhuBase {
className = 'ActionButtonUtils';
private hasAdded: boolean = false;
public add(txt: string, func: (ev: Event) => void = () => null): void {
if (!this.hasAdded) this.handle(txt, func);
else Log.warn('ActionButton已存在');
}
private handle(txt, func): void {
let btn = document.createElement('button');
btn.style.padding = '8px 13px 8px 0';
btn.style.verticalAlign = 'bottom';
btn.style.color = '#4CAF50';
btn.innerHTML = txt;
btn.addEventListener('click', func);
ZhongIcon.ZhongNode.querySelector('button').after(btn);
this.hasAdded = true;
Log.info('ActionButton已添加', { txt, func, btn });
}
}

View File

@ -1,14 +1,13 @@
import Log from "../Log";
import IWHNotify from "../../interface/IWHNotify"; import IWHNotify from "../../interface/IWHNotify";
import NotificationUtils from "./NotificationUtils"; import NotificationUtils from "./NotificationUtils";
import WuhuBase from "../WuhuBase";
import MathUtils from "./MathUtils"; import MathUtils from "./MathUtils";
import NOTIFY_HTML from "../../../static/html/notify.html"; import NOTIFY_HTML from "../../static/html/notify.html";
import WindowActiveState from "../action/WindowActiveState"; import WindowActiveState from "../action/WindowActiveState";
import { Container } from "../../container/Container";
import Logger from "../Logger";
import ClassName from "../../container/ClassName";
@ClassName('Alert') export default class Alert extends WuhuBase {
export default class Alert { className = 'Alert';
private static container: HTMLElement = null; private static container: HTMLElement = null;
private static totalCounter: number = 0; private static totalCounter: number = 0;
@ -16,41 +15,34 @@ export default class Alert {
private intervalID = -1; private intervalID = -1;
private readonly callback: Function; private readonly callback: Function;
public constructor( public constructor(msg: string, options: IWHNotify = {}) {
msg: string, super();
options: IWHNotify = {},
private readonly mathUtils: MathUtils = Container.factory(MathUtils),
private readonly windowActiveState: WindowActiveState = Container.factory(WindowActiveState),
private readonly notificationUtils: NotificationUtils = Container.factory(NotificationUtils),
private readonly logger: Logger = Container.factory(Logger),
) {
let { timeout, callback, sysNotify, force } = options; let { timeout, callback, sysNotify, force } = options;
// 后台窗口、iframe内判断 // 后台窗口、iframe内判断
if (!this.windowActiveState.get() || (self !== top)) { if (!WindowActiveState.getInstance().get() || (self !== top)) {
if (!force) { if (!force) {
this.logger.warn('后台通知已被屏蔽'); Log.warn('后台通知已被屏蔽');
return null; return null;
} else { } else {
this.logger.info('强制后台通知'); Log.info('强制后台通知');
} }
} }
// 通知的容器 // 通知的容器
this.logger.info('通知的容器', Alert.container); if (Alert.container === null) Alert.initContainer();
if (!Alert.container || !document.contains(Alert.container)) Alert.initContainer();
this.callback = callback || (() => null); this.callback = callback || (() => null);
Alert.create(this, msg, timeout || 3); Alert.create(this, msg, timeout || 3);
Alert.totalCounter++; Alert.totalCounter++;
this.logger.info('创建新通知:', this, msg); Log.info('创建新通知:', this, msg);
if (sysNotify) this.notificationUtils.push(msg, options); if (sysNotify) NotificationUtils.getInstance().push(msg, options);
} }
private static create(that: Alert, msg, timeout): void { private static create(that: Alert, msg, timeout): void {
// 通知的唯一id // 通知的唯一id
const uid = '' + that.mathUtils.getRandomInt(1000, 9999); const uid = '' + MathUtils.getInstance().getRandomInt(1000, 9999);
// 每条通知 // 每条通知
const element: MyHTMLElement = document.createElement('div'); const element: MyHTMLElement = document.createElement('div');
element.id = `wh-notify-${ uid }`; element.id = `wh-notify-${ uid }`;

View File

@ -1,53 +1,32 @@
import UserScriptEngine from "../../enum/UserScriptEngine"; import UserScriptEngine from "../../enum/UserScriptEngine";
import WuhuBase from "../WuhuBase";
import Log from "../Log";
import Device from "../../enum/Device"; import Device from "../../enum/Device";
import LOADING_IMG_HTML from "../../../static/html/loading_img.html"; import LOADING_IMG_HTML from "../../static/html/loading_img.html";
import Timer from "./Timer"; import Timer from "./Timer";
import FetchUtils from "./FetchUtils"; import FetchUtils from "./FetchUtils";
import TornStyleSwitch from "./TornStyleSwitch"; import TornStyleSwitch from "./TornStyleSwitch";
import WuhuConfig from "../WuhuConfig";
import { MenuItemConfig } from "../ZhongIcon"; import { MenuItemConfig } from "../ZhongIcon";
import TRAVEL_STATE from "../../enum/TravelState"; import TRAVEL_STATE from "../../enum/TravelState";
import InventoryItemInfo from "../../interface/responseType/InventoryItemInfo";
import { Injectable } from "../../container/Injectable";
import ClassName from "../../container/ClassName";
import LocalConfigWrapper from "../LocalConfigWrapper";
import Logger from "../Logger";
import Global from "../Global";
import { Container } from "../../container/Container";
import TornPDAUtils from "./TornPDAUtils";
import { InjectionKey } from "vue";
@Injectable() export default class CommonUtils extends WuhuBase {
@ClassName('CommonUtils') className = 'CommonUtils';
export default class CommonUtils {
constructor(
private readonly localConfigWrapper: LocalConfigWrapper,
private readonly fetchUtils: FetchUtils,
private readonly logger: Logger,
private readonly global: Global,
private readonly tornPDAUtils: TornPDAUtils,
) {
}
/**
* @deprecated
*/
static getScriptEngine() { static getScriptEngine() {
let glob = Container.factory(Global); let glob = CommonUtils.glob;
let tornPDAUtils = Container.factory(TornPDAUtils); return glob.GM_xmlhttpRequest ? UserScriptEngine.GM : glob.isPDA
return glob.GM_xmlhttpRequest ? UserScriptEngine.GM : tornPDAUtils.isPDA()
? UserScriptEngine.PDA : UserScriptEngine.RAW; ? UserScriptEngine.PDA : UserScriptEngine.RAW;
} }
static COFetch(url: URL | string, method: 'get' | 'post' | string = 'get', body: any = null): Promise<string> { static COFetch(url: URL | string, method: 'get' | 'post' = 'get', body: any = null): Promise<string> {
let logger = Container.factory(Logger);
let start = new Timer();
const engine = this.getScriptEngine(); const engine = this.getScriptEngine();
logger.info(`跨域请求 -> ${url}, 脚本引擎: ${engine}`); let start = performance.now();
Log.info('跨域获取数据开始, 脚本引擎: ' + engine);
return new Promise<string>((resolve, reject) => { return new Promise<string>((resolve, reject) => {
switch (engine) { switch (engine) {
case UserScriptEngine.RAW: { case UserScriptEngine.RAW: {
logger.error(`跨域请求错误:${ UserScriptEngine.RAW }环境下无法进行跨域请求`); Log.error(`跨域请求错误:${ UserScriptEngine.RAW }环境下无法进行跨域请求`);
reject(`错误:${ UserScriptEngine.RAW }环境下无法进行跨域请求`); reject(`错误:${ UserScriptEngine.RAW }环境下无法进行跨域请求`);
break; break;
} }
@ -56,38 +35,38 @@ export default class CommonUtils {
// get // get
if (method === 'get') { if (method === 'get') {
if (typeof PDA_httpGet !== 'function') { if (typeof PDA_httpGet !== 'function') {
logger.error('COFetch网络错误PDA版本不支持'); Log.error('COFetch网络错误PDA版本不支持');
reject('COFetch网络错误PDA版本不支持'); reject('COFetch网络错误PDA版本不支持');
} }
PDA_httpGet(url) PDA_httpGet(url)
.then(res => { .then(res => {
logger.info('跨域获取数据成功, 耗时' + start.getTimeMs()); Log.info('跨域获取数据成功, 耗时' + (performance.now() - start | 0) + 'ms');
resolve(res.responseText); resolve(res.responseText);
}) })
.catch(e => { .catch(e => {
logger.error('COFetch网络错误', e); Log.error('COFetch网络错误', e);
reject(`COFetch网络错误 ${ e }`); reject(`COFetch网络错误 ${ e }`);
}) })
} }
// post // post
else { else {
if (typeof PDA_httpPost !== 'function') { if (typeof PDA_httpPost !== 'function') {
logger.error('COFetch网络错误PDA版本不支持'); Log.error('COFetch网络错误PDA版本不支持');
reject('COFetch网络错误PDA版本不支持'); reject('COFetch网络错误PDA版本不支持');
} }
PDA_httpPost(url, { 'content-type': 'application/json' }, body) PDA_httpPost(url, { 'content-type': 'application/json' }, body)
.then(res => resolve(res.responseText)) .then(res => resolve(res.responseText))
.catch(e => { .catch(e => {
logger.error('COFetch网络错误', e); Log.error('COFetch网络错误', e);
reject(`COFetch网络错误 ${ e }`); reject(`COFetch网络错误 ${ e }`);
}); });
} }
break; break;
} }
case UserScriptEngine.GM: { case UserScriptEngine.GM: {
let { GM_xmlhttpRequest } = Container.factory(Global); let { GM_xmlhttpRequest } = CommonUtils.glob;
if (typeof GM_xmlhttpRequest !== 'function') { if (typeof GM_xmlhttpRequest !== 'function') {
logger.error('COFetch网络错误用户脚本扩展API错误'); Log.error('COFetch网络错误用户脚本扩展API错误');
reject('错误用户脚本扩展API错误'); reject('错误用户脚本扩展API错误');
} }
GM_xmlhttpRequest({ GM_xmlhttpRequest({
@ -96,7 +75,7 @@ export default class CommonUtils {
data: method === 'get' ? null : body, data: method === 'get' ? null : body,
headers: method === 'get' ? null : { 'content-type': 'application/json' }, headers: method === 'get' ? null : { 'content-type': 'application/json' },
onload: res => { onload: res => {
logger.info('跨域获取数据成功,耗时' + start.getTimeMs()); Log.info('跨域获取数据成功,耗时' + (performance.now() - start | 0) + 'ms');
resolve(res.response); resolve(res.response);
}, },
onerror: res => reject(`连接错误 ${ JSON.stringify(res) }`), onerror: res => reject(`连接错误 ${ JSON.stringify(res) }`),
@ -107,13 +86,6 @@ export default class CommonUtils {
}); });
} }
getScriptEngine() {
// let glob = Container.factory(Global);
// let tornPDAUtils = Container.factory(TornPDAUtils);
return this.global.GM_xmlhttpRequest ? UserScriptEngine.GM : this.tornPDAUtils.isPDA()
? UserScriptEngine.PDA : UserScriptEngine.RAW;
}
// /** // /**
// * 返回玩家信息的对象 { playername: string, userID: number } // * 返回玩家信息的对象 { playername: string, userID: number }
// * @return {PlayerInfo} rs // * @return {PlayerInfo} rs
@ -175,27 +147,26 @@ export default class CommonUtils {
* @returns {Promise<HTMLElement|null>} * @returns {Promise<HTMLElement|null>}
*/ */
public static elementReady(selectors: string, content: Document = document, timeout: number = 30000): Promise<HTMLElement> { public static elementReady(selectors: string, content: Document = document, timeout: number = 30000): Promise<HTMLElement> {
const logger = Container.factory(Logger); Log.info('等待元素:' + selectors);
logger.info('等待元素:' + selectors);
let timer = new Timer(); let timer = new Timer();
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let el = content.querySelector(selectors) as HTMLElement; let el = content.querySelector(selectors) as HTMLElement;
if (el) { if (el) {
logger.info('已获取元素, 耗时' + timer.getTimeMs(), el); Log.info('已获取元素, 耗时' + timer.getTimeMs(), el);
resolve(el); resolve(el);
return; return;
} }
let observer = new MutationObserver((_, observer) => { let observer = new MutationObserver((_, observer) => {
content.querySelectorAll(selectors).forEach((element) => { content.querySelectorAll(selectors).forEach((element) => {
logger.info({ innerHTML: element.innerHTML, element }); Log.info({ innerHTML: element.innerHTML, element });
observer.disconnect(); observer.disconnect();
logger.info('已获取元素, 耗时' + timer.getTimeMs(), element); Log.info('已获取元素, 耗时' + timer.getTimeMs(), element);
resolve(element as HTMLElement); resolve(element as HTMLElement);
}); });
}); });
window.setTimeout(() => { setTimeout(() => {
observer.disconnect(); observer.disconnect();
logger.error(`等待元素超时! [${ selectors }]\n${ content.documentElement.tagName }, 耗时` + timer.getTimeMs()); Log.error(`等待元素超时! [${ selectors }]\n${ content.documentElement.tagName }, 耗时` + timer.getTimeMs());
reject(`等待元素超时! [${ selectors }]\n${ content.documentElement.tagName }, 耗时` + timer.getTimeMs()); reject(`等待元素超时! [${ selectors }]\n${ content.documentElement.tagName }, 耗时` + timer.getTimeMs());
}, timeout); }, timeout);
observer.observe(content.documentElement, { childList: true, subtree: true }); observer.observe(content.documentElement, { childList: true, subtree: true });
@ -212,12 +183,7 @@ export default class CommonUtils {
return CommonUtils.elementReady(selectors, content, timeout); return CommonUtils.elementReady(selectors, content, timeout);
} }
public querySelector(selectors: string, content: Document = document, timeout: number = 30000): Promise<HTMLElement> {
return CommonUtils.elementReady(selectors, content, timeout);
}
public static addStyle(rules: string): void { public static addStyle(rules: string): void {
const logger = Container.factory(Logger);
let element = document.querySelector('style#wh-trans-gStyle'); let element = document.querySelector('style#wh-trans-gStyle');
if (element) { if (element) {
element.innerHTML += rules; element.innerHTML += rules;
@ -227,14 +193,7 @@ export default class CommonUtils {
element.innerHTML = rules; element.innerHTML = rules;
document.head.appendChild(element); document.head.appendChild(element);
} }
logger.info('CSS规则已添加', element); Log.info('CSS规则已添加', element);
}
public styleInject(rules: string): void {
const element = document.createElement("style");
element.setAttribute('type', 'text/css');
element.innerHTML = rules;
document.head.appendChild(element);
} }
public static loading_gif_html(): string { public static loading_gif_html(): string {
@ -246,19 +205,12 @@ export default class CommonUtils {
* @param {string} url URL * @param {string} url URL
* @returns {undefined} * @returns {undefined}
*/ */
public audioPlay(url: string = 'https://www.torn.com/js/chat/sounds/Warble_1.mp3'): Promise<void> { public audioPlay(url: string = 'https://www.torn.com/js/chat/sounds/Warble_1.mp3') {
return new Promise((resolve, reject) => {
const audio = new Audio(url); const audio = new Audio(url);
audio.addEventListener("canplaythrough", () => { audio.addEventListener("canplaythrough", () => {
audio.play() audio.play()
.catch(err => { .catch(err => Log.error(err))
this.logger.error('播放音频出错', err.message, err.stack); .then();
reject();
})
.then(
() => resolve()
);
});
}); });
} }
@ -276,11 +228,11 @@ export default class CommonUtils {
} }
public jQueryReady(): Promise<null> { public jQueryReady(): Promise<null> {
this.logger.info('等待jQuery加载中...'); Log.info('等待jQuery加载中...');
this.fetchUtils.fetchText('/js/script/lib/jquery-1.8.2.js?v=f9128651g') FetchUtils.getInstance().fetchText('/js/script/lib/jquery-1.8.2.js?v=f9128651g')
.then(res => window.eval(res)); .then(res => window.eval(res));
let intervalId = window.setInterval(() => { let intervalId = window.setInterval(() => {
this.logger.info('仍在等待jQuery加载中...'); Log.info('仍在等待jQuery加载中...');
}, 1000); }, 1000);
return new Promise(async resolve => { return new Promise(async resolve => {
while (true) { while (true) {
@ -288,7 +240,7 @@ export default class CommonUtils {
await this.sleep(100); await this.sleep(100);
} }
window.clearInterval(intervalId); window.clearInterval(intervalId);
this.logger.info('jQuery已加载'); Log.info('jQuery已加载');
resolve(null); resolve(null);
}); });
} }
@ -315,9 +267,9 @@ export default class CommonUtils {
let _input = switcher.getInput(); let _input = switcher.getInput();
switcher.getBase().id = domId; switcher.getBase().id = domId;
(tip) && (switcher.getBase().setAttribute('title', tip)); (tip) && (switcher.getBase().setAttribute('title', tip));
_input.checked = this.localConfigWrapper.config[dictName]; _input.checked = WuhuConfig.get(dictName);
_input.onchange = e => { _input.onchange = e => {
this.localConfigWrapper.config[dictName] = _input.checked; WuhuConfig.set(dictName, _input.checked, true);
if (changeEv) changeEv(e); if (changeEv) changeEv(e);
}; };
new_node.appendChild(switcher.getBase()); new_node.appendChild(switcher.getBase());
@ -348,11 +300,11 @@ export default class CommonUtils {
let option = document.createElement('option'); let option = document.createElement('option');
option.value = domVal; option.value = domVal;
option.innerHTML = domText; option.innerHTML = domText;
option.selected = i === this.localConfigWrapper.config[dictName]; option.selected = i === WuhuConfig.get(dictName);
option.innerHTML = domText; option.innerHTML = domText;
select.appendChild(option); select.appendChild(option);
}); });
select.onchange = e => this.localConfigWrapper.config[dictName] = (<HTMLSelectElement>e.target).selectedIndex; select.onchange = e => WuhuConfig.set(dictName, (<HTMLSelectElement>e.target).selectedIndex);
label.appendChild(text); label.appendChild(text);
label.appendChild(select); label.appendChild(select);
new_node.appendChild(label); new_node.appendChild(label);
@ -388,7 +340,7 @@ export default class CommonUtils {
} }
public getTravelStage(): TRAVEL_STATE { public getTravelStage(): TRAVEL_STATE {
let global = Container.factory(Global); let global = CommonUtils.glob;
if (global.bodyAttrs["data-abroad"] === 'false') { if (global.bodyAttrs["data-abroad"] === 'false') {
return TRAVEL_STATE.IN_TORN; return TRAVEL_STATE.IN_TORN;
} }
@ -401,55 +353,4 @@ export default class CommonUtils {
return TRAVEL_STATE.FLYING; return TRAVEL_STATE.FLYING;
} }
} }
public matchOne(src: string, reg: string | RegExp): string {
let regExp = typeof reg === 'string' ? new RegExp(reg) : reg,
ret = null;
let match = src.match(regExp);
if (match.length > 0) ret = match[0];
return ret;
}
/**
*
*
* `日 时 分 秒`
* @param s
*/
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;
}
/**
* @param key id或物品名
* @param m1 id->name map
* @param m2 name->item map
*/
public getItemByIdOrName(key: string, m1, m2: {
[k: string]: Partial<InventoryItemInfo>
}): Partial<InventoryItemInfo> {
return m1[key] ? m2[m1[key]] : m2[key];
}
} }
export const CommonUtilsKey = Symbol('CommonUtilsKey') as InjectionKey<CommonUtils>;

View File

@ -1,21 +1,19 @@
import DIALOG_MSG_BOX_HTML from "../../../static/html/dialog_msg_box.html"; import Log from "../Log";
import Logger from "../Logger"; import DIALOG_MSG_BOX_HTML from "../../static/html/dialog_msg_box.html";
import { Container } from "../../container/Container";
export default class DialogMsgBox { export default class DialogMsgBox {
private static existed = false; private static existed = false;
private readonly container: HTMLElement; private readonly container: HTMLElement;
constructor(msg: string, opt: DialogMsgBoxOptions, constructor(msg: string, opt: DialogMsgBoxOptions) {
private readonly logger: Logger = Container.factory(Logger)) { Log.info('创建DialogMsgBox', { msg, opt });
logger.info('创建DialogMsgBox', { msg, opt });
let { title = '提示', callback, cancel } = opt; let { title = '提示', callback, cancel } = opt;
if (!callback) { if (!callback) {
logger.error('无callback'); Log.error('无callback');
throw new Error('无callback'); throw new Error('无callback');
} }
if (DialogMsgBox.existed) { if (DialogMsgBox.existed) {
logger.error('无法创建DialogMsgBox已存在'); Log.error('无法创建DialogMsgBox已存在');
throw new Error('无法创建DialogMsgBox已存在'); throw new Error('无法创建DialogMsgBox已存在');
} }
this.container = document.createElement('div'); this.container = document.createElement('div');

View File

@ -1,16 +1,10 @@
import WuhuBase from "../WuhuBase";
import Log from "../Log";
import AjaxFetchOption from "../../interface/AjaxFetchOption"; import AjaxFetchOption from "../../interface/AjaxFetchOption";
import IUserProfileData from "../../interface/IUserProfileData"; import IUserProfileData from "../../interface/IUserProfileData";
import ClassName from "../../container/ClassName";
import { Injectable } from "../../container/Injectable";
import Logger from "../Logger";
@ClassName('FetchUtils') export default class FetchUtils extends WuhuBase {
@Injectable() className = 'FetchUtils';
export default class FetchUtils {
constructor(
private readonly logger: Logger,
) {
}
/** /**
* jquery ajax string * jquery ajax string
@ -32,15 +26,6 @@ export default class FetchUtils {
}); });
} }
/**
* jquery ajax xhr, X-Requested-With: XMLHttpRequest
* return fetch
* @param opt
* @param opt.url
* @param opt.referrer : /
* @param opt.method POST|GET
* @param opt.body ?
*/
public ajaxFetch(opt: AjaxFetchOption) { public ajaxFetch(opt: AjaxFetchOption) {
let { url, referrer = '/', method, body = null } = opt; let { url, referrer = '/', method, body = null } = opt;
let req_params: RequestInit = { let req_params: RequestInit = {
@ -61,7 +46,7 @@ export default class FetchUtils {
.then(res => res.text()) .then(res => res.text())
.then(t => resolve(t)) .then(t => resolve(t))
.catch(err => { .catch(err => {
this.logger.error('fetchText出错了', err); Log.error('fetchText出错了', err);
reject(err); reject(err);
}) })
); );
@ -76,11 +61,11 @@ export default class FetchUtils {
o.json().then((res) => { o.json().then((res) => {
resolve(res); resolve(res);
}).catch(e => { }).catch(e => {
this.logger.error('[ProfileHelper] JSON解析错误: ', e.message, '错误堆栈: ', e.stack); Log.error('[ProfileHelper] JSON解析错误: ', e.message, '错误堆栈: ', e.stack);
reject(e); reject(e);
}); });
}).catch(e => { }).catch(e => {
this.logger.error('[ProfileHelper] 网络错误: ', e.message, '错误堆栈: ', e.stack); Log.error('[ProfileHelper] 网络错误: ', e.message, '错误堆栈: ', e.stack);
reject(e); reject(e);
}); });
}); });

View File

@ -0,0 +1,59 @@
import WuhuBase from "../WuhuBase";
import Alert from "./Alert";
import ISidebarData from "../../interface/ISidebarData";
import Log from "../Log";
import CommonUtils from "./CommonUtils";
import FetchUtils from "./FetchUtils";
export default class InfoUtils extends WuhuBase {
className = 'InfoUtils';
/**
* { playername: string, userID: number }
* @return {PlayerInfo} rs
*/
public getPlayerInfo(): PlayerInfo {
const node = document.querySelector('script[uid]');
if (node) {
return {
playername: node.getAttribute('name'),
userID: parseInt(node.getAttribute('uid')),
}
} else {
new Alert('严重错误:芜湖助手无法获取用户数据,已退出');
throw '芜湖助手无法获取用户数据';
}
}
public async getSessionData(): Promise<ISidebarData> {
let field: string = 'sidebarData' + this.getPlayerInfo().userID;
let ret: ISidebarData = {};
return new Promise(async resolve => {
let c = 0;
while (!sessionStorage.getItem(field) && c < 50) {
c++;
await CommonUtils.getInstance().sleep(10);
}
if (sessionStorage.getItem(field)) {
ret = JSON.parse(sessionStorage.getItem(field));
} else {
Log.info('无法从sessionStorage获取数据')
ret = await (await FetchUtils.getInstance().ajaxFetch({
url: window.addRFC('/sidebarAjaxAction.php?q=getSidebarData'),
method: 'POST',
})).json();
sessionStorage.setItem(field, JSON.stringify(ret));
}
ret.headerData = JSON.parse(sessionStorage.getItem('headerData'));
resolve(ret);
});
}
public async getSidebarData() {
return (await this.getSessionData()).areas;
}
public async getUserState() {
return (await this.getSessionData()).headerData.user.state;
}
}

View File

@ -1,9 +1,7 @@
import ClassName from "../../container/ClassName"; import WuhuBase from "../WuhuBase";
import { Injectable } from "../../container/Injectable";
@ClassName('MDUtils') export default class MDUtils extends WuhuBase {
@Injectable() className = 'MDUtils';
export default class MDUtils {
/** /**
* Markdown * Markdown
* @param {String} from * @param {String} from

View File

@ -1,12 +1,7 @@
import ClassName from "../../container/ClassName"; import WuhuBase from "../WuhuBase";
import { Injectable } from "../../container/Injectable";
import { InjectionKey } from "vue";
@ClassName('MathUtils') export default class MathUtils extends WuhuBase {
@Injectable()
export default class MathUtils {
className = 'MathUtils'; className = 'MathUtils';
// 得到一个两数之间的随机整数 // 得到一个两数之间的随机整数
public getRandomInt(min: number, max: number): number { public getRandomInt(min: number, max: number): number {
min = Math.ceil(min); min = Math.ceil(min);
@ -15,5 +10,3 @@ export default class MathUtils {
return Math.floor(Math.random() * (max - min)) + min; return Math.floor(Math.random() * (max - min)) + min;
} }
} }
export const MathUtilsKey = Symbol('MathUtilsKey') as InjectionKey<MathUtils>

View File

@ -0,0 +1,45 @@
import IWHNotify from "../../interface/IWHNotify";
import Log from "../Log";
import WuhuBase from "../WuhuBase";
export default class NotificationUtils extends WuhuBase {
className = 'NotificationUtils';
private permission: boolean = window.Notification && window.Notification.permission === 'granted';
public push(msg: string, options: IWHNotify = {}): void {
let { notifies } = NotificationUtils.glob;
if (options.sysNotify && this.permission) {
let tmpNode = document.createElement('p');
tmpNode.innerHTML = msg;
let notify = new Notification('芜湖助手', {
body: Log.getTime() + '\r\n' + tmpNode.innerText,
// requireInteraction: true,
// renotify: true,
// tag: '芜湖助手' + Utils.getRandomInt(0, 99),
});
let id = notifies.count++;
notifies[id] = notify;
notify.addEventListener(
'close',
() => {
notifies[id] = null;
}
);
notify.addEventListener(
'click',
() => {
options.sysNotifyClick ? options.sysNotifyClick() : null;
window.focus();
}
);
notify.addEventListener(
'show',
() => {
// setTimeout(() => notify.close(), (options.timeout || 3) * 1000);
Log.info('通知id: ', id)
}
);
}
}
}

54
src/class/utils/Popup.ts Normal file
View File

@ -0,0 +1,54 @@
import WuhuBase from "../WuhuBase";
import POPUP_HTML from "../../static/html/popup.html";
import Log from "../Log";
export default class Popup extends WuhuBase {
className = 'Popup';
private readonly container: HTMLElement = null;
private readonly node: HTMLElement = null;
constructor(innerHTML: string, title: string = '芜湖助手') {
super();
if (Popup.glob.popup_node) {
Log.info('关闭前一个弹窗');
Popup.glob.popup_node.close();
}
Log.info('新建弹窗', { innerHTML, title });
const popup = document.createElement('div');
popup.id = 'wh-popup';
popup.innerHTML = POPUP_HTML.replace('{{}}', title).replace('{{}}', innerHTML);
document.body.append(popup);
popup.addEventListener('click', e => {
e.stopImmediatePropagation();
if (e.target === popup) this.close();
});
this.container = popup;
this.node = popup.querySelector('#wh-popup-cont');
this.hideChat();
Popup.glob.popup_node = this;
}
public close() {
this.container.remove();
this.showChat();
}
/**
* @return {HTMLElement} id=wh-popup-cont
*/
public getElement(): HTMLElement {
return this.node;
}
private hideChat() {
document.querySelector('#chatRoot').classList.add('wh-hide');
}
private showChat() {
document.querySelector('#chatRoot').classList.remove('wh-hide');
}
// 禁止单例调用
private getInstance() {
}
}

View File

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

View File

@ -1,16 +1,12 @@
import Log from "../Log"; import Log from "../Log";
import MathUtils from "./MathUtils"; import MathUtils from "./MathUtils";
import { Container } from "../../container/Container";
export default class TornStyleBlock { export default class TornStyleBlock {
private readonly baseElement: HTMLElement; private readonly baseElement: HTMLElement;
private readonly headElement: HTMLElement; private readonly headElement: HTMLElement;
private readonly elem: HTMLElement; private readonly elem: HTMLElement;
public constructor( public constructor(title: string) {
private readonly title: string,
private readonly mathUtils: MathUtils = Container.factory(MathUtils),
) {
this.baseElement = document.createElement('div'); this.baseElement = document.createElement('div');
this.headElement = document.createElement('div'); this.headElement = document.createElement('div');
this.elem = document.createElement('div'); this.elem = document.createElement('div');
@ -23,7 +19,7 @@ export default class TornStyleBlock {
// hr.classList.add('delimiter-999', 'm-top10', 'm-bottom10'); // hr.classList.add('delimiter-999', 'm-top10', 'm-bottom10');
this.baseElement.append(this.headElement, this.elem); this.baseElement.append(this.headElement, this.elem);
this.baseElement.id = 'WHTornStyleBlock' + mathUtils.getRandomInt(0, 100); this.baseElement.id = 'WHTornStyleBlock' + MathUtils.getInstance().getRandomInt(0, 100);
this.baseElement.insertAdjacentHTML('beforeend', '<hr class="delimiter-999 m-top10 m-bottom10" />'); this.baseElement.insertAdjacentHTML('beforeend', '<hr class="delimiter-999 m-top10 m-bottom10" />');
} }

View File

@ -1,17 +1,12 @@
import MathUtils from "./MathUtils"; import MathUtils from "./MathUtils";
import { Container } from "../../container/Container";
export default class TornStyleSwitch { export default class TornStyleSwitch {
private readonly baseElement; private readonly baseElement;
private readonly randomId; private readonly randomId;
private readonly input; private readonly input;
constructor( constructor(label: string, checked: boolean = false) {
private readonly label: string, this.randomId = MathUtils.getInstance().getRandomInt(100, 2000);
private readonly checked: boolean = false,
private readonly mathUtils: MathUtils = Container.factory(MathUtils),
) {
this.randomId = mathUtils.getRandomInt(100, 2000);
this.baseElement = document.createElement('span'); this.baseElement = document.createElement('span');
this.baseElement.id = 'WHSwitch' + this.randomId; this.baseElement.id = 'WHSwitch' + this.randomId;
this.baseElement.innerHTML = `<input class="checkbox-css" type="checkbox" id="WHCheck${ this.randomId }" ${ checked ? 'checked' : '' }/> this.baseElement.innerHTML = `<input class="checkbox-css" type="checkbox" id="WHCheck${ this.randomId }" ${ checked ? 'checked' : '' }/>

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,7 @@
import Popup from "../../class/utils/Popup"; import Popup from "../../class/utils/Popup";
import { Container } from "../../container/Container";
import Logger from "../../class/Logger";
// 传单助手 // 传单助手
export default function adHelper() { export default function adHelper() {
Container.factory(Logger).error('adHelper')
let popup = new Popup('', '传单助手').getElement(); let popup = new Popup('', '传单助手').getElement();
document.querySelector('#chatRoot').classList.remove('wh-hide'); document.querySelector('#chatRoot').classList.remove('wh-hide');
let info = document.createElement('p'); let info = document.createElement('p');

View File

@ -1,26 +1,22 @@
import WT_HTML from "../../../static/html/xmasTown/wt.html"; import WuhuConfig from "../../class/WuhuConfig";
import WT_XMAS_TOWN_HTML from "../../../static/html/xmasTown/wt_xmas_town.html"; import WT_HTML from "../../static/html/xmasTown/wt.html";
import WT_MALTESE_SNOW_GLOBE_HTML from "../../../static/html/xmasTown/wt_maltese_snow_globe.html"; import WT_XMAS_TOWN_HTML from "../../static/html/xmasTown/wt_xmas_town.html";
import WT_LONG_WAY_FROM_HOME_HTML from "../../../static/html/xmasTown/wt_long_way_from_home.html"; import WT_MALTESE_SNOW_GLOBE_HTML from "../../static/html/xmasTown/wt_maltese_snow_globe.html";
import WT_CHEDBURN_TOWERS_HTML from "../../../static/html/xmasTown/wt_chedburn_towers.html"; import WT_LONG_WAY_FROM_HOME_HTML from "../../static/html/xmasTown/wt_long_way_from_home.html";
import WT_KIDNAPPED_SANTA_HTML from "../../../static/html/xmasTown/wt_kidnapped_santa.html"; import WT_CHEDBURN_TOWERS_HTML from "../../static/html/xmasTown/wt_chedburn_towers.html";
import WT_HOLIDAY_TERROR_HTML from "../../../static/html/xmasTown/wt_holiday_terror.html"; import WT_KIDNAPPED_SANTA_HTML from "../../static/html/xmasTown/wt_kidnapped_santa.html";
import WT_AMONG_US_HTML from "../../../static/html/xmasTown/wt_among_us.html"; import WT_HOLIDAY_TERROR_HTML from "../../static/html/xmasTown/wt_holiday_terror.html";
import WT_KISS_MY_FESTIVUS_HTML from "../../../static/html/xmasTown/wt_kiss_my_festivus.html"; import WT_AMONG_US_HTML from "../../static/html/xmasTown/wt_among_us.html";
import WT_STANLEY_HOTEL_HTML from "../../../static/html/xmasTown/wt_stanley_hotel.html"; import WT_KISS_MY_FESTIVUS_HTML from "../../static/html/xmasTown/wt_kiss_my_festivus.html";
import WT_DOGGOQUEST_HTML from "../../../static/html/xmasTown/wt_doggoQuest.html"; import WT_STANLEY_HOTEL_HTML from "../../static/html/xmasTown/wt_stanley_hotel.html";
import WT_POKEMON_CT_HTML from "../../../static/html/xmasTown/wt_pokemon_ct.html"; import WT_DOGGOQUEST_HTML from "../../static/html/xmasTown/wt_doggoQuest.html";
import WT_WINTER_IN_GATLIN_HTML from "../../../static/html/xmasTown/wt_winter_in_gatlin.html"; import WT_POKEMON_CT_HTML from "../../static/html/xmasTown/wt_pokemon_ct.html";
import XMAS_TOWN_NOTIFY_HTML from "../../../static/html/xmasTown/xmas_town_notify.html"; import WT_WINTER_IN_GATLIN_HTML from "../../static/html/xmasTown/wt_winter_in_gatlin.html";
import { Container } from "../../container/Container"; import XMAS_TOWN_NOTIFY_HTML from "../../static/html/xmasTown/xmas_town_notify.html";
import LocalConfigWrapper from "../../class/LocalConfigWrapper";
export default function christmasTownHelper() { export default function christmasTownHelper() {
const localConfigWrapper = Container.factory(LocalConfigWrapper);
let $root = document.querySelector('#christmastownroot'); let $root = document.querySelector('#christmastownroot');
const xmasTownWT = localConfigWrapper.config.xmasTownWT; const [xmasTownWT, xmasTownNotify] = WuhuConfig.get(['xmasTownWT', 'xmasTownNotify']);
const xmasTownNotify = localConfigWrapper.config.xmasTownNotify;
// 解密攻略 // 解密攻略
if (xmasTownWT) { if (xmasTownWT) {
const insert_html = WT_HTML; const insert_html = WT_HTML;
@ -257,7 +253,7 @@ export default function christmasTownHelper() {
const now = new Date(); const now = new Date();
dropHist[hist_key] = { dropHist[hist_key] = {
pos: `[${ nearby_item.x },${ nearby_item.y }]`, pos: `[${ nearby_item.x },${ nearby_item.y }]`,
data: $ct_title.firstChild.nodeValue.trim(), map: $ct_title.firstChild.nodeValue.trim(),
last: `${ now.getFullYear() }-${ now.getMonth() + 1 }-${ now.getDate() } ${ now.getHours() }:${ now.getMinutes() }:${ now.getSeconds() }`, last: `${ now.getFullYear() }-${ now.getMonth() + 1 }-${ now.getDate() } ${ now.getHours() }:${ now.getMinutes() }:${ now.getSeconds() }`,
name: item_name, name: item_name,
id: Object.keys(dropHist).length, id: Object.keys(dropHist).length,
@ -280,7 +276,7 @@ export default function christmasTownHelper() {
const history = Object.keys(dropHist).map(key => dropHist[key]).sort((a, b) => a.id - b.id); const history = Object.keys(dropHist).map(key => dropHist[key]).sort((a, b) => a.id - b.id);
let table_html = ''; let table_html = '';
history.forEach(e => { history.forEach(e => {
table_html += `<tr><td>${ e.pos }</td><td>${ e.map ?? e.data }</td><td>${ e.name }</td><td>${ e.last }</td><td>${ e.isPassed ? '已取得' : '不确定' }</td></tr>`; table_html += `<tr><td>${ e.pos }</td><td>${ e.map }</td><td>${ e.name }</td><td>${ e.last }</td><td>${ e.isPassed ? '已取得' : '不确定' }</td></tr>`;
}); });
$tbody.innerHTML = table_html; $tbody.innerHTML = table_html;
localStorage.setItem('wh-loot-store', JSON.stringify(dropHist)); localStorage.setItem('wh-loot-store', JSON.stringify(dropHist));

View File

@ -0,0 +1,99 @@
import toThousands from "../utils/toThousands";
import CommonUtils from "../../class/utils/CommonUtils";
import Log from "../../class/Log";
import CITY_FINDER_CSS from "../../static/css/city_finder.css";
import TornStyleBlock from "../../class/utils/TornStyleBlock";
export default function cityFinder(): void {
CommonUtils.addStyle(CITY_FINDER_CSS);
// 物品名与价格
let items = null;
// const base = document.createElement('div');
// base.id = 'wh-city-finder';
// const container = document.createElement('div');
// container.id = 'wh-city-finder-cont';
// const header = document.createElement('div');
// header.id = 'wh-city-finder-header';
// header.innerHTML = '捡垃圾助手';
const info = document.createElement('div');
info.innerHTML = '已找到物品:';
// container.append(info);
// base.append(header);
// base.append(container);
let _base = new TornStyleBlock('捡垃圾助手').insert2Dom().append(info);
document.body.classList.add('wh-city-finds');
CommonUtils.COFetch('https://jjins.github.io/item_price_raw.json')
.then(r => items = JSON.parse(r))
.catch(err => {
Log.error(err);
items = undefined
});
CommonUtils.elementReady('div.leaflet-marker-pane').then(elem => {
// document.querySelector('.content-wrapper').prepend(base);
// 发现的物品id与map img node
const founds = [];
elem.querySelectorAll('img.map-user-item-icon').forEach(node => {
const item_id = node.src.split('/')[5];
const finder_item = document.createElement('span');
finder_item.id = 'wh-city-finder-item' + item_id;
finder_item.innerHTML = item_id;
founds.push({ 'id': item_id, 'node': finder_item, 'map_item': node });
// container.append(finder_item);
_base.append(finder_item);
});
// 未发现物品 返回
if (founds.length === 0) {
info.innerHTML = '空空如也,请大佬明天再来';
return;
}
// 将id显示为物品名与价格的函数
const displayNamePrice = () => {
// 总价
let total = 0;
founds.forEach(el => {
const value = items[el.id]['price'];
el.node.innerHTML = `<img src="${ el.map_item.src }" alt="" />${ items[el.id]['name'] } ($${ toThousands(value) })`;
// 灰色 100k以下
if (value < 100000) el.node.style.backgroundColor = '#9e9e9e';
// 绿色 1m以下
else if (value < 1000000) el.node.style.backgroundColor = '#4caf50';
// 蓝色 25m以下
else if (value < 25000000) el.node.style.backgroundColor = '#03a9f4';
// 橙色 449m以下
else if (value < 449000000) el.node.style.backgroundColor = '#ffc107';
// 红色 >449m
else if (value >= 449000000) el.node.style.backgroundColor = '#f44336';
total += items[el.id]['price'];
});
// header.innerHTML = `捡垃圾助手 - ${ founds.length } 个物品,总价值 $${ toThousands(total) }`;
_base.setTitle(`捡垃圾助手 - ${ founds.length } 个物品,总价值 $${ toThousands(total) }`);
};
// 未取到数据时添加循环来调用函数
if (items === null) {
// 15s超时
let timeout = 30;
const interval = window.setInterval(() => {
timeout--;
if (items !== null) {
displayNamePrice();
window.clearInterval(interval);
}
if (0 === timeout) {
Log.info('获取物品名称与价格信息超时')
window.clearInterval(interval)
}
}, 500);
}
// 无法跨域获取数据时
else if (items === undefined) {
info.innerHTML += '(当前平台暂不支持查询价格)';
}
// 调用函数
else {
displayNamePrice();
}
})
}

View File

@ -1,36 +1,31 @@
import WuhuBase from "../../class/WuhuBase";
import CommonUtils from "../../class/utils/CommonUtils"; import CommonUtils from "../../class/utils/CommonUtils";
import Log from "../../class/Log";
import Alert from "../../class/utils/Alert"; import Alert from "../../class/utils/Alert";
import ActionButtonUtils from "../../class/utils/ActionButtonUtils"; import ActionButtonUtils from "../../class/utils/ActionButtonUtils";
import WuhuConfig from "../../class/WuhuConfig";
import FetchUtils from "../../class/utils/FetchUtils"; import FetchUtils from "../../class/utils/FetchUtils";
import DEPO_CSS from "../../../static/css/depo.module.css"; import DEPO_CSS from "../../static/css/depo.css";
import TornStyleBlock from "../../class/utils/TornStyleBlock"; import TornStyleBlock from "../../class/utils/TornStyleBlock";
import { Container } from "../../container/Container";
import LocalConfigWrapper from "../../class/LocalConfigWrapper";
import Logger from "../../class/Logger";
const fetchUtils = Container.factory(FetchUtils);
export default function depoHelper() { export default function depoHelper() {
let logger: Logger = Container.factory(Logger); let actionButtonUtils: ActionButtonUtils = ActionButtonUtils.getInstance();
let actionButtonUtils: ActionButtonUtils = Container.factory(ActionButtonUtils); let { href } = WuhuBase.glob;
let localConfigWrapper: LocalConfigWrapper = Container.factory(LocalConfigWrapper);
let commonUtils: CommonUtils = Container.factory(CommonUtils);
let href = window.location.href;
let channel: 'CMPY' | 'FAC'; let channel: 'CMPY' | 'FAC';
const selector = { 'CMPY': "div#funds div.deposit", 'FAC': "div#armoury-donate div.cash" }; const selector = { 'CMPY': "div#funds div.deposit", 'FAC': "div#armoury-donate div.cash" };
// 公司 // 公司
if (href.includes('companies.php')) { if (href.includes('companies.php')) {
channel = "CMPY"; channel = "CMPY";
// 公司转跳存钱 // 公司转跳存钱
if (!href.includes('funds') && localConfigWrapper.config.companyRedirect) { if (!href.includes('funds') && WuhuConfig.get('companyRedirect')) {
const btn = document.getElementById('ui-id-9'); const btn = document.getElementById('ui-id-9');
if (btn) { if (btn) {
btn.click(); btn.click();
logger.info('已自动打开存钱页面'); Log.info('已自动打开存钱页面');
} }
} }
// 收起冰蛙表格 // 收起冰蛙表格
if (localConfigWrapper.config.companyBWCollapse) { if (WuhuConfig.get('companyBWCollapse')) {
CommonUtils.elementReady('#effectiveness-wrap').then(BWTable_node => { CommonUtils.elementReady('#effectiveness-wrap').then(BWTable_node => {
document.body.classList.add('wh-bwtable-ctrl'); document.body.classList.add('wh-bwtable-ctrl');
CommonUtils.addStyle(`.wh-bwtable-ctrl #effectiveness-wrap {display:none !important;}`); CommonUtils.addStyle(`.wh-bwtable-ctrl #effectiveness-wrap {display:none !important;}`);
@ -53,9 +48,9 @@ export default function depoHelper() {
actionButtonUtils.add('一键存钱', factionDeposit); actionButtonUtils.add('一键存钱', factionDeposit);
} }
// 存钱框浮动 // 存钱框浮动
if (localConfigWrapper.config.floatDepo && channel) { if (WuhuConfig.get('floatDepo') && channel) {
document.body.classList.add('wh-depo-helper'); document.body.classList.add('wh-depo-helper');
commonUtils.styleInject(DEPO_CSS); CommonUtils.addStyle(DEPO_CSS);
CommonUtils.elementReady(selector[channel]).then(node => { CommonUtils.elementReady(selector[channel]).then(node => {
const close_btn = document.createElement('button'); const close_btn = document.createElement('button');
close_btn.addEventListener('click', () => { close_btn.addEventListener('click', () => {
@ -81,20 +76,20 @@ export default function depoHelper() {
} }
return; return;
} }
logger.info('已添加GT助手'); Log.info('已添加GT助手');
// 获取交易id // 获取交易id
let query_params = location.hash.slice(1); let query_params = location.hash.slice(1);
let traceId = id; let traceId = id;
if (!traceId) query_params.split('&').forEach(param => if (!traceId) query_params.split('&').forEach(param =>
(param.startsWith('ID=')) && (traceId = param.slice(3)) (param.startsWith('ID=')) && (traceId = param.slice(3))
); );
logger.info('交易id为', traceId); Log.info('交易id为', traceId);
// 获取全部的钱数 // 获取全部的钱数
let getTraceMoney = async () => { let getTraceMoney = async () => {
if (typeof addRFC === 'function') { if (typeof addRFC === 'function') {
let url = addRFC('/trade.php?step=getFullMoney&ID=' + traceId); let url = addRFC('/trade.php?step=getFullMoney&ID=' + traceId);
return (await fetchUtils.ajaxFetch({ return (await FetchUtils.getInstance().ajaxFetch({
url: url, url: url,
method: 'GET', method: 'GET',
referrer: 'trade.php' referrer: 'trade.php'
@ -102,7 +97,7 @@ export default function depoHelper() {
} }
}; };
// 监听jquery ajax请求 // 监听jquery ajax请求
if (logger.debug()) $(document).ajaxComplete((_, xhr, settings) => logger.info({ xhr, settings })); if (Log.debug()) $(document).ajaxComplete((_, xhr, settings) => Log.info({ xhr, settings }));
// react 加载完成后将节点加入视图中 // react 加载完成后将节点加入视图中
CommonUtils.elementReady('#trade-container').then(() => CommonUtils.elementReady('#trade-container').then(() =>
document.querySelector('#trade-container').before(_node.getBase()) document.querySelector('#trade-container').before(_node.getBase())
@ -157,7 +152,7 @@ export default function depoHelper() {
new Alert('无法定额取钱,原因:数不对'); new Alert('无法定额取钱,原因:数不对');
return; return;
} }
await fetchUtils.ajaxFetch({ await FetchUtils.getInstance().ajaxFetch({
url: addRFC('/trade.php'), url: addRFC('/trade.php'),
method: 'POST', method: 'POST',
referrer: 'trade.php', referrer: 'trade.php',
@ -169,7 +164,7 @@ export default function depoHelper() {
buttonDepositAll.addEventListener('click', async () => { buttonDepositAll.addEventListener('click', async () => {
let money = await getTraceMoney(); let money = await getTraceMoney();
if (money === '0') return; if (money === '0') return;
await fetchUtils.ajaxFetch({ await FetchUtils.getInstance().ajaxFetch({
url: addRFC('/trade.php'), url: addRFC('/trade.php'),
method: 'POST', method: 'POST',
referrer: 'trade.php', referrer: 'trade.php',
@ -179,7 +174,7 @@ export default function depoHelper() {
}); });
// 全取 // 全取
buttonWithdrawAll.addEventListener('click', async () => { buttonWithdrawAll.addEventListener('click', async () => {
await fetchUtils.ajaxFetch({ await FetchUtils.getInstance().ajaxFetch({
url: addRFC('/trade.php'), url: addRFC('/trade.php'),
method: 'POST', method: 'POST',
referrer: 'trade.php', referrer: 'trade.php',
@ -198,20 +193,20 @@ export default function depoHelper() {
} else { } else {
if (node_link) node_link.remove(); if (node_link) node_link.remove();
node_link = null; node_link = null;
logger.info('已移除GT助手'); Log.info('已移除GT助手');
} }
}); });
} }
// 任何位置公司一键存钱 // 任何位置公司一键存钱
if (localConfigWrapper.config.companyDepositAnywhere) { if (WuhuConfig.get('companyDepositAnywhere')) {
actionButtonUtils.add('公司存钱', () => companyDepositAnywhere()); actionButtonUtils.add('公司存钱', companyDepositAnywhere);
} }
} }
// 公司一键存钱 // 公司一键存钱
async function companyDeposit() { async function companyDeposit() {
// let fetchUtils: FetchUtils = FetchUtils.getInstance(); let fetchUtils: FetchUtils = FetchUtils.getInstance();
if (!location.href.contains('option=funds')) { if (!location.href.contains('option=funds')) {
new Alert('请先打开公司金库'); new Alert('请先打开公司金库');
return; return;
@ -233,7 +228,7 @@ async function companyDeposit() {
// 帮派一键存钱 // 帮派一键存钱
async function factionDeposit() { async function factionDeposit() {
// let fetchUtils: FetchUtils = FetchUtils.getInstance(); let fetchUtils: FetchUtils = FetchUtils.getInstance();
let form = document.querySelector('#armoury-donate form'); let form = document.querySelector('#armoury-donate form');
if (!location.hash.includes('tab=armoury') || !form) { if (!location.hash.includes('tab=armoury') || !form) {
new Alert('请先打开金库'); new Alert('请先打开金库');
@ -263,7 +258,7 @@ async function factionDeposit() {
// 所有页面公司一键存钱 // 所有页面公司一键存钱
async function companyDepositAnywhere() { async function companyDepositAnywhere() {
const logger: Logger = Container.factory(Logger); let fetchUtils: FetchUtils = FetchUtils.getInstance();
let { addRFC } = window; let { addRFC } = window;
if (typeof addRFC !== 'function') return; if (typeof addRFC !== 'function') return;
let url = addRFC('https://www.torn.com/inputMoneyAction.php?step=generalAction'); let url = addRFC('https://www.torn.com/inputMoneyAction.php?step=generalAction');
@ -275,7 +270,7 @@ async function companyDepositAnywhere() {
body: 'deposit=' + money, body: 'deposit=' + money,
headers: { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/x-www-form-urlencoded' } headers: { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/x-www-form-urlencoded' }
})).text(); })).text();
logger.info(res); Log.info(res);
let node = document.createElement('div'); let node = document.createElement('div');
node.innerHTML = res; node.innerHTML = res;
let success = node.querySelector('.success-message'); let success = node.querySelector('.success-message');

View File

@ -1,11 +1,8 @@
import WuhuConfig from "../../class/WuhuConfig";
import Popup from "../../class/utils/Popup"; import Popup from "../../class/utils/Popup";
import LocalConfigWrapper from "../../class/LocalConfigWrapper";
import { Container } from "../../container/Container";
// 落地转跳设置 // 落地转跳设置
export default function landedRedirect() { export default function landedRedirect() {
let localConfigWrapper: LocalConfigWrapper = Container.factory(LocalConfigWrapper);
let p = document.createElement('p'); let p = document.createElement('p');
let input = document.createElement('input'); let input = document.createElement('input');
let buttonSave = document.createElement('button'); let buttonSave = document.createElement('button');
@ -16,7 +13,7 @@ export default function landedRedirect() {
p.innerHTML = '飞机落地后转跳的页面,关闭功能请置空:'; p.innerHTML = '飞机落地后转跳的页面,关闭功能请置空:';
input.placeholder = 'URL'; input.placeholder = 'URL';
input.value = localConfigWrapper.config.landedRedirect ?? ''; input.value = WuhuConfig.get('landedRedirect') || '';
input.style.display = 'block'; input.style.display = 'block';
input.style.textAlign = 'left'; input.style.textAlign = 'left';
input.style.width = '100%'; input.style.width = '100%';
@ -27,7 +24,7 @@ export default function landedRedirect() {
buttonFct.innerHTML = '填入帮派金库金库'; buttonFct.innerHTML = '填入帮派金库金库';
buttonTest.innerHTML = '测试链接'; buttonTest.innerHTML = '测试链接';
buttonSave.addEventListener('click', () => localConfigWrapper.config.landedRedirect = input.value); buttonSave.addEventListener('click', () => WuhuConfig.set('landedRedirect', input.value, true));
buttonCmp.addEventListener('click', () => input.value = 'https://www.torn.com/companies.php#/option=funds'); buttonCmp.addEventListener('click', () => input.value = 'https://www.torn.com/companies.php#/option=funds');
buttonFct.addEventListener('click', () => input.value = 'https://www.torn.com/factions.php?step=your#/tab=armoury'); buttonFct.addEventListener('click', () => input.value = 'https://www.torn.com/factions.php?step=your#/tab=armoury');
buttonTest.addEventListener('click', () => window.open(input.value)); buttonTest.addEventListener('click', () => window.open(input.value));

119
src/func/module/loadGS.ts Normal file
View File

@ -0,0 +1,119 @@
import UserScriptEngine from "../../enum/UserScriptEngine";
import addStyle from "../utils/@deprecated/addStyle";
import log from "../utils/@deprecated/log";
import CommonUtils from "../../class/utils/CommonUtils";
import Alert from "../../class/utils/Alert";
// gs loader
export default function loadGS(use) {
if (use === UserScriptEngine.PDA) {
let ifr: HTMLIFrameElement = document.querySelector('#wh-gs-loader-ifr');
if (ifr) {
new Alert('飞贼小助手已经加载了');
return;
}
const container = document.createElement('div');
container.id = 'wh-gs-loader';
ifr = document.createElement('iframe');
ifr.id = 'wh-gs-loader-ifr';
ifr.src = 'https://www.torn.com/crimes.php';
container.append(ifr);
document.body.append(container);
addStyle(`
#wh-gs-loader {
position:fixed;
top:0;
left:0;
z-index:100001;
}
`);
let notify = new Alert('加载中');
ifr.onload = () => {
notify.close();
const _window = ifr.contentWindow;
const _docu = _window.document;
_docu.head.innerHTML = '';
_docu.body.innerHTML = '';
notify = new Alert('加载依赖');
CommonUtils.COFetch('https://cdn.staticfile.org/vue/2.2.2/vue.min.js')
.then(vuejs => {
notify.close();
_window.eval(vuejs);
_window.GM_getValue = (k, v = undefined) => {
const objV = JSON.parse(_window.localStorage.getItem('wh-gs-storage') || '{}')[k];
return objV || v;
};
_window.GM_setValue = (k, v) => {
const obj = JSON.parse(_window.localStorage.getItem('wh-gs-storage') || '{}');
obj[k] = v;
_window.localStorage.setItem('wh-gs-storage', JSON.stringify(obj));
};
_window.GM_xmlhttpRequest = function (opt) {
// 暂不适配pda post
if (opt.method.toLowerCase() === 'post') return;
CommonUtils.COFetch(opt.url).then(res => {
const obj = {
responseText: res
};
opt.onload(obj);
});
};
notify = new Alert('加载飞贼小助手');
CommonUtils.COFetch(`https://gitee.com/ameto_kasao/tornjs/raw/master/GoldenSnitch.js?${ performance.now() }`)
.then(res => {
_window.eval(res.replace('http://222.160.142.50:8154/mugger', `https://api.ljs-lyt.com/mugger`));
_window.GM_setValue("gsp_x", 10);
_window.GM_setValue("gsp_y", 10);
notify.close();
notify = new Alert('飞贼小助手已加载', { timeout: 1 });
const gsp: HTMLElement = _docu.querySelector('#gsp');
const thisRun = () => {
ifr.style.height = `${ gsp.offsetHeight + 10 }px`;
ifr.style.width = `${ gsp.offsetWidth + 20 }px`;
gsp.style.top = '10px';
gsp.style.left = '10px';
};
new MutationObserver(thisRun).observe(gsp, { childList: true, subtree: true });
thisRun();
if (log.debug()) _window.GM_setValue("gsp_showContent", true)
});
});
};
return;
}
if (use === UserScriptEngine.GM) {
if (typeof window.Vue !== 'function') {
let notify = new Alert('正在加载依赖');
CommonUtils.COFetch('https://cdn.staticfile.org/vue/2.2.2/vue.min.js')
.then(VueJS => {
window.eval(VueJS);
notify.close();
notify = new Alert('已载入依赖');
window.GM_getValue = (k, v = undefined) => {
const objV = JSON.parse(window.localStorage.getItem('wh-gs-storage') || '{}')[k];
return objV || v;
};
window.GM_setValue = (k, v) => {
const obj = JSON.parse(window.localStorage.getItem('wh-gs-storage') || '{}');
obj[k] = v;
window.localStorage.setItem('wh-gs-storage', JSON.stringify(obj));
};
// TODO
// window.GM_xmlhttpRequest = GM_xmlhttpRequest;
CommonUtils.COFetch(`https://gitee.com/ameto_kasao/tornjs/raw/master/GoldenSnitch.js?${ performance.now() }`)
.then(GSJS => {
window.eval(GSJS);
if (log.debug()) window.GM_setValue("gsp_showContent", true);
notify.close();
notify = new Alert('已载入飞贼助手');
})
.catch(err => new Alert(`PDA API错误。${ JSON.stringify(err) }`));
})
.catch(err => new Alert(JSON.stringify(err)));
} else {
new Alert('飞贼助手已经加载了');
}
return;
}
new Alert('暂不支持');
}

View File

@ -1,16 +1,13 @@
import toThousands from "../utils/toThousands"; import toThousands from "../utils/toThousands";
import Log from "../../class/Log"; import Log from "../../class/Log";
import Alert from "../../class/utils/Alert"; import Alert from "../../class/utils/Alert";
import LocalConfigWrapper from "../../class/LocalConfigWrapper"; import WuhuConfig from "../../class/WuhuConfig";
import { Container } from "../../container/Container";
// 价格监视handle // 价格监视handle
export default function priceWatcherHandle(isPDA: boolean, PDA_APIKey: string) { export default function priceWatcherHandle(isPDA: boolean, PDA_APIKey: string) {
let localConfigWrapper: LocalConfigWrapper = Container.factory(LocalConfigWrapper);
let priceTemp = {}; let priceTemp = {};
let intervalId = window.setInterval(() => { let intervalId = window.setInterval(() => {
const price_conf = localConfigWrapper.config.priceWatcher; const price_conf = WuhuConfig.get('priceWatcher');
const apikey = isPDA ? PDA_APIKey : localStorage.getItem('APIKey'); const apikey = isPDA ? PDA_APIKey : localStorage.getItem('APIKey');
if (!apikey || (price_conf['pt'] === -1 && price_conf['xan'] === -1)) { if (!apikey || (price_conf['pt'] === -1 && price_conf['xan'] === -1)) {
Log.warn('价格监视关闭无apikey或设置未打开'); Log.warn('价格监视关闭无apikey或设置未打开');

View File

@ -1,14 +1,10 @@
import Alert from "../../class/utils/Alert"; import Alert from "../../class/utils/Alert";
import InfoUtils from "../../class/utils/InfoUtils"; import InfoUtils from "../../class/utils/InfoUtils";
import Log from "../../class/Log";
import Popup from "../../class/utils/Popup"; import Popup from "../../class/utils/Popup";
import { Container } from "../../container/Container";
import Logger from "../../class/Logger";
// 守望者 // 守望者
export default function safeKeeper() { export default function safeKeeper() {
let infoUtils = Container.factory(InfoUtils);
let logger = Container.factory(Logger);
let url = `https://www.torn.com/loader.php?sid=attackData&mode=json&step=poll&user2ID=`; let url = `https://www.torn.com/loader.php?sid=attackData&mode=json&step=poll&user2ID=`;
let popup = new Popup('<p>监测目标ID玩家的防御状态找出隐身攻击者</p>', '守望者 (测试中)'); let popup = new Popup('<p>监测目标ID玩家的防御状态找出隐身攻击者</p>', '守望者 (测试中)');
let p = document.createElement('p'); let p = document.createElement('p');
@ -52,13 +48,13 @@ export default function safeKeeper() {
} else new Alert('守望者运行中,请先停止', { timeout: 2 }); } else new Alert('守望者运行中,请先停止', { timeout: 2 });
} }
popup.element.appendChild(p); popup.getElement().appendChild(p);
popup.element.appendChild(uid); popup.getElement().appendChild(uid);
popup.element.appendChild(start); popup.getElement().appendChild(start);
popup.element.appendChild(stop); popup.getElement().appendChild(stop);
popup.element.appendChild(self_target); popup.getElement().appendChild(self_target);
popup.element.appendChild(attackers); popup.getElement().appendChild(attackers);
popup.element.appendChild(records); popup.getElement().appendChild(records);
start.addEventListener('click', () => { start.addEventListener('click', () => {
if (loop_id !== null || !uid.value) return; if (loop_id !== null || !uid.value) return;
@ -76,7 +72,7 @@ export default function safeKeeper() {
})).text(); })).text();
if (loop_id !== that_id) return; if (loop_id !== that_id) return;
let data = JSON.parse(res.split('<div')[0]); let data = JSON.parse(res.split('<div')[0]);
logger.info(count++, data); Log.info(count++, data);
let { DB, currentFightStatistics, histLog } = data; let { DB, currentFightStatistics, histLog } = data;
// 攻击人 // 攻击人
// 格式currentFightStatistics = {uid: {...}, uid2: {...}} // 格式currentFightStatistics = {uid: {...}, uid2: {...}}
@ -122,5 +118,5 @@ export default function safeKeeper() {
loop_id = null; loop_id = null;
p.innerHTML = '状态:已关 ❎'; p.innerHTML = '状态:已关 ❎';
}); });
self_target.addEventListener('click', () => uid.value = (infoUtils.getPlayerInfo()['userID']) + ''); self_target.addEventListener('click', () => uid.value = (InfoUtils.getInstance().getPlayerInfo()['userID']) + '');
} }

View File

@ -0,0 +1,318 @@
import titleTrans from "../translate/titleTrans";
import contentTitleLinksTrans from "../translate/contentTitleLinksTrans";
import Device from "../../enum/Device";
import WuhuBase from "../../class/WuhuBase";
import Alert from "../../class/utils/Alert";
import ActionButtonUtils from "../../class/utils/ActionButtonUtils";
import WuhuConfig from "../../class/WuhuConfig";
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";
import TRAVEL_STATE from "../../enum/TravelState";
export default async function travelHelper(): Promise<void> {
let { href, bodyAttrs, device } = WuhuBase.glob;
if (href.includes('index.php')) {
switch (CommonUtils.getInstance().getTravelStage()) {
// 飞行中
case TRAVEL_STATE.FLYING: {
// 飞行闹钟
if (device === Device.PC && WuhuConfig.get('trvAlarm')) {
// 获取目的地
let dest_cn;
let country = document.body.getAttribute('data-country');
if (country === 'torn') {
dest_cn = '回城';
} else {
dest_cn = {
'uk': "英国",
'switzerland': "瑞士",
'mexico': '墨西哥',
'canada': '加拿大',
'cayman': '开曼',
'hawaii': '夏威夷',
'argentina': '阿根廷',
'japan': '日本',
'china': '中国',
'uae': 'UAE',
'south-africa': '南非',
}[country] || country;
}
// 剩余时间
const remaining_arr = document.querySelector('#countrTravel').getAttribute('data-to');
const wh_trv_alarm = localStorage.getItem('wh_trv_alarm')
? JSON.parse(localStorage.getItem('wh_trv_alarm'))
: { 'enable': true, 'alert_time': 30, 'node_pos': [240, 240] };
const save_trv_settings = () => localStorage.setItem('wh_trv_alarm', JSON.stringify(wh_trv_alarm));
const wh_trv_alarm_node = document.createElement('div');
wh_trv_alarm_node.id = 'wh-trv-alarm';
wh_trv_alarm_node.style.left = `${ wh_trv_alarm.node_pos[0] }px`;
wh_trv_alarm_node.style.top = `${ wh_trv_alarm.node_pos[1] }px`;
wh_trv_alarm_node.innerHTML = TRAVEL_ALARM_HTML
.replace('{{}}', dest_cn === '回城' ? dest_cn : '飞往' + dest_cn)
.replace('{{}}', wh_trv_alarm.enable ? 'checked ' : '')
.replace('{{}}', wh_trv_alarm.alert_time || 30);
CommonUtils.addStyle(TRAVEL_ALARM_CSS);
document.body.append(wh_trv_alarm_node);
// 报错dom
const error_node = wh_trv_alarm_node.querySelector('#wh-trv-error') as HTMLElement;
// jquery拖动
// @ts-ignore
$(wh_trv_alarm_node).draggable({
containment: "body",
distance: 5,
handle: "#wh-trv-alarm-title",
stop: () => {
wh_trv_alarm.node_pos = [parseInt(wh_trv_alarm_node.style.left), parseInt(wh_trv_alarm_node.style.top)];
save_trv_settings();
},
scroll: false,
});
// 剩余时间dom
const remaining_node = wh_trv_alarm_node.querySelector('#wh-trv-alarm-remaining');
// 设定闹钟响的按钮
const set_node = wh_trv_alarm_node.querySelectorAll('#wh-trv-alarm-cont button')[0] as HTMLButtonElement;
// 落地前响铃时长
const cd_time = wh_trv_alarm_node.querySelector('input[type="number"]') as HTMLInputElement;
let count_down_notify: MyHTMLElement | { close: Function } = {
close: () => {
}
};
set_node.onclick = () => {
try {
wh_trv_alarm.alert_time = parseInt(cd_time.value);
} catch {
wh_trv_alarm.alert_time = 30;
}
save_trv_settings();
set_node.value = wh_trv_alarm.alert_time;
count_down_notify.close();
count_down_notify = new Alert('设置已更新');
};
// 停止响铃按钮
const stop_node = wh_trv_alarm_node.querySelectorAll('#wh-trv-alarm-cont button')[1] as HTMLButtonElement;
stop_node.onclick = () => {
user_stop_alert = true;
stop_node.innerText = '本次已关闭';
stop_node.disabled = true;
}
// 开启闹钟勾选
const enable_node = wh_trv_alarm_node.querySelector('#wh-trv-alarm-cont input[type="checkbox"]') as HTMLInputElement;
let on_off_notify: MyHTMLElement | { close: Function } = {
close: () => {
}
};
enable_node.onchange = ev => {
wh_trv_alarm.enable = (<HTMLInputElement>ev.target).checked;
save_trv_settings();
on_off_notify.close();
on_off_notify = new Alert(wh_trv_alarm.enable ? '闹钟已开启' : '闹钟已关闭');
};
// 剩余时间 秒
const remaining_sec = parseInt(remaining_arr);
// 落地时timestamp
const land_timestamp = Date.now() + remaining_sec * 1000;
// 音频dom
const audio = document.createElement('audio');
audio.src = 'https://www.torn.com/js/chat/sounds/Warble_1.mp3';
audio.play()
.then(() => audio.pause())
.catch(() => {
error_node.style.display = 'table';
const func = () => {
error_node.remove();
document.body.removeEventListener('click', func);
};
document.body.addEventListener('click', func);
});
// 是否正在响铃
let audio_play_flag = false;
// 用户是否停止当前响铃
let user_stop_alert = false;
// 响铃循环id
let audio_play_id = null;
// 响铃的方法
let audio_play_handle = () => {
if (user_stop_alert) {
clearInterval(audio_play_id);
audio_play_id = null;
return;
}
if (!audio_play_flag || !wh_trv_alarm.enable) return;
audio.play().then();
};
// 飞机小动画字符
const flying_arr = [
'✈ ',
'&nbsp;&nbsp;✈ ',
'&nbsp;&nbsp;&nbsp;&nbsp;✈ ',
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;✈ ',
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;✈ ',
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;✈ ',
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;✈ ',
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;✈ ',
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;✈ ',
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;✈ ',
];
// 飞行的状态dom
const flying_status = wh_trv_alarm_node.querySelector('#wh-trv-status');
// 飞机的小动画dom
const flying_ani = flying_status.nextElementSibling;
// 飞机的计数
let flying_index = 0;
const id = window.setInterval(() => {
const remaining_time = (land_timestamp - Date.now()) / 1000 | 0;
remaining_node.innerText = `${ remaining_time / 3600 | 0 }${ remaining_time % 3600 / 60 | 0 }${ remaining_time % 60 }`;
if (remaining_time < wh_trv_alarm.alert_time) {
// flying_status.innerHTML = `即将落地...`;
if (wh_trv_alarm.enable) {
// 播放提示音
audio_play_flag = true;
if (audio_play_id === null && !user_stop_alert) audio_play_id = window.setInterval(audio_play_handle, 750);
stop_node.parentElement.classList.remove('wh-trv-alarm-stop-hide');
}
} else {
// flying_status.innerHTML = `飞行中...`;
if (wh_trv_alarm.enable) {
clearInterval(audio_play_id);
audio_play_id = null;
stop_node.parentElement.classList.add('wh-trv-alarm-stop-hide');
}
}
flying_ani.innerHTML = `${ flying_arr[flying_index] }`;
flying_index = (flying_index + 1) % flying_arr.length;
}, 1000);
}
// 落地转跳 落地前事件
if (WuhuConfig.get('landedRedirect') && document.querySelector('#tcLogo[title]') === null) {
window.addEventListener('beforeunload', () => {
let obj = { url: WuhuConfig.get('landedRedirect'), timestamp: Date.now() };
sessionStorage['wh-landed-redirect'] = JSON.stringify(obj);
});
}
break;
}
// 海外落地
case TRAVEL_STATE.ABROAD: {
// 一键回城
ActionButtonUtils.getInstance().add('直接回城', travelBack);
// 海外警告
if (WuhuConfig.get('abroadWarning')) {
let c = 1;
setInterval(() => new Alert(`警告:您已海外落地${ c++ * 30 }`, {
timeout: 30,
sysNotify: true
}), 30000);
}
// 解毒提醒
if (bodyAttrs['data-country'] === 'switzerland') {
let block = new TornStyleBlock('解毒提醒');
block.setContent('<p><a href="/index.php?page=rehab">❤️ 点击前往解毒</a></p>');
document.querySelector('h4#skip-to-content').before(block.getBase());
}
break;
}
// 主页界面
case TRAVEL_STATE.IN_TORN: {
// 落地转跳
if (sessionStorage['wh-landed-redirect']) {
let { url, timestamp } = JSON.parse(sessionStorage['wh-landed-redirect']);
if (Date.now() - timestamp < 30000) {
sessionStorage.removeItem('wh-landed-redirect');
location.href = url;
}
}
break;
}
}
}
// 起飞页面
else if (href.contains(/travelagency\.php/)) {
// 起飞提醒 TODO 去除jquery mutation
if (WuhuConfig.get('energyAlert')) {
const contentWrapper = document.querySelector('.content-wrapper');
const OB = new MutationObserver(() => {
OB.disconnect();
titleTrans();
contentTitleLinksTrans();
trans();
OB.observe(contentWrapper, {
characterData: true,
attributes: true,
subtree: true,
childList: true
});
});
const trans = () => {
// 当前能量e
const energyBarStr = $('#barEnergy p[class^="bar-value__"]').text().trim();
const [curE, maxE] = energyBarStr.split('/').length === 2
? [parseInt(energyBarStr.split('/')[0]), parseInt(energyBarStr.split('/')[1])]
: [NaN, NaN];
const incTime = maxE === 150 ? 10 : 15;
const fullEnergyTime = !(isNaN(curE) || isNaN(maxE)) ? (maxE - 5 - curE) / 5 * incTime
+ (incTime - new Date().getMinutes() % incTime) : NaN;
// 起飞前提示
$('.travel-confirm .travel-question .q-wrap span:nth-of-type(2)').each((i, e) => {
if (isNaN(fullEnergyTime)) return;
const spl = e.innerText.trim().split(' ');
const [hours, minutes] = spl.length === 5
? [parseInt(spl[0]), parseInt(spl[3])]
: [0, parseInt(spl[0])];
if (fullEnergyTime < (hours * 60 + minutes) * 2) {
if (!$(e).parent().hasClass('wh-translated')) {
$(e).parent()
.prepend(`<div style="color: red">警告:该次飞行往返时间大于体力回复时间,将会爆体!</div>`)
.addClass('wh-translated');
}
}
});
};
trans();
OB.observe(contentWrapper, {
characterData: true,
attributes: true,
subtree: true,
childList: true
});
}
// 一键起飞
if (sessionStorage['wh-quick-fly']) {
QuickFlyBtnHandler.doQuickFly();
}
}
}
async function travelBack(): Promise<null> {
if (typeof window['getAction'] !== 'function') return;
let backHomeAction = function (): Promise<string> {
return new Promise(resolve => {
window.getAction({
type: "post",
action: 'travelagency.php',
data: {
step: 'backHomeAction'
},
success: function (msg) {
resolve(msg);
}
});
});
};
let res = await backHomeAction();
new Alert(res);
if (!res.includes('error')) {
new Alert('成功,即将刷新');
window.setTimeout(() => location.reload(), 3000);
} else {
new Alert('出错了');
}
}

View File

@ -1,6 +1,5 @@
import { eventsDict, gymList, ocList } from "../../dictionary/translation"; import { eventsDict, gymList, ocList } from "../../dictionary/translation";
import log from "../utils/@deprecated/log";
let log = { info: (args) => null };
export default function eventsTrans(events: JQuery = $('span.mail-link')) { export default function eventsTrans(events: JQuery = $('span.mail-link')) {
const index = window.location.href.indexOf('events.php#/step=received') >= 0 ? 1 : 0; const index = window.location.href.indexOf('events.php#/step=received') >= 0 ? 1 : 0;
@ -554,9 +553,9 @@ export default function eventsTrans(events: JQuery = $('span.mail-link')) {
const num = spl[3] === 'a' ? '1' : spl[3]; const num = spl[3] === 'a' ? '1' : spl[3];
const price = reasonSpl[0].split(' ').slice(-1)[0]; const price = reasonSpl[0].split(' ').slice(-1)[0];
const reason = reasonSpl[1] ? reasonSpl[1] : null; const reason = reasonSpl[1] ? reasonSpl[1] : null;
const trans = `${ someone ?? '某人1' }对你进行了 ${ num } 次赏金为 ${ price } 的悬赏${ reason ? ',原因:' + reason : '' }`; const trans = `${ someone ? '某人' : ' ' }对你进行了 ${ num } 次赏金为 ${ price } 的悬赏${ reason ? ',原因:' + reason : '' }`;
// 匿名悬赏 // 匿名悬赏
if (!!someone) { if (someone) {
$(e).text(trans); $(e).text(trans);
} }
// 实名悬赏 // 实名悬赏

View File

@ -1,4 +1,4 @@
let log = { info: (args) => null }; import log from "../utils/@deprecated/log";
/** /**
* observe * observe

View File

@ -34,16 +34,11 @@ import initOB from "./initOB";
import titleTrans from "./titleTrans"; import titleTrans from "./titleTrans";
import contentTitleLinksTrans from "./contentTitleLinksTrans"; import contentTitleLinksTrans from "./contentTitleLinksTrans";
import showItemInfoTrans from "./showItemInfoTrans"; import showItemInfoTrans from "./showItemInfoTrans";
import log from "../utils/@deprecated/log";
import contentTitleLinksTransReact from "./contentTitleLinksTransReact"; import contentTitleLinksTransReact from "./contentTitleLinksTransReact";
import titleTransReact from "./titleTransReact"; import titleTransReact from "./titleTransReact";
import Log from "../../class/Log"; import Log from "../../class/Log";
let log = { info: (args) => null };
/**
* @deprecated
* @param href
*/
export default function translateMain(href: string): void { export default function translateMain(href: string): void {
// 时分秒转换 // 时分秒转换
String.prototype.replaceHMS = function replaceHMS() { String.prototype.replaceHMS = function replaceHMS() {
@ -67,57 +62,57 @@ export default function translateMain(href: string): void {
}; };
// 边栏 // 边栏
// let sidebarTimeOut = 60; let sidebarTimeOut = 60;
// const sidebarInterval = setInterval(() => { const sidebarInterval = setInterval(() => {
// // 60秒后取消定时 // 60秒后取消定时
// if ($('div[class^="sidebar"]').length === 0) { if ($('div[class^="sidebar"]').length === 0) {
// sidebarTimeOut--; sidebarTimeOut--;
// if (sidebarTimeOut < 0) { if (sidebarTimeOut < 0) {
// clearInterval(sidebarInterval); clearInterval(sidebarInterval);
// } }
// return; return;
// } }
// // 边栏块标题 // 边栏块标题
// $('h2[class^="header"]').each((i, e) => { $('h2[class^="header"]').each((i, e) => {
// if (!sidebarDict[e.firstChild.nodeValue]) return; if (!sidebarDict[e.firstChild.nodeValue]) return;
// e.firstChild.nodeValue = sidebarDict[e.firstChild.nodeValue]; e.firstChild.nodeValue = sidebarDict[e.firstChild.nodeValue];
// }); });
// // 边栏人物名字 // 边栏人物名字
// $('span[class^="menu-name"]').each((i, e) => { $('span[class^="menu-name"]').each((i, e) => {
// e.firstChild.nodeValue = '名字:'; e.firstChild.nodeValue = '名字:';
// }); });
// // 钱 等级 pt 天赋点 // 钱 等级 pt 天赋点
// $('p[class^="point-block"]').each((i, e) => { $('p[class^="point-block"]').each((i, e) => {
// if (sidebarDict[e.firstChild.firstChild.nodeValue]) if (sidebarDict[e.firstChild.firstChild.nodeValue])
// e.firstChild.firstChild.nodeValue = sidebarDict[e.firstChild.firstChild.nodeValue]; e.firstChild.firstChild.nodeValue = sidebarDict[e.firstChild.firstChild.nodeValue];
// }); });
// // 4条 状态条 // 4条 状态条
// $('p[class^="bar-name"]').each((i, e) => { $('p[class^="bar-name"]').each((i, e) => {
// if (sidebarDict[e.firstChild.nodeValue]) if (sidebarDict[e.firstChild.nodeValue])
// e.firstChild.nodeValue = sidebarDict[e.firstChild.nodeValue]; e.firstChild.nodeValue = sidebarDict[e.firstChild.nodeValue];
// }); });
// // 边栏菜单 // 边栏菜单
// $('span[class^="linkName"]').each((i, e) => { $('span[class^="linkName"]').each((i, e) => {
// if (sidebarDict[e.firstChild.nodeValue]) if (sidebarDict[e.firstChild.nodeValue])
// e.firstChild.nodeValue = sidebarDict[e.firstChild.nodeValue]; e.firstChild.nodeValue = sidebarDict[e.firstChild.nodeValue];
// }); });
// // [use]按钮 // [use]按钮
// if (document.querySelector('#pointsMerits')) if (document.querySelector('#pointsMerits'))
// $('#pointsMerits')[0].firstChild.nodeValue = '[使用]'; $('#pointsMerits')[0].firstChild.nodeValue = '[使用]';
// if (document.querySelector('#pointsPoints')) if (document.querySelector('#pointsPoints'))
// $('#pointsPoints')[0].firstChild.nodeValue = '[使用]'; $('#pointsPoints')[0].firstChild.nodeValue = '[使用]';
// if (document.querySelector('#pointsLevel')) if (document.querySelector('#pointsLevel'))
// $('#pointsLevel')[0].firstChild.nodeValue = '[升级]'; $('#pointsLevel')[0].firstChild.nodeValue = '[升级]';
//
// // 手机 区域菜单 // 手机 区域菜单
// $('div[class*="areas-mobile"] span:nth-child(2)').contents().each((i, e) => { $('div[class*="areas-mobile"] span:nth-child(2)').contents().each((i, e) => {
// //log(e); //log(e);
// if (sidebarDict[e.nodeValue]) if (sidebarDict[e.nodeValue])
// e.nodeValue = sidebarDict[e.nodeValue]; e.nodeValue = sidebarDict[e.nodeValue];
// }); });
//
// clearInterval(sidebarInterval); clearInterval(sidebarInterval);
// }, 1000); }, 1000);
// header // header
if (document.querySelector('div#header-root')) { if (document.querySelector('div#header-root')) {
@ -1113,7 +1108,7 @@ export default function translateMain(href: string): void {
} }
} else { } else {
if ($('.wh-translated').length <= 0) { if ($('.wh-translated').length <= 0) {
log.info(`未找到翻译: ${ action_desc.text().trim() }`); log.info(`未找到翻译: ${ action_desc.text().trim() }`);
} }
} }
// 添加敌人或朋友的界面 // 添加敌人或朋友的界面

View File

@ -0,0 +1,98 @@
import audioPlay from "./audioPlay";
import MathUtils from "../../../class/utils/MathUtils";
import Alert from "../../../class/utils/Alert";
import InfoUtils from "../../../class/utils/InfoUtils";
import WuhuConfig from "../../../class/WuhuConfig";
import Log from "../../../class/Log";
/**
* @deprecated
*/
export default function BuyBeer() {
// 正在通知
let is_notified = false;
let time: number = WuhuConfig.get('_15AlarmTime') || 30;
let loop: BeerMonitorLoop = {};
// 循环id
let started = null;
loop.start = () => {
if (started) {
Log.info('啤酒助手已在运行');
return;
}
started = setInterval(async () => {
// 海外取消提醒
let { isTravelling, isAbroad } = await InfoUtils.getInstance().getUserState();
if (isTravelling || isAbroad) {
loop.stop();
return;
}
let dt = new Date();
// 已选当天不提醒
const now = [dt.getUTCFullYear(), dt.getUTCMonth(), dt.getUTCDate()];
const ignore_date = WuhuConfig.get('_15_alarm_ignore') || '{}';
if (JSON.stringify(now) === JSON.stringify(ignore_date)) return;
// 正常提醒
let m = 14 - (dt.getMinutes() % 15);
let s = 60 - dt.getSeconds();
if (m === 0 && s < time) {
// 如从通知点开,则本次通知跳过
if (location.href.includes('#clickfromnotify')) {
is_notified = true;
location.hash = '';
return;
}
// 本次已通知
if (is_notified) return;
is_notified = true;
// 发送通知
const notify = new Alert(notify_html, {
timeout: 30,
sysNotify: true,
});
notify.getElement().querySelector('.wh-notify-msg button').addEventListener('click', () => loop.skip_today);
notify.getElement().addEventListener('click', ev => {
if ((ev.target as HTMLElement).tagName.toLowerCase() === 'a') {
// notify.sys_notify.close();
notify.close();
}
});
window.setTimeout(audioPlay, 800);
window.setTimeout(audioPlay, 800 * 2);
window.setTimeout(audioPlay, 800 * 3);
} else {
is_notified = false;
}
}, 1000);
};
loop.stop = () => {
if (started) {
clearInterval(started);
started = null;
}
};
loop.set_time = (t) => time = t;
loop.status = () => started ? '已启动' : '未启动';
loop.is_running = () => !!started;
let mathUtils: MathUtils = MathUtils.getInstance();
let notify_html = `<span style="background-color:green;color:white;border-radius:3px;font-size:14px;line-height:21px;padding:2px 4px;">啤酒小助手</span><br/>提醒您:还有不到 50 秒 NPC 的商品就要刷新了,啤酒血包要抢的可以准备咯。<button id="wh-rd-btn-${ mathUtils.getRandomInt(0, 100) }">【今日不再提醒】</button><br/><a href="/shops.php?step=bitsnbobs#clickfromnotify" target="_blank">【啤酒店】</a> <a href="/shops.php?step=pharmacy#clickfromnotify" target="_blank">【血包店】</a>`
loop.skip_today = () => {
const date = new Date();
WuhuConfig.set('_15_alarm_ignore', [date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()], false);
// 通知
const notify = new Alert(`明早8点前将不再提醒 <button id="wh-rd-btn-${ mathUtils.getRandomInt(0, 100) }">取消</button>`);
// 通知中的取消按钮
notify.getElement().querySelector('.wh-notify-msg button').addEventListener('click', () => WuhuConfig.set('_15_alarm_ignore', undefined));
};
return loop;
}
export interface BeerMonitorLoop {
start?: Function;
stop?: Function;
set_time?: Function;
status?: Function;
is_running?: Function;
skip_today?: Function;
}

View File

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

Some files were not shown because too many files have changed in this diff Show More