Compare commits

..

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

270 changed files with 8017 additions and 46332 deletions

8
.gitignore vendored
View File

@ -1,8 +0,0 @@
/node_modules
/.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

@ -2,12 +2,7 @@
<module type="JAVA_MODULE" version="4"> <module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true"> <component name="NewModuleRootManager" inherit-compiler-output="true">
<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$/misc" />
<excludeFolder url="file://$MODULE_DIR$/dist" />
<excludePattern pattern="release.min.user.js" />
</content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>

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,648 +1,9 @@
# CHANGE # TODO
## 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
2022年11月8日
### 添加
- 搜索页-可选添加底部空白占位区
- 全屏菜单
- 自定义CSS
## 0.6.8
2022年11月4日
### 添加
- 边栏-可选隐藏侧边栏
## 0.6.7
2022年11月3日
### 修改
- 重做光速跑路(需要更多测试)
### 添加
- 战斗-盯梢模式
## 0.6.6
2022年10月31日
### 修改
- 寻找木桩添加停止操作
### 添加
- 个人资料隐藏头像、显示曾用名
## 0.6.5
2022年10月26日
### 修改
- 寻找木桩逻辑优化
## 0.6.4
2022年10月25日
### 修改
- 一键存钱错误修复
## 0.6.3
2022年10月24日
### 修改
- 公司助手-火车检测时区检测完善
- 飞行闹钟目的地完善
- UI修改
## 0.6.2
2022年10月20日
### 添加
- 公司助手-火车检测开关
- jQuery载入问题临时解决
## 0.6.1
2022年10月19日
### 添加
- 公司助手-火车检测
- 测试添加对Userscript Safari (ios) 的支持
## 0.6.0
2022年10月18日
### 修改
- 解毒提醒UI调整
- 传单助手UI调整
- 光速拔刀UI错误修复
- 光速跑路功能暂时关闭
### 添加
- 更多设置
## 0.5.9
2022年10月14日
### 修改
- 设置错误修复
### 添加
- 寻找木桩
## 0.5.8
2022年10月13日
### 修改
- UI调整
### 添加
- PT一键购买开关
## 0.5.7
2022年10月12日
### 修改
- UI调整
- 错误修复
## 0.5.6
2022年10月11日
### 修改
- UI调整
## 0.5.5
2022年10月10日
### 添加
- 彩票助手
## 0.5.4
2022年10月09日
### 修改
- 翻译baza npc商店、imarket、imarket搜索结果
- TS重构 - TS重构
- 修复啤酒助手的错误
- 修复通知的错误 # CHANGE
## 0.5.3 ## 0.5.3

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 安装。

21
build.js Normal file
View File

@ -0,0 +1,21 @@
let fs = require('fs');
let date = new Date();
let version = process.env.npm_package_version;
let head = `// ==UserScript==
// @lastmodified ${date.getFullYear()}${('0' + (date.getMonth() + 1)).slice(-2)}${('0' + date.getDate()).slice(-2)}${('0' + date.getHours()).slice(-2)}${('0' + date.getMinutes()).slice(-2)}
// @name 芜湖助手
// @namespace WOOH
// @version ${version}
// @description 托恩,起飞!
// @author Woohoo[2687093] Sabrina_Devil[2696209]
// @match https://www.torn.com/*
// @grant GM_xmlhttpRequest
// @grant unsafeWindow
// @connect *
// ==/UserScript==
`
const data = fs.readFileSync('./bundle.min.js', 'utf8');
fs.writeFileSync('./release.min.user.js', head + data.replace('$$WUHU_DEV_VERSION$$', version), 'utf8');
console.log('构建完成');

View File

