import titleTrans from "../translate/titleTrans"; import contentTitleLinksTrans from "../translate/contentTitleLinksTrans"; import Device from "../../enum/Device"; import ActionButtonUtils from "../../class/utils/ActionButtonUtils"; import CommonUtils from "../../class/utils/CommonUtils"; import TRAVEL_ALARM_CSS from "../../../static/css/travel_alarm.module.css"; import TRAVEL_ALARM_HTML from "../../../static/html/travel_alarm.html"; import TornStyleBlock from "../../class/utils/TornStyleBlock"; import QuickFlyBtnHandler from "../../class/handler/QuickFlyBtnHandler"; import TRAVEL_STATE from "../../enum/TravelState"; import Global from "../../class/Global"; import ClassName from "../../container/ClassName"; import { Injectable } from "../../container/Injectable"; import LocalConfigWrapper from "../../class/LocalConfigWrapper"; import MsgWrapper from "../../class/utils/MsgWrapper"; /** * 飞行助手 * - 飞行闹钟 * - 一键回城 * - 解毒提醒 * - 落地转跳 * - 海外警告 */ @ClassName('TravelHelper') @Injectable() export default class TravelHelper { constructor( private readonly global: Global, private readonly commonUtils: CommonUtils, private readonly actionButtonUtils: ActionButtonUtils, private readonly localConfigWrapper: LocalConfigWrapper, private readonly msgWrapper: MsgWrapper, ) { } init() { let { bodyAttrs, device } = this.global; let href = window.location.href; if (href.includes('index.php')) { switch (this.commonUtils.getTravelStage()) { // 飞行中 case TRAVEL_STATE.FLYING: { // 飞行闹钟 if (device === Device.PC && this.localConfigWrapper.config.trvAlarm) { // 获取目的地 let dest_cn; let country = document.body.getAttribute('data-country'); if (country === 'torn') { dest_cn = '回城'; } else { dest_cn = { 'uk': "英国", 'switzerland': "瑞士", 'mexico': '墨西哥', 'canada': '加拿大', 'cayman': '开曼', 'hawaii': '夏威夷', 'argentina': '阿根廷', 'japan': '日本', 'china': '中国', 'uae': 'UAE', 'south-africa': '南非', }[country] || country; } // 剩余时间 const remaining_arr = document.querySelector('#countrTravel').getAttribute('data-to'); const wh_trv_alarm = localStorage.getItem('wh_trv_alarm') ? JSON.parse(localStorage.getItem('wh_trv_alarm')) : { 'enable': true, 'alert_time': 30, 'node_pos': [240, 240] }; const save_trv_settings = () => localStorage.setItem('wh_trv_alarm', JSON.stringify(wh_trv_alarm)); const wh_trv_alarm_node = document.createElement('div'); wh_trv_alarm_node.id = 'wh-trv-alarm'; wh_trv_alarm_node.style.left = `${ wh_trv_alarm.node_pos[0] }px`; wh_trv_alarm_node.style.top = `${ wh_trv_alarm.node_pos[1] }px`; wh_trv_alarm_node.innerHTML = TRAVEL_ALARM_HTML .replace('{{}}', dest_cn === '回城' ? dest_cn : '飞往' + dest_cn) .replace('{{}}', wh_trv_alarm.enable ? 'checked ' : '') .replace('{{}}', wh_trv_alarm.alert_time || 30); this.commonUtils.styleInject(TRAVEL_ALARM_CSS); document.body.append(wh_trv_alarm_node); // 报错dom const error_node = wh_trv_alarm_node.querySelector('#wh-trv-error') as HTMLElement; // jquery拖动 // @ts-ignore $(wh_trv_alarm_node).draggable({ containment: "body", distance: 5, handle: "#wh-trv-alarm-title", stop: () => { wh_trv_alarm.node_pos = [parseInt(wh_trv_alarm_node.style.left), parseInt(wh_trv_alarm_node.style.top)]; save_trv_settings(); }, scroll: false, }); // 剩余时间dom const remaining_node = wh_trv_alarm_node.querySelector('#wh-trv-alarm-remaining'); // 设定闹钟响的按钮 const set_node = wh_trv_alarm_node.querySelectorAll('#wh-trv-alarm-cont button')[0] as HTMLButtonElement; // 落地前响铃时长 const cd_time = wh_trv_alarm_node.querySelector('input[type="number"]') as HTMLInputElement; set_node.onclick = () => { try { wh_trv_alarm.alert_time = parseInt(cd_time.value); } catch { wh_trv_alarm.alert_time = 30; } save_trv_settings(); set_node.value = wh_trv_alarm.alert_time; this.msgWrapper.create('设置已更新'); }; // 停止响铃按钮 const stop_node = wh_trv_alarm_node.querySelectorAll('#wh-trv-alarm-cont button')[1] as HTMLButtonElement; stop_node.onclick = () => { user_stop_alert = true; stop_node.innerText = '本次已关闭'; stop_node.disabled = true; } // 开启闹钟勾选 const enable_node = wh_trv_alarm_node.querySelector('#wh-trv-alarm-cont input[type="checkbox"]') as HTMLInputElement; enable_node.onchange = ev => { wh_trv_alarm.enable = (ev.target).checked; save_trv_settings(); this.msgWrapper.create(wh_trv_alarm.enable ? '闹钟已开启' : '闹钟已关闭'); }; // 剩余时间 秒 const remaining_sec = parseInt(remaining_arr); // 落地时timestamp const land_timestamp = Date.now() + remaining_sec * 1000; // 音频dom const audio = document.createElement('audio'); audio.src = 'https://www.torn.com/js/chat/sounds/Warble_1.mp3'; audio.play() .then(() => audio.pause()) .catch(() => { error_node.style.display = 'table'; const func = () => { error_node.remove(); document.body.removeEventListener('click', func); }; document.body.addEventListener('click', func); }); // 是否正在响铃 let audio_play_flag = false; // 用户是否停止当前响铃 let user_stop_alert = false; // 响铃循环id let audio_play_id = null; // 响铃的方法 let audio_play_handle = () => { if (user_stop_alert) { clearInterval(audio_play_id); audio_play_id = null; return; } if (!audio_play_flag || !wh_trv_alarm.enable) return; audio.play().then(); }; // 飞机小动画字符 const flying_arr = [ '✈ ', '  ✈ ', '    ✈ ', '      ✈ ', '        ✈ ', '          ✈ ', '            ✈ ', '              ✈ ', '                ✈ ', '                  ✈ ', ]; // 飞行的状态dom const flying_status = wh_trv_alarm_node.querySelector('#wh-trv-status'); // 飞机的小动画dom const flying_ani = flying_status.nextElementSibling; // 飞机的计数 let flying_index = 0; const id = window.setInterval(() => { const remaining_time = (land_timestamp - Date.now()) / 1000 | 0; remaining_node.innerText = `${ remaining_time / 3600 | 0 }时${ remaining_time % 3600 / 60 | 0 }分${ remaining_time % 60 }秒`; if (remaining_time < wh_trv_alarm.alert_time) { // flying_status.innerHTML = `即将落地...`; if (wh_trv_alarm.enable) { // 播放提示音 audio_play_flag = true; if (audio_play_id === null && !user_stop_alert) audio_play_id = window.setInterval(audio_play_handle, 750); stop_node.parentElement.classList.remove('wh-trv-alarm-stop-hide'); } } else { // flying_status.innerHTML = `飞行中...`; if (wh_trv_alarm.enable) { clearInterval(audio_play_id); audio_play_id = null; stop_node.parentElement.classList.add('wh-trv-alarm-stop-hide'); } } flying_ani.innerHTML = `${ flying_arr[flying_index] }`; flying_index = (flying_index + 1) % flying_arr.length; }, 1000); } // 落地转跳 落地前事件 if (this.localConfigWrapper.config.landedRedirect && document.querySelector('#tcLogo[title]') === null) { window.addEventListener('beforeunload', () => { let obj = { url: this.localConfigWrapper.config.landedRedirect, timestamp: Date.now() }; sessionStorage['wh-landed-redirect'] = JSON.stringify(obj); }); } break; } // 海外落地 case TRAVEL_STATE.ABROAD: { // 一键回城 this.actionButtonUtils.add('直接回城', () => this.doTravelBack()); // 海外警告 if (this.localConfigWrapper.config.abroadWarning) { let c = 1; setInterval(() => this.msgWrapper.create(`警告:您已海外落地${ c++ * 30 }秒`, { timeout: 30, sysNotify: true }), 30000); } // 解毒提醒 if (bodyAttrs['data-country'] === 'switzerland') { let block = new TornStyleBlock('解毒提醒'); block.setContent('

❤️ 点击前往解毒

'); document.querySelector('h4#skip-to-content').before(block.getBase()); } break; } // 主页界面 case TRAVEL_STATE.IN_TORN: { // 落地转跳 if (sessionStorage['wh-landed-redirect']) { let { url, timestamp } = JSON.parse(sessionStorage['wh-landed-redirect']); if (Date.now() - timestamp < 30000) { sessionStorage.removeItem('wh-landed-redirect'); location.href = url; } } break; } } } // 起飞页面 else if (href.contains(/travelagency\.php/)) { // 起飞提醒 TODO 去除jquery mutation if (this.localConfigWrapper.config.energyAlert) { const contentWrapper = document.querySelector('.content-wrapper'); const OB = new MutationObserver(() => { OB.disconnect(); titleTrans(); contentTitleLinksTrans(); trans(); OB.observe(contentWrapper, { characterData: true, attributes: true, subtree: true, childList: true }); }); const trans = () => { // 当前能量e const energyBarStr = $('#barEnergy p[class^="bar-value__"]').text().trim(); const [curE, maxE] = energyBarStr.split('/').length === 2 ? [parseInt(energyBarStr.split('/')[0]), parseInt(energyBarStr.split('/')[1])] : [NaN, NaN]; const incTime = maxE === 150 ? 10 : 15; const fullEnergyTime = !(isNaN(curE) || isNaN(maxE)) ? (maxE - 5 - curE) / 5 * incTime + (incTime - new Date().getMinutes() % incTime) : NaN; // 起飞前提示 $('.travel-confirm .travel-question .q-wrap span:nth-of-type(2)').each((i, e) => { if (isNaN(fullEnergyTime)) return; const spl = e.innerText.trim().split(' '); const [hours, minutes] = spl.length === 5 ? [parseInt(spl[0]), parseInt(spl[3])] : [0, parseInt(spl[0])]; if (fullEnergyTime < (hours * 60 + minutes) * 2) { if (!$(e).parent().hasClass('wh-translated')) { $(e).parent() .prepend(`
警告:该次飞行往返时间大于体力回复时间,将会爆体!
`) .addClass('wh-translated'); } } }); }; trans(); OB.observe(contentWrapper, { characterData: true, attributes: true, subtree: true, childList: true }); } // 一键起飞 if (window.sessionStorage['wh-quick-fly']) { QuickFlyBtnHandler.doQuickFly(); } } } /** TODO */ inTravelPage() { } async doTravelBack(): Promise { if (typeof window['getAction'] !== 'function') return; let backHomeAction = function (): Promise { return new Promise(resolve => { window.getAction({ type: "post", action: 'travelagency.php', data: { step: 'backHomeAction' }, success: function (msg) { resolve(msg); } }); }); }; let res = await backHomeAction(); this.msgWrapper.create(res); if (!res.includes('error')) { this.msgWrapper.create('成功,即将刷新'); window.setTimeout(() => location.reload(), 3000); } else { this.msgWrapper.create('出错了'); } } }