TS重构
This commit is contained in:
parent
d1c5d22f29
commit
a5f0a82211
42
global.d.ts
vendored
Normal file
42
global.d.ts
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
declare interface String {
|
||||
contains(keywords: RegExp | string): boolean;
|
||||
}
|
||||
|
||||
declare interface Window {
|
||||
unsafeWindow?: Window & typeof globalThis;
|
||||
$?: JQueryStatic;
|
||||
jQuery?: JQueryStatic;
|
||||
WHPARAMS?: any;
|
||||
ReactDOM?: any;
|
||||
|
||||
addRFC(url: URL | string): string;
|
||||
|
||||
PDA_httpGet(url: URL | string): Promise<PDA_Response>;
|
||||
|
||||
PDA_httpPost(url: URL | string, init: any, body: any): Promise<PDA_Response>;
|
||||
|
||||
GM_xmlhttpRequest(init: GM_RequestParams);
|
||||
}
|
||||
|
||||
declare interface GM_RequestParams {
|
||||
method?: string,
|
||||
url?: URL | string,
|
||||
data?: any,
|
||||
headers?: any,
|
||||
onload?: Function,
|
||||
onerror?: Function,
|
||||
ontimeout?: Function,
|
||||
}
|
||||
|
||||
declare interface PDA_Response {
|
||||
responseText: string
|
||||
}
|
||||
|
||||
declare interface Element {
|
||||
innerText?: string;
|
||||
src?: string;
|
||||
}
|
||||
|
||||
declare interface Notification {
|
||||
id?: number;
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
export default interface Global {
|
||||
startTimestamp: number;
|
||||
}
|
||||
@ -2696,44 +2696,6 @@ export const calDict = {
|
||||
}
|
||||
// 中文字符集正则
|
||||
export const CC_set = /[\u4e00-\u9fa5]/
|
||||
// const transDict = {};
|
||||
// transDict.titleDict = titleDict;
|
||||
// transDict.titleLinksDict = titleLinksDict;
|
||||
// transDict.sidebarDict = sidebarDict;
|
||||
// transDict.tooltipDict = tooltipDict;
|
||||
// transDict.statusDict = statusDict;
|
||||
// transDict.miniProfileDict = miniProfileDict;
|
||||
// transDict.homeDict = homeDict;
|
||||
// transDict.attackDict = attackDict;
|
||||
// transDict.newspaperDict = newspaperDict;
|
||||
// transDict.propertyDict = propertyDict;
|
||||
// transDict.travelingDict = travelingDict;
|
||||
// transDict.tipsDict = tipsDict;
|
||||
// transDict.cityDict = cityDict;
|
||||
// transDict.gymDict = gymDict;
|
||||
// transDict.gymList = gymList;
|
||||
// transDict.eduDict = eduDict;
|
||||
// transDict.headerDict = headerDict;
|
||||
// transDict.eventsDict = eventsDict;
|
||||
// transDict.chatDict = chatDict;
|
||||
// transDict.hosDict = hosDict;
|
||||
// transDict.awDict = awDict;
|
||||
// transDict.playerTitleList = playerTitleList;
|
||||
// transDict.ocList = ocList;
|
||||
// transDict.profileDict = profileDict;
|
||||
// transDict.sendCashDict = sendCashDict;
|
||||
// transDict.stockDict = stockDict;
|
||||
// transDict.itemPageDict = itemPageDict;
|
||||
// transDict.itemNameDict = itemNameDict;
|
||||
// transDict.itemDescDict = itemDescDict;
|
||||
// transDict.itemEffectDict = itemEffectDict;
|
||||
// transDict.itemTypeDict = itemTypeDict;
|
||||
// transDict.itemReqDict = itemReqDict;
|
||||
// transDict.tornSettingsDict = tornSettingsDict;
|
||||
// transDict.missionDict = missionDict;
|
||||
// transDict.pcDict = pcDict;
|
||||
// transDict.npcShopDict = npcShopDict;
|
||||
// transDict.calDict = calDict;
|
||||
// if (!localStorage.getItem('wh_trans_transDict')) localStorage.setItem('wh_trans_transDict', JSON.stringify(transDict))
|
||||
|
||||
export * from './translation'
|
||||
@ -1,5 +1,5 @@
|
||||
import {eventsDict, ocList, gymList} from "../dictionary/translation";
|
||||
import log from "./utils/log";
|
||||
import {eventsDict, ocList, gymList} from "../../dictionary/translation";
|
||||
import log from "../utils/log";
|
||||
|
||||
export default function eventsTrans(events: JQuery = $('span.mail-link')) {
|
||||
const index = window.location.href.indexOf('events.php#/step=received') >= 0 ? 1 : 0;
|
||||
92
src/func/utils/BuyBeer.ts
Normal file
92
src/func/utils/BuyBeer.ts
Normal file
@ -0,0 +1,92 @@
|
||||
import getWhSettingObj from "./getWhSettingObj";
|
||||
import log from "./log";
|
||||
import WHNotify from "./WHNotify";
|
||||
|
||||
// 啤酒
|
||||
export default function BuyBeer() {
|
||||
// 正在通知
|
||||
let is_notified = false;
|
||||
let time: number = getWhSettingObj()['_15AlarmTime'] || 50;
|
||||
let loop: BeerMonitorLoop = {};
|
||||
// 循环id
|
||||
let started = null;
|
||||
loop.start = () => {
|
||||
if (started) {
|
||||
log.info('啤酒助手已在运行');
|
||||
return;
|
||||
}
|
||||
started = setInterval(() => {
|
||||
// 海外取消提醒
|
||||
let {isTravelling, isAbroad} = getUserState();
|
||||
if (isTravelling || isAbroad) {
|
||||
loop.stop();
|
||||
return;
|
||||
}
|
||||
let dt = new Date();
|
||||
// 已选当天不提醒
|
||||
const now = [dt.getUTCFullYear(), dt.getUTCMonth(), dt.getUTCDate()];
|
||||
const ignore_date = getWhSettingObj()['_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 = WHNotify(notify_html, {
|
||||
timeout: 30,
|
||||
sysNotify: true,
|
||||
});
|
||||
notify.querySelector('.wh-notify-msg button').addEventListener('click', ()=>loop.skip_today);
|
||||
notify.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 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-${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();
|
||||
setWhSetting('_15_alarm_ignore', [date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()], false);
|
||||
// 通知
|
||||
const notify = WHNotify(`明早8点前将不再提醒 <button id="wh-rd-btn-${getRandomInt(0, 100)}">取消</button>`);
|
||||
// 通知中的取消按钮
|
||||
notify.querySelector('.wh-notify-msg button').addEventListener('click', () => setWhSetting('_15_alarm_ignore', undefined));
|
||||
};
|
||||
return loop;
|
||||
}
|
||||
|
||||
interface BeerMonitorLoop {
|
||||
start?: Function;
|
||||
stop?: Function;
|
||||
set_time?: Function;
|
||||
status?: Function;
|
||||
is_running?: Function;
|
||||
skip_today?: Function;
|
||||
}
|
||||
@ -1,7 +1,8 @@
|
||||
// 跨域get请求 返回text
|
||||
import UserScriptEngine from "../../enum/UserScriptEngine";
|
||||
import getScriptEngine from "./getScriptEngine";
|
||||
|
||||
function COFetch(url, method = 'get', body = null) {
|
||||
// 跨域get请求 返回text
|
||||
function COFetch(url:URL|string, method:string = 'get', body:any = null):Promise<string> {
|
||||
const engine = getScriptEngine();
|
||||
switch (engine) {
|
||||
case UserScriptEngine.RAW: {
|
||||
@ -20,11 +21,11 @@ function COFetch(url, method = 'get', body = null) {
|
||||
reject('错误:PDA版本不支持');
|
||||
}
|
||||
PDA_httpGet(url)
|
||||
.then(res => resolve(res.responseText))
|
||||
.catch(e => {
|
||||
console.error('[wh] 网络错误', e);
|
||||
reject(`[wh] 网络错误 ${e}`);
|
||||
})
|
||||
.then(res => resolve(res.responseText));
|
||||
});
|
||||
}) :
|
||||
// post
|
||||
new Promise((resolve, reject) => {
|
||||
@ -33,14 +34,15 @@ function COFetch(url, method = 'get', body = null) {
|
||||
reject('错误:PDA版本不支持');
|
||||
}
|
||||
PDA_httpPost(url, {'content-type': 'application/json'}, body)
|
||||
.then(res => resolve(res.responseText))
|
||||
.catch(e => {
|
||||
console.error('[wh] 网络错误', e);
|
||||
reject(`[wh] 网络错误 ${e}`);
|
||||
})
|
||||
.then(res => resolve(res.responseText));
|
||||
});
|
||||
});
|
||||
}
|
||||
case UserScriptEngine.GM: {
|
||||
let {GM_xmlhttpRequest} = window;
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof GM_xmlhttpRequest !== 'function') {
|
||||
console.error('[wh] 跨域请求错误:用户脚本扩展API错误');
|
||||
|
||||
148
src/func/utils/WHNotify.ts
Normal file
148
src/func/utils/WHNotify.ts
Normal file
@ -0,0 +1,148 @@
|
||||
import getRandomInt from "./getRandomInt";
|
||||
import addStyle from "./addStyle";
|
||||
|
||||
/**
|
||||
* 通知方法
|
||||
* @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}
|
||||
*/
|
||||
export default function WHNotify(msg, options: WHNotifyOpt = {}): MyHTMLElement {
|
||||
let glob = window.WHPARAMS;
|
||||
let {isIframe, isWindowActive, notifies} = glob;
|
||||
|
||||
let {
|
||||
timeout = 3,
|
||||
callback = function () {
|
||||
},
|
||||
sysNotify = false,
|
||||
sysNotifyTag = '芜湖助手',
|
||||
sysNotifyClick = () => window.focus()
|
||||
} = options;
|
||||
if (!isWindowActive() || isIframe) return null;
|
||||
const date = new Date();
|
||||
// 通知的唯一id
|
||||
const uid = `${date.getHours()}${date.getSeconds()}${date.getMilliseconds()}${getRandomInt(1000, 9999)}`;
|
||||
// 通知容器id
|
||||
const node_id = 'wh-notify';
|
||||
// 通知的容器
|
||||
let notify_contain: MyHTMLElement = document.querySelector(`#${node_id}`);
|
||||
// 添加通知到容器
|
||||
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 = node_id;
|
||||
addStyle(`
|
||||
#${node_id} {
|
||||
display: inline-block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: calc(50% - 180px);
|
||||
width: 360px;
|
||||
z-index: 9999990;
|
||||
color:#333;
|
||||
}
|
||||
#${node_id} a{
|
||||
color:red;
|
||||
text-decoration:none;
|
||||
}
|
||||
#${node_id} .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;
|
||||
}
|
||||
#${node_id} .wh-notify-item:hover {
|
||||
background: rgb(239 249 255 / 98%);
|
||||
}
|
||||
#${node_id} .wh-notify-item .wh-notify-bar {
|
||||
height:2px;
|
||||
background:#2196f3;
|
||||
}
|
||||
#${node_id} .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;
|
||||
}
|
||||
#${node_id} .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 + 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;
|
||||
}
|
||||
18
src/func/utils/addStyle.ts
Normal file
18
src/func/utils/addStyle.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import log from "./log";
|
||||
|
||||
/**
|
||||
* 添加全局style
|
||||
* @param {string} css CSS规则
|
||||
*/
|
||||
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);
|
||||
}
|
||||
@ -1,3 +1,5 @@
|
||||
import COFetch from "./COFetch";
|
||||
|
||||
/**
|
||||
* 循环获取json对象
|
||||
* @param dest
|
||||
|
||||
@ -3,18 +3,11 @@
|
||||
* @return {PlayerInfo} rs
|
||||
*/
|
||||
function getPlayerInfo(): PlayerInfo {
|
||||
let rs = new PlayerInfo();
|
||||
const node = document.querySelector('script[uid]');
|
||||
if (node) {
|
||||
rs.playername = node.getAttribute('name');
|
||||
rs.userID = node.getAttribute('uid') as unknown as number;
|
||||
if (node) return {
|
||||
playername: node.getAttribute('name'),
|
||||
userID: node.getAttribute('uid') as unknown as number,
|
||||
}
|
||||
return rs;
|
||||
}
|
||||
|
||||
class PlayerInfo {
|
||||
playername: string
|
||||
userID: number
|
||||
}
|
||||
|
||||
export default getPlayerInfo
|
||||
7
src/func/utils/getRandomInt.ts
Normal file
7
src/func/utils/getRandomInt.ts
Normal file
@ -0,0 +1,7 @@
|
||||
// 得到一个两数之间的随机整数
|
||||
export default function getRandomInt(min:number, max:number):number {
|
||||
min = Math.ceil(min);
|
||||
max = Math.floor(max);
|
||||
//不含最大值,含最小值
|
||||
return Math.floor(Math.random() * (max - min)) + min;
|
||||
}
|
||||
9
src/func/utils/getScriptEngine.ts
Normal file
9
src/func/utils/getScriptEngine.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import UserScriptEngine from "../../enum/UserScriptEngine";
|
||||
import Global from "../../interface/GlobalVars";
|
||||
|
||||
// 用户脚本平台类型
|
||||
export default function () {
|
||||
let glob = window.WHPARAMS;
|
||||
return glob.UWCopy ? UserScriptEngine.GM : glob.isPDA
|
||||
? UserScriptEngine.PDA : UserScriptEngine.RAW;
|
||||
}
|
||||
7
src/func/utils/getUserState.ts
Normal file
7
src/func/utils/getUserState.ts
Normal file
@ -0,0 +1,7 @@
|
||||
// 玩家状态
|
||||
export default function getUserState(): {} | any {
|
||||
let obj = {};
|
||||
let hdd = sessionStorage['headerData'];
|
||||
if (hdd) obj = JSON.parse(hdd)['user']['state'];
|
||||
return obj;
|
||||
}
|
||||
77
src/func/utils/priceWatcherHandle.ts
Normal file
77
src/func/utils/priceWatcherHandle.ts
Normal file
@ -0,0 +1,77 @@
|
||||
// 价格监视handle
|
||||
import getWhSettingObj from "./getWhSettingObj";
|
||||
import log from "./log";
|
||||
import toThousands from "./toThousands";
|
||||
import WHNotify from "./WHNotify";
|
||||
|
||||
let glob = window.WHPARAMS;
|
||||
let {isPDA, PDA_APIKey, priceWatcher} = glob;
|
||||
|
||||
export default function priceWatcherHandle() {
|
||||
setInterval(() => {
|
||||
const price_conf = getWhSettingObj()['priceWatcher'];
|
||||
const apikey = isPDA ? PDA_APIKey : localStorage.getItem('APIKey');
|
||||
if (!apikey) {
|
||||
log.info('无法获取APIKey')
|
||||
return;
|
||||
}
|
||||
if (price_conf['pt'] !== -1) priceWatcherPt(apikey, price_conf['pt']).then();
|
||||
if (price_conf['xan'] !== -1) priceWatcherXan(apikey, price_conf['xan']).then();
|
||||
}, 10000)
|
||||
return {status: true};
|
||||
}
|
||||
|
||||
// pt价格监视
|
||||
async function priceWatcherPt(apikey, lower_price) {
|
||||
if (!priceWatcher['watch-pt-lower-id']) priceWatcher['watch-pt-lower-id'] = [];
|
||||
const res = await fetch('https://api.torn.com/market/?selections=pointsmarket&key=' + apikey);
|
||||
const obj = await res.json();
|
||||
if (obj['pointsmarket']) {
|
||||
// 过滤低于价格的物品出售id
|
||||
const lower_arr = [];
|
||||
let low = Infinity;
|
||||
Object.keys(obj['pointsmarket']).forEach(key => {
|
||||
if (obj['pointsmarket'][key]['cost'] <= lower_price) {
|
||||
lower_arr.push(key);
|
||||
if (obj['pointsmarket'][key]['cost'] < low) low = obj['pointsmarket'][key]['cost'];
|
||||
}
|
||||
});
|
||||
if (lower_arr.length === 0) return;
|
||||
// 将id与之前存在的比较,不相同时发送通知
|
||||
if (JSON.stringify(priceWatcher['watch-pt-lower-id']) !== JSON.stringify(lower_arr)) {
|
||||
priceWatcher['watch-pt-lower-id'] = lower_arr;
|
||||
WHNotify(`PT新低价:$${toThousands(low)}( < $${toThousands(lower_price)}) - <a href="/pmarket.php" target="_blank">点击转跳</a>`, {
|
||||
timeout: 6,
|
||||
sysNotify: true,
|
||||
sysNotifyClick: () => window.open('https://www.torn.com/pmarket.php'),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// 查询出错了
|
||||
log('pt查询出错了')
|
||||
}
|
||||
}
|
||||
|
||||
// xan价格监视
|
||||
async function priceWatcherXan(apikey, lower_price) {
|
||||
// 初始化记录上一个条目的id,避免重复发送通知
|
||||
if (!priceWatcher['watch-xan-lower-id']) priceWatcher['watch-xan-lower-id'] = '';
|
||||
const res = await fetch('https://api.torn.com/market/206?selections=bazaar&key=' + apikey);
|
||||
const obj = await res.json();
|
||||
if (obj['bazaar']) {
|
||||
const lowest_item = obj['bazaar'][0]
|
||||
if (lowest_item['cost'] <= lower_price) {
|
||||
if (priceWatcher['watch-xan-lower-id'] !== lowest_item['ID']) {
|
||||
priceWatcher['watch-xan-lower-id'] = lowest_item['ID'];
|
||||
WHNotify(`XAN新低价:$${toThousands(lowest_item['cost'])}( < $${toThousands(lower_price)}) - <a href="/imarket.php#/p=shop&step=shop&type=&searchname=Xanax" target="_blank">点击转跳</a>`, {
|
||||
timeout: 6,
|
||||
sysNotify: true,
|
||||
sysNotifyClick: () => window.open('https://www.torn.com/imarket.php#/p=shop&step=shop&type=&searchname=Xanax')
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 查询出错了
|
||||
log('xan查询出错了')
|
||||
}
|
||||
}
|
||||
13
src/func/utils/toThousands.ts
Normal file
13
src/func/utils/toThousands.ts
Normal file
@ -0,0 +1,13 @@
|
||||
// 格式化金额数字
|
||||
export default function toThousands(num: string|number):string {
|
||||
num = (num || 0).toString();
|
||||
let result = '';
|
||||
while (num.length > 3) {
|
||||
result = ',' + num.slice(-3) + result;
|
||||
num = num.slice(0, num.length - 3);
|
||||
}
|
||||
if (num) {
|
||||
result = num + result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
95
src/init.ts
95
src/init.ts
@ -1,53 +1,55 @@
|
||||
import './global'
|
||||
import '../global'
|
||||
import log from "./func/utils/log";
|
||||
import getWhSettingObj from "./func/utils/getWhSettingObj";
|
||||
import miniprofTrans from "./func/translate/miniprofTrans";
|
||||
import Global from "./interface/GlobalVars";
|
||||
import Device from "./enum/Device";
|
||||
import getPlayerInfo from "./func/utils/getPlayerInfo";
|
||||
import autoFetchJSON from "./func/utils/autoFetchJSON";
|
||||
import priceWatcherHandle from "./func/utils/priceWatcherHandle";
|
||||
|
||||
export default function init() {
|
||||
const UWCopy: Window & typeof globalThis = window["unsafeWindow"];
|
||||
try {
|
||||
window = UWCopy || window;
|
||||
} catch {
|
||||
// 初始化方法,获取必要全局参数
|
||||
export default function init(glob: Global) {
|
||||
glob.window = window;
|
||||
window.WHPARAMS = glob;
|
||||
let UWCopy = null;
|
||||
if (window.hasOwnProperty('unsafeWindow')) {
|
||||
UWCopy = window.unsafeWindow;
|
||||
try {
|
||||
window = UWCopy;
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
// 防止脚本重复运行
|
||||
if (window["WHTRANS"]) throw new DOMException('已在运行');
|
||||
window["WHTRANS"] = true;
|
||||
glob.UWCopy = UWCopy;
|
||||
|
||||
// 脚本版本
|
||||
const version = '$$WUHU_DEV_VERSION$$';
|
||||
glob.version = '$$WUHU_DEV_VERSION$$';
|
||||
|
||||
// iframe运行
|
||||
const isIframe = self !== top;
|
||||
const $ = window['jQuery'];
|
||||
// PDA
|
||||
const PDA_APIKey = '###PDA-APIKEY###';
|
||||
const isPDA = PDA_APIKey.slice(-1) !== '#';
|
||||
glob.isIframe = self !== top;
|
||||
|
||||
// 通知权限
|
||||
// PDA
|
||||
glob.PDA_APIKey = '###PDA-APIKEY###';
|
||||
glob.isPDA = glob.PDA_APIKey.slice(-1) !== '#';
|
||||
|
||||
// 请求通知权限
|
||||
if (window.Notification) {
|
||||
Notification.requestPermission().then(status => {
|
||||
// 这将使我们能在 Chrome/Safari 中使用 Notification.permission
|
||||
if (Notification.permission !== status) {
|
||||
// @ts-ignore
|
||||
Notification['permission'] = status;
|
||||
}
|
||||
})
|
||||
Notification.requestPermission().then();
|
||||
}
|
||||
|
||||
// regexp test
|
||||
String.prototype.contains = function (keywords: RegExp) {
|
||||
let that: String = this;
|
||||
// 扩展String正则方法
|
||||
String.prototype.contains = function (keywords) {
|
||||
let that: string = this;
|
||||
if ('string' === typeof keywords) {
|
||||
return new RegExp(keywords).test(that);
|
||||
}
|
||||
if (keywords.test) {
|
||||
} else {
|
||||
return keywords.test(that);
|
||||
}
|
||||
};
|
||||
|
||||
// region 监听fetch
|
||||
// 监听fetch
|
||||
const ori_fetch = window.fetch;
|
||||
window.fetch = async (url, init) => {
|
||||
window.fetch = async (url: string, init: RequestInit) => {
|
||||
if (url.contains('newsTickers')) {
|
||||
// 阻止获取新闻横幅
|
||||
return new Response('{}');
|
||||
@ -59,9 +61,36 @@ export default function init() {
|
||||
}
|
||||
let clone = res.clone();
|
||||
let text = await res.text();
|
||||
log({url, init, text});
|
||||
log.info({url, init, text});
|
||||
return clone;
|
||||
};
|
||||
// endregion
|
||||
return {version, isIframe, $, PDA_APIKey, isPDA};
|
||||
|
||||
glob.device = window.innerWidth >= 1000
|
||||
? Device.PC : window.innerWidth <= 600 ? Device.MOBILE : Device.TABLET;
|
||||
|
||||
// 玩家信息
|
||||
glob.player_info = getPlayerInfo();
|
||||
|
||||
// 海外库存对象
|
||||
glob.fstock = autoFetchJSON('https://yata.yt/api/v1/travel/export/');
|
||||
|
||||
// 价格监视实例对象
|
||||
glob.priceWatcher = glob.isIframe ? null : priceWatcherHandle();
|
||||
|
||||
// 抢啤酒
|
||||
glob.beer = buyBeer();
|
||||
glob.popup_node = null;
|
||||
|
||||
// 当窗口关闭时关闭所有还存在的通知
|
||||
glob.notifies = {count: 0};
|
||||
window.addEventListener(
|
||||
'beforeunload',
|
||||
() => {
|
||||
if (glob.notifies.count !== 0) {
|
||||
for (let i = 0; i < glob.notifies.count; i++) {
|
||||
(glob.notifies[i] !== null) && (glob.notifies[i].close())
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
16
src/interface/GlobalVars.ts
Normal file
16
src/interface/GlobalVars.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import Device from "../enum/Device";
|
||||
|
||||
export default interface Global {
|
||||
notifies?: NotifyWrapper;
|
||||
priceWatcher?: { status: boolean };
|
||||
fstock?: { get: () => Promise<any> };
|
||||
player_info?: PlayerInfo;
|
||||
device?: Device;
|
||||
isPDA?: boolean;
|
||||
PDA_APIKey?: string;
|
||||
isIframe?: boolean;
|
||||
version?: string;
|
||||
window?: Window;
|
||||
UWCopy?: Window & typeof globalThis;
|
||||
startTimestamp: number;
|
||||
}
|
||||
5
src/interface/MyHTMLElement.ts
Normal file
5
src/interface/MyHTMLElement.ts
Normal file
@ -0,0 +1,5 @@
|
||||
interface MyHTMLElement extends HTMLElement {
|
||||
sys_notify?: Notification;
|
||||
msgInnerText?: string;
|
||||
close?: () => void;
|
||||
}
|
||||
5
src/interface/NotifyWrapper.ts
Normal file
5
src/interface/NotifyWrapper.ts
Normal file
@ -0,0 +1,5 @@
|
||||
interface NotifyWrapper {
|
||||
count: number;
|
||||
|
||||
[notifyId: number]: Notification;
|
||||
}
|
||||
4
src/interface/PlayerInfo.ts
Normal file
4
src/interface/PlayerInfo.ts
Normal file
@ -0,0 +1,4 @@
|
||||
interface PlayerInfo {
|
||||
playername: string
|
||||
userID: number
|
||||
}
|
||||
5
src/main.d.ts
vendored
5
src/main.d.ts
vendored
@ -1,5 +0,0 @@
|
||||
declare interface String {
|
||||
|
||||
contains(keywords: RegExp|String): boolean
|
||||
|
||||
}
|
||||
@ -1,7 +1,8 @@
|
||||
import userscript from "./userscript";
|
||||
import Global from "./global";
|
||||
import Global from "./interface/GlobalVars";
|
||||
|
||||
const glob: Global = {
|
||||
startTimestamp: -1,
|
||||
};
|
||||
|
||||
userscript(glob);
|
||||
@ -43,46 +43,21 @@ import * as DICTION from './dictionary/translation'
|
||||
import Device from "./enum/Device";
|
||||
import UserScriptEngine from "./enum/UserScriptEngine";
|
||||
import getPlayerInfo from "./func/utils/getPlayerInfo";
|
||||
import autoFetchJSON from "./func/utils/autoFetchJSON";
|
||||
import Global from "./global";
|
||||
import Global from "./interface/GlobalVars";
|
||||
|
||||
export default function userscript(glob: Global): void {
|
||||
glob.startTimestamp = Date.now();
|
||||
if (document.title.toLowerCase().includes('just a moment')) return;
|
||||
|
||||
let {version, isIframe, $, PDA_APIKey, isPDA} = init();
|
||||
init(glob);
|
||||
let {version, isIframe, PDA_APIKey, isPDA, player_info, fstock, notifies} = glob;
|
||||
|
||||
const date = new Date();
|
||||
const device = window.innerWidth >= 1000
|
||||
? Device.PC : window.innerWidth <= 600 ? Device.MOBILE : Device.TABLET;
|
||||
// 玩家信息
|
||||
const player_info = getPlayerInfo();
|
||||
// 海外库存对象
|
||||
const fstock = autoFetchJSON('https://yata.yt/api/v1/travel/export/');
|
||||
// 价格监视实例对象
|
||||
const priceWatcher = isIframe ? null : priceWatcherHandle();
|
||||
// 返回一个加载中gif图形HTML
|
||||
const loading_gif_html = () => {
|
||||
const gif_base64 = `data:image/svg+xml,%3Csvg t='1656084442571' class='icon' viewBox='0 0 1024 1024' version='1.1' xmlns='http://www.w3.org/2000/svg' p-id='3924' width='14' height='14'%3E%3Cpath d='M512.032002 237.105181a29.310168 29.310168 0 0 1-29.310168-29.246172V29.310168a29.310168 29.310168 0 0 1 58.620336 0v178.548841A29.310168 29.310168 0 0 1 512.032002 237.105181zM512.032002 1024a29.310168 29.310168 0 0 1-29.310168-29.310168v-178.484845a29.310168 29.310168 0 1 1 58.620336 0v178.548841A29.310168 29.310168 0 0 1 512.032002 1024z m482.657834-482.657834h-178.484845a29.310168 29.310168 0 1 1 0-58.620336h178.548841a29.310168 29.310168 0 1 1 0 58.620336z m-786.830823 0H29.310172a29.310168 29.310168 0 0 1 0-58.620336h178.548841a29.310168 29.310168 0 0 1 0 58.620336z m519.263546-215.090557a29.182176 29.182176 0 0 1-20.734704-49.980876l126.264108-126.264108a29.310168 29.310168 0 1 1 41.405412 41.405412l-126.264108 126.264108a29.182176 29.182176 0 0 1-20.670708 8.575464zM170.741333 882.568839a29.182176 29.182176 0 0 1-20.734704-49.980876l126.264108-126.264108a29.246172 29.246172 0 1 1 41.405412 41.405412L191.412041 874.057371a29.182176 29.182176 0 0 1-20.670708 8.575464z m682.581338 0a29.182176 29.182176 0 0 1-20.670708-8.575464l-126.264108-126.264108a29.310168 29.310168 0 1 1 41.405412-41.405412l126.264108 126.264108a29.310168 29.310168 0 0 1-20.734704 49.91688zM297.005441 326.251609a29.182176 29.182176 0 0 1-20.670708-8.575464L150.006629 191.412037a29.310168 29.310168 0 1 1 41.405412-41.405412l126.264108 126.264108a29.310168 29.310168 0 0 1-20.734704 49.91688z' p-id='3925'%3E%3C/path%3E%3C/svg%3E`
|
||||
return `<img src="${gif_base64}" alt="lgif" style="width:14px;height:14px;" />`;
|
||||
}
|
||||
// 抢啤酒
|
||||
let beer = buyBeer();
|
||||
let popup_node = null;
|
||||
// 当窗口关闭时关闭所有还存在的通知
|
||||
let notifies = {count: 0};
|
||||
window.addEventListener(
|
||||
'beforeunload',
|
||||
() => {
|
||||
if (notifies.count !== 0) {
|
||||
for (let i = 0; i < notifies.count; i++) {
|
||||
(notifies[i] !== null) && (notifies[i].close())
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
// 引入rfc方法
|
||||
let addRFC = window['addRFC'];
|
||||
|
||||
// 记录当前窗口唯一id
|
||||
const isWindowActive = getWindowActiveState();
|
||||
@ -316,7 +291,7 @@ export default function userscript(glob: Global): void {
|
||||
tip: '海外落地后每30秒通知警告',
|
||||
});
|
||||
// 落地转跳
|
||||
setting_list.push({domType: 'button', domId: '', domText: '落地转跳', clickFunc: landedRedirect});
|
||||
setting_list.push({ domType: 'button', domId: '', domText: '落地转跳', clickFunc: landedRedirect });
|
||||
|
||||
// 公司
|
||||
setting_list.push({
|
||||
@ -383,7 +358,7 @@ export default function userscript(glob: Global): void {
|
||||
domId: '',
|
||||
domText: '啤酒提醒状态',
|
||||
clickFunc: function () {
|
||||
WHNotify(`啤酒提醒${beer.status()}`);
|
||||
WHNotify(`啤酒提醒${ beer.status() }`);
|
||||
}
|
||||
});
|
||||
// 啤酒提醒时间
|
||||
@ -394,7 +369,7 @@ export default function userscript(glob: Global): void {
|
||||
// tip: '通知提前时间',
|
||||
clickFunc: function () {
|
||||
popup_node.close();
|
||||
let popup = popupMsg(`<label>提前提醒时间(秒):<input type="number" value="${getWhSettingObj()['_15AlarmTime']}" /></label><p>区间为 1 ~ 60,默认 50</p>`, '啤酒提醒时间设定');
|
||||
let popup = popupMsg(`<label>提前提醒时间(秒):<input type="number" value="${ getWhSettingObj()['_15AlarmTime'] }" /></label><p>区间为 1 ~ 60,默认 50</p>`, '啤酒提醒时间设定');
|
||||
let confirm = document.createElement('button');
|
||||
confirm.innerHTML = '确定';
|
||||
confirm.style.float = 'right';
|
||||
@ -541,7 +516,7 @@ export default function userscript(glob: Global): void {
|
||||
setting_list.push({
|
||||
domType: 'checkbox',
|
||||
domId: 'wh-dev-mode',
|
||||
domText: ` 开发者模式${isDev() ? ' <button id="wh-devInfo">详情</button>' : ''}`,
|
||||
domText: ` 开发者模式${ isDev() ? ' <button id="wh-devInfo">详情</button>' : '' }`,
|
||||
dictName: 'isDev',
|
||||
isHide: true,
|
||||
});
|
||||
@ -563,39 +538,39 @@ export default function userscript(glob: Global): void {
|
||||
menu_list.push({
|
||||
domType: 'plain',
|
||||
domId: 'wh-trans-welcome',
|
||||
domHTML: `<span>欢迎 <a href="/profiles.php?XID=${player_info.userID}" target="_blank">${player_info.playername}</a>[${player_info.userID}] 大佬</span>`,
|
||||
domHTML: `<span>欢迎 <a href="/profiles.php?XID=${ player_info.userID }" target="_blank">${ player_info.playername }</a>[${ player_info.userID }] 大佬</span>`,
|
||||
});
|
||||
}
|
||||
// 节日
|
||||
let fest_date_html = '<button>节日</button>: ';
|
||||
{
|
||||
const fest_date_dict = {
|
||||
'0105': {name: '周末自驾游', eff: '获得双倍的赛车点数与赛车技能等级增益'},
|
||||
'0114': {name: '情人节', eff: '使用爱情果汁(Love Juice)后获得降低攻击与复活的能量消耗的增益'},
|
||||
'0204': {name: '员工激励日', eff: '获得三倍的工作点数与火车增益'},
|
||||
'0217': {name: '圣帕特里克日', eff: '获得双倍的酒类效果增益,城市中可以捡到绿色世涛(Green Stout)'},
|
||||
'0320': {name: '420日', eff: '获得三倍的大麻(Cannabis)效果增益'},
|
||||
'0418': {name: '博物馆日', eff: '获得10%提高的博物馆PT兑换增益'},
|
||||
'0514': {name: '世界献血日', eff: '获得减半的抽血CD和扣血增益'},
|
||||
'0611': {name: '世界人口日', eff: '获得双倍的通过攻击获取的经验的增益'},
|
||||
'0629': {name: '世界老虎日', eff: '获得5倍的狩猎技能增益'},
|
||||
'0705': {name: '国际啤酒节', eff: '获得5倍的啤酒物品效果增益'},
|
||||
'0827': {name: '旅游节', eff: '获得双倍的起飞后物品携带容量增益'},
|
||||
'0915': {name: '饮料节', eff: '获得双倍的能量饮料效果增益'},
|
||||
'1014': {name: '世界糖尿病日', eff: '获得三倍的糖类效果增益'},
|
||||
'1015': {name: '周年庆', eff: '左上角的TORN图标可以食用'},
|
||||
'1025': {name: '黑色星期五', eff: '某些商家将提供1元购活动'},
|
||||
'1114': {name: '住院日', eff: '获得降低75%的住院时间增益'},
|
||||
'0105': { name: '周末自驾游', eff: '获得双倍的赛车点数与赛车技能等级增益' },
|
||||
'0114': { name: '情人节', eff: '使用爱情果汁(Love Juice)后获得降低攻击与复活的能量消耗的增益' },
|
||||
'0204': { name: '员工激励日', eff: '获得三倍的工作点数与火车增益' },
|
||||
'0217': { name: '圣帕特里克日', eff: '获得双倍的酒类效果增益,城市中可以捡到绿色世涛(Green Stout)' },
|
||||
'0320': { name: '420日', eff: '获得三倍的大麻(Cannabis)效果增益' },
|
||||
'0418': { name: '博物馆日', eff: '获得10%提高的博物馆PT兑换增益' },
|
||||
'0514': { name: '世界献血日', eff: '获得减半的抽血CD和扣血增益' },
|
||||
'0611': { name: '世界人口日', eff: '获得双倍的通过攻击获取的经验的增益' },
|
||||
'0629': { name: '世界老虎日', eff: '获得5倍的狩猎技能增益' },
|
||||
'0705': { name: '国际啤酒节', eff: '获得5倍的啤酒物品效果增益' },
|
||||
'0827': { name: '旅游节', eff: '获得双倍的起飞后物品携带容量增益' },
|
||||
'0915': { name: '饮料节', eff: '获得双倍的能量饮料效果增益' },
|
||||
'1014': { name: '世界糖尿病日', eff: '获得三倍的糖类效果增益' },
|
||||
'1015': { name: '周年庆', eff: '左上角的TORN图标可以食用' },
|
||||
'1025': { name: '黑色星期五', eff: '某些商家将提供1元购活动' },
|
||||
'1114': { name: '住院日', eff: '获得降低75%的住院时间增益' },
|
||||
};
|
||||
menu_list.fest_date_dict = fest_date_dict;
|
||||
menu_list.fest_date_list = Object.keys(fest_date_dict);
|
||||
const formatMMDD = (m, d) => {
|
||||
const MM = m < 10 ? `0${m}` : m.toString();
|
||||
const DD = d < 10 ? `0${d}` : d.toString();
|
||||
const MM = m < 10 ? `0${ m }` : m.toString();
|
||||
const DD = d < 10 ? `0${ d }` : d.toString();
|
||||
return MM + DD;
|
||||
}
|
||||
const fest_date_key = formatMMDD(date.getUTCMonth(), date.getUTCDate());
|
||||
if (fest_date_dict[fest_date_key]) fest_date_html += `今天 - ${fest_date_dict[fest_date_key]['name']}(<button title="${fest_date_dict[fest_date_key]['eff']}">效果</button>)`;
|
||||
if (fest_date_dict[fest_date_key]) fest_date_html += `今天 - ${ fest_date_dict[fest_date_key]['name'] }(<button title="${ fest_date_dict[fest_date_key]['eff'] }">效果</button>)`;
|
||||
else {
|
||||
// 月日列表
|
||||
let fest_date_list = Object.keys(fest_date_dict);
|
||||
@ -611,7 +586,7 @@ export default function userscript(glob: Global): void {
|
||||
fest_date_list[next_fest_date_index !== fest_date_list.length ? next_fest_date_index : 0].slice(2) / 1,
|
||||
8
|
||||
) - date) / 86400000 | 0;
|
||||
fest_date_html += `${days_left}天后 - ${next_fest_date.name}(<button title="${next_fest_date.eff}">效果</button>)`;
|
||||
fest_date_html += `${ days_left }天后 - ${ next_fest_date.name }(<button title="${ next_fest_date.eff }">效果</button>)`;
|
||||
}
|
||||
}
|
||||
menu_list.push({
|
||||
@ -692,8 +667,8 @@ export default function userscript(glob: Global): void {
|
||||
});
|
||||
eventObj.html = '<button>活动</button>: ';
|
||||
eventObj.onEv
|
||||
? eventObj.html += `${eventObj.current.name}(<button title="${eventObj.current.eff}">详情</button>) - 剩余${eventObj.daysLeft}天`
|
||||
: eventObj.html += `${eventObj.daysLeft}天后 - ${eventObj.next.name}(<button title="${eventObj.next.eff}">详情</button>)`;
|
||||
? eventObj.html += `${ eventObj.current.name }(<button title="${ eventObj.current.eff }">详情</button>) - 剩余${ eventObj.daysLeft }天`
|
||||
: eventObj.html += `${ eventObj.daysLeft }天后 - ${ eventObj.next.name }(<button title="${ eventObj.next.eff }">详情</button>)`;
|
||||
menu_list.push({
|
||||
domType: 'plain',
|
||||
domId: 'wh-trans-event-cont',
|
||||
@ -780,7 +755,7 @@ info{display:block;}
|
||||
`;
|
||||
const [dest_node, type_node] = node.querySelectorAll('select');
|
||||
node.querySelector('button').addEventListener('click', () => {
|
||||
sessionStorage['wh-quick-fly'] = `${dest_node.selectedIndex} ${type_node.selectedIndex} ${new Date().getTime()}`;
|
||||
sessionStorage['wh-quick-fly'] = `${ dest_node.selectedIndex } ${ type_node.selectedIndex } ${ new Date().getTime() }`;
|
||||
if (!href.contains('travelagency.php')) {
|
||||
WHNotify('正在转跳');
|
||||
location.href = 'https://www.torn.com/travelagency.php';
|
||||
@ -816,13 +791,13 @@ info{display:block;}
|
||||
['~9时54分', '~6时56分', '~4时58分', '~2时58分',],
|
||||
];
|
||||
const showTime = function () {
|
||||
time_predict.innerHTML = `往返时间:${predict[dest_node.selectedIndex][type_node.selectedIndex]}`;
|
||||
time_predict.innerHTML = `往返时间:${ predict[dest_node.selectedIndex][type_node.selectedIndex] }`;
|
||||
}
|
||||
dest_node.addEventListener('change', showTime);
|
||||
type_node.addEventListener('change', showTime);
|
||||
document.body.append(node);
|
||||
showTime();
|
||||
yaoCD.innerHTML = `药CD剩余:${getYaoCD()}`;
|
||||
yaoCD.innerHTML = `药CD剩余:${ getYaoCD() }`;
|
||||
},
|
||||
});
|
||||
// NPC LOOT
|
||||
@ -840,7 +815,7 @@ info{display:block;}
|
||||
<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>`;
|
||||
<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>`;
|
||||
popupMsg(insert, 'NPC LOOT');
|
||||
},
|
||||
tip: '显示5个可击杀NPC的开打时间',
|
||||
@ -866,8 +841,8 @@ info{display:block;}
|
||||
<input type="radio" name="wh-nnb-check-select" value="bw" checked/><b> 冰蛙或PDA (推荐)</b>
|
||||
<p>由于需要用到APIKey,因此需要冰蛙或PDA提供</p>
|
||||
<p>当前可以使用的APIKey:<br/>
|
||||
<input readonly value="${localStorage.getItem('APIKey') || '不可用'}">(来自冰蛙)<br/>
|
||||
<input readonly value="${isPDA ? PDA_APIKey : '不可用'}">(来自PDA)</p>
|
||||
<input readonly value="${ localStorage.getItem('APIKey') || '不可用' }">(来自冰蛙)<br/>
|
||||
<input readonly value="${ isPDA ? PDA_APIKey : '不可用' }">(来自PDA)</p>
|
||||
</label>
|
||||
<label>
|
||||
<input type="radio" name="wh-nnb-check-select" value="ori"/><b> 普通方法</b>
|
||||
@ -885,11 +860,11 @@ info{display:block;}
|
||||
// API 计算
|
||||
if (select.checked) {
|
||||
const api_key = isPDA ? PDA_APIKey : window.localStorage.getItem('APIKey');
|
||||
fetch(`https://api.torn.com/user/?selections=bars,perks&key=${api_key}`)
|
||||
fetch(`https://api.torn.com/user/?selections=bars,perks&key=${ api_key }`)
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data['error']) {
|
||||
node.innerHTML = `出错了 ${Obj2Str(data['error'])}`;
|
||||
node.innerHTML = `出错了 ${ Obj2Str(data['error']) }`;
|
||||
ev.target.style.display = null;
|
||||
return;
|
||||
}
|
||||
@ -901,7 +876,7 @@ info{display:block;}
|
||||
s.includes('maximum nerve') && (perks += /[0-9]./.exec(s)[0] | 0)
|
||||
})
|
||||
});
|
||||
node.innerHTML = `NNB: ${nb - perks}`;
|
||||
node.innerHTML = `NNB: ${ nb - perks }`;
|
||||
ev.target.style.display = null;
|
||||
});
|
||||
}
|
||||
@ -914,7 +889,7 @@ info{display:block;}
|
||||
const str = elem.innerText.toLowerCase();
|
||||
str.includes('maximum nerve') && (perks += /[0-9]./.exec(str)[0] | 0)
|
||||
});
|
||||
node.innerHTML = `NNB: ${nb - perks}`;
|
||||
node.innerHTML = `NNB: ${ nb - perks }`;
|
||||
ev.target.style.display = null;
|
||||
return;
|
||||
}
|
||||
@ -1016,7 +991,7 @@ background-size: 100% auto !important;
|
||||
});
|
||||
let insert = '<p>';
|
||||
quick_link_dict.forEach(el => {
|
||||
insert += `<a href="${el.url}"${el.new_tab ? ' target="_blank"' : ''}><span class="wh-link-collection-img" style="background: url(${el.img})"></span><span>${el.name}</span></a>`;
|
||||
insert += `<a href="${ el.url }"${ el.new_tab ? ' target="_blank"' : '' }><span class="wh-link-collection-img" style="background: url(${ el.img })"></span><span>${ el.name }</span></a>`;
|
||||
});
|
||||
insert += '</p>'
|
||||
let popup = popupMsg(insert, '常用链接');
|
||||
@ -1053,11 +1028,11 @@ background-size: 100% auto !important;
|
||||
</style>
|
||||
<p>输入需要监视的价格,低于该价格发出通知,-1为关闭</p>
|
||||
<p>注:需要APIKey,当前可用APIKey为<br/>
|
||||
<input readonly value="${localStorage.getItem('APIKey') || '不可用'}">(来自冰蛙)<br/>
|
||||
<input readonly value="${isPDA ? PDA_APIKey : '不可用'}">(来自PDA)
|
||||
<input readonly value="${ localStorage.getItem('APIKey') || '不可用' }">(来自冰蛙)<br/>
|
||||
<input readonly value="${ isPDA ? PDA_APIKey : '不可用' }">(来自PDA)
|
||||
</p>
|
||||
<p><b>PT</b><label> $ <input type="number" value="${watcher_conf['pt'] || -1}" /></label></p>
|
||||
<p><b>XAN</b><label> $ <input type="number" value="${watcher_conf['xan'] || -1}" /></label></p>
|
||||
<p><b>PT</b><label> $ <input type="number" value="${ watcher_conf['pt'] || -1 }" /></label></p>
|
||||
<p><b>XAN</b><label> $ <input type="number" value="${ watcher_conf['xan'] || -1 }" /></label></p>
|
||||
<p><button>确定</button></p>
|
||||
`;
|
||||
const popup = popupMsg(html, '价格监视设置');
|
||||
@ -1078,7 +1053,7 @@ background-size: 100% auto !important;
|
||||
clickFunc: function () {
|
||||
// 弹出小窗口
|
||||
const ifHTML = `<iframe src="/crimes.php?step=main" style="width:100%;max-width: 450px;margin: 0 auto;display: none;height: 340px;"></iframe>`;
|
||||
const popup_insert = `<p>加载中请稍后${loading_gif_html()}</p><div id="wh-quick-crime-if-container"></div>`;
|
||||
const popup_insert = `<p>加载中请稍后${ loading_gif_html() }</p><div id="wh-quick-crime-if-container"></div>`;
|
||||
const $popup = popupMsg(popup_insert, '小窗快速犯罪');
|
||||
// 运行状态node
|
||||
let loading_node = $popup.querySelector('p:first-of-type');
|
||||
@ -1141,9 +1116,9 @@ background-size: 100% auto !important;
|
||||
new MutationObserver((m, o) => {
|
||||
o.disconnect();
|
||||
if (!elem.querySelector('.wh-translate')) elem.prepend(mobile_prepend_node);
|
||||
o.observe(elem, {childList: true, subtree: true});
|
||||
o.observe(elem, { childList: true, subtree: true });
|
||||
})
|
||||
.observe(elem, {childList: true, subtree: true});
|
||||
.observe(elem, { childList: true, subtree: true });
|
||||
});
|
||||
// 隐藏返回顶部按钮
|
||||
elementReady('#go-to-top-btn button', ifDocu).then(e => e.style.display = 'none');
|
||||
@ -1185,7 +1160,7 @@ background-size: 100% auto !important;
|
||||
clickFunc: function (e) {
|
||||
e.target.blur();
|
||||
const insert = `<p>即将打开危险功能,使用这些功能可能会造成账号封禁。请自行考虑是否使用。</p>
|
||||
<p><label><input type="checkbox" ${getWhSettingObj()['dangerZone'] ? 'checked ' : ' '}/> 知道了,开启</label></p>
|
||||
<p><label><input type="checkbox" ${ getWhSettingObj()['dangerZone'] ? 'checked ' : ' ' }/> 知道了,开启</label></p>
|
||||
<div><button disabled>保存</button></div>`;
|
||||
const popup = popupMsg(insert, '⚠️警告');
|
||||
const warning_check = popup.querySelector('input');
|
||||
@ -1216,8 +1191,35 @@ background-size: 100% auto !important;
|
||||
});
|
||||
// 更新历史
|
||||
menu_list.push({
|
||||
domType: 'button', domId: '', domText: '🐞 更新历史', clickFunc: () => {
|
||||
popupMsg('更新历史现已迁移:<br/><a target="_blank" href="https://gitlab.com/JJins/wuhu-torn-helper/-/blob/dev/CHANGELOG.md">https://gitlab.com/JJins/wuhu-torn-helper/-/blob/dev/CHANGELOG.md</a>', '更新历史');
|
||||
domType: 'button', domId: '', domText: '🐞 更新历史', clickFunc: async () => {
|
||||
let popup = popupMsg(
|
||||
'更新历史:<br/><a target="_blank" href="https://gitlab.com/JJins/wuhu-torn-helper/-/blob/dev/CHANGELOG.md">https://gitlab.com/JJins/wuhu-torn-helper/-/blob/dev/CHANGELOG.md</a><br/>',
|
||||
'更新历史'
|
||||
);
|
||||
popup.classList.add('wh-changelog');
|
||||
let progressBar = document.createElement('div');
|
||||
progressBar.style.height = '2px';
|
||||
progressBar.style.width = '1%';
|
||||
progressBar.style.backgroundColor = 'red';
|
||||
let progressText = document.createElement('p');
|
||||
progressText.innerText = '加载更新文件……';
|
||||
progressText.style.textAlign = 'center';
|
||||
let style = document.createElement('style');
|
||||
style.innerHTML = `.wh-changelog h2,.wh-changelog h3,.wh-changelog h4 {margin:8px 0;}.wh-changelog li{list-style: inside;}`;
|
||||
|
||||
popup.append(progressBar, progressText, style);
|
||||
let update = await COFetch('https://gitlab.com/JJins/wuhu-torn-helper/-/raw/dev/CHANGELOG.md?' + Date.now());
|
||||
progressBar.style.width = '60%';
|
||||
progressText.innerText = '解析中……';
|
||||
let md = mdParse(update);
|
||||
popup.append(md);
|
||||
progressBar.style.width = '100%';
|
||||
progressText.innerText = '加载完成';
|
||||
|
||||
setTimeout(() => {
|
||||
progressBar.remove();
|
||||
progressText.remove()
|
||||
}, 3000);
|
||||
},
|
||||
});
|
||||
// 助手设置
|
||||
@ -1240,16 +1242,16 @@ background-size: 100% auto !important;
|
||||
}
|
||||
|
||||
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>${getDeviceType().toUpperCase()}</td></tr>
|
||||
<tr><td>脚本运行方式</td><td>${{'gm': '油猴', 'raw': '直接运行', 'pda': 'TornPDA'}[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>${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>${player_info.userID}</td></tr>
|
||||
<tr><td>用户名</td><td>${player_info.playername}</td></tr>
|
||||
<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>${ getDeviceType().toUpperCase() }</td></tr>
|
||||
<tr><td>脚本运行方式</td><td>${ { 'gm': '油猴', 'raw': '直接运行', 'pda': 'TornPDA' }[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>${ 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>${ player_info.userID }</td></tr>
|
||||
<tr><td>用户名</td><td>${ player_info.playername }</td></tr>
|
||||
</table>
|
||||
<style>
|
||||
#wh-dev-info-tb td{
|
||||
@ -1268,8 +1270,9 @@ color:black;
|
||||
domType: 'button',
|
||||
domId: '',
|
||||
domText: '📐️ 测试',
|
||||
clickFunc: function () {
|
||||
WHNotify('芜湖助手', {sysNotify: true, timeout: 15})
|
||||
clickFunc: async function () {
|
||||
let res = await COFetch('https://gitlab.com/JJins/wuhu-torn-helper/-/raw/dev/CHANGELOG.md')
|
||||
log(mdParse(res))
|
||||
},
|
||||
});
|
||||
// endregion
|
||||
@ -3260,7 +3263,8 @@ margin: 0 0 3px;
|
||||
addActionBtn('公司存钱', companyDepositAnywhere, $zhongNode);
|
||||
}
|
||||
|
||||
if (getPlayerInfo()['userID'] === 2687093) {
|
||||
if (getPlayerInfo()['userID'] === 2687093 && getDeviceType() === Device.PC) {
|
||||
await getSidebarData();
|
||||
let item = document.getElementById('nav-items');
|
||||
if (item) {
|
||||
let copy = item.cloneNode(true);
|
||||
@ -4200,22 +4204,7 @@ margin: 0 0 3px;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加全局style
|
||||
* @param {CSSRule.cssText|String} css CSS规则
|
||||
*/
|
||||
function addStyle(css) {
|
||||
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('CSS规则已添加', wh_gStyle);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
添加左侧图标
|
||||
@ -4396,18 +4385,7 @@ margin: 0 0 3px;
|
||||
});
|
||||
}
|
||||
|
||||
// 得到一个两数之间的随机整数
|
||||
function getRandomInt(min, max) {
|
||||
min = Math.ceil(min);
|
||||
max = Math.floor(max);
|
||||
return Math.floor(Math.random() * (max - min)) + min; //不含最大值,含最小值
|
||||
}
|
||||
|
||||
// 用户脚本平台类型
|
||||
function getScriptEngine() {
|
||||
return UWCopy ? UserScriptEngine.GM : PDA_APIKey.slice(-1) !== '#'
|
||||
? UserScriptEngine.PDA : UserScriptEngine.RAW;
|
||||
}
|
||||
|
||||
// 用户设备类型 对应PC MOBILE TABLET
|
||||
function getDeviceType() {
|
||||
@ -4415,209 +4393,12 @@ margin: 0 0 3px;
|
||||
? Device.PC : window.innerWidth <= 600 ? Device.MOBILE : Device.TABLET;
|
||||
}
|
||||
|
||||
// 跨域get请求 返回text
|
||||
function COFetch(url, method = 'get', body = null) {
|
||||
const engine = getScriptEngine();
|
||||
switch (engine) {
|
||||
case UserScriptEngine.RAW: {
|
||||
return new Promise((_, reject) => {
|
||||
console.error(`[wh] 跨域请求错误:${UserScriptEngine.RAW}环境下无法进行跨域请求`);
|
||||
reject(`错误:${UserScriptEngine.RAW}环境下无法进行跨域请求`);
|
||||
});
|
||||
}
|
||||
case UserScriptEngine.PDA: {
|
||||
const {PDA_httpGet, PDA_httpPost} = window;
|
||||
return method === 'get' ?
|
||||
// get
|
||||
new Promise((resolve, reject) => {
|
||||
if (typeof PDA_httpGet !== 'function') {
|
||||
console.error('[wh] 跨域请求错误:PDA版本不支持');
|
||||
reject('错误:PDA版本不支持');
|
||||
}
|
||||
PDA_httpGet(url)
|
||||
.catch(e => {
|
||||
console.error('[wh] 网络错误', e);
|
||||
reject(`[wh] 网络错误 ${e}`);
|
||||
})
|
||||
.then(res => resolve(res.responseText));
|
||||
}) :
|
||||
// post
|
||||
new Promise((resolve, reject) => {
|
||||
if (typeof PDA_httpPost !== 'function') {
|
||||
console.error('[wh] 跨域请求错误:PDA版本不支持');
|
||||
reject('错误:PDA版本不支持');
|
||||
}
|
||||
PDA_httpPost(url, {'content-type': 'application/json'}, body)
|
||||
.catch(e => {
|
||||
console.error('[wh] 网络错误', e);
|
||||
reject(`[wh] 网络错误 ${e}`);
|
||||
})
|
||||
.then(res => resolve(res.responseText));
|
||||
});
|
||||
}
|
||||
case UserScriptEngine.GM: {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof GM_xmlhttpRequest !== 'function') {
|
||||
console.error('[wh] 跨域请求错误:用户脚本扩展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)}`),
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 简单 object 转字符串
|
||||
function Obj2Str(obj) {
|
||||
return JSON.stringify(obj);
|
||||
}
|
||||
|
||||
// console.log改写
|
||||
function log(...o) {
|
||||
if (isDev()) console.log('[WH]', ...o)
|
||||
}
|
||||
|
||||
/**
|
||||
* 通知方法
|
||||
* @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}
|
||||
*/
|
||||
function WHNotify(msg, options = {}) {
|
||||
let {
|
||||
timeout = 3,
|
||||
callback = doNothing,
|
||||
sysNotify = false,
|
||||
sysNotifyTag = '芜湖助手',
|
||||
sysNotifyClick = () => window.focus()
|
||||
} = options;
|
||||
if (!isWindowActive() || isIframe) return null;
|
||||
const date = new Date();
|
||||
// 通知的唯一id
|
||||
const uid = `${date.getHours()}${date.getSeconds()}${date.getMilliseconds()}${getRandomInt(1000, 9999)}`;
|
||||
// 通知容器id
|
||||
const node_id = 'wh-notify';
|
||||
// 通知的容器
|
||||
let notify_contain = document.querySelector(`#${node_id}`);
|
||||
// 添加通知到容器
|
||||
const add_notify = () => {
|
||||
// 每条通知
|
||||
const new_node = 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 = 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 = node_id;
|
||||
addStyle(`
|
||||
#${node_id} {
|
||||
display: inline-block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: calc(50% - 180px);
|
||||
width: 360px;
|
||||
z-index: 9999990;
|
||||
color:#333;
|
||||
}
|
||||
#${node_id} a{
|
||||
color:red;
|
||||
text-decoration:none;
|
||||
}
|
||||
#${node_id} .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;
|
||||
}
|
||||
#${node_id} .wh-notify-item:hover {
|
||||
background: rgb(239 249 255 / 98%);
|
||||
}
|
||||
#${node_id} .wh-notify-item .wh-notify-bar {
|
||||
height:2px;
|
||||
background:#2196f3;
|
||||
}
|
||||
#${node_id} .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;
|
||||
}
|
||||
#${node_id} .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 + getRandomInt(0, 99),
|
||||
});
|
||||
notify_obj.sys_notify.onclick = 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;
|
||||
}
|
||||
|
||||
// gs loader
|
||||
function loadGS(use) {
|
||||
@ -4745,19 +4526,6 @@ z-index:100001;
|
||||
});
|
||||
}
|
||||
|
||||
// 格式化金额数字
|
||||
function toThousands(num) {
|
||||
num = (num || 0).toString();
|
||||
let result = '';
|
||||
while (num.length > 3) {
|
||||
result = ',' + num.slice(-3) + result;
|
||||
num = num.slice(0, num.length - 3);
|
||||
}
|
||||
if (num) {
|
||||
result = num + result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// 插件的配置 getter
|
||||
function getWhSettingObj() {
|
||||
@ -4776,75 +4544,7 @@ z-index:100001;
|
||||
|
||||
|
||||
|
||||
// 价格监视handle
|
||||
function priceWatcherHandle() {
|
||||
setInterval(() => {
|
||||
const price_conf = getWhSettingObj()['priceWatcher'];
|
||||
const apikey = isPDA ? PDA_APIKey : localStorage.getItem('APIKey');
|
||||
if (!apikey) {
|
||||
log('无法获取APIKey')
|
||||
return;
|
||||
}
|
||||
if (price_conf['pt'] !== -1) priceWatcherPt(apikey, price_conf['pt']).then();
|
||||
if (price_conf['xan'] !== -1) priceWatcherXan(apikey, price_conf['xan']).then();
|
||||
}, 10000)
|
||||
return {status: true};
|
||||
}
|
||||
|
||||
// pt价格监视
|
||||
async function priceWatcherPt(apikey, lower_price) {
|
||||
if (!priceWatcher['watch-pt-lower-id']) priceWatcher['watch-pt-lower-id'] = [];
|
||||
const res = await fetch('https://api.torn.com/market/?selections=pointsmarket&key=' + apikey);
|
||||
const obj = await res.json();
|
||||
if (obj['pointsmarket']) {
|
||||
// 过滤低于价格的物品出售id
|
||||
const lower_arr = [];
|
||||
let low = Infinity;
|
||||
Object.keys(obj['pointsmarket']).forEach(key => {
|
||||
if (obj['pointsmarket'][key]['cost'] <= lower_price) {
|
||||
lower_arr.push(key);
|
||||
if (obj['pointsmarket'][key]['cost'] < low) low = obj['pointsmarket'][key]['cost'];
|
||||
}
|
||||
});
|
||||
if (lower_arr.length === 0) return;
|
||||
// 将id与之前存在的比较,不相同时发送通知
|
||||
if (JSON.stringify(priceWatcher['watch-pt-lower-id']) !== JSON.stringify(lower_arr)) {
|
||||
priceWatcher['watch-pt-lower-id'] = lower_arr;
|
||||
WHNotify(`PT新低价:$${toThousands(low)}( < $${toThousands(lower_price)}) - <a href="/pmarket.php" target="_blank">点击转跳</a>`, {
|
||||
timeout: 6,
|
||||
sysNotify: true,
|
||||
sysNotifyClick: () => window.open('https://www.torn.com/pmarket.php'),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// 查询出错了
|
||||
log('pt查询出错了')
|
||||
}
|
||||
}
|
||||
|
||||
// xan价格监视
|
||||
async function priceWatcherXan(apikey, lower_price) {
|
||||
// 初始化记录上一个条目的id,避免重复发送通知
|
||||
if (!priceWatcher['watch-xan-lower-id']) priceWatcher['watch-xan-lower-id'] = '';
|
||||
const res = await fetch('https://api.torn.com/market/206?selections=bazaar&key=' + apikey);
|
||||
const obj = await res.json();
|
||||
if (obj['bazaar']) {
|
||||
const lowest_item = obj['bazaar'][0]
|
||||
if (lowest_item['cost'] <= lower_price) {
|
||||
if (priceWatcher['watch-xan-lower-id'] !== lowest_item['ID']) {
|
||||
priceWatcher['watch-xan-lower-id'] = lowest_item['ID'];
|
||||
WHNotify(`XAN新低价:$${toThousands(lowest_item['cost'])}( < $${toThousands(lower_price)}) - <a href="/imarket.php#/p=shop&step=shop&type=&searchname=Xanax" target="_blank">点击转跳</a>`, {
|
||||
timeout: 6,
|
||||
sysNotify: true,
|
||||
sysNotifyClick: () => window.open('https://www.torn.com/imarket.php#/p=shop&step=shop&type=&searchname=Xanax')
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 查询出错了
|
||||
log('xan查询出错了')
|
||||
}
|
||||
}
|
||||
|
||||
// 空函数
|
||||
function doNothing() {
|
||||
@ -7342,13 +7042,7 @@ z-index:100001;
|
||||
document.head.appendChild(node);
|
||||
}
|
||||
|
||||
// 玩家状态
|
||||
function getUserState() {
|
||||
let obj = {};
|
||||
let hdd = sessionStorage['headerData'];
|
||||
if (hdd) obj = JSON.parse(hdd)['user']['state'];
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
// 一键起飞
|
||||
function doQuickFly() {
|
||||
@ -7675,9 +7369,45 @@ z-index:100001;
|
||||
}
|
||||
}
|
||||
|
||||
// 边栏信息
|
||||
function getSidebarData() {
|
||||
return JSON.parse(document.querySelector('#sidebar_data').innerHTML)
|
||||
/**
|
||||
* 边栏信息
|
||||
* @deprecated
|
||||
* @returns {any}
|
||||
*/
|
||||
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) {
|
||||
// TODO 当前根据侧边栏等待 sessionData
|
||||
await 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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -7746,7 +7476,70 @@ z-index:100001;
|
||||
return fetch(url, req_params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 Markdown 内容
|
||||
* @param {String} from
|
||||
* @param {Number} max_line 最大行数,默认500
|
||||
* @returns {HTMLDivElement}
|
||||
*/
|
||||
function mdParse(from, max_line) {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待毫秒数
|
||||
* @param {Number} ms 毫秒
|
||||
* @returns {Promise<unknown>}
|
||||
*/
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
$zhongNode.initTimer.innerHTML = `助手加载时间 ${Date.now() - start_timestamp}ms`;
|
||||
}
|
||||
|
||||
// export userscript;
|
||||
@ -12,8 +12,11 @@ async function main() {
|
||||
}
|
||||
}
|
||||
// 防止脚本重复运行
|
||||
if (window.hasOwnProperty('WHTRANS')) return;
|
||||
else window.WHTRANS = true;
|
||||
if (window.hasOwnProperty('WHTRANS')) {
|
||||
return;
|
||||
} else {
|
||||
window.WHTRANS = true;
|
||||
}
|
||||
const version = '$$WUHU_DEV_VERSION$$';
|
||||
const isIframe = self !== top;
|
||||
const $ = window['jQuery'];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user