@ -1,39 +0,0 @@
/**
* 此脚本用于加入userscript meta
* 并生成日期时间与版本号
*/
import { readFileSync, writeFileSync } from "fs";
import { prodConfig } from "./rollup.config.js";
let date = new Date();
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 metaData =
`// ==UserScript==
// @lastmodified ${ formattedDateTime }
// @name 芜湖助手
// @namespace WOOH
// @version ${ version }
// @description 托恩,起飞!
// @author Woohoo[2687093] Sabrina_Devil[2696209]
// @match https://www.torn.com/*
// @downloadURL https://gitlab.com/JJins/wuhu-torn-helper/-/raw/dev/release.min.user.js
// @grant GM_xmlhttpRequest
// @grant unsafeWindow
// @connect yata.yt
// @connect github.io
// @connect gitlab.com
// @connect staticfile.org
// @connect gitee.com
// ==/UserScript==
`
const data = readFileSync('./' + prodConfig.output.file, 'utf8');
writeFileSync(
'./release.min.user.js',
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 })`;
};

59
global.d.ts vendored
View File

@ -14,50 +14,40 @@ declare interface Window {
$?: JQueryStatic; $?: JQueryStatic;
jQuery?: JQueryStatic; jQuery?: JQueryStatic;
WHPARAMS?: any; WHPARAMS?: any;
ReactDOM?: any;
hasWHQuickFlyOpt?: boolean; hasWHQuickFlyOpt?: boolean;
// 插件运行标识 // 插件运行标识
WHTRANS?: number; WHTRANS?: boolean;
Vue?: Function; Vue?: Function;
/** /* 油猴脚本引擎自带 */
*
*/
unsafeWindow?: Window & typeof globalThis; unsafeWindow?: Window & typeof globalThis;
/**
* google
*/
_gaUserPrefs?: unknown;
GM_xmlhttpRequest(init: GM_RequestParams): void;
GM_getValue(k: string, def: any): unknown;
GM_setValue(k: string, v: any): void;
/**
* TORN自带
*/
ReactDOM?: any;
dataLayer?: unknown;
eval(exc: string): void; eval(exc: string): void;
/* TORN自带 */
addRFC(url: URL | string): string; addRFC(url: URL | string): string;
// initMiniProf(selector: string): void;
getAction(opt: TornGetActionParams): void; getAction(opt: TornGetActionParams): void;
initializeTooltip(selector: string, elemId: string): void; initializeTooltip(selector: string, elemId: string): void;
renderMiniProfile(node: Element, props: any): never; renderMiniProfile(node: Element, props: any): never;
/** /* PDA自带 */
* PDA自带
*/
PDA_httpGet(url: URL | string): Promise<PDA_Response>; PDA_httpGet(url: URL | string): Promise<PDA_Response>;
PDA_httpPost(url: URL | string, init: any, body: any): Promise<PDA_Response>; PDA_httpPost(url: URL | string, init: any, body: any): Promise<PDA_Response>;
GM_xmlhttpRequest(init: GM_RequestParams): void;
GM_getValue(k: string, def: any): unknown;
GM_setValue(k: string, v: any): void;
// TODO 临时测试用 // TODO 临时测试用
// [key: string]: unknown; [key: string]: unknown;
} }
declare interface GM_RequestParams { declare interface GM_RequestParams {
@ -108,22 +98,11 @@ 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;
// const classes: { [key: string]: string };
// export default classes;
export default css;
// export { css };
} }
declare function GM_xmlhttpRequest(init: any): void; declare module "*.css" {
const value: string;
declare var unsafeWindow: Window & typeof globalThis; export default value;
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

10608
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.5.4",
"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 };

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

@ -0,0 +1,34 @@
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";
export default class Application {
private readonly common = Common.getInstance();
main() {
let started = performance.now();
WuhuBase.PDAExecute();
WuhuBase.conditionInterrupt();
let app = new WuHuTornHelper();
app.init();
let glob = WuhuBase.glob;
ZhongIcon.getInstance().initialize();
// Common.resolve();
this.common.resolve();
UrlPattern.resolve();
if (WuhuConfig.get('transEnable')) translateMain(glob.href);
let runTime: number = (performance.now() - started) | 0;
ZhongIcon.ZhongNode.initTimer.innerHTML = `助手加载时间 ${ runTime }ms`;
}
}

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

@ -0,0 +1,82 @@
import depoHelper from "../func/module/depoHelper";
import travelHelper from "../func/module/travelHelper";
import attackHelper from "../func/module/attackHelper";
import priceWatcherHandle from "../func/module/priceWatcherHandle";
import WuhuBase from "./WuhuBase";
import WuhuConfig from "./WuhuConfig";
import CommonUtils from "./utils/CommonUtils";
export class Common extends WuhuBase {
resolve() {
let glob = Common.glob;
// 价格监控
priceWatcherHandle(glob.isPDA, glob.PDA_APIKey);
// 啤酒提醒
if (WuhuConfig.get('_15Alarm')) glob.beer.start();
// 点击4条转跳对应的页面
if (WuhuConfig.get('barsRedirect')) {
const eb = document.getElementById('barEnergy') as HTMLAnchorElement;
const nb = document.getElementById('barNerve') as HTMLAnchorElement;
const hb = document.getElementById('barHappy') as HTMLAnchorElement;
const lb = document.getElementById('barLife') as HTMLAnchorElement;
if (eb) {
eb.addEventListener('click', () => location.href = '/gym.php');
eb.href = '/gym.php';
} else {
CommonUtils.elementReady('#barEnergy').then(eb => {
eb.addEventListener('click', () => location.href = '/gym.php');
(eb as HTMLAnchorElement).href = '/gym.php';
});
}
if (nb) {
nb.addEventListener('click', () => location.href = '/crimes.php');
nb.href = '/crimes.php';
} else {
CommonUtils.elementReady('#barNerve').then(nb => {
nb.addEventListener('click', () => location.href = '/crimes.php');
(nb as HTMLAnchorElement).href = '/crimes.php';
});
}
if (hb) {
hb.addEventListener('click', () => location.href = '/item.php#boosters-items');
hb.href = '/item.php#boosters-items';
} else {
CommonUtils.elementReady('#barHappy').then(hb => {
hb.addEventListener('click', () => location.href = '/item.php#boosters-items');
(hb as HTMLAnchorElement).href = '/item.php#boosters-items';
});
}
if (lb) {
lb.addEventListener('click', () => location.href = '/item.php#medical-items');
lb.href = '/item.php#medical-items';
} else {
CommonUtils.elementReady('#barLife').then(lb => {
lb.addEventListener('click', () => location.href = '/item.php#medical-items');
(lb as HTMLAnchorElement).href = '/item.php#medical-items';
});
}
}
/**
*
* TODO
*/
if (WuhuConfig.get('removeScripts')) {
document.querySelectorAll('script[src*="google"]').forEach(item => item.remove());
document.querySelectorAll('#gtm_tag').forEach(item => item.remove());
document.querySelectorAll('script[src*="chat/gonline"]').forEach(item => item.remove());
document.querySelectorAll('head script[nonce]').forEach(item => item.remove());
}
// 存钱相关
depoHelper();
// 飞行相关
travelHelper().then();
// 战斗相关
attackHelper().then();
}
}

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

@ -0,0 +1,88 @@
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 {
GM_xmlhttpRequest: Function = null;
href: string = window.location.href;
// 弹窗
popup_node: MyHTMLElement = null;
// 啤酒助手
beer = null;
// 留存的通知
notifies: NotifyWrapper = null;
// 海外库存
fStock: { get: () => Promise<any> } = 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'?: string;
'data-abroad'?: string;
// [key: string]: string;
} = null;
constructor() {
Log.info('WH脚本参数初始化');
super();
this.window = window;
this.unsafeWindow = window.unsafeWindow || null;
this.GM_xmlhttpRequest = window.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 = {};
if (this.unsafeWindow) {
try {
window = this.unsafeWindow || this.window;
Log.info('替换window上下文');
} catch {
this.unsafeWindow = null;
this.GM_xmlhttpRequest = null;
}
}
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脚本参数初始化结束');
}
}

62
src/class/Log.ts Normal file
View File

@ -0,0 +1,62 @@
export default class Log {
private static logs = '';
static info(...o): void {
let time = this.getTime();
let flag = '[WH] IFO';
if (this.debug()) {
console.log(flag, time, ...o);
}
this.saveLogs(flag, time, ...o);
}
static error(...o): void {
let time = this.getTime();
let flag = '[WH] ERR';
(this.debug()) && (console.error(flag, time, ...o));
this.saveLogs(flag, time, ...o);
}
static warn(...o): void {
let time = this.getTime();
let flag = '[WH] WRN';
(this.debug()) && (console.warn(flag, time, ...o));
this.saveLogs(flag, time, ...o);
}
static debug(): boolean {
let ret: boolean;
try {
let local = JSON.parse(localStorage.getItem('wh_trans_settings'));
if (local) ret = local['isDev'];
else ret = false;
} catch {
ret = false;
}
return ret;
}
static getTime(): string {
let d = new Date();
let year = d.getFullYear();
let month = ('0' + (d.getMonth() + 1)).slice(-2);
let date = ('0' + d.getDate()).slice(-2);
let hours = ('0' + d.getHours()).slice(-2);
let minutes = ('0' + d.getMinutes()).slice(-2);
let seconds = ('0' + d.getSeconds()).slice(-2);
let ms = ('00' + d.getMilliseconds()).slice(-3);
return `[${ year }-${ month }-${ date } ${ hours }:${ minutes }:${ seconds }.${ ms }]`;
}
static getLogs() {
return this.logs;
}
private static saveLogs(...o) {
o.forEach(item => {
if (typeof item === 'string') this.logs += item;
else this.logs += ` [${ item.toString() }] [${ JSON.stringify(item) }] `;
})
this.logs += '\r\n';
}
}

269
src/class/UrlMatch.ts Normal file
View File

@ -0,0 +1,269 @@
import cityFinder from "../func/module/cityFinder";
import { missionDict } from "../dictionary/translation";
import getTaskHint from "../func/translate/getTaskHint";
import Device from "../enum/Device";
import WuhuBase from "./WuhuBase";
import CommonUtils from "./utils/CommonUtils";
import Log from "./Log";
import WuhuConfig from "./WuhuConfig";
import Alert from "./utils/Alert";
import InfoUtils from "./utils/InfoUtils";
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";
export default class UrlPattern extends WuhuBase {
static resolve() {
let { href, beer } = UrlPattern.glob;
// 捡垃圾助手
if (href.includes('city.php') && WuhuConfig.get('cityFinder')) {
cityFinder();
}
// pt一键购买
if (WuhuConfig.get('ptQuickBuy') && href.includes('pmarket.php')) {
new Alert('一键购买已开启');
// ns脚本
const rmv_cfm = (e) => {
let el = e.firstElementChild;
el.className += ' yes';
let old_href = el.getAttribute('href');
let new_href = old_href.replace(/=buy/, '=buy1').replace(/&points=\d{1,9}$/, '');
el.setAttribute('href', new_href);
};
let points_sales = document.querySelector('.users-point-sell');
for (const index in points_sales.children) {
'LI' === points_sales.children[index].tagName && rmv_cfm(points_sales.children[index])
}
new MutationObserver(e => {
for (const t of e) {
// for (const e of t.addedNodes) {
// 'LI' === e.tagName && rmv_cfm(e)
// }
t.addedNodes.forEach(e => 'LI' === (e as HTMLElement).tagName && rmv_cfm(e))
}
}).observe(points_sales, { childList: true });
}
// 叠e助手
if (href.includes('gym.php')) {
let cont = null;
const switch_node = document.createElement('div');
switch_node.innerHTML = `<label><input type="checkbox" ${ WuhuConfig.get('SEProtect') ? 'checked' : '' }/> 叠E保护</label>`;
switch_node.id = 'wh-gym-info-cont';
switch_node.querySelector('input').onchange = e => {
let target = e.target as HTMLInputElement;
cont.classList.toggle('wh-display-none');
WuhuConfig.set('SEProtect', target.checked, true);
};
CommonUtils.elementReady('#gymroot').then(node => {
cont = node;
if (WuhuConfig.get('SEProtect')) node.classList.add('wh-display-none');
node.before(switch_node);
});
}
// 啤酒店
if (href.includes('shops.php?step=bitsnbobs')) {
// 加入啤酒
CommonUtils.elementReady('ul.items-list').then(node => {
const add_btn_node = document.createElement('div');
add_btn_node.id = 'wh-gym-info-cont';
add_btn_node.innerHTML = ADD_BEER_HEAD_HTML;
add_btn_node.querySelector('button').addEventListener('click', e => {
const msg_node = add_btn_node.querySelector('#wh-msg');
if (node.querySelector('span[id="180-name"]')) {
msg_node.innerHTML = '❌ 页面已经有啤酒了';
return;
}
const clear_node = node.querySelector('li.clear');
const beer = document.createElement('li');
beer.classList.add('torn-divider', 'divider-vertical');
beer.style.backgroundColor = '#c8c8c8';
beer.innerHTML = SHOP_BEER_STATIC_ITEM_HTML;
if (clear_node) clear_node.before(beer);
else node.append(beer);
(<MyHTMLElement>e.target).remove();
msg_node.innerHTML = '添加成功';
});
document.querySelector('.content-wrapper').prepend(add_btn_node);
});
// 监听啤酒购买
$(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('已检测成功购买啤酒');
beer.skip_today();
}
});
}
// 快速crime TODO 重构、与翻译解藕
if (href.contains(/crimes\.php/) && WuhuConfig.get('quickCrime')) {
if (self !== top) {
const isValidate = document.querySelector('h4#skip-to-content').innerText.toLowerCase().includes('validate');
CommonUtils.elementReady('#header-root').then(e => e.style.display = 'none');
CommonUtils.elementReady('#sidebarroot').then(e => e.style.display = 'none');
CommonUtils.elementReady('#chatRoot').then(e => e.style.display = 'none');
if (!isValidate) document.body.style.overflow = 'hidden';
CommonUtils.elementReady('.content-wrapper').then(e => {
e.style.margin = '0px';
e.style.position = 'absolute';
e.style.top = '-35px';
});
CommonUtils.elementReady('#go-to-top-btn button').then(e => e.style.display = 'none');
}
const $$ = document.querySelector('.content-wrapper');
const OB = new MutationObserver(() => {
OB.disconnect();
// titleTrans();
// contentTitleLinksTrans();
trans();
OB.observe($$, {
characterData: true,
attributes: true,
subtree: true,
childList: true
});
});
const trans = () => {
const dom = QUICK_CRIMES_HTML;
const is_wh_translate = $$.querySelector('.wh-translate') !== null;
const is_captcha = $$.querySelector('div#tab-menu.captcha') !== null;
const $title = $('div.content-title');
const $info = $('.info-msg-cont');
if (!is_wh_translate && !is_captcha) {
if ($title.length > 0) $title.before(dom);
else if ($info.length > 0) $info.before(dom);
}
};
trans();
OB.observe($$, {
characterData: true,
attributes: true,
subtree: true,
childList: true
});
}
// 任务助手 TODO 重构、与翻译解藕
if (href.contains(/loader\.php\?sid=missions/) && WuhuConfig.get('missionHint')) {
const $$ = $('.content-wrapper');
const OB = new MutationObserver(() => {
OB.disconnect();
// titleTrans();
// contentTitleLinksTrans();
trans();
OB.observe($$.get(0), {
characterData: true,
attributes: true,
subtree: true,
childList: true
});
});
const taskList = {};
const trans = () => {
$('ul#giver-tabs a.ui-tabs-anchor').each((i, e) => {
if ($(e).children().hasClass('mission-complete-icon')) {
taskList[i] = e.innerText.trim();
} else {
taskList[i] = $(e).clone().children().remove().end().text().trim();
}
});
// 助手注入
$('div.max-height-fix.info').each((i, e) => {
if ($(e).find('.wh-translated').length !== 0) return;
$(e).append(`<div class="wh-translated"><h6 style="color:green"><b>任务助手</b></h6><p>${ getTaskHint(taskList[i]) }</p></div>`);
});
// 任务目标
$('ul.tasks-list span.title-wrap').contents().each((i, e) => {
if (e.nodeType === 3) {
if (missionDict[e.nodeValue.trim()]) {
e.nodeValue = missionDict[e.nodeValue.trim()];
}
}
});
};
trans();
OB.observe($$.get(0), {
characterData: true,
attributes: true,
subtree: true,
childList: true
});
}
// 圣诞小镇
if (href.contains(/christmas_town\.php/) && new Date().getMonth() > 9) christmasTownHelper();
// rw雷达
if (href.includes('profiles.php?XID=0')) {
const utl = {
set: function (k, v) {
const obj = JSON.parse(localStorage['wh_rw_raider']) || {};
obj[k] = v;
localStorage['wh_rw_raider'] = JSON.stringify(obj);
},
get: function (k) {
const obj = JSON.parse(localStorage['wh_rw_raider']) || {};
return obj[k];
},
setFactionID: function (id) {
this.set('faction', id);
},
setRWFactionID: function (id) {
this.set('rw_faction', id);
},
getFactionID: async function (apikey) {
const response = await fetch('https://api.torn.com/faction/?selections=basic&key=' + apikey);
const res_obj = await response.json();
const faction_id = res_obj['ID'];
if (faction_id) {
this.setFactionID(faction_id);
return faction_id;
} else return -1;
},
getRWFactionID: function (apikey) {
},
};
const rw_raider = async function () {
if (href.includes('#rader')) {
CommonUtils.addStyle('div.content-title,div.info-msg-cont{display:none;}');
const wh_node = document.createElement('div');
wh_node.id = 'wh-rd-cont';
wh_node.innerHTML = RW_RIDER_HTML;
// 原页面完全加载
await CommonUtils.elementReady('div.msg[role="alert"]');
const t_cont = document.querySelector('div.content-wrapper');
// t
t_cont.append(wh_node);
}
};
addEventListener('hashchange', rw_raider);
rw_raider().then();
}
// 特定
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);
}
});
}
}
}

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

@ -0,0 +1,39 @@
import IGlobal from "../interface/IGlobal";
import IWHSettings from "../interface/IWHSettings";
import Log from "./Log";
import Provider from "./provider/Provider";
export default class WuhuBase extends Provider {
static glob: IGlobal = null;
protected static className = 'WuhuBase';
constructor() {
super();
// Log.info({ 'constructor': this.constructor, this: this, test: this.getClassName() });
Log.info('创建对象:', this);
}
static getLocal(): IWHSettings {
return JSON.parse(localStorage.getItem('wh_trans_settings')) || {};
}
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 '芜湖';
}
static PDAExecute() {
if (window.WHTRANS) throw '已运行,退出';
window.WHTRANS = true;
}
// public toString() {
// return `[${ JSON.stringify(this) }]`;
// }
}

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

@ -0,0 +1,30 @@
import WuhuBase from "./WuhuBase";
import Alert from "./utils/Alert";
import Log from "./Log";
export default class WuhuConfig extends WuhuBase {
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;
}
}
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;
}
}

View File

@ -0,0 +1,77 @@
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 {
init() {
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
const ori_fetch = window.fetch;
window.fetch = async (url: string, init: RequestInit) => {
if (url.contains('newsTickers')) {
// 阻止获取新闻横幅
return new Response('{}');
}
if (url.includes('google')) {
return new Response('{}');
}
const res = await ori_fetch(url, init);
// mini profile 翻译
if (url.includes('profiles.php?step=getUserNameContextMenu') && WuhuConfig.get('transEnable')) {
setTimeout(() => miniprofTrans(), 200);
}
let clone = res.clone();
let text = await res.text();
Log.info({ url, init, text });
return clone;
};
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'));
}
}
Log.info('WuHuTornHelper初始化结束');
return this;
}
}

1310
src/class/ZhongIcon.ts Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,110 @@
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";
export default class BuyBeerHelper extends WuhuBase implements BeerMonitorLoop {
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;
Log.info('不提醒状态', now, ignore_date);
// 正常提醒
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));
}
}
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 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 {
private obj: any = null;
private res: any = null;
public constructor() {
super();
window.setInterval(async () => {
if (!WindowActiveState.getInstance().get()) return;
Log.info('fetching https://yata.yt/api/v1/travel/export/');
const res = await CommonUtils.COFetch('https://yata.yt/api/v1/travel/export/');
Log.info('fetch returned: ', res);
this.obj = JSON.parse(res);
}, 30 * 1000);
}
async get() {
if (!this.obj) {
const str = await this.res
this.obj = JSON.parse(str);
}
return this.obj;
}
// 呈现内容
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.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;
}
}
}

View File

@ -1,14 +1,12 @@
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() isFocus = false;
export default class WindowActiveState { uuid = uuidv4();
private isFocus = false;
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 +16,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

@ -0,0 +1,27 @@
/**
*
*/
export default class 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) {
this.instance = new this();
Provider.pool[this.name] = this.instance;
}
return this.instance;
}
public static getPool() {
return {
pool: Provider.pool,
// Json: JSON.stringify(Provider.pool)
}
}
}

View File

@ -0,0 +1,12 @@
import Log from "../Log";
export default class Starter {
public static run(T): void {
try {
new T().main();
} catch (error) {
Log.error(error);
Log.error('[Starter] trace: ', JSON.stringify({ error }));
}
}
}

View File

@ -0,0 +1,24 @@
import WuhuBase from "../WuhuBase";
import Log from "../Log";
import ZhongIcon from "../ZhongIcon";
export default class ActionButtonUtils extends WuhuBase {
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,56 +1,38 @@
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 {
private static container: HTMLElement = null; private static container: HTMLElement = null;
private static totalCounter: number = 0;
private notify: MyHTMLElement = null; private notify: MyHTMLElement = null;
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, } = options;
// 后台窗口、iframe内判断 // 后台窗口、iframe内判断
if (!this.windowActiveState.get() || (self !== top)) { if (!WindowActiveState.getInstance().get() || (self !== top)) return null;
if (!force) {
this.logger.warn('后台通知已被屏蔽');
return null;
} else {
this.logger.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++; Log.info('创建新通知:', this);
this.logger.info('创建新通知:', this, msg); if (sysNotify) NotificationUtils.getInstance().push(msg, options);
if (sysNotify) this.notificationUtils.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 }`;
@ -63,7 +45,7 @@ export default class Alert {
let mouse_enter = false; let mouse_enter = false;
element.addEventListener('mouseenter', () => mouse_enter = true, true); element.addEventListener('mouseenter', () => mouse_enter = true, true);
element.addEventListener('mouseleave', () => mouse_enter = false); element.addEventListener('mouseleave', () => mouse_enter = false);
// 通知进度条 TODO 改进 // 通知进度条
let progressCount = 101; let progressCount = 101;
// 计时器 // 计时器
that.intervalID = window.setInterval(() => { that.intervalID = window.setInterval(() => {
@ -93,7 +75,6 @@ export default class Alert {
this.notify = null; this.notify = null;
this.callback(); this.callback();
window.clearInterval(this.intervalID); window.clearInterval(this.intervalID);
Alert.totalCounter--;
} }
public getElement() { public getElement() {

View File

@ -0,0 +1,194 @@
import UserScriptEngine from "../../enum/UserScriptEngine";
import WuhuBase from "../WuhuBase";
import Log from "../Log";
import Device from "../../enum/Device";
import AjaxFetchOption from "../../interface/AjaxFetchOption";
import Alert from "./Alert";
import LOADING_IMG_HTML from "../../static/html/loading_img.html";
export default class CommonUtils extends WuhuBase {
static getScriptEngine() {
let glob = CommonUtils.glob;
return glob.unsafeWindow ? UserScriptEngine.GM : glob.isPDA
? UserScriptEngine.PDA : UserScriptEngine.RAW;
}
static COFetch(url: URL | string, method: 'get' | 'post' = 'get', body: any = null): Promise<string> {
const engine = this.getScriptEngine();
let start = performance.now();
Log.info('跨域获取数据开始, 脚本引擎: ' + engine);
return new Promise<string>((resolve, reject) => {
switch (engine) {
case UserScriptEngine.RAW: {
Log.error(`跨域请求错误:${ 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 => {
Log.info('跨域获取数据成功, 耗时' + (performance.now() - start | 0) + 'ms');
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 } = CommonUtils.glob;
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 => {
Log.info('跨域获取数据成功,耗时' + (performance.now() - start | 0) + 'ms');
resolve(res.response);
},
onerror: res => reject(`连接错误 ${ JSON.stringify(res) }`),
ontimeout: res => reject(`连接超时 ${ JSON.stringify(res) }`),
});
}
}
});
}
/**
* { playername: string, userID: number }
* @return {PlayerInfo} rs
*/
static getPlayerInfo(): PlayerInfo {
const node = document.querySelector('script[uid]');
if (node) {
return {
playername: node.getAttribute('name'),
userID: node.getAttribute('uid') as unknown as number,
}
} else {
new Alert('严重错误:芜湖助手无法获取用户数据,已退出');
throw '芜湖助手无法获取用户数据';
}
}
// 用户设备类型 对应PC MOBILE TABLET
static getDeviceType(): Device {
return window.innerWidth >= 1000
? Device.PC : window.innerWidth <= 600 ? Device.MOBILE : Device.TABLET;
}
static getYaoCD(): string {
if (document.querySelector("#icon49-sidebar")) { // 0-10min
return '<10分'
} else if (document.querySelector("#icon50-sidebar")) { // 10min-1h
return '<1时'
} else if (document.querySelector("#icon51-sidebar")) { // 1h-2h
return '1~2时'
} else if (document.querySelector("#icon52-sidebar")) { // 2h-5h
return '2~5时'
} else if (document.querySelector("#icon53-sidebar")) { // 5h+
return '>5时'
} else {
return '无效'
}
}
static ajaxFetch(opt: AjaxFetchOption) {
let { url, referrer = '/', method, body = null } = opt;
let req_params: RequestInit = {
headers: { 'X-Requested-With': 'XMLHttpRequest' },
referrer,
method,
};
if (method === 'POST') {
req_params.headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
req_params.body = body;
}
return fetch(url, req_params);
}
/**
* mutation.observe
* @param {String} selector - CSS规则的HTML元素选择器
* @param {Document} content -
* @param {number} timeout -
* @returns {Promise<HTMLElement|null>}
*/
static elementReady(selector: string, content: Document = document, timeout: number = 30000): Promise<HTMLElement> {
return new Promise((resolve, reject) => {
let el = content.querySelector(selector) as HTMLElement;
if (el) {
resolve(el);
return
}
let observer = new MutationObserver((_, observer) => {
content.querySelectorAll(selector).forEach((element) => {
observer.disconnect();
resolve(element as HTMLElement);
});
});
setTimeout(() => {
observer.disconnect();
reject(`等待元素超时! [${ selector }]\n${ content.documentElement.tagName }`);
}, timeout);
observer.observe(content.documentElement, { childList: true, subtree: true });
});
}
static addStyle(rules: string): void {
let element = document.querySelector('style#wh-trans-gStyle');
if (element) {
element.innerHTML += rules;
} else {
element = document.createElement("style");
element.id = 'wh-trans-gStyle';
element.innerHTML = rules;
document.head.appendChild(element);
}
Log.info('CSS规则已添加', element);
}
static loading_gif_html(): string {
return LOADING_IMG_HTML;
}
/**
*
* @param {string} url URL
* @returns {undefined}
*/
public audioPlay(url: string = 'https://www.torn.com/js/chat/sounds/Warble_1.mp3') {
const audio = new Audio(url);
audio.addEventListener("canplaythrough", () => {
audio.play()
.catch(err => Log.error(err))
.then();
});
}
}

View File

@ -0,0 +1,23 @@
import WuhuBase from "../WuhuBase";
export default class FetchUtils extends WuhuBase {
/**
* jquery ajax string
* @param url
* @param method
*/
public ajax(url: string, method: 'GET' | 'POST'): Promise<string> {
return new Promise((res, rej) => {
$.ajax({
method: method,
url: url,
success: function (data) {
res(data)
},
error: function (e) {
rej(e)
}
});
});
}
}

View File

@ -0,0 +1,66 @@
import WuhuBase from "../WuhuBase";
import Alert from "./Alert";
import ISidebarData from "../../interface/ISidebarData";
import Log from "../Log";
import CommonUtils from "./CommonUtils";
export default class InfoUtils extends WuhuBase {
/**
* { 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 this.sleep(10);
}
if (sessionStorage.getItem(field)) {
ret = JSON.parse(sessionStorage.getItem(field));
} else {
Log.info('无法从sessionStorage获取数据')
ret = await (await CommonUtils.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;
}
/**
*
* @param {Number} ms
* @returns {Promise<void>}
*/
private sleep(ms) {
let time = Math.max(ms, 10);
return new Promise(resolve => setTimeout(() => resolve(null), time));
}
}

View File

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

View File

@ -0,0 +1,11 @@
import WuhuBase from "../WuhuBase";
export default class MathUtils extends WuhuBase {
// 得到一个两数之间的随机整数
public getRandomInt(min: number, max: number): number {
min = Math.ceil(min);
max = Math.floor(max);
//不含最大值,含最小值
return Math.floor(Math.random() * (max - min)) + min;
}
}

View File

@ -0,0 +1,44 @@
import IWHNotify from "../../interface/IWHNotify";
import Log from "../Log";
import WuhuBase from "../WuhuBase";
export default class NotificationUtils extends WuhuBase {
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)
}
);
}
}
}

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

@ -0,0 +1,45 @@
import WuhuBase from "../WuhuBase";
import POPUP_HTML from "../../static/html/popup.html";
export default class Popup extends WuhuBase {
protected className = 'Popup';
private readonly container: HTMLElement = null;
private readonly node: HTMLElement = null;
constructor(innerHTML: string, title: string = '芜湖助手') {
super();
if (Popup.glob.popup_node) Popup.glob.popup_node.close();
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();
}
public close() {
this.container.remove();
this.showChat();
}
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() {
}
}

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');
@ -22,9 +19,6 @@ export default function adHelper() {
clear_button.innerText = '清空所有聊天框'; clear_button.innerText = '清空所有聊天框';
paste_button.innerText = '粘贴剪切板'; paste_button.innerText = '粘贴剪切板';
style.innerHTML = '#chatRoot > div{z-index:199999 !important;}'; style.innerHTML = '#chatRoot > div{z-index:199999 !important;}';
place_button.classList.add('torn-btn');
clear_button.classList.add('torn-btn');
paste_button.classList.add('torn-btn');
place_button.addEventListener('click', () => { place_button.addEventListener('click', () => {
let chats = Array.from(document.querySelectorAll('#chatRoot textarea[name="chatbox2"]') as NodeListOf<HTMLTextAreaElement>); let chats = Array.from(document.querySelectorAll('#chatRoot textarea[name="chatbox2"]') as NodeListOf<HTMLTextAreaElement>);

View File

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

View File

@ -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,138 @@
import toThousands from "../utils/toThousands";
import log from "../utils/@deprecated/log";
import CommonUtils from "../../class/utils/CommonUtils";
import Log from "../../class/Log";
export default function cityFinder(): void {
CommonUtils.addStyle(`
.wh-city-finds .leaflet-marker-pane img[src*="torn.com/images/items/"]{
display: block !important;
box-sizing: border-box;
width: 40px !important;
height: 40px !important;
left: -20px !important;
top: -20px !important;
padding: 10px 0;
border: none;
border-radius: 100%;
background-color:#d2d2d28c;
box-shadow:0 0 10px 5px #000;
z-index: 999 !important;
}
.wh-city-finds .leaflet-marker-pane.leaflet-marker-icon.user-item-pinpoint.leaflet-clickable{display: none !important;}
#wh-city-finder{
box-shadow: 0 0 3px 0px #696969;
border-radius: 4px;
}
#wh-city-finder-header{
background-color: #3f51b5;
color: white;
padding: 8px;
font-size: 15px;
border-radius: 4px 4px 0 0;
text-shadow: 0 0 2px black;
background-image: linear-gradient(90deg,transparent 50%,rgba(0,0,0,.07) 0);
background-size: 4px;
}
#wh-city-finder-cont{
background: #616161;
padding: 8px;
color: #c7c7c7;
border-radius: 0 0 4px 4px;
font-size: 13px;
}
#wh-city-finder-cont span{
margin:2px 4px 2px 0;
padding:2px;
border-radius:2px;
background:green;
color:white;
display:inline-block;
}
`);
// 物品名与价格
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);
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('#map').classList.add('wh-city-finds');
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);
});
// 未发现物品 返回
if (founds.length === 0) {
// header.innerHTML = '捡垃圾助手';
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';
// 橙色 500m以下
else if (value < 500000000) el.node.style.backgroundColor = '#ffc107';
// 红色 >500m
else if (value >= 500000000) el.node.style.backgroundColor = '#f44336';
total += items[el.id]['price'];
});
header.innerHTML = `捡垃圾助手 - ${ founds.length } 个物品,总价值 $${ toThousands(total) }`;
};
// 未取到数据时添加循环来调用函数
if (items === null) {
// 15s超时
let timeout = 30;
const interval = window.setInterval(() => {
timeout--;
if (items !== null) {
displayNamePrice();
clearInterval(interval);
}
if (0 === timeout) {
log.info('获取物品名称与价格信息超时')
clearInterval(interval)
}
}, 500);
}
// 无法跨域获取数据时
else if (items === undefined) {
info.innerHTML += '(当前平台暂不支持查询价格)';
}
// 调用函数
else {
displayNamePrice();
}
})
}

View File

@ -1,36 +1,30 @@
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 { 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 +47,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', () => {
@ -71,78 +65,63 @@ export default function depoHelper() {
if (location.pathname.startsWith('/trade.php')) { if (location.pathname.startsWith('/trade.php')) {
// GT助手 // GT助手
let node_link = null; let node_link = null;
let handle = (id: string = null) => { let handle = () => {
let { addRFC } = window; let { addRFC } = window;
// 不重复加载、已关闭的交易不加载 // 不重复加载、已关闭的交易不加载
if (node_link !== null || location.hash.toLowerCase().includes('logview')) { if (node_link !== null || location.hash.includes('Logview')) return;
if (node_link) { Log.info('已添加GT助手');
node_link.return();
node_link = null;
}
return;
}
logger.info('已添加GT助手');
// 获取交易id // 获取交易id
let query_params = location.hash.slice(1); let query_params = location.hash.slice(1);
let traceId = id; let traceId;
if (!traceId) query_params.split('&').forEach(param => query_params.split('&')
(param.startsWith('ID=')) && (traceId = param.slice(3)) .forEach(param =>
); (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 CommonUtils.ajaxFetch({ url: url, method: 'GET', referrer: 'trade.php' })).text();
url: url,
method: 'GET',
referrer: 'trade.php'
})).text();
} }
}; };
// 监听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)
); );
// 构建dom节点 // 构建dom节点
// let node = document.createElement('div'); let node = document.createElement('div');
let _node = new TornStyleBlock('GT助手'); node_link = node;
// node_link = node; let nodeTitle = document.createElement('div');
node_link = _node; let nodeCont = document.createElement('div');
// let nodeTitle = document.createElement('div');
// let nodeCont = document.createElement('div');
let inputMoney = document.createElement('input'); let inputMoney = document.createElement('input');
let buttonDepositAll = document.createElement('button'); let buttonDepositAll = document.createElement('button');
let buttonWithdraw = document.createElement('button'); let buttonWithdraw = document.createElement('button');
let buttonWithdrawAll = document.createElement('button'); let buttonWithdrawAll = document.createElement('button');
// let style = document.createElement('style'); let style = document.createElement('style');
inputMoney.placeholder = '定额取钱'; inputMoney.placeholder = '定额取钱';
inputMoney.type = 'number'; inputMoney.type = 'number';
inputMoney.style.padding = '7px'; inputMoney.style.padding = '7px';
inputMoney.style.paddingLeft = '14px'; inputMoney.style.paddingLeft = '14px';
// inputMoney.classList.add('m-right10'); inputMoney.classList.add('m-right10');
buttonDepositAll.innerHTML = '全存'; buttonDepositAll.innerHTML = '全存';
buttonDepositAll.style.color = 'green'; buttonDepositAll.style.color = 'green';
buttonDepositAll.classList.add('torn-btn');
buttonWithdraw.innerHTML = '定取'; buttonWithdraw.innerHTML = '定取';
buttonWithdraw.classList.add('torn-btn');
buttonWithdrawAll.innerHTML = '全取'; buttonWithdrawAll.innerHTML = '全取';
buttonWithdrawAll.style.color = 'red'; buttonWithdrawAll.style.color = 'red';
buttonWithdrawAll.classList.add('torn-btn'); nodeTitle.innerHTML = 'GT助手';
// nodeTitle.innerHTML = 'GT助手'; nodeTitle.classList.add('title-black', 'top-round');
// nodeTitle.classList.add('title-black', 'top-round'); style.innerHTML = '#WHGTHelper button{cursor:pointer;}#WHGTHelper button:hover{opacity:0.5;}';
// style.innerHTML = '#WHGTHelper button{cursor:pointer;}#WHGTHelper button:hover{opacity:0.5;}'; nodeCont.append(inputMoney, buttonWithdraw, buttonDepositAll, buttonWithdrawAll);
// nodeCont.append(inputMoney, buttonWithdraw, buttonDepositAll, buttonWithdrawAll); nodeCont.classList.add('cont-gray', 'bottom-round');
// nodeCont.classList.add('cont-gray', 'bottom-round'); nodeCont.style.padding = '10px';
// nodeCont.style.padding = '10px'; node.id = 'WHGTHelper';
// node.id = 'WHGTHelper'; node.classList.add('m-bottom10');
// node.classList.add('m-bottom10'); node.append(nodeTitle, nodeCont, style);
// node.append(nodeTitle, nodeCont, style);
_node.append(inputMoney, buttonWithdraw, buttonDepositAll, buttonWithdrawAll);
// 定取 // 定取
buttonWithdraw.addEventListener('click', async () => { buttonWithdraw.addEventListener('click', async () => {
@ -157,7 +136,7 @@ export default function depoHelper() {
new Alert('无法定额取钱,原因:数不对'); new Alert('无法定额取钱,原因:数不对');
return; return;
} }
await fetchUtils.ajaxFetch({ await CommonUtils.ajaxFetch({
url: addRFC('/trade.php'), url: addRFC('/trade.php'),
method: 'POST', method: 'POST',
referrer: 'trade.php', referrer: 'trade.php',
@ -169,7 +148,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 CommonUtils.ajaxFetch({
url: addRFC('/trade.php'), url: addRFC('/trade.php'),
method: 'POST', method: 'POST',
referrer: 'trade.php', referrer: 'trade.php',
@ -179,7 +158,7 @@ export default function depoHelper() {
}); });
// 全取 // 全取
buttonWithdrawAll.addEventListener('click', async () => { buttonWithdrawAll.addEventListener('click', async () => {
await fetchUtils.ajaxFetch({ await CommonUtils.ajaxFetch({
url: addRFC('/trade.php'), url: addRFC('/trade.php'),
method: 'POST', method: 'POST',
referrer: 'trade.php', referrer: 'trade.php',
@ -191,27 +170,23 @@ export default function depoHelper() {
if (location.hash.includes('ID=')) handle(); if (location.hash.includes('ID=')) handle();
addEventListener('hashchange', () => { addEventListener('hashchange', () => {
if (location.hash.includes('ID=')) handle(); if (location.hash.includes('ID=')) handle();
else if (location.hash.includes('initiateTrade')) { else {
CommonUtils.elementReady('a[href*="trade.php#step=addmoney"]').then(node => { node_link.remove();
handle(node.getAttribute('href').split('ID=')[1])
});
} else {
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 +208,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('请先打开金库');
@ -250,7 +225,7 @@ async function factionDeposit() {
}); });
$(form).trigger('submit'); $(form).trigger('submit');
let dataStr = `ajax=true&step=armouryDonate&type=cash&amount=${ money }`; let dataStr = `ajax=true&step=armouryDonate&type=cash&amount=${ money }`;
let res = await (await window.fetch(window.addRFC('https://www.torn.com/factions.php'), { let res = await (await fetch(window.addRFC('https://www.torn.com/factions.php'), {
method: 'POST', method: 'POST',
body: dataStr, body: dataStr,
headers: { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/x-www-form-urlencoded' } headers: { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/x-www-form-urlencoded' }
@ -263,19 +238,19 @@ 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');
let money = await fetchUtils.ajax(url, 'GET'); let money = await fetchUtils.ajax(url, 'GET');
if (money === '0') return; if (money === '0') return;
let res = await (await window.fetch(addRFC('https://www.torn.com/companies.php?step=funds'), { let res = await (await fetch(addRFC('https://www.torn.com/companies.php?step=funds'), {
method: 'POST', method: 'POST',
referrer: 'companies.php', referrer: 'companies.php',
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

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

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,32 +1,29 @@
import getWhSettingObj from "../utils/@deprecated/getWhSettingObj";
import log from "../utils/@deprecated/log";
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 { 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(() => { setInterval(() => {
const price_conf = localConfigWrapper.config.priceWatcher; const price_conf = getWhSettingObj()['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) {
Log.warn('价格监视关闭无apikey或设置未打开'); Log.error('价格监视失败无apikey')
window.clearInterval(intervalId);
return; return;
} }
if (price_conf['pt'] !== -1) priceWatcherPt(apikey, price_conf['pt'], priceTemp).then(); if (price_conf['pt'] !== -1) priceWatcherPt(apikey, price_conf['pt'], priceTemp).then();
if (price_conf['xan'] !== -1) priceWatcherXan(apikey, price_conf['xan'], priceTemp).then(); if (price_conf['xan'] !== -1) priceWatcherXan(apikey, price_conf['xan'], priceTemp).then();
}, 10000) }, 10000)
// return { status: true };
} }
// pt价格监视 // pt价格监视
async function priceWatcherPt(apikey, lower_price, priceWatcher) { async function priceWatcherPt(apikey, lower_price, priceWatcher) {
Log.info('pt价格监视开始', { apikey: typeof apikey, lower_price, priceWatcher });
if (!priceWatcher['watch-pt-lower-id']) priceWatcher['watch-pt-lower-id'] = []; if (!priceWatcher['watch-pt-lower-id']) priceWatcher['watch-pt-lower-id'] = [];
const res = await window.fetch('https://api.torn.com/market/?selections=pointsmarket&key=' + apikey); const res = await fetch('https://api.torn.com/market/?selections=pointsmarket&key=' + apikey);
const obj = await res.json(); const obj = await res.json();
if (obj['pointsmarket']) { if (obj['pointsmarket']) {
// 过滤低于价格的物品出售id // 过滤低于价格的物品出售id
@ -58,7 +55,7 @@ async function priceWatcherPt(apikey, lower_price, priceWatcher) {
async function priceWatcherXan(apikey, lower_price, priceWatcher) { async function priceWatcherXan(apikey, lower_price, priceWatcher) {
// 初始化记录上一个条目的id避免重复发送通知 // 初始化记录上一个条目的id避免重复发送通知
if (!priceWatcher['watch-xan-lower-id']) priceWatcher['watch-xan-lower-id'] = ''; if (!priceWatcher['watch-xan-lower-id']) priceWatcher['watch-xan-lower-id'] = '';
const res = await window.fetch('https://api.torn.com/market/206?selections=bazaar&key=' + apikey); const res = await fetch('https://api.torn.com/market/206?selections=bazaar&key=' + apikey);
const obj = await res.json(); const obj = await res.json();
if (obj['bazaar']) { if (obj['bazaar']) {
const lowest_item = obj['bazaar'][0] const lowest_item = obj['bazaar'][0]
@ -74,6 +71,6 @@ async function priceWatcherXan(apikey, lower_price, priceWatcher) {
} }
} else { } else {
// 查询出错了 // 查询出错了
Log.error('xan查询出错了') log.info('xan查询出错了')
} }
} }

View File

@ -1,16 +1,12 @@
import popupMsg from "../utils/@deprecated/popupMsg";
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 Popup from "../../class/utils/Popup"; import Log from "../../class/Log";
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 = popupMsg('<p>监测目标ID玩家的防御状态找出隐身攻击者</p>', '守望者 (测试中)');
let p = document.createElement('p'); let p = document.createElement('p');
let uid: HTMLInputElement = document.createElement('input'); let uid: HTMLInputElement = document.createElement('input');
let start = document.createElement('button'); let start = document.createElement('button');
@ -46,19 +42,17 @@ export default function safeKeeper() {
// 弹出窗口关闭时结束 // 弹出窗口关闭时结束
let popup_close = popup.close; let popup_close = popup.close;
popup.close = () => { popup.close = () => {
if (loop_id === null) { if (loop_id === null) popup_close();
popup.close = popup_close; else new Alert('守望者运行中,请先停止', { timeout: 2 });
popup.close();
} else new Alert('守望者运行中,请先停止', { timeout: 2 });
} }
popup.element.appendChild(p); popup.appendChild(p);
popup.element.appendChild(uid); popup.appendChild(uid);
popup.element.appendChild(start); popup.appendChild(start);
popup.element.appendChild(stop); popup.appendChild(stop);
popup.element.appendChild(self_target); popup.appendChild(self_target);
popup.element.appendChild(attackers); popup.appendChild(attackers);
popup.element.appendChild(records); popup.appendChild(records);
start.addEventListener('click', () => { start.addEventListener('click', () => {
if (loop_id !== null || !uid.value) return; if (loop_id !== null || !uid.value) return;
@ -67,16 +61,16 @@ export default function safeKeeper() {
uid.readOnly = true; uid.readOnly = true;
p.innerHTML = '状态:已开 ✅'; p.innerHTML = '状态:已开 ✅';
let count = 0; let count = 0;
loop_id = window.setInterval(async () => { loop_id = setInterval(async () => {
// 记录当前循环的id // 记录当前循环的id
let that_id = loop_id; let that_id = loop_id;
let res = await (await window.fetch(url + uid.value, { let res = await (await fetch(url + uid.value, {
headers: { 'X-Requested-With': 'XMLHttpRequest' }, headers: { 'X-Requested-With': 'XMLHttpRequest' },
referrer: "loader.php?sid=attack&user2ID=" + uid.value referrer: "loader.php?sid=attack&user2ID=" + uid.value
})).text(); })).text();
if (loop_id !== that_id) return; if (loop_id !== that_id) return;
let data = JSON.parse(res.split('<div')[0]); let data = JSON.parse(res.split('<div')[0]);
logger.info(count++, data); Log.info(count++, data);
let { DB, currentFightStatistics, histLog } = data; let { DB, currentFightStatistics, histLog } = data;
// 攻击人 // 攻击人
// 格式currentFightStatistics = {uid: {...}, uid2: {...}} // 格式currentFightStatistics = {uid: {...}, uid2: {...}}
@ -118,9 +112,9 @@ export default function safeKeeper() {
start.disabled = false; start.disabled = false;
stop.disabled = true; stop.disabled = true;
uid.readOnly = false; uid.readOnly = false;
window.clearInterval(loop_id); clearInterval(loop_id);
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,409 @@
import titleTrans from "../translate/titleTrans";
import contentTitleLinksTrans from "../translate/contentTitleLinksTrans";
import Device from "../../enum/Device";
import doQuickFly from "./doQuickFly";
import WuhuBase from "../../class/WuhuBase";
import Alert from "../../class/utils/Alert";
import ActionButtonUtils from "../../class/utils/ActionButtonUtils";
import WuhuConfig from "../../class/WuhuConfig";
import CommonUtils from "../../class/utils/CommonUtils";
import Log from "../../class/Log";
export default async function travelHelper(): Promise<null> {
let { href, bodyAttrs, device } = WuhuBase.glob;
// URL判断 + 人不在城内
if (href.includes('index.php') && bodyAttrs['data-abroad'] === 'true') {
// 飞行中
if (bodyAttrs["data-traveling"] === 'true') {
// 飞行闹钟
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', 'sa': '南非',
}[country] || country;
}
// 剩余时间
const remaining_arr = document.querySelector('#countrTravel').getAttribute('data-to');
const wh_trv_alarm = localStorage.getItem('wh_trv_alarm')
? JSON.parse(localStorage.getItem('wh_trv_alarm'))
: { 'enable': true, 'alert_time': 30, 'node_pos': [240, 240] };
const save_trv_settings = () => localStorage.setItem('wh_trv_alarm', JSON.stringify(wh_trv_alarm));
const wh_trv_alarm_node = document.createElement('div');
wh_trv_alarm_node.id = 'wh-trv-alarm';
wh_trv_alarm_node.style.left = `${ wh_trv_alarm.node_pos[0] }px`;
wh_trv_alarm_node.style.top = `${ wh_trv_alarm.node_pos[1] }px`;
wh_trv_alarm_node.innerHTML = `<div id="wh-trv-error"><p><b>❌ 没有权限</b><br/>点击网页内任意位置以激活闹钟</p></div>
<div id="wh-trv-alarm-title">
<h5 id="wh-trv-alarm-header"></h5>
</div>
<div id="wh-trv-alarm-bottom">
<div id="wh-trv-alarm-cont">
<p id="wh-trv-alarm-remaining"></p>
<p><span id="wh-trv-status">${ dest_cn === '回城' ? dest_cn : '飞往' + dest_cn } </span><span></span></p>
<div><label><input type="checkbox" ${ wh_trv_alarm.enable ? 'checked ' : ' ' }/> </label></div>
<div><label>(): <input type="number" value="${ wh_trv_alarm.alert_time || 30 }" /></label><button></button></div>
<div class="wh-trv-alarm-stop-hide"><button></button></div>
</div>
</div>
`;
CommonUtils.addStyle(`
#wh-trv-alarm{
position:absolute;
width:248px;
/*left:${ wh_trv_alarm.node_pos[0] || 240 }px;
top:${ wh_trv_alarm.node_pos[1] || 240 }px;*/
background:white;
border-radius:4px;
box-shadow:#0000001f 0 0 10px 4px;
border:solid 1px #aaa;
z-index:100001;
margin:2em;
}
#wh-trv-alarm button{
margin:0;
}
#wh-trv-error{
position:absolute;
width:100%;
height:100%;
/*display: table;*/
display:none;
}
#wh-trv-error p{
background:#ffd0d0;
color:red;
display:table-cell;
vertical-align:middle;
padding:1em;
text-align:center;
}
#wh-trv-alarm-title{
height: 30px;
border-bottom: solid #aaa 1px;
cursor: move;
}
/*#wh-trv-alarm-move-btn span{
background:url(/images/v2/home_main/move.svg);
width: 30px;
height: 30px;
float: right;
cursor: move;
}*/
h5#wh-trv-alarm-header{
height: 100%;
line-height: 30px;
padding:0 12px;
font-weight: bold;
text-align: center;
}
#wh-trv-alarm-bottom{
padding: 12px;
}
#wh-trv-alarm-remaining{
float:right;
color:red;
}
#wh-trv-alarm-cont input[type="number"]{
width: 42px;
border-bottom: solid 1px #aaa;
}
.wh-trv-alarm-stop-hide{
display:none;
}
`);
document.body.append(wh_trv_alarm_node);
// 报错dom
const error_node = wh_trv_alarm_node.querySelector('#wh-trv-error') as HTMLElement;
// jquery拖动
// @ts-ignore
$(wh_trv_alarm_node).draggable({
containment: "body",
distance: 5,
handle: "#wh-trv-alarm-title",
stop: () => {
wh_trv_alarm.node_pos = [parseInt(wh_trv_alarm_node.style.left), parseInt(wh_trv_alarm_node.style.top)];
save_trv_settings();
},
scroll: false,
});
// 剩余时间dom
const remaining_node = wh_trv_alarm_node.querySelector('#wh-trv-alarm-remaining');
// 设定闹钟响的按钮
const set_node = wh_trv_alarm_node.querySelectorAll('#wh-trv-alarm-cont button')[0] as HTMLButtonElement;
// 落地前响铃时长
const cd_time = wh_trv_alarm_node.querySelector('input[type="number"]') as HTMLInputElement;
let count_down_notify: MyHTMLElement | { close: Function } = {
close: () => {
}
};
set_node.onclick = () => {
try {
wh_trv_alarm.alert_time = parseInt(cd_time.value);
} catch {
wh_trv_alarm.alert_time = 30;
}
save_trv_settings();
set_node.value = wh_trv_alarm.alert_time;
count_down_notify.close();
count_down_notify = 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);
Log.info({
dest_cn,
remaining_arr,
wh_trv_alarm,
wh_trv_alarm_node,
error_node,
remaining_node,
set_node,
cd_time,
count_down_notify,
stop_node,
enable_node,
remaining_sec,
land_timestamp,
audio,
audio_play_flag,
user_stop_alert,
audio_play_id,
flying_status,
flying_index,
id
});
}
// 落地转跳 落地前事件
if (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);
});
}
}
// 不在飞行中 海外落地页面
else {
// 一键回城
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 page_title = document.querySelector('h4#skip-to-content');
let msg = document.createElement('div');
msg.innerHTML = `<div class="info-msg border-round">
<i class="info-icon"></i>
<div class="delimiter">
<div class="msg right-round" tabindex="0" role="alert">
<p><a href="/index.php?page=rehab"> </a></p>
</div>
</div>
</div>`;
msg.classList.add('info-msg-cont', 'green', 'border-round', 'm-bottom10');
page_title.before(msg);
}
}
return;
}
// URL判断 + 人在城内
else if (href.includes('index.php') && bodyAttrs['data-abroad'] === 'false') {
// 落地转跳
if (sessionStorage['wh-landed-redirect']) {
let { url, timestamp } = JSON.parse(sessionStorage['wh-landed-redirect']);
if (Date.now() - timestamp < 30000) {
sessionStorage.removeItem('wh-landed-redirect');
location.href = url;
}
}
}
// 起飞页面
if (href.contains(/travelagency\.php/)) {
// 起飞提醒
if (WuhuConfig.get('energyAlert')) {
const $$ = $('.content-wrapper');
const OB = new MutationObserver(() => {
OB.disconnect();
titleTrans();
contentTitleLinksTrans();
trans();
OB.observe($$.get(0), {
characterData: true,
attributes: true,
subtree: true,
childList: true
});
});
const trans = () => {
// 当前能量e
const energyBarStr = $('#barEnergy p[class^="bar-value__"]').text().trim();
const [curE, maxE] = energyBarStr.split('/').length === 2
? [parseInt(energyBarStr.split('/')[0]), parseInt(energyBarStr.split('/')[1])]
: [NaN, NaN];
const incTime = maxE === 150 ? 10 : 15;
const fullEnergyTime = !(isNaN(curE) || isNaN(maxE)) ? (maxE - 5 - curE) / 5 * incTime
+ (incTime - new Date().getMinutes() % incTime) : NaN;
// 起飞前提示
$('.travel-confirm .travel-question .q-wrap span:nth-of-type(2)').each((i, e) => {
if (isNaN(fullEnergyTime)) return;
const spl = e.innerText.trim().split(' ');
const [hours, minutes] = spl.length === 5
? [parseInt(spl[0]), parseInt(spl[3])]
: [0, parseInt(spl[0])];
if (fullEnergyTime < (hours * 60 + minutes) * 2) {
if (!$(e).parent().hasClass('wh-translated')) {
$(e).parent()
.prepend(`<div style="color: red">警告:该次飞行往返时间大于体力回复时间,将会爆体!</div>`)
.addClass('wh-translated');
}
}
});
};
trans();
OB.observe($$.get(0), {
characterData: true,
attributes: true,
subtree: true,
childList: true
});
}
// 一键起飞
if (sessionStorage['wh-quick-fly']) {
doQuickFly();
}
}
}
async function travelBack(): Promise<null> {
if (typeof window['getAction'] !== 'function') return;
let backHomeAction = function (): Promise<string> {
return new Promise(resolve => {
window.getAction({
type: "post",
action: 'travelagency.php',
data: {
step: 'backHomeAction'
},
success: function (msg) {
resolve(msg);
}
});
});
};
let res = await backHomeAction();
new Alert(res);
if (!res.includes('error')) {
new Alert('成功,即将刷新');
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,10 @@ 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";
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 +61,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')) {
@ -129,14 +123,12 @@ export default function translateMain(href: string): void {
const headerTrans = function headerTrans() { const headerTrans = function headerTrans() {
// 搜索内容下拉框中的文字 已选中 // 搜索内容下拉框中的文字 已选中
let $toggle = $('div.find button.toggler.down'); if (headerDict[$('div.find button.toggler.down').text()])
if (headerDict[$toggle.text()]) $('div.find button.toggler.down').text(headerDict[$('div.find button.toggler.down').text()]);
$toggle.text(headerDict[$toggle.text()]);
// pc端 搜索下拉框点击后的搜索类型文字 // pc端 搜索下拉框点击后的搜索类型文字
$('div.find li.item').each((i, e) => { $('div.find li.item').each((i, e) => {
let $e = $(e); if (headerDict[$(e).text()])
if (headerDict[$e.text()]) $(e).text(headerDict[$(e).text()]);
$e.text(headerDict[$e.text()]);
}); });
// 手机端 搜索下拉框点击后的搜索类型文字 // 手机端 搜索下拉框点击后的搜索类型文字
$('li[class^="search-type-"] label').each((i, e) => { $('li[class^="search-type-"] label').each((i, e) => {
@ -144,54 +136,46 @@ export default function translateMain(href: string): void {
$(e).text(headerDict[$(e).text()]); $(e).text(headerDict[$(e).text()]);
}); });
// 搜索框placeholder // 搜索框placeholder
let $searchInput = $('input[class^="searchInput"]'); if (headerDict[$('input[class^="searchInput"]').attr('placeholder')])
if (headerDict[$searchInput.attr('placeholder')]) $('input[class^="searchInput"]').attr('placeholder',
$searchInput.attr('placeholder', headerDict[$('input[class^="searchInput"]').attr('placeholder')]);
headerDict[$searchInput.attr('placeholder')]);
// 高级搜索框 search by // 高级搜索框 search by
if (headerDict[document.querySelector('div#header-root legend.title').innerText]) { if (headerDict[document.querySelector('div#header-root legend.title').innerText])
let $title = $('div#header-root legend.title'); $('div#header-root legend.title').text(headerDict[$('div#header-root legend.title').text()]);
$title.text(headerDict[$title.text()]);
}
// 高级搜索框的条件 左 键 // 高级搜索框的条件 左 键
$('ul.advancedSearchFormBody label.label').each((i, e) => { $('ul.advancedSearchFormBody label.label').each((i, e) => {
let $e = $(e); if (headerDict[$(e).text()])
if (headerDict[$e.text()]) $(e).text(headerDict[$(e).text()]);
$e.text(headerDict[$e.text()]);
}); });
// 高级搜索框的已选中 // 高级搜索框的已选中
$('ul.advancedSearchFormBody div.select-wrapper button.toggler.down').each((i, e) => { $('ul.advancedSearchFormBody div.select-wrapper button.toggler.down').each((i, e) => {
let $e = $(e); // log($(e).text())
if (headerDict[$e.text().trim()]) if (headerDict[$(e).text().trim()])
$e.text(headerDict[$e.text().trim()]); $(e).text(headerDict[$(e).text().trim()]);
else if (propertyDict[$e.text().trim()]) else if (propertyDict[$(e).text().trim()])
$e.text(propertyDict[$e.text().trim()]); $(e).text(propertyDict[$(e).text().trim()]);
}); });
// 高级搜索的下拉选项 // 高级搜索的下拉选项
$('ul.advancedSearchFormBody li.item').each((i, e) => { $('ul.advancedSearchFormBody li.item').each((i, e) => {
let $e = $(e); if (headerDict[$(e).text()])
if (headerDict[$e.text()]) $(e).text(headerDict[$(e).text()]);
$e.text(headerDict[$e.text()]); else if (propertyDict[$(e).text()])
else if (propertyDict[$e.text()]) $(e).text(propertyDict[$(e).text()]);
$e.text(propertyDict[$e.text()]);
}); });
// 高级搜索的"Not" // 高级搜索的"Not"
$('ul.advancedSearchFormBody label.search-condition-not').each((i, e) => { $('ul.advancedSearchFormBody label.search-condition-not').each((i, e) => {
let $e = $(e); if (headerDict[$(e).text()])
if (headerDict[$e.text()]) $(e).text(headerDict[$(e).text()]);
$e.text(headerDict[$e.text()]);
}); });
// 高级搜索的"to" // 高级搜索的"to"
$('ul.advancedSearchFormBody label[for*="To"]').each((i, e) => { $('ul.advancedSearchFormBody label[for*="To"]').each((i, e) => {
let $e = $(e); if (headerDict[$(e).text()])
if (headerDict[$e.text()]) $(e).text(headerDict[$(e).text()]);
$e.text(headerDict[$e.text()]);
}); });
// 高级搜索的reset search按钮 // 高级搜索的reset search按钮
$('form.form-search-extend div.bottom button').each((i, e) => { $('form.form-search-extend div.bottom button').each((i, e) => {
let $e = $(e); if (headerDict[$(e).text()])
if (headerDict[$e.text()]) $(e).text(headerDict[$(e).text()]);
$e.text(headerDict[$e.text()]);
}); });
// log按钮“view log” // log按钮“view log”
const $view_log = $('div.recentHistory a[class^="link"] span[class^="text"]') const $view_log = $('div.recentHistory a[class^="link"] span[class^="text"]')
@ -200,9 +184,8 @@ export default function translateMain(href: string): void {
.text(headerDict[$view_log.text().trim()]); .text(headerDict[$view_log.text().trim()]);
// 点击头像打开的菜单 // 点击头像打开的菜单
$('ul.settings-menu span').each((i, e) => { $('ul.settings-menu span').each((i, e) => {
let $e = $(e); if (headerDict[$(e).text()] && e.childNodes.length === 1)
if (headerDict[$e.text()] && e.childNodes.length === 1) $(e).text(headerDict[$(e).text()]);
$e.text(headerDict[$e.text()]);
else if (e.childNodes.length === 3) else if (e.childNodes.length === 3)
if (headerDict[e.firstChild.nodeValue]) if (headerDict[e.firstChild.nodeValue])
e.firstChild.nodeValue = headerDict[e.firstChild.nodeValue]; e.firstChild.nodeValue = headerDict[e.firstChild.nodeValue];
@ -222,22 +205,20 @@ export default function translateMain(href: string): void {
const chatTrans = function chatTrans() { const chatTrans = function chatTrans() {
// 聊天框的标题 // 聊天框的标题
$('div#chatRoot div[class^="chat-box-title"] span[class^="name"]').each((i, e) => { $('div#chatRoot div[class^="chat-box-title"] span[class^="name"]').each((i, e) => {
let $e = $(e); if (chatDict[$(e).text().trim()])
if (chatDict[$e.text().trim()]) $(e).text(chatDict[$(e).text().trim()]);
$e.text(chatDict[$e.text().trim()]);
}); });
// 聊天设置的左边label // 聊天设置的左边label
$('div[class^="chat-settings-opts"] div[class*="label"]').each((i, e) => { $('div[class^="chat-settings-opts"] div[class*="label"]').each((i, e) => {
let $e = $(e); if ($(e).next().children('div.rc-slider').length > 0) {
if ($e.next().children('div.rc-slider').length > 0) {
// 高度和宽度有响应式的% // 高度和宽度有响应式的%
if (chatDict[$e.text().split(' ')[0]]) { if (chatDict[$(e).text().split(' ')[0]]) {
$e.text($e.text().replace($e.text().split(' ')[0], chatDict[$e.text().split(' ')[0]])); $(e).text($(e).text().replace($(e).text().split(' ')[0], chatDict[$(e).text().split(' ')[0]]));
} }
return; return;
} }
if (chatDict[$e.text().trim()]) if (chatDict[$(e).text().trim()])
$e.text(chatDict[$e.text().trim()]); $(e).text(chatDict[$(e).text().trim()]);
}); });
// 选项下拉栏 // 选项下拉栏
$('div[class^="dropdown-root"]').find('*').contents().each((i, e) => { $('div[class^="dropdown-root"]').find('*').contents().each((i, e) => {
@ -247,30 +228,29 @@ export default function translateMain(href: string): void {
}); });
// 设置的两个选项 // 设置的两个选项
$('label[class^="privacy-label"]').each((i, e) => { $('label[class^="privacy-label"]').each((i, e) => {
let $e = $(e); if (chatDict[$(e).text().trim()])
if (chatDict[$e.text().trim()]) $(e).text(chatDict[$(e).text().trim()]);
$e.text(chatDict[$e.text().trim()]);
}); });
// people中的5个分类 faction friend... // people中的5个分类 faction friend...
$('ul[class^="type-list"] li a').each((i, e) => { $('ul[class^="type-list"] li a').each((i, e) => {
let $e = $(e); if (chatDict[$(e).text().trim()])
if (chatDict[$e.text().trim()]) $(e).text(chatDict[$(e).text().trim()]);
$e.text(chatDict[$e.text().trim()]);
}); });
// people中的列表添加框placeholder // people中的列表添加框placeholder
$('div.ac-wrapper input.ac-search').each((i, e) => { $('div.ac-wrapper input.ac-search').each((i, e) => {
let $e = $(e); if (chatDict[$(e).attr('placeholder')])
if (chatDict[$e.attr('placeholder')]) $(e).attr('placeholder', chatDict[$(e).attr('placeholder')]);
$e.attr('placeholder', chatDict[$e.attr('placeholder')]);
}); });
// //
let $chatRootOverview = document.querySelector('div#chatRoot div[class^="overview"] > div > div:nth-child(2)'); if (eventsDict[$('div#chatRoot div[class^="overview"] > div > div:nth-child(2)').text().trim()]) {
if (eventsDict[$chatRootOverview.innerText.trim()]) { $('div#chatRoot div[class^="overview"] > div > div:nth-child(2)')
$chatRootOverview.innerText = eventsDict[$chatRootOverview.innerText.trim()]; .text(
eventsDict[document.querySelector('div#chatRoot div[class^="overview"] > div > div:nth-child(2)').innerText.trim()]
);
} }
}; };
chatTrans(); chatTrans();
chatOB.observe(document.querySelector('div#chatRoot'), { childList: true, subtree: true, attributes: true }); chatOB.observe($('div#chatRoot').get(0), { childList: true, subtree: true, attributes: true });
} }
// 搜索玩家的4个分类按钮 // 搜索玩家的4个分类按钮
@ -347,18 +327,18 @@ export default function translateMain(href: string): void {
// 翻译最近5个攻击 // 翻译最近5个攻击
else if (e.firstChild.nodeValue === 'Latest Attacks') { else if (e.firstChild.nodeValue === 'Latest Attacks') {
$(e).parent().next().find('span').each(function () { $(e).parent().next().find('span').each(function () {
let $this = $(this); let nodes = $(this)[0].childNodes;
let nodes = $this[0].childNodes;
nodes.forEach((v, i) => { nodes.forEach((v, i) => {
if (v.nodeValue !== null) { if (v.nodeValue !== null) {
// let waitToTsf = v.nodeValue.toString().indexOf(" "); let waitToTsf = v.nodeValue.toString().indexOf(" ");
let words = v.nodeValue.replace("\n", "").toString().split(" "); let words = v.nodeValue.replace("\n", "").toString().split(" ");
words.forEach((word, j) => { words.forEach((word, j) => {
if (attackDict.hasOwnProperty(word)) { if (attackDict.hasOwnProperty(word)) {
if (word === "Someone") { if (word === "Someone") {
$this[0].childNodes[i].nodeValue = $(this)[0].childNodes[i].nodeValue.replace(" ", ""); $(this)[0].childNodes[i].nodeValue = $(this)[0].childNodes[i].nodeValue.replace(" ", "");
} }
$this[0].childNodes[i].nodeValue = $this[0].childNodes[i].nodeValue.replace(word, attackDict[word]); let change = $(this)[0].childNodes[i].nodeValue.replace(word, attackDict[word]);
$(this)[0].childNodes[i].nodeValue = change;
} }
}) })
@ -393,13 +373,13 @@ export default function translateMain(href: string): void {
}); });
// 标志建筑 标题 // 标志建筑 标题
let $divTitleBlack = document.querySelector('div.title-black'); if (cityDict[$('div.title-black').text()])
if (cityDict[$divTitleBlack.innerText]) $('div.title-black').text(cityDict[$('div.title-black').text()]);
$divTitleBlack.innerText = cityDict[$divTitleBlack.innerText];
// 标志建筑 6个分类 // 标志建筑 6个分类
$('ul.map-symbols span').each((i, e) => { $('ul.map-symbols span').each((i, e) => {
if (cityDict[e.innerText]) e.innerText = cityDict[e.innerText]; if (cityDict[$(e).text()])
$(e).text(cityDict[$(e).text()]);
}); });
// 地图显示模式 // 地图显示模式
@ -408,13 +388,13 @@ export default function translateMain(href: string): void {
// 完全显示 文字 // 完全显示 文字
$('span.active-mode').text(cityDict['active-mode']); $('span.active-mode').text(cityDict['active-mode']);
// 开关 // 开关
document.querySelector('div.on-label').innerText = '已开启'; $('div.on-label').text('已开启');
document.querySelector('div.off-label').innerText = '已关闭'; $('div.off-label').text('已关闭');
// 快速链接中的分类标题 // 快速链接中的分类标题
$('li.title').each((i, e) => { $('li.title').each((i, e) => {
if (cityDict[e.innerText]) if (cityDict[$(e).text()])
e.innerText = cityDict[e.innerText]; $(e).text(cityDict[$(e).text()]);
}); });
// 快速链接中的区域 // 快速链接中的区域
@ -1113,7 +1093,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() }`);
} }
} }
// 添加敌人或朋友的界面 // 添加敌人或朋友的界面
@ -1255,10 +1235,9 @@ export default function translateMain(href: string): void {
let newspaperTrans = function newspaperTrans() { let newspaperTrans = function newspaperTrans() {
titleTrans(); titleTrans();
contentTitleLinksTrans(); contentTitleLinksTrans();
let $newspaperLink = $('a.newspaper-link'); if ($('a.newspaper-link').length === 0) return;
if ($newspaperLink.length === 0) return;
// 导航菜单 // 导航菜单
$newspaperLink.contents().each((i, e) => { $('a.newspaper-link').contents().each((i, e) => {
if (newspaperDict[e.nodeValue]) if (newspaperDict[e.nodeValue])
e.nodeValue = newspaperDict[e.nodeValue]; e.nodeValue = newspaperDict[e.nodeValue];
}); });
@ -1305,9 +1284,8 @@ export default function translateMain(href: string): void {
}); });
// 底部链接 // 底部链接
// Why not visit our sponsor? // Why not visit our sponsor?
let $linkLeft = document.querySelector('div.link-left'); if (newspaperDict[$('div.link-left').text().trim()])
if (newspaperDict[$linkLeft.innerText.trim()]) $('div.link-left').text(newspaperDict[$('div.link-left').text().trim()]);
$linkLeft.innerText = newspaperDict[$linkLeft.innerText.trim()];
// View all | Advertise here // View all | Advertise here
$('div.link-right a').contents().each((i, e) => { $('div.link-right a').contents().each((i, e) => {
if (newspaperDict[e.nodeValue.trim()]) if (newspaperDict[e.nodeValue.trim()])
@ -1328,9 +1306,8 @@ export default function translateMain(href: string): void {
} }
// 漫画 // 漫画
if (window.location.href.contains(/freebies/)) { if (window.location.href.contains(/freebies/)) {
let $bonusWrapA = document.querySelector('div.bonus-wrap a'); if (newspaperDict[$('div.bonus-wrap a').text().trim()])
if (newspaperDict[$bonusWrapA.innerText.trim()]) $('div.bonus-wrap a').text(newspaperDict[$('div.bonus-wrap a').text().trim()]);
$bonusWrapA.innerText = newspaperDict[$bonusWrapA.innerText.trim()];
} }
// 悬赏 // 悬赏
if (window.location.href.contains(/bounties/)) { if (window.location.href.contains(/bounties/)) {
@ -1983,42 +1960,39 @@ export default function translateMain(href: string): void {
//攻击链盒 //攻击链盒
$('div[class^="chain-box"]').contents().each((i, e) => { $('div[class^="chain-box"]').contents().each((i, e) => {
let $e = $(e); if (factionDict[$(e).text().trim()]) {
if (factionDict[$e.text().trim()]) { $(e).text(factionDict[$(e).text().trim()]);
$e.text(factionDict[$e.text().trim()]);
} }
}) })
//帮派消息类别 //帮派消息类别
$('div[class^="newsHeader"]').contents().each((i, e) => { $('div[class^="newsHeader"]').contents().each((i, e) => {
let $e = $(e); if (factionDict[$(e).text().trim()]) {
if (factionDict[$e.text().trim()]) { $(e).text(factionDict[$(e).text().trim()]);
$e.text(factionDict[$e.text().trim()]);
} }
}) })
//帮派主要消息日志 //帮派主要消息日志
$('button[class^="tab"] ').each((i, e) => { $('button[class^="tab"] ').each((i, e) => {
if (e.classList.contains('active')) { if ($(e).attr('class').indexOf("active") >= 0) {
Log.info(e.innerText); log.info($(e).text());
let $newListInfo = $('ul[class^="news-list"] span[class^="info"]'); switch ($(e).text().trim()) {
switch (e.innerText.trim()) {
case "主要消息": case "主要消息":
$newListInfo.contents().each((i, u) => { $('ul[class^="news-list"] span[class^="info"]').contents().each((i, u) => {
if (factionDict[$(u).text().trim()]) { if (factionDict[$(u).text().trim()]) {
u.nodeValue = u.nodeValue.replace($(u).text().trim(), factionDict[$(u).text().trim()]); u.nodeValue = u.nodeValue.replace($(u).text().trim(), factionDict[$(u).text().trim()]);
} }
}) })
break; break;
case "攻击": case "攻击":
$newListInfo.find('*').contents().each((i, u) => { $('ul[class^="news-list"] span[class^="info"]').find('*').contents().each((i, u) => {
Log.info($(u).text().trim()); log.info($(u).text().trim())
if (factionDict[$(u).text().trim()]) { if (factionDict[$(u).text().trim()]) {
u.nodeValue = factionDict[$(u).text().trim()]; u.nodeValue = factionDict[$(u).text().trim()];
} }
}) })
break; break;
case "资金流动": case "资金流动":
$newListInfo.contents().each((i, u) => { $('ul[class^="news-list"] span[class^="info"]').contents().each((i, u) => {
if (u.nodeValue) { if (u.nodeValue) {
u.nodeValue = u.nodeValue.replace("deposited", "存放了"); u.nodeValue = u.nodeValue.replace("deposited", "存放了");
} }

View File

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

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) }`),
});
}
}
});
}

View File

@ -0,0 +1,56 @@
/**
* Markdown
* @param {String} from
* @param {Number} max_line 500
* @returns {HTMLDivElement}
* @deprecated
*/
export default function mdParse(from: string, max_line?: number): HTMLElement {
max_line = max_line || 500;
const base = document.createElement('div');
let lines = from.split('\n');
if (lines.length > max_line) {
lines = lines.slice(0, max_line);
lines.push("...");
}
let prev = '';
let child_cont;
lines.forEach(line => {
if (line.trim() === '') return;
let node;
let spl = line.split(' ');
let md_flag = spl[0];
switch (md_flag) {
// 标题
case '#':
case '##':
case '###':
if (prev === 'li') {
child_cont = null;
}
prev = 'h' + (md_flag.length + 1);
node = document.createElement(prev);
node.innerText = line.slice(md_flag.length + 1);
base.append(node);
return;
// 列表
case '-':
if (prev !== 'li') {
child_cont = document.createElement('ul');
if (!base.contains(child_cont)) base.append(child_cont);
}
prev = 'li';
node = document.createElement(prev);
node.innerText = line.slice(2);
child_cont.append(node);
return;
}
prev = 'p';
node = document.createElement(prev);
node.innerText = line.trim();
base.append(node);
})
return base;
}

View File

@ -0,0 +1,151 @@
import addStyle from "./addStyle";
import WuhuBase from "../../../class/WuhuBase";
import MathUtils from "../../../class/utils/MathUtils";
import WindowActiveState from "../../../class/action/WindowActiveState";
/**
*
* @param {string} msg -
* @param {Object} [options] -
* @param {number} [options.timeout] -
* @param {function} [options.callback] -
* @param {boolean} [options.sysNotify] -
* @param {string} [options.sysNotifyTag] -
* @param {function} [options.sysNotifyClick] -
* @return {HTMLElement}
* @deprecated
*/
export default function WHNotify(msg: string, options: WHNotifyOpt = {}): MyHTMLElement {
let { notifies } = WuhuBase.glob;
let mathUtils: MathUtils = MathUtils.getInstance();
let {
timeout = 3,
callback = function () {
},
sysNotify = false,
sysNotifyTag = '芜湖助手',
sysNotifyClick = () => window.focus()
} = options;
if (!WindowActiveState.getInstance().get() || (self !== top)) return null;
const date = new Date();
// 通知的唯一id
const uid = `${ date.getHours() }${ date.getSeconds() }${ date.getMilliseconds() }${ mathUtils.getRandomInt(1000, 9999) }`;
// 通知容器id
// 通知的容器
let notify_contain: MyHTMLElement = document.querySelector(`#wh-notify`);
// 添加通知到容器
const add_notify = () => {
// 每条通知
const new_node: MyHTMLElement = document.createElement('div');
new_node.id = `wh-notify-${ uid }`;
new_node.classList.add('wh-notify-item');
new_node.innerHTML = `<div class="wh-notify-bar"></div>
<div class="wh-notify-cont">
<div class="wh-notify-close"></div>
<div class="wh-notify-msg"><p>${ msg }</p></div>
</div>`;
notify_contain.append(new_node);
notify_contain['msgInnerText'] = new_node.querySelector('.wh-notify-msg').innerText;
// 进度条node
const progressBar: HTMLElement = new_node.querySelector('.wh-notify-bar');
// 是否hover
let mouse_enter = false;
new_node.addEventListener('mouseenter', () => mouse_enter = true, true);
new_node.addEventListener('mouseleave', () => mouse_enter = false);
// 通知进度条
let progressCount = 101;
// 删除通知
new_node.close = () => {
clearInterval(intervalID);
new_node.remove();
callback();
};
// 计时器
let intervalID = window.setInterval(() => {
if (mouse_enter) {
progressCount = 101;
progressBar.style.width = '100%';
return;
}
progressCount--;
progressBar.style.width = `${ progressCount }%`;
if (progressCount === 0) new_node.remove();
}, timeout * 1000 / 100);
new_node.querySelector('.wh-notify-close').addEventListener('click', new_node.close);
return new_node;
};
// 不存在容器 创建
if (!notify_contain) {
notify_contain = document.createElement('div');
notify_contain.id = 'wh-notify';
addStyle(`
#wh-notify {
display: inline-block;
position: fixed;
top: 0;
left: calc(50% - 180px);
width: 360px;
z-index: 9999990;
color:#333;
}
#wh-notify a{
color:red;
text-decoration:none;
}
#wh-notify .wh-notify-item {
/*height: 50px;*/
background: rgb(239 249 255 / 90%);
border-radius: 2px;
margin: 0.5em 0 0 0;
box-shadow: 0 0 5px 0px #959595;
}
#wh-notify .wh-notify-item:hover {
background: rgb(239 249 255 / 98%);
}
#wh-notify .wh-notify-item .wh-notify-bar {
height:2px;
background:#2196f3;
}
#wh-notify .wh-notify-item .wh-notify-close {
float:right;
padding:0;
width:16px;height:16px;
background:url('data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%201024%201024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M923%20571H130.7c-27.6%200-50-22.4-50-50s22.4-50%2050-50H923c27.6%200%2050%2022.4%2050%2050s-22.4%2050-50%2050z%22%20fill%3D%22%232196f3%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E') no-repeat center;
background-size:100%;
margin: 6px 6px 0 0;
cursor: pointer;
}
#wh-notify .wh-notify-item .wh-notify-msg {
padding:12px;
}
`);
document.body.append(notify_contain);
}
const notify_obj = add_notify();
// 浏览器通知
if (window.Notification && Notification.permission === 'granted' && sysNotify) {
const date_local_string = `[${ date.getHours() }:${ date.getMinutes() }:${ date.getSeconds() }]\r`;
notify_obj.sys_notify = new Notification('芜湖助手', {
body: date_local_string + notify_contain.msgInnerText,
requireInteraction: true,
renotify: true,
tag: sysNotifyTag + mathUtils.getRandomInt(0, 99),
});
notify_obj.sys_notify.addEventListener('close', () => sysNotifyClick());
notify_obj.sys_notify.onshow = () => setTimeout(() => notify_obj.sys_notify.close(), timeout * 1000);
notify_obj.sys_notify.id = notifies.count++;
notifies[notify_obj.sys_notify.id] = notify_obj.sys_notify;
notify_obj.sys_notify.addEventListener('close', () => notifies[notify_obj.sys_notify.id] = null);
}
return notify_obj;
}
interface WHNotifyOpt {
timeout?: number;
callback?: Function;
sysNotify?: boolean;
sysNotifyTag?: string;
sysNotifyClick?: Function;
}

View File

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

View File

@ -0,0 +1,17 @@
import log from "./log";
/**
* @deprecated
*/
export default function addStyle(css: string) {
let wh_gStyle = document.querySelector('style#wh-trans-gStyle');
if (wh_gStyle) {
wh_gStyle.innerHTML += css;
} else {
wh_gStyle = document.createElement("style");
wh_gStyle.id = 'wh-trans-gStyle';
wh_gStyle.innerHTML = css;
document.head.append(wh_gStyle);
}
log.info('CSS规则已添加', wh_gStyle);
}

View File

@ -0,0 +1,23 @@
/**
* @deprecated
*/
export default function ajaxFetch(opt) {
let { url, referrer, method, body = null } = opt;
let req_params: AjaxFetchOpt = {
headers: { 'X-Requested-With': 'XMLHttpRequest' },
referrer,
method,
};
if (method === 'POST') {
req_params.headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
req_params.body = body;
}
return fetch(url, req_params);
}
interface AjaxFetchOpt {
headers: { 'X-Requested-With'?: string, 'Content-Type'?: string };
referrer: string;
method: string;
body?: any;
}

View File

@ -0,0 +1,27 @@
import CommonUtils from "../../../class/utils/CommonUtils";
import WindowActiveState from "../../../class/action/WindowActiveState";
/**
* json对象
* @deprecated
* @param dest
* @param time
*/
function autoFetchJSON(dest, time = 30) {
let obj;
const res = CommonUtils.COFetch(dest);
setInterval(async () => {
if (!WindowActiveState.getInstance().get()) return;
const res = await CommonUtils.COFetch(dest);
obj = JSON.parse(res);
}, time * 1000);
return {
get: async function () {
if (!obj) {
const str = await res
return obj = JSON.parse(str);
}
return obj;
}
};
}

View File

@ -0,0 +1,40 @@
import UserScriptEngine from "../../../enum/UserScriptEngine";
import WuhuBase from "../../../class/WuhuBase";
import CommonUtils from "../../../class/utils/CommonUtils";
import Popup from "../../../class/utils/Popup";
import * as FILTER from "../../../static/json/for_stock_item_filter.json";
/**
* @deprecated
*/
export default async function forStock() {
if (CommonUtils.getScriptEngine() === UserScriptEngine.RAW) {
const insert = `<img alt="stock.png" src="https://jjins.github.io/t2i/stock.png?{{}}" style="max-width:100%;display:block;margin:0 auto;" />`;
new Popup(insert, '飞花库存');
} 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;
const now = new Date();
const res = await WuhuBase.glob.fStock.get();
if (!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;
}
}

View File

@ -0,0 +1,11 @@
import UserScriptEngine from "../../../enum/UserScriptEngine";
import WuhuBase from "../../../class/WuhuBase";
/**
* @deprecated
*/
export default function getScriptEngine() {
let glob = WuhuBase.glob;
return glob.unsafeWindow ? UserScriptEngine.GM : glob.isPDA
? UserScriptEngine.PDA : UserScriptEngine.RAW;
}

View File

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

View File

@ -0,0 +1,9 @@
/**
* @deprecated
*/
export default function getUserState(): {} | any {
let obj = {};
let hdd = sessionStorage['headerData'];
if (hdd) obj = JSON.parse(hdd)['user']['state'];
return obj;
}

View File

@ -0,0 +1,11 @@
/**
* @deprecated
*/
export default function getWhSettingObj(): WHSettings {
return JSON.parse(localStorage.getItem('wh_trans_settings')) || {}
}
interface WHSettings {
// TODO 补全
[key: string]: any;
}

View File

@ -0,0 +1,36 @@
import getWhSettingObj from "./getWhSettingObj";
/**
* @deprecated
*/
function debug() {
try {
return getWhSettingObj()['isDev'] || false;
} catch (e) {
console.error(`[wh] dev状态错误 ${ e }`);
return false;
}
}
/**
* @deprecated
*/
const log = {
/**
* @deprecated
*/
error: (...o) => (debug()) && (console.error('[WH]', ...o)),
/**
* @deprecated
*/
info: (...o) => (debug()) && (console.log('[WH]', ...o)),
/**
* @deprecated
*/
debug,
}
/**
* @deprecated
*/
export default log

View File

@ -0,0 +1,29 @@
import WuhuBase from "../../../class/WuhuBase";
/**
* @deprecated 使new Popup()
*/
export default function popupMsg(innerHTML, title = '芜湖助手') {
let glob = WuhuBase.glob;
if (glob.popup_node) glob.popup_node.close();
const chatRoot = document.querySelector('#chatRoot');
chatRoot.classList.add('wh-hide');
const popup = document.createElement('div');
popup.id = 'wh-popup';
popup.innerHTML = `<div id="wh-popup-container">
<div id="wh-popup-title"><p>${ title }</p></div>
<div id="wh-popup-cont">${ innerHTML }</div>
</div>`;
document.body.append(popup);
const rt: MyHTMLElement = popup.querySelector('#wh-popup-cont');
rt.close = function () {
popup.remove();
chatRoot.classList.remove('wh-hide');
}
popup.addEventListener('click', e => {
e.stopImmediatePropagation();
if (e.target === popup) rt.close();
});
glob.popup_node = rt;
return rt;
}

View File

@ -0,0 +1,14 @@
import getWhSettingObj from "./getWhSettingObj";
import Alert from "../../../class/utils/Alert";
/**
* @deprecated
*/
export default function setWhSetting(key: string, value: any, notify: boolean = true) {
const obj = getWhSettingObj()
obj[key] = value
localStorage.setItem('wh_trans_settings', JSON.stringify(obj))
// 通知
if (notify) new Alert('已保存设置')
}

View File

@ -28,41 +28,37 @@ export default function initMiniProf(selector) {
const that = this; const that = this;
let width = $(window).width(); let width = $(window).width();
function handleResize(this: Window, e) { function handleResize(e) {
let $this = $(this); if ($(this).width() !== width) {
if ($this.width() !== width) { width = $(this).width();
width = $this.width();
hideMiniProfile.call(that, e); hideMiniProfile.call(that, e);
} }
} }
function handleScroll(this, e) { function handleScroll(e) {
if (!document.activeElement.classList.contains('send-cash-input')) { if (!document.activeElement.classList.contains('send-cash-input')) {
hideMiniProfile.call(that, e); hideMiniProfile.call(that, e);
} }
} }
function hideMiniProfile(this: typeof profileMini, e) { function hideMiniProfile(e) {
if ($(e.target).closest(this.rootSelector).length === 0 || ['resize', 'scroll'].includes(e.type)) { if ($(e.target).closest(this.rootSelector).length === 0 || ['resize', 'scroll'].includes(e.type)) {
that.targetElement = null; that.targetElement = null
let $thisUserNameSelector = $(this.userNameSelector);
window.ReactDOM.unmountComponentAtNode($(this.rootSelector).get(0)); window.ReactDOM.unmountComponentAtNode($(this.rootSelector).get(0));
$thisUserNameSelector.off('click', this.handleUserNameClick); $(this.userNameSelector).off('click', this.handleUserNameClick);
$thisUserNameSelector.unbind('contextmenu'); $(this.userNameSelector).unbind('contextmenu');
$(document).off('click', hideMiniProfile); $(document).off('click', hideMiniProfile);
let $window = $(window); $(window).off('hashchange', hideMiniProfile);
$window.off('hashchange', hideMiniProfile); $(window).off('resize', handleResize);
$window.off('resize', handleResize); $(window).off('scroll', handleScroll);
$window.off('scroll', handleScroll);
} }
} }
let $window = $(window);
$(document).on('click', hideMiniProfile.bind(this)); $(document).on('click', hideMiniProfile.bind(this));
$window.on('hashchange', hideMiniProfile.bind(this)); $(window).on('hashchange', hideMiniProfile.bind(this));
$window.on('resize', handleResize); $(window).on('resize', handleResize);
if (that.targetElement.closest('#chatRoot')) { if (that.targetElement.closest('#chatRoot')) {
$window.on('scroll', handleScroll); $(window).on('scroll', handleScroll);
} }
}, },
subscribeForUserNameClick: function () { subscribeForUserNameClick: function () {
@ -91,7 +87,7 @@ export default function initMiniProf(selector) {
that.targetElement = e.currentTarget; that.targetElement = e.currentTarget;
that.subscribeForContextMenu(that.targetElement); that.subscribeForContextMenu(that.targetElement);
that.handleFocusLost(e.currentTarget); that.handleFocusLost(e.currentTarget);
that.timeout = window.setTimeout(function () { that.timeout = setTimeout(function () {
if (e.type !== 'touchstart') { if (e.type !== 'touchstart') {
that.setClickable(false); that.setClickable(false);
that.subscribeForUserNameClick(); that.subscribeForUserNameClick();

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