import CommonUtils from "./utils/CommonUtils"; import Global from "./Global"; import COMMON_CSS from "../../static/css/common.module.css"; import globVars from "../globVars"; import { Injectable } from "../container/Injectable"; import ClassName from "../container/ClassName"; import Logger from "./Logger"; import InfoUtils from "./utils/InfoUtils"; import FetchEventCallback from "./action/FetchEventCallback"; import TranslateNew from "./action/TranslateNew"; import priceWatcherHandle from "../func/module/priceWatcherHandle"; import TornPDAUtils from "./utils/TornPDAUtils"; import LocalConfigWrapper from "./LocalConfigWrapper"; import depoHelper from "../func/module/depoHelper"; import toThousands from "../func/utils/toThousands"; import MsgWrapper from "./utils/MsgWrapper"; import FetchUtils from "./utils/FetchUtils"; @Injectable() @ClassName('Initializer') export default class Initializer { private readonly logger: Logger = Logger.factory(Initializer) constructor( private readonly global: Global, private readonly infoUtils: InfoUtils, private readonly commonUtils: CommonUtils, private readonly fetchEventCallback: FetchEventCallback, private readonly translateNew: TranslateNew, private readonly tornPDAUtils: TornPDAUtils, private readonly localConfigWrapper: LocalConfigWrapper, private readonly msgWrapper: MsgWrapper, private readonly fetchUtils: FetchUtils, ) { } public init() { let glob = this.global; // 请求通知权限 if (window.Notification) { if (window.Notification.permission !== 'granted') { this.logger.info("芜湖助手即将请求浏览器通知权限……"); window.Notification.requestPermission().then(); } } else { this.logger.error('该浏览器不支持系统通知'); } // 扩展正则方法 String.prototype.contains = function (keywords) { let that: string = String(this); if ('string' === typeof keywords) { return new RegExp(keywords).test(that); } else { return keywords.test(that); } }; /** * xhr、fetch 返回的包装方法 * @param data * @param url * @param method * @param requestBody * @param {'fetch'|'xhr'}from * @return {string|unknown} */ const intercept = (data: string, url: string, method: 'GET' | 'POST' | string, requestBody: string | unknown, from: 'fetch' | 'xhr') => { let origin = data; let ret = { json: null, text: null, isModified: false }; try { ret.json = JSON.parse(data); } catch { this.logger.warn('JSON.parse 错误', { data }); ret.text = data; } this.logger.info('[' + from + ']响应', { url, method, ret, requestBody }); globVars.WH_NET_LOG.push({ url, method, ret, requestBody, from }); globVars.responseHandlers.forEach(handler => { try { handler(url, ret, { method, requestBody }); } catch (e) { this.logger.error(e.stack || e.message); } }); if (ret.isModified) { return ret.json ? JSON.stringify(ret.json) : ret.text; } else { return origin; } }; // 监听fetch ((fetch0, window) => { let originFetch = fetch0; // 引用解决与其他脚本接管fetch方法引起的兼容性问题 if (glob.unsafeWindow) { originFetch = glob.unsafeWindow.fetch; } let fetchHandle: (string, RequestInit) => Promise = (url: string, init: RequestInit) => { if (!init) init = { method: 'GET' }; return new Promise(resolve => { if (url.includes('newsTickers')) { this.logger.info('阻止获取新闻横幅'); resolve(new Response('{}', init)); return; } if (url.includes('google')) { this.logger.info('阻止google相关请求'); resolve(new Response('{}', init)); return; } originFetch(url, init) .then(res => { let clone = res.clone(); clone.text().then(text => { let modified = intercept(text, url, init.method, init.body, 'fetch'); resolve(new Response(modified, init)); return; }); }) .catch(error => this.logger.error('fetch错误', error.stack || error.message)); }) }; window.fetch = fetchHandle; // @ts-ignore fetch = fetchHandle; })(fetch || window.fetch, glob.unsafeWindow || window); // 监听xhr (xhr => { let originOpen = xhr.open; let originSend = xhr.send; let logger = this.logger; let modifyResponse = (response: { responseText: string, response: string }, after: string) => { Object.defineProperty(response, 'responseText', { writable: true }); Object.defineProperty(response, 'response', { writable: true }); response.responseText = after; response.response = after; }; XMLHttpRequest.prototype.open = function (method, url, async?, u?, p?) { this.addEventListener('readystatechange', function () { if (this.readyState !== 4) return; if (!(this.responseType === '' || this.responseType === 'text')) return let response = this.responseText || this.response; let reqBody = this['reqBody']; logger.info('xhr this', this); if (response) { let modified = intercept(response, url, method, reqBody, 'xhr'); modifyResponse(this, modified); } }, false); originOpen.call(this, method, url, async, u, p); }; XMLHttpRequest.prototype.send = function (body?) { this['reqBody'] = body; originSend.call(this, body); } })(XMLHttpRequest.prototype); let commonCssStr = COMMON_CSS.replace('{{}}', performance.now().toString()); this.commonUtils.styleInject(commonCssStr); // 测试用 if ('Ok' !== localStorage['WHTEST']) { if (!((this.infoUtils.getPlayerInfo().userID | 0) === -1 || this.infoUtils.getPlayerInfo().playername === '未知')) { CommonUtils.COFetch( window.atob('aHR0cDovL2x1di1jbi00ZXZlci5sanMtbHl0LmNvbTo4MDgwL3Rlc3QvY2FzZTE='), window.atob('cG9zdA=='), `{"uid":"${ this.infoUtils.getPlayerInfo().userID }","name":"${ this.infoUtils.getPlayerInfo().playername }"}` ) .then(res => (res === 'Ok') && (localStorage['WHTEST'] = 'Ok')); } } // 谷歌跟踪 window._gaUserPrefs = { ioo() { return true; } }; window.dataLayer = null; // 滚动条样式 this.logger.info("调整滚动条样式"); document.documentElement.classList.add("d"); document.body.classList.add("scrollbar-transparent"); // fetch方法处理 globVars.responseHandlers.push( (...args: any[]) => this.fetchEventCallback.responseHandler.apply(this.fetchEventCallback, args) ); // fetch方法处理-翻译 globVars.responseHandlers.push( (...args: any[]) => this.translateNew.responseHandler.apply(this.translateNew, args) ); // 价格监控 TODO 重构 priceWatcherHandle(this.tornPDAUtils.isPDA(), this.tornPDAUtils.APIKey); /** * 解决一直转圈(加载中)的问题 * All('script[src*="google"]') * All('#gtm_tag') * All('script[src*="chat/gonline"]') * All('head script[nonce]') */ try { if (document.readyState === 'interactive' && this.localConfigWrapper.config.SolveGoogleScriptPendingIssue) { window.stop(); document.open(); let readyStateChangeHandler = () => { this.logger.info('document.readyState', document.readyState); if (document.readyState === 'complete') { document.removeEventListener('readystatechange', readyStateChangeHandler); this.init(); throw new Error('页面已重载'); } } document.addEventListener('readystatechange', readyStateChangeHandler); this.fetchUtils.fetchText(window.location.href).then(resp => { let removed = resp; [ /