This commit is contained in:
Liwanyi 2022-10-05 16:05:48 +08:00
parent 6e92fa774a
commit 3963f1c6e4
24 changed files with 1125 additions and 210 deletions

5
global.d.ts vendored
View File

@ -101,4 +101,9 @@ declare interface TornGetActionParams {
declare module "*.html" {
const value: string;
export default value;
}
declare module "*.css" {
const value: string;
export default value;
}

874
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,15 @@
{
"name": "wuhu-torn-helper",
"version": "0.5.2",
"version": "0.5.4",
"description": "芜湖助手",
"dependencies": {},
"scripts": {
"release": "rollup -c rollup-prod.config.js && node build.js",
"minify": "uglifyjs misc/wuhu-torn-helper.js -o release.min.user.js -m",
"serve": "",
"build": "rollup -c",
"compile": "tsc --outDir output",
"rollup_watch": "rollup -c -w"
"release": "rollup -c rollup-prod.config.js && node build.js # 发布",
"build": "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": {
"@rollup/plugin-json": "^4.1.0",

View File

@ -2,7 +2,6 @@ import typescript from "@rollup/plugin-typescript";
import json from "@rollup/plugin-json";
// import template from "rollup-plugin-html-literals";
import { string } from "rollup-plugin-string";
// import { uglify } from "rollup-plugin-uglify";
export default {
input: 'src/index.ts',
@ -18,7 +17,7 @@ export default {
typescript(),
json(),
string({
include: "**/*.html"
include: ["**/*.html", "**/*.css"]
}),
// uglify(),
],

View File

@ -7,9 +7,13 @@ 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();
@ -17,7 +21,8 @@ export default class Application {
let glob = WuhuBase.glob;
ZhongIcon.getInstance().initialize();
Common.resolve();
// Common.resolve();
this.common.resolve();
UrlPattern.resolve();

View File

@ -7,7 +7,7 @@ import WuhuConfig from "./WuhuConfig";
import CommonUtils from "./utils/CommonUtils";
export class Common extends WuhuBase {
static resolve() {
resolve() {
let glob = Common.glob;
// 价格监控
priceWatcherHandle(glob.isPDA, glob.PDA_APIKey);

View File

@ -44,9 +44,9 @@ export default class Global extends WuhuBase implements IGlobal {
// 窗口活动状态
// isWindowActive = null;
isWindowActive = WindowActiveState.getInstance() as WindowActiveState;
isWindowActive = WindowActiveState.getInstance();
private constructor() {
constructor() {
Log.info('WH脚本参数初始化');
super();
this.window = window;

View File

@ -5,6 +5,7 @@ import Provider from "./provider/Provider";
export default class WuhuBase extends Provider {
static glob: IGlobal = null;
protected static className = 'WuhuBase';
static getLocal(): IWHSettings {
return JSON.parse(localStorage.getItem('wh_trans_settings')) || {};
@ -23,6 +24,16 @@ export default class WuhuBase extends Provider {
constructor() {
super();
Log.info('创建对象:' + this.constructor.name)
// Log.info({ 'constructor': this.constructor, this: this });
Log.info('创建对象:', this);
}
static PDAExecute() {
if (window.WHTRANS) throw '已运行,退出';
window.WHTRANS = true;
}
public toString() {
return `[${ JSON.stringify(this) }]`;
}
}

View File

@ -11,7 +11,6 @@ import Log from "./Log";
import CommonUtils from "./utils/CommonUtils";
import WuhuConfig from "./WuhuConfig";
import Alert from "./utils/Alert";
import Test from "../test/Test";
import * as EVENTS from "../json/event.json";
import * as FEST from "../json/fest.json";
import Popup from "./utils/Popup";
@ -20,6 +19,14 @@ import QUICK_FLY_HTML from "../html/quick_fly.html";
import NNB_INFO_HTML from "../html/nnb_info.html";
import PRICE_WATCHER_HTML from "../html/price_watcher.html";
import DANGER_ZONE_HTML from "../html/danger_zone.html";
import ActionButtonUtils from "./utils/ActionButtonUtils";
import ZHONG_MENU_HTML from "../html/zhong/zhong_menu.html";
import ZHONG_UPDATE_HTML from "../html/zhong/zhong_update.html";
import ZHONG_LOOT_HTML from "../html/zhong/zhong_loot.html";
import QUICK_CRIMES_HTML from "../html/quick_crimes.html";
import DEV_DETAILS_HTML from "../html/zhong/setting/dev_details.html";
import QUICK_FLY_CSS from "../css/quick_fly.css";
import QUICK_LINK_CSS from "../css/quick_link.css";
export default class ZhongIcon extends WuhuBase {
public static ZhongNode: MyHTMLElement = null;
@ -120,16 +127,7 @@ export default class ZhongIcon extends WuhuBase {
zhong_node = document.createElement('div');
zhong_node.id = 'wh-trans-icon';
zhong_node.classList.add('cont-gray');
zhong_node.innerHTML = `<div><button id="wh-trans-icon-btn"></button></div>
<div class="wh-container">
<div class="wh-main">
<div><b></b></div>
<div id="wh-gSettings"></div>
<div><p>当前版本: ${ version.slice(-1) === '$' ? 'DEV' : version } <button id="wh-update-btn"></button></p></div>
<div><p>: <span id="wh-latest-version"></span></p></div>
<div><p id="wh-inittimer"></p></div>
</div>
</div>`;
zhong_node.innerHTML = ZHONG_MENU_HTML.replace('{{}}', version.slice(-1) === '$' ? 'DEV' : version);
// 助手菜单
const menu_cont = zhong_node.querySelector('#wh-gSettings');
// 设置选项
@ -163,17 +161,7 @@ export default class ZhongIcon extends WuhuBase {
// 更新按钮点击事件
(<MyHTMLElement>zhong_node.querySelector('#wh-update-btn')).onclick = e => {
(<HTMLButtonElement>e.target).blur();
const innerHtml = `<h4>电脑</h4>
<p>使<a href="https://gitlab.com/JJins/wuhu-torn-helper/-/raw/dev/release.min.user.js" target="_blank"></a></p>
<p><img src="//jjins.github.io/tm.png" alt="tm.png" /><img src="//jjins.github.io/vm.png" alt="vm.png" /></p>
<p></p>
<h4></h4>
<p> KIWI 👆</p>
<p>Torn PDA app Alook <a href="//jjins.github.io/fyfuzhi/" target="_blank"></a></p>
<h4></h4>
<p></p>
<p><button></button></p>
`;
const innerHtml = ZHONG_UPDATE_HTML;
// 直接复制的按钮
new Popup(innerHtml, '如何更新')
.getElement()
@ -341,52 +329,8 @@ export default class ZhongIcon extends WuhuBase {
clickFunc: async function () {
if (window.hasWHQuickFlyOpt) return;
window.hasWHQuickFlyOpt = true;
CommonUtils.addStyle(`#wh-quick-fly-opt{
position:fixed;
left:64px;
top:64px;
background: #008000db;
padding: 8px;
border-radius: 4px;
box-shadow: 0 0 5px 1px #ffffff29;
color: white;
font-size: 15px;
width: 220px;
z-index: 199999;
}
#wh-quick-fly-opt p{margin:4px 0;}
#wh-quick-fly-opt a{
cursor: pointer;
border: 1px solid;
padding: 4px;
display: inline-block;
border-radius: 2px;
}
#wh-quick-fly-opt label{
display:block;
}
#wh-quick-fly-opt select{
width: 100%;
padding: 6px;
margin: 4px 0;
}
#wh-quick-fly-opt button{
font-size: 16px;
color: white;
cursor: pointer;
float: right;
background: #00BCD4;
padding: 8px;
border-radius: 4px;
}
#wh-quick-fly-opt.wh-quick-fly-opt-hide *{
display: none;
}
#wh-quick-fly-opt.wh-quick-fly-opt-hide input{
display: inline-block;
}
info{display:block;}
`);
// TODO
CommonUtils.addStyle(QUICK_FLY_CSS);
const node = document.createElement('div');
node.id = 'wh-quick-fly-opt';
node.innerHTML = QUICK_FLY_HTML;
@ -445,15 +389,7 @@ info{display:block;}
domText: '🔫 LOOT',
clickFunc: function (e) {
e.target.blur();
const insert = `<p>点击开打:</p>
<ul>
<li><a href="https://www.torn.com/loader.php?sid=attack&user2ID=4" target="_blank">Duke</a></li>
<li><a href="https://www.torn.com/loader.php?sid=attack&user2ID=15" target="_blank">Leslie</a></li>
<li><a href="https://www.torn.com/loader.php?sid=attack&user2ID=19" target="_blank">Jimmy()</a></li>
<li><a href="https://www.torn.com/loader.php?sid=attack&user2ID=20" target="_blank">Fernando()</a></li>
<li><a href="https://www.torn.com/loader.php?sid=attack&user2ID=21" target="_blank">Tiny()</a></li>
</ul>
<div><img alt="stock.png" src="https://jjins.github.io/t2i/loot.png?${ performance.now() }" style="max-width:100%;display:block;margin:0 auto;" /></div>`;
const insert = ZHONG_LOOT_HTML.replace('{{}}', performance.now().toString());
new Popup(insert, 'NPC LOOT');
},
tip: '显示5个可击杀NPC的开打时间',
@ -524,29 +460,7 @@ info{display:block;}
domText: '🔗 常用链接',
clickFunc: function (e) {
if (!this.styleAdded) {
CommonUtils.addStyle(`
.wh-link-collection-cont a{
display: inline-block;
border: solid 1px #b3b3b3;
border-radius: 4px;
margin: 0 5px 2px 0;
padding: 4px 8px;
text-align:center;
background: #efefef;
background: linear-gradient(#f1f1f1,#e3e3e3);
color:black !important;
}
.wh-link-collection-cont span{
display: block;
/*padding: 0 4px 8px;*/
}
.wh-link-collection-cont .wh-link-collection-img{
display: block;
width:60px;
height:30px;
background-size: 100% auto !important;
}
`);
CommonUtils.addStyle(QUICK_LINK_CSS);
this.styleAdded = true;
}
e.target.blur();
@ -675,22 +589,7 @@ background-size: 100% auto !important;
// if内未加载脚本时插入的快捷crime node
const mobile_prepend_node = document.createElement('div');
mobile_prepend_node.classList.add('wh-translate');
mobile_prepend_node.innerHTML = `<div class="title-black" style="border-radius: 5px 5px 0 0;"><span>快捷操作:</span></div><div class="cont-gray" style="padding: 6px 0;border-radius: 0 0 5px 5px;">
<form id="wh-translate-quick" action="crimes.php?step=docrime4" method="post" style="display: inline-block;margin: 0 5px">
<input name="nervetake" type="hidden" value="18">
<input name="crime" type="hidden" value="hackbank">
<input style="-webkit-appearance:none;padding: 4px;background: #e91e63;border-radius: 5px;color: white;" type="submit" value="18-1" />
</form>
<form id="wh-translate-quick" action="crimes.php?step=docrime4" method="post" style="display: inline-block;margin: 0 5px">
<input name="nervetake" type="hidden" value="11">
<input name="crime" type="hidden" value="warehouse">
<input style="-webkit-appearance:none;padding: 4px;background: #2196f3;border-radius: 5px;color: white;" type="submit" value="烧仓库" />
</form>
<form id="wh-translate-quick" action="crimes.php?step=docrime4" method="post" style="display: inline-block;margin: 0 5px">
<input name="nervetake" type="hidden" value="4">
<input name="crime" type="hidden" value="jacket">
<input style="-webkit-appearance:none;padding: 4px;background: #009688;border-radius: 5px;color: white;" type="submit" value="偷夹克" />
</form></div><hr class="page-head-delimiter m-top10 m-bottom10 r1854">`;
mobile_prepend_node.innerHTML = QUICK_CRIMES_HTML;
// if对象加载后运行
let cIframe = $popup.querySelector('iframe');
@ -852,26 +751,8 @@ background-size: 100% auto !important;
} catch {
}
const insert = `<table id="wh-dev-info-tb">
<tr><td>URL</td><td>${ window.location.href }</td></tr>
<tr><td></td><td>${ window.innerWidth }x${ window.innerHeight }</td></tr>
<tr><td></td><td>${ CommonUtils.getDeviceType().toUpperCase() }</td></tr>
<tr><td></td><td>${ { 'gm': '油猴', 'raw': '直接运行', 'pda': 'TornPDA' }[CommonUtils.getScriptEngine()] }</td></tr>
<tr><td></td><td>${ date.getFullYear() }/${ date.getMonth() + 1 }/${ date.getDate() } ${ date.getHours() }:${ date.getMinutes() }:${ date.getSeconds() }</td></tr>
<tr><td></td><td>${ glob.version }</td></tr>
<tr><td></td><td>${ os }</td></tr>
<tr><td>UA</td><td>${ window.navigator.userAgent }</td></tr>
<tr><td>ID</td><td>${ glob.player_info.userID }</td></tr>
<tr><td></td><td>${ glob.player_info.playername }</td></tr>
</table>
<style>
#wh-dev-info-tb td{
padding: 2px 4px;
color:black;
}
</style>`;
pop.close();
new Popup(insert, '开发者详情');
new Popup(DEV_DETAILS_HTML, '开发者详情');
};
(window.initializeTooltip) && (window.initializeTooltip('#wh-popup-cont', 'white-tooltip'));
},
@ -884,7 +765,9 @@ color:black;
clickFunc: async function () {
Log.info('测试开始');
Test.getInstance().test();
new Popup('<button>123</button>').getElement()
.querySelector('button').onclick = () => new Alert('123');
ActionButtonUtils.getInstance().add('123');
Log.info('测试结束');
},
@ -1323,7 +1206,7 @@ color:black;
// 默认设置
private setDefaultSettings(): void {
Log.info('设置默认值');
Log.info('设置默认值开始');
let count = 0;
[
// 开启翻译
@ -1389,7 +1272,7 @@ color:black;
count++;
}
});
Log.info('设置默认值结束,设置' + count);
Log.info('设置默认值结束,新:' + count);
}
}

View File

@ -4,7 +4,7 @@ import WuhuBase from "../WuhuBase";
import UserScriptEngine from "../../enum/UserScriptEngine";
import Popup from "../utils/Popup";
import STOCK_IMG_HTML from "../../html/stock_img.html";
import * as FILTER from "../../json/ForStockItemFilter.json";
import * as FILTER from "../../json/for_stock_item_filter.json";
export default class TravelItem extends WuhuBase {
private obj: any = null;
@ -13,7 +13,7 @@ export default class TravelItem extends WuhuBase {
// private commonUtils: CommonUtils = CommonUtils.getInstance();
// TODO bug修复
private constructor() {
public constructor() {
super();
window.setInterval(async () => {
if (!TravelItem.glob.isWindowActive.get()) return;

View File

@ -5,7 +5,7 @@ export default class WindowActiveState extends WuhuBase {
isFocus = false;
uuid = uuidv4();
private constructor() {
constructor() {
super();
if (self !== top) return null;
localStorage.setItem('whuuid', this.uuid);
@ -24,24 +24,4 @@ export default class WindowActiveState extends WuhuBase {
// 全部在后台使用唯一id判断
return this.uuid === localStorage.getItem('whuuid')
}
}
// export default function WindowActiveState() {
// if (self !== top) return null;
// const uuid = uuidv4();
// let isFocus = false;
// localStorage.setItem('whuuid', uuid);
// document.addEventListener('visibilitychange', () =>
// (document.visibilityState !== 'hidden') && (localStorage.setItem('whuuid', uuid))
// );
// addEventListener('focus', () => isFocus = true)
// addEventListener('blur', () => isFocus = false)
// return function (): boolean {
// // 当前窗口获得了焦点 优先级最高
// if (isFocus) return true;
// // 可视性
// if (!document.hidden) return true;
// // 全部在后台使用唯一id判断
// return uuid === localStorage.getItem('whuuid')
// };
// }
}

View File

@ -1,15 +0,0 @@
// import WuhuBase from "../WuhuBase";
//
// export default class WuhuBaseAction extends WuhuBase {
// name: string
//
// protected constructor() {
// super();
// }
//
// // static getInstance(this) {
// // if (!this.instance)
// // this.instance = new this();
// // return this.instance;
// // }
// }

View File

@ -1,12 +1,13 @@
/**
*
*/
export default class Provider {
protected instance;
private static instance;
constructor() {
}
// static getInstance<T extends Provider>(this:ExtendClass<T>):ExtendClass<T>{
static getInstance<T extends Provider>(this): T & typeof this {
if (!this.instance) this.instance = new this();
return this.instance;
static getInstance<T extends typeof Provider>(this: T): InstanceType<T> {
return this.instance ||= new this();
}
}

View File

@ -1,19 +1,17 @@
import WuhuBase from "../WuhuBase";
import POPUP_HTML from "../../html/popup.html";
export default class Popup extends WuhuBase {
private readonly container: HTMLElement = null;
private readonly node: HTMLElement = null;
protected className = 'Popup';
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 = `<div id="wh-popup-container">
<style>html{overflow: hidden !important;}</style>
<div id="wh-popup-title"><p>${ title }</p></div>
<div id="wh-popup-cont">${ innerHTML }</div>
</div>`;
popup.innerHTML = POPUP_HTML.replace('{{}}', title).replace('{{}}', innerHTML);
document.body.append(popup);
popup.addEventListener('click', e => {
e.stopImmediatePropagation();
@ -41,6 +39,7 @@ export default class Popup extends WuhuBase {
document.querySelector('#chatRoot').classList.remove('wh-hide');
}
// 禁止单例调用
private getInstance() {
}
}

57
src/css/quick_fly.css Normal file
View File

@ -0,0 +1,57 @@
#wh-quick-fly-opt {
position: fixed;
left: 64px;
top: 64px;
background: #008000db;
padding: 8px;
border-radius: 4px;
box-shadow: 0 0 5px 1px #ffffff29;
color: white;
font-size: 15px;
width: 220px;
z-index: 199999;
}
#wh-quick-fly-opt p {
margin: 4px 0;
}
#wh-quick-fly-opt a {
cursor: pointer;
border: 1px solid;
padding: 4px;
display: inline-block;
border-radius: 2px;
}
#wh-quick-fly-opt label {
display: block;
}
#wh-quick-fly-opt select {
width: 100%;
padding: 6px;
margin: 4px 0;
}
#wh-quick-fly-opt button {
font-size: 16px;
color: white;
cursor: pointer;
float: right;
background: #00BCD4;
padding: 8px;
border-radius: 4px;
}
#wh-quick-fly-opt.wh-quick-fly-opt-hide * {
display: none;
}
#wh-quick-fly-opt.wh-quick-fly-opt-hide input {
display: inline-block;
}
info {
display: block;
}

23
src/css/quick_link.css Normal file
View File

@ -0,0 +1,23 @@
.wh-link-collection-cont a {
display: inline-block;
border: solid 1px #b3b3b3;
border-radius: 4px;
margin: 0 5px 2px 0;
padding: 4px 8px;
text-align: center;
background: #efefef;
background: linear-gradient(#f1f1f1, #e3e3e3);
color: black !important;
}
.wh-link-collection-cont span {
display: block;
/*padding: 0 4px 8px;*/
}
.wh-link-collection-cont .wh-link-collection-img {
display: block;
width: 60px;
height: 30px;
background-size: 100% auto !important;
}

View File

@ -1,15 +1,14 @@
import UserScriptEngine from "../../enum/UserScriptEngine";
import WuhuBase from "../../class/WuhuBase";
import CommonUtils from "../../class/utils/CommonUtils";
import InfoUtils from "../../class/utils/InfoUtils";
import Popup from "../../class/utils/Popup";
import * as FILTER from "../../json/ForStockItemFilter.json";
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 "../../../json/for_stock_item_filter.json";
/**
* @deprecated
*/
export default async function forStock() {
if (InfoUtils.getInstance().getScriptEngine() === UserScriptEngine.RAW) {
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 {

7
src/html/popup.html Normal file
View File

@ -0,0 +1,7 @@
<div id="wh-popup-container">
<style>html {
overflow: hidden !important;
}</style>
<div id="wh-popup-title"><p>{{}}</p></div>
<div id="wh-popup-cont">{{}}</div>
</div>

View File

@ -0,0 +1,50 @@
<table id="wh-dev-info-tb">
<tr>
<td>URL</td>
<td>${ window.location.href }</td>
</tr>
<tr>
<td>页面尺寸</td>
<td>${ window.innerWidth }x${ window.innerHeight }</td>
</tr>
<tr>
<td>设备类型</td>
<td>${ CommonUtils.getDeviceType().toUpperCase() }</td>
</tr>
<tr>
<td>脚本运行方式</td>
<td>${ { 'gm': '油猴', 'raw': '直接运行', 'pda': 'TornPDA' }[CommonUtils.getScriptEngine()] }</td>
</tr>
<tr>
<td>时间</td>
<td>${ date.getFullYear() }/${ date.getMonth() + 1 }/${ date.getDate() } ${ date.getHours() }:${
date.getMinutes() }:${ date.getSeconds() }
</td>
</tr>
<tr>
<td>插件版本</td>
<td>${ glob.version }</td>
</tr>
<tr>
<td>操作系统</td>
<td>${ os }</td>
</tr>
<tr>
<td>UA</td>
<td>${ window.navigator.userAgent }</td>
</tr>
<tr>
<td>用户ID</td>
<td>${ glob.player_info.userID }</td>
</tr>
<tr>
<td>用户名</td>
<td>${ glob.player_info.playername }</td>
</tr>
</table>
<style>
#wh-dev-info-tb td {
padding: 2px 4px;
color: black;
}
</style>

View File

@ -0,0 +1,10 @@
<p>点击开打:</p>
<ul>
<li><a href="https://www.torn.com/loader.php?sid=attack&user2ID=4" target="_blank">Duke</a></li>
<li><a href="https://www.torn.com/loader.php?sid=attack&user2ID=15" target="_blank">Leslie</a></li>
<li><a href="https://www.torn.com/loader.php?sid=attack&user2ID=19" target="_blank">Jimmy(面包刀)</a></li>
<li><a href="https://www.torn.com/loader.php?sid=attack&user2ID=20" target="_blank">Fernando(毒伞)</a></li>
<li><a href="https://www.torn.com/loader.php?sid=attack&user2ID=21" target="_blank">Tiny(大锤)</a></li>
</ul>
<div><img alt="stock.png" src="https://jjins.github.io/t2i/loot.png?{{}}"
style="max-width:100%;display:block;margin:0 auto;"/></div>

View File

@ -0,0 +1,16 @@
<div>
<button id="wh-trans-icon-btn"></button>
</div>
<div class="wh-container">
<div class="wh-main">
<div><b>芜湖助手</b></div>
<div id="wh-gSettings"></div>
<div>
<p>当前版本: {{}}
<button id="wh-update-btn">更新</button>
</p>
</div>
<div><p>最新版本: <span id="wh-latest-version"></span></p></div>
<div><p id="wh-inittimer"></p></div>
</div>
</div>

View File

View File

@ -0,0 +1,14 @@
<h4>电脑</h4>
<p>通常电脑浏览器装有油猴等用户脚本扩展时可以使用链接安装(自动更新):<a
href="https://gitlab.com/JJins/wuhu-torn-helper/-/raw/dev/release.min.user.js" target="_blank">点此安装</a></p>
<p>这些扩展长这样:<img alt="tm.png" src="//jjins.github.io/tm.png"/><img alt="vm.png" src="//jjins.github.io/vm.png"/>
</p>
<p></p>
<h4>手机</h4>
<p>安卓 KIWI 等可以用油猴脚本的浏览器也可以点上面的链接安装👆</p>
<p>Torn PDA app 或 Alook 用户可打开<a href="//jjins.github.io/fyfuzhi/" target="_blank">这个网页</a>快捷复制粘贴。</p>
<h4>直接复制</h4>
<p>加载脚本然后直接复制粘贴到用户脚本处。</p>
<p>
<button>加载</button>
</p>