性能优化,修复一些翻译错误,添加XAN价格监视

This commit is contained in:
woohoo 2022-02-23 17:24:00 +08:00
parent 1262fd17c7
commit 05ebda213d

View File

@ -1,8 +1,8 @@
// ==UserScript==
// @lastmodified 202202222055
// @lastmodified 202202231723
// @name 芜湖助手
// @namespace WOOH
// @version 0.3.19
// @version 0.3.20
// @description 托恩,起飞!
// @author Woohoo[2687093] Sabrina_Devil[2696209]
// @match https://www.torn.com/*
@ -23,13 +23,18 @@
if (window.WHTRANS) return;
window.WHTRANS = true;
// 版本
const version = '0.3.19';
const version = '0.3.20';
// 修改历史
const changelist = [
{
todo: true,
cont: `翻译baza npc商店、imarket、imarket搜索结果`,
},
{
ver: '0.3.20',
date: '20220223',
cont: `性能优化修复一些翻译错误添加XAN价格监视`,
},
{
ver: '0.3.19',
date: '20220222',
@ -349,17 +354,16 @@
const PDA_APIKey = '###PDA-APIKEY###';
// isPDA
const isPDA = PDA_APIKey.slice(-1) !== '#';
// uuid
window.whuuid = uuidv4();
// 请求通知权限
try {
if (window.Notification) {
Notification.requestPermission().then(status => {
// 这将使我们能在 Chrome/Safari 中使用 Notification.permission
if (Notification.permission !== status) {
Notification.permission = status;
}
})
} catch (e) {
window.Notification = undefined;
log(e)
}
const titleDict = {
@ -3119,7 +3123,7 @@
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 = () => {
@ -3127,6 +3131,9 @@
return `<img src="${gif_base64}" alt="lgif" style="width:14px;height:14px;" />`;
}
// 对当前窗口记录唯一id
const isWindowActive = getWindowActiveState();
// 对新值应用默认设置
[
// 开启翻译
@ -3167,11 +3174,11 @@
// 危险行为⚠️
{key: 'dangerZone', val: false},
].forEach(_default => {
if (typeof getWhSetting()[_default.key] !== typeof _default.val) setWhSetting(_default.key, _default.val);
if (typeof getWhSettingObj()[_default.key] !== typeof _default.val) setWhSetting(_default.key, _default.val);
});
// 是否开启翻译
const isTransEnabled = getWhSetting()['transEnable'];
const isTransEnabled = getWhSettingObj()['transEnable'];
// 菜单配置列表
const settingsArr = [];
@ -3454,7 +3461,7 @@
dictName: 'quickFinishAtt',
});
// 危险行为⚠️
if (getWhSetting()['dangerZone'] === true) {
if (getWhSettingObj()['dangerZone'] === true) {
// 攻击界面自刷新
settingsArr.push({
domType: 'select',
@ -3512,11 +3519,7 @@
popupMsg(insert, '飞花库存');
} else {
const popup = popupMsg(`请稍后${loading_gif_html()}`, '飞花库存');
let table = `<style>
#wh-popup-cont table{width:100%;border-collapse:collapse;border:1px solid;}
#wh-popup-cont td, #wh-popup-cont th{border-collapse:collapse;padding:4px;border:1px solid;}
</style>
<table><tr><th colspan="2">目的地 - 更新时间</th><th colspan="3"></th></tr>`;
let table = `<table><tr><th colspan="2">目的地 - 更新时间</th><th colspan="3">库存</th></tr>`;
const dest = [
{
name: 'mex', show: '墨西哥',
@ -3617,22 +3620,24 @@
#wh-popup-cont label span{font-weight:bold;}
</style>
<p id="wh-nnb-info-container"></p>
<p><b>NNB</b>, <b>N</b>atural <b>N</b>erve <b>B</b>ar, </p>
<p>一般来说左侧红色的犯罪条(称为<b>N</b>erve <b>B</b>ar/<b>NB</b>, NNB)</p>
<p>查看NNB的方法很简单在Torn主页面的最下方有一栏PerksNB上限扣除加成的犯罪条上限后就是NNB</p>
<p><b>NNB</b><b>N</b>atural <b>N</b>erve <b>B</b>ar</p>
<p>一般来说左侧红色的犯罪条<b>N</b>erve <b>B</b>ar/<b>NB</b></p>
<p>查看NNB的方法很简单在Torn主页面的最下方有一栏PerksNB-Perks=NNB</p>
<div>
<p>不想算</p>
<p>以下是两种计算NNB的方法</p>
<label>
<input type="radio" name="wh-nnb-check-select" value="bw" checked/><span> 冰蛙或PDA (推荐)</span>
<p>需要用到APIKey</p>
<p>正常运行的冰蛙或设置过APIKey的PDA</p>
<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>
</label>
<label>
<input type="radio" name="wh-nnb-check-select" value="ori"/><span> 普通方法</span>
<input type="radio" name="wh-nnb-check-select" value="ori"/><b> 普通方法</b>
<p>该方法不需要APIKey但是仅限在主页面海外或飞行状态不可用的时候</p>
</label>
</div>
<button>查看NNB</button>
<button>计算</button>
`;
const popup = popupMsg(insert, '查看NNB');
const select = popup.querySelector('input');
@ -3774,30 +3779,26 @@ height:30px;
domId: 'wh-price-watcher-btn',
domText: '价格监视',
clickFunc: function () {
const watcher_conf = getWhSetting()['priceWatcher'];
const watcher_conf = getWhSettingObj()['priceWatcher'];
const html = `<style>
#wh-popup-cont input{
padding: 2px;
width: 8em;
text-align: center;
border: 1px solid #fff0;
border-radius: 5px;
}
#wh-popup-cont input:focus{border-color:blue;}
#wh-popup-cont input{width:12em;}
#wh-popup-cont input[type="number"]{width:8em;}
</style>
<p>输入需要监视的价格低于该价格发出通知-1为关闭</p>
<p>需要APIKey将从冰蛙选择</p>
<p>需要APIKey当前可用APIKey为<br/>
<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>
`;
const popup = popupMsg(html, '价格监视设置', () => save_settings());
const save_settings = () => {
const popup = popupMsg(html, '价格监视设置', () => {
const pre_str = JSON.stringify(watcher_conf);
const [pt_node, xan_node] = popup.querySelectorAll('input');
const [pt_node, xan_node] = popup.querySelectorAll('input[type="number"]');
watcher_conf.pt = pt_node.value | 0;
watcher_conf.xan = xan_node.value | 0;
if (JSON.stringify(watcher_conf) !== pre_str) setWhSetting('priceWatcher', watcher_conf)
}
});
}
});
// 危险行为开关⚠️
@ -3808,7 +3809,7 @@ height:30px;
clickFunc: function (e) {
e.target.blur();
const insert = `<p>即将打开危险功能,使用这些功能可能会造成账号封禁。请自行考虑是否使用。</p>
<p><label><input type="checkbox" ${getWhSetting()['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');
@ -3816,6 +3817,7 @@ height:30px;
warning_check.onchange = () => ok_btn.disabled = false;
ok_btn.onclick = () => {
setWhSetting('dangerZone', warning_check.checked);
popup.close();
window.location.reload();
};
},
@ -3888,20 +3890,19 @@ height:30px;
// 节日
$zhongNode.querySelectorAll('#wh-trans-fest-date button').forEach((el, i) => i === 0
? el.addEventListener('click', () => {
let html = '';
settingsArr.fest_date_list.sort().forEach(date => html += `${1 + (date.slice(0, 2) | 0)}${date.slice(2)} ${settingsArr.fest_date_dict[date].name} - ${settingsArr.fest_date_dict[date].eff}<br/>`);
popupMsg(html, '节日');
let html = '<table>';
settingsArr.fest_date_list.sort().forEach(date => html += `<tr><td>${1 + (date.slice(0, 2) | 0)}${date.slice(2)}</td><td>${settingsArr.fest_date_dict[date].name}</td><td>${settingsArr.fest_date_dict[date].eff}</td></tr>`);
popupMsg(html += '</table>', '节日');
})
: el.addEventListener('click', ev => popupMsg(ev.target.attributes['title'].nodeValue))
);
// 活动
$zhongNode.querySelectorAll('#wh-trans-event-cont button').forEach((el, i) => i === 0
? el.addEventListener('click', () => {
let html = '';
let html = '<table>';
settingsArr.events.forEach(el =>
html += `<p>${el.start[0] + 1}${el.start[1]}${el.start[2]}:00~${el.end[0] + 1}${el.end[1]}${el.end[2]}:00【${el.name}】<br/>${el.eff}</p>`);
html += '<p>更多信息请关注群聊和公众号</p>'
popupMsg(html, '活动');
html += `<tr><td><b>${el.name}</b></td><td>${el.start[0] + 1}${el.start[1]}${el.start[2]}:00~${el.end[0] + 1}${el.end[1]}${el.end[2]}:00</td></tr><tr><td colspan="2">${el.eff}</td></tr>`);
popupMsg(html += '</table><p>更多信息请关注群聊和公众号</p>', '活动');
})
: el.addEventListener('click', ev => popupMsg(ev.target.attributes['title'].nodeValue))
);
@ -4045,7 +4046,7 @@ color:black;
popupMsg(insert, '开发者详情');
};
// 啤酒提醒
if (getWhSetting()['_15Alarm']) {
if (getWhSettingObj()['_15Alarm']) {
// 今日不再提醒
const ign = () => {
const date = new Date();
@ -4063,14 +4064,15 @@ color:black;
// 循环函数
const loop = () => {
const now = [new Date().getUTCFullYear(), new Date().getUTCMonth(), new Date().getUTCDate()];
const ignore_date = getWhSetting()['_15_alarm_ignore'] || '{}';
const ignore_date = getWhSettingObj()['_15_alarm_ignore'] || '{}';
if (JSON.stringify(now) === JSON.stringify(ignore_date)) return;
const notify = WHNotify(
`<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" target="_blank">啤酒店</a> <a href="/shops.php?step=pharmacy" target="_blank"></a>`,
30,
null,
true);
{
timeout: 30,
sysNotify: true,
});
notify.querySelector('.wh-notify-msg button').addEventListener('click', ign);
window.setTimeout(audioPlay, 800);
window.setTimeout(audioPlay, 800 * 2);
@ -4177,6 +4179,16 @@ div#wh-popup::after {
color: black;
border-radius: 3px;
}
#wh-popup-cont input{
padding: 2px;
text-align: center;
border: 1px solid #fff0;
border-radius: 5px;
margin:1px 2px;
}
#wh-popup-cont input:focus{border-color:blue;}
#wh-popup-cont table{width:100%;border-collapse:collapse;border:1px solid;}
#wh-popup-cont td, #wh-popup-cont th{border-collapse:collapse;padding:4px;border:1px solid;}
`);
/**
@ -4549,7 +4561,7 @@ div#wh-popup::after {
travelOB.observe(document.querySelector('div.content-wrapper'), {childList: true, subtree: true});
}
// 飞行闹钟
if (device === Device.PC && getWhSetting().trvAlarm) elementReady('#countrTravel.hasCountdown').then(node => {
if (device === Device.PC && getWhSettingObj().trvAlarm) elementReady('#countrTravel.hasCountdown').then(node => {
const logo_node = document.querySelector('#tcLogo[title]');
// const DEST_STR = {
// 'Mexico': '墨西哥', 'Canada': '加拿大', 'Cayman Islands': '开曼',
@ -4841,7 +4853,7 @@ display:none;
*/
if (window.location.href.contains(/travelagency\.php/)) {
const $$ = $('.content-wrapper');
if (getWhSetting().energyAlert) {
if (getWhSettingObj().energyAlert) {
const OB = new MutationObserver(() => {
OB.disconnect();
titleTrans();
@ -4894,9 +4906,9 @@ display:none;
if (window.location.href.contains(/loader\.php\?sid=attack/)) {
let stop_reload = false;
// 光速拔刀
if (getWhSetting().quickAttIndex !== 6) {
if (getWhSettingObj().quickAttIndex !== 6) {
// const selectedId = ['weapon_main', 'weapon_second', 'weapon_melee', 'weapon_temp', 'weapon_fists', 'weapon_boots']
// [getWhSetting().quickAttIndex];
// [getWhSettingObj().quickAttIndex];
elementReady('div[class^="modal___"] button').then(btn => {
if (!(btn.innerText.toLowerCase().includes('start fight') || btn.innerText.toLowerCase().includes('join'))) return;
// 判断是否存在脚踢
@ -4912,7 +4924,7 @@ display:none;
modal.style.display = 'none';
// 根据选择的武器调整css
let css_top = '0';
switch (getWhSetting().quickAttIndex) {
switch (getWhSettingObj().quickAttIndex) {
case 1: { // weapon_second
css_top = '97px';
break;
@ -4942,7 +4954,7 @@ display:none;
document.body.classList.toggle('wh-move-btn');
// 绑定点击事件
btn.onclick = () => {
if (getWhSetting().quickFinishAtt !== 3) {
if (getWhSettingObj().quickFinishAtt !== 3) {
btn.remove();
// 停止自动刷新
stop_reload = true;
@ -4960,7 +4972,7 @@ display:none;
// 判断有没有脚踢
if (hasKick) {
// 根据选择的武器调整
switch (getWhSetting().quickAttIndex) {
switch (getWhSettingObj().quickAttIndex) {
case 1: { // weapon_second
css_top = '76px';
break;
@ -4987,7 +4999,7 @@ display:none;
const height = slot.offsetHeight + 1;
slot_height = height;
// 根据选择的武器调整
switch (getWhSetting().quickAttIndex) {
switch (getWhSettingObj().quickAttIndex) {
case 1: { // weapon_second
css_top = `${height}px`;
break;
@ -5020,7 +5032,7 @@ display:none;
addStyle(css_rule);
document.body.classList.toggle('wh-move-btn');
btn.onclick = () => {
if (getWhSetting().quickFinishAtt !== 3) {
if (getWhSettingObj().quickFinishAtt !== 3) {
btn.remove();
// 停止自动刷新
stop_reload = true;
@ -5035,7 +5047,7 @@ display:none;
}
}
// 自动开打
if (getWhSetting().autoStartFinish === true) {
if (getWhSettingObj().autoStartFinish === true) {
if (btn.innerText.includes('(')) {
let interval_id = window.setInterval(() => {
if (!btn) {
@ -5069,8 +5081,8 @@ display:none;
}
}
// 光速跑路
if (getWhSetting().quickFinishAtt !== 3) {
const user_btn_select = ['leave', 'mug', 'hosp'][getWhSetting().quickFinishAtt];
if (getWhSettingObj().quickFinishAtt !== 3) {
const user_btn_select = ['leave', 'mug', 'hosp'][getWhSettingObj().quickFinishAtt];
const wrap = document.querySelector('#react-root');
log('光速跑路选项选中:', user_btn_select);
new MutationObserver(() => {
@ -5080,7 +5092,7 @@ display:none;
log('按钮内容:', btn.innerText, ',是否包含选中:', flag);
if (!flag) btn.style.display = 'none';
// 自动结束
else if (getWhSetting().autoStartFinish === true) {
else if (getWhSettingObj().autoStartFinish === true) {
try {
btn.click();
} catch {
@ -5091,7 +5103,7 @@ display:none;
}
// 自刷新
let audio_played_flag;
if (getWhSetting().attReload !== 6 && stop_reload !== true) {
if (getWhSettingObj().attReload !== 6 && stop_reload !== true) {
const selector_device_map = {
'pc': '#defender div[class^="modal___"]',
'mobile': '#attacker div[class^="modal___"]',
@ -5100,11 +5112,11 @@ display:none;
const selector = selector_device_map[device];
elementReady(selector).then(elem => {
if (!elem.querySelector('button')) {
if (getWhSetting().attReload === 0 && stop_reload !== true) {
if (getWhSettingObj().attReload === 0 && stop_reload !== true) {
window.location.reload();
} else {
let reload_flag;
const timeout = getWhSetting().attReload * 1000 + getRandomInt(-500, 500);
const timeout = getWhSettingObj().attReload * 1000 + getRandomInt(-500, 500);
log(`[WH] ${timeout / 1000}s 后自动刷新`);
window.setInterval(() => {
if (reload_flag === undefined) {
@ -5131,7 +5143,7 @@ display:none;
}
// 错误的攻击页面
if (getWhSetting()['attRelocate'] && window.location.href.includes('loader2.php')) {
if (getWhSettingObj()['attRelocate'] && window.location.href.includes('loader2.php')) {
const spl = window.location.href.trim().split('=');
const uid = spl[spl.length - 1];
if (!/^[0-9]+$/.test(uid)) return;
@ -5222,7 +5234,7 @@ display:none;
cityOB.observe(document.querySelector('div.content-wrapper'), {childList: true, subtree: true});
}
// 捡垃圾
if (getWhSetting().cityFinder) {
if (getWhSettingObj().cityFinder) {
addStyle(`
.wh-city-finds .leaflet-marker-pane img[src*="torn.com/images/items/"]{
display: block !important;
@ -5474,7 +5486,7 @@ display:inline-block;
gymTrans();
gymOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true, attributes: true});
}
if (getWhSetting().SEProtect) {
if (getWhSettingObj().SEProtect) {
elementReady('#gymroot').then(node => {
addStyle(`.wh-display-none{
display:none !important;
@ -5557,7 +5569,7 @@ display:none !important;
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 && getWhSetting().quickCrime) {
if (!is_wh_translate && !is_captcha && getWhSettingObj().quickCrime) {
if ($title.length > 0) $title.before(dom);
else if ($info.length > 0) $info.before(dom);
}
@ -5822,7 +5834,7 @@ display:none !important;
*/
if (window.location.href.contains(/loader\.php\?sid=missions/)) {
const $$ = $('.content-wrapper');
if (getWhSetting()['missionHint']) {
if (getWhSettingObj()['missionHint']) {
const OB = new MutationObserver(() => {
OB.disconnect();
titleTrans();
@ -7198,7 +7210,7 @@ display:none !important;
});
}
// 解密攻略
if (getWhSetting().xmasTownWT) {
if (getWhSettingObj().xmasTownWT) {
const insert_html = `<div id="wh-xmas-cont">
<div class="title-black"><span>水晶球解密地图攻略</span><span><button style="color: white">[]</button></span></div>
<div class="cont-gray select-wrap dropdown-new dropdown-default">
@ -7501,7 +7513,7 @@ margin: 0 0 3px;
});
}
// 宝箱检测
if (getWhSetting().xmasTownNotify) {
if (getWhSettingObj().xmasTownNotify) {
const chestTypeDict = {'1': '金', '2': '银', '3': '铜',};
const chestTypeColorDict = {'1': 'gold', '2': 'silver', '3': 'sandybrown',};
const lootTypeDict = {'chests': '钥匙箱', 'gifts': '礼物', 'combinationChest': '密码箱', 'keys': '钥匙',};
@ -8698,8 +8710,7 @@ margin: 0 0 3px;
/*
ob
*/
function initOB(dom = document, opt = {}, func = () => {
}, dev = false, once = false) {
function initOB(dom = document, opt = {}, func = doNothing, dev = false, once = false) {
//let count = -1;
if (dev) {
const mo = new MutationObserver((mutation) => {
@ -8766,7 +8777,7 @@ margin: 0 0 3px;
const newNode = document.createElement('div');
switch (setting.domType) {
case 'checkbox': {
newNode.innerHTML += `<label><input type="checkbox" id="${setting.domId}" ${getWhSetting()[setting.dictName] ? "checked" : ''} />${setting.domText}</label>`;
newNode.innerHTML += `<label><input type="checkbox" id="${setting.domId}" ${getWhSettingObj()[setting.dictName] ? "checked" : ''} />${setting.domText}</label>`;
settingNode.appendChild(newNode);
settingNode.querySelector(`#${setting.domId}`).onchange = (elem) => {
setWhSetting(setting.dictName, elem.target.checked);
@ -8782,7 +8793,7 @@ margin: 0 0 3px;
case 'select': {
let optHtml = '';
setting.domSelectOpt.forEach((optObj, i) => {
const selected = i === getWhSetting()[setting.dictName] ? 'selected' : '';
const selected = i === getWhSettingObj()[setting.dictName] ? 'selected' : '';
optHtml += `<option value="${optObj.domVal}" ${selected}>${optObj.domText}</option>`;
});
newNode.innerHTML += `<label>${setting.domText}<select id="${setting.domId}">${optHtml}</select></label>`;
@ -8838,7 +8849,7 @@ margin: 0 0 3px;
// bool 返回当前是否dev状态
function isDev() {
try {
return getWhSetting().isDev || false;
return getWhSettingObj().isDev || false;
} catch (e) {
console.error(`[wh] dev状态错误 ${e}`);
return false;
@ -8855,16 +8866,19 @@ margin: 0 0 3px;
<div id="wh-popup-cont">${innerHTML}</div>
</div>`;
document.body.append(popup);
const clickFunc = e => {
popup.addEventListener('click', e => {
e.stopImmediatePropagation();
if (e.target === popup) {
popup.removeEventListener('click', clickFunc);
popup.remove();
callback();
}
});
const rt = popup.querySelector('#wh-popup-cont')
rt.close = () => {
popup.remove();
callback();
};
popup.addEventListener('click', clickFunc);
return popup.querySelector('#wh-popup-cont');
return rt;
}
// 弹出窗口是否存在
@ -8975,16 +8989,14 @@ margin: 0 0 3px;
if (isDev()) console.log('[WH]', ...o)
}
/**
* 通知
*
* @param {String?} msg 通知上显示的内容默认为空
* @param {Number?} timeout 停留的时间默认3秒
* @param {Function?} callback 通知结束后执行的函数
* @param {Boolean?} sysNotify 是否显示系统通知
* @returns {HTMLElement} 通知的node
*/
function WHNotify(msg = '', timeout = 3, callback = null, sysNotify = false) {
function WHNotify(msg = '', {
timeout = 3,
callback = doNothing,
sysNotify = false,
sysNotifyTag = '芜湖助手',
sysNotifyClick = () => window.focus(),
} = {}) {
if (!isWindowActive() || isIframe) return null;
const date = new Date();
// 通知的唯一id
const uid = `${date.getHours()}${date.getSeconds()}${date.getMilliseconds()}${getRandomInt(1000, 9999)}`;
@ -9028,7 +9040,7 @@ margin: 0 0 3px;
const removeNode = () => {
clearInterval(intervalID);
new_node.remove();
if (callback !== null) callback();
callback();
};
new_node.del = removeNode;
new_node.querySelector('.wh-notify-close button').addEventListener('click', removeNode);
@ -9083,21 +9095,15 @@ text-decoration:none;
}
const notify_obj = add_notify();
// 浏览器通知
try {
if (Notification.permission === 'granted' && sysNotify) {
const last_notify = getWhSetting('lastNotify');
const last_notify_date = new Date(last_notify);
const date_local_string = `[${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}]\r`
if (!!last_notify_date || date - last_notify_date > 3000) {
new Notification('芜湖助手', {
if (window.Notification && Notification.permission === 'granted' && sysNotify) {
const date_local_string = `[${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}]\r`;
const sys_notify = new Notification('芜湖助手', {
body: date_local_string + notify_contain.msgInnerText,
requireInteraction: false
requireInteraction: true,
renotify: true,
tag: sysNotifyTag,
});
setWhSetting('lastNotify', date.getTime(), false)
}
}
} catch (e) {
log(e)
sys_notify.onclick = sysNotifyClick;
}
return notify_obj;
}
@ -9162,7 +9168,7 @@ z-index:100001;
_window.GM_setValue("gsp_x", 10);
_window.GM_setValue("gsp_y", 10);
notify.del();
notify = WHNotify('飞贼小助手已加载', 1);
notify = WHNotify('飞贼小助手已加载', {timeout: 1});
const gsp = _docu.querySelector('#gsp');
const init = () => {
ifr.style.height = `${gsp.offsetHeight + 10}px`;
@ -9216,9 +9222,8 @@ z-index:100001;
/**
* 播放音频
*
* @param url:String 播放的音频URL
* @returns void
* @param {string} url 播放的音频URL
* @returns {undefined}
*/
function audioPlay(url = 'https://www.torn.com/js/chat/sounds/Warble_1.mp3') {
const audio = new Audio(url);
@ -9252,18 +9257,18 @@ z-index:100001;
}
// 插件的配置 getter
function getWhSetting() {
function getWhSettingObj() {
return JSON.parse(localStorage.getItem('wh_trans_settings')) || {}
}
// 插件的配置 setter
function setWhSetting(key, value, notify = true) {
const obj = getWhSetting()
const obj = getWhSettingObj()
obj[key] = value
localStorage.setItem('wh_trans_settings', JSON.stringify(obj))
// 通知
if (notify) WHNotify('已保存设置', 3, null, false)
if (notify) WHNotify('已保存设置')
}
// 循环获取json对象
@ -9271,6 +9276,7 @@ z-index:100001;
let obj;
const res = COFetch(dest);
setInterval(async () => {
if (!isWindowActive()) return;
const res = await COFetch(dest);
obj = JSON.parse(res);
}, time * 1000);
@ -9288,10 +9294,14 @@ z-index:100001;
// 价格监视handle
function priceWatcherHandle() {
setInterval(() => {
const price_conf = getWhSetting()['priceWatcher'];
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).then();
if (price_conf['xan'] !== -1) priceWatcherXan(apikey, price_conf['xan']).then();
}, 10000)
return {status: true};
}
@ -9315,7 +9325,11 @@ z-index:100001;
// 将id与之前存在的比较不相同时发送通知
if (JSON.stringify(priceWatcher['watch-pt-lower-id']) !== JSON.stringify(lower_arr)) {
priceWatcher['watch-pt-lower-id'] = lower_arr;
WHNotify(`PT新低价$${low}(<${lower_price}) - <a href="/pmarket.php" target="_blank">点击转跳</a>`, 3, null, true);
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 {
// 查询出错了
@ -9324,10 +9338,59 @@ z-index:100001;
}
// xan价格监视
async function priceWatcherXan(apikey) {
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() {
}
// 返回UUID
function uuidv4() {
if (crypto.randomUUID) return crypto.randomUUID();
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
);
}
// 返回一个可用查询当前窗口是否激活的函数
function getWindowActiveState() {
if (isIframe) return false;
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 () {
// 当前窗口获得了焦点 优先级最高
if (isFocus) return true;
// 可视性
if (!document.hidden) return true;
// 全部在后台使用唯一id判断
return uuid === localStorage.getItem('whuuid')
};
}
}());