// ==UserScript== // @name Magic Way Idle // @namespace http://tampermonkey.net/ // @version 1.0.0 // @description 法师助手 // @match https://www.milkywayidle.com/* // @match https://test.milkywayidle.com/* // @run-at document-start // @grant GM_getValue // @grant GM_setValue // @grant GM_notification // @grant GM_xmlhttpRequest // @downloadURL none // ==/UserScript== (function () { //法师排行榜 const secureData = { app_id: "cli_a66edef774b8d00d", secret: "RfrFWOp2N4o83FOuNGF6vfIqSAf10W6h", baseToken: "PtCAbTAR5aI1YxsdKhic5VnPnFb", tableID: "tblhiqRHvAtx7Rba", }; let tenant_access_token = ""; //脚本初始化 script_init(); function script_init(){ //切换logo提示脚本已生效 replaceIcon(); replaceText(); //通知权限测试 Notification.requestPermission().then(function(result) { if (result === 'denied') { console.log('拒绝显示系统通知'); return; } if (result === 'default') { console.log('默认'); return; } console.log('允许显示系统通知') }); //拦截WS hookWS(); //更新飞书Token getTenantToken(); } //改logo(脚本生效测试) function replaceIcon() { const targetDiv = document.querySelector('div.Header_logoContainer__1sCnZ'); const load_check=document.querySelector('div.Header_totalLevel__8LY3Q'); if (load_check && targetDiv && targetDiv.children.length > 0 && targetDiv.querySelector('svg')) { let originalIcon = targetDiv.firstChild; originalIcon.innerHTML =``; }else { setTimeout(replaceIcon, 500); } } //改title(脚本生效测试) function replaceText() { const targetDiv = document.querySelector('div.Header_title__5Mj8z'); const load_check=document.querySelector('div.Header_totalLevel__8LY3Q'); if (load_check && targetDiv && targetDiv.children.length > 0 && targetDiv.querySelector('svg')) { const originaltext = targetDiv.firstChild; const newtext = document.createElement('img'); newtext.src = 'https://tupian.li/images/2024/10/03/66fd73f009f84.png'; newtext.width = '64'; newtext.height = '64'; originaltext.parentNode.replaceChild(newtext, originaltext); }else { setTimeout(replaceText, 500); } } //拦截WS function hookWS() { const dataProperty = Object.getOwnPropertyDescriptor(MessageEvent.prototype, "data"); const oriGet = dataProperty.get; dataProperty.get = hookedGet; Object.defineProperty(MessageEvent.prototype, "data", dataProperty); function hookedGet() { const socket = this.currentTarget; if (!(socket instanceof WebSocket)) { return oriGet.call(this); } if (socket.url.indexOf("api.milkywayidle.com/ws") <= -1 && socket.url.indexOf("api-test.milkywayidle.com/ws") <= -1) { return oriGet.call(this); } const message = oriGet.call(this); Object.defineProperty(this, "data", { value: message }); return handleMessage(message); } } //WS拦截后处理 function handleMessage(message,debug=false) { let obj = JSON.parse(message); //死亡报警 if (obj && obj.type === "new_battle") { if(debug)console.log(obj); obj.players.forEach((player) => { if(player.isActive==false){ showNotification("有人死了"); } }); } else if (obj && obj.type === "battle_updated") { if(debug)console.log(obj); for (const key in obj.pMap) { //防继承 if (obj.pMap.hasOwnProperty(key)) { const player = obj.pMap[key]; if(player.cHP==0){ showNotification("有人死了"); } } } } //提交数据库 try{ if (obj && obj.type === "profile_shared") { const profile = obj.profile; const name = profile.sharableCharacter.name; const guild_name = profile.guildName; const skills = profile.characterSkills; const birth = profile.sharableCharacter.createdAt.slice(0, 10).replace(/-/g, '/'); console.log("Name:", name); console.log("Guild Name:", guild_name); console.log("Skills and Experience:"); const info = [name, guild_name, birth]; const skillOrder = [ "stamina", "intelligence", "attack", "power", "defense", "ranged", "magic", "total_level", ]; for (let skillName of skillOrder) { const skill = skills.find((s) => s.skillHrid.endsWith(skillName)); if (skill) { const skillLevel = skill.level; const skillExp = Math.round(skill.experience); // 保留经验为整数 info.push(skillLevel, skillExp); } } console.log(info.join(", ")); RecordInfo(info); } } catch (error) { console.error("提交数据库失败:", error); return message; } //other return message; } //正式通知 function showNotification(text_to_print){ let notification = new Notification('Magic Way Idle', { body: text_to_print, }); } //用户记录 async function RecordInfo(info) { let [ 姓名, 公会名, 生日, 耐力等级, 耐力经验, 智力等级, 智力经验, 攻击等级, 攻击经验, 力量等级, 力量经验, 防御等级, 防御经验, 远程等级, 远程经验, 魔法等级, 魔法经验, 总等级, 总经验 ] = info; const req_url = `https://open.feishu.cn/open-apis/bitable/v1/apps/${secureData.baseToken}/tables/${secureData.tableID}/records`; const post_header = { Authorization: `Bearer ${tenant_access_token}`, "Content-Type": "application/json", }; // Build record payload const payload = { fields: { 姓名: 姓名, 公会名: 公会名, 生日: 生日, 耐力等级: 耐力等级, 耐力经验: 耐力经验, 智力等级: 智力等级, 智力经验: 智力经验, 攻击等级: 攻击等级, 攻击经验: 攻击经验, 力量等级: 力量等级, 力量经验: 力量经验, 防御等级: 防御等级, 防御经验: 防御经验, 远程等级: 远程等级, 远程经验: 远程经验, 魔法等级: 魔法等级, 魔法经验: 魔法经验, 总等级: 总等级, 总经验: 总经验 }, }; console.log("???:",JSON.stringify(payload)); // Send POST request to record information GM_xmlhttpRequest({ method: "POST", url: req_url, headers: post_header, data: JSON.stringify(payload), onload: function (response) { // console.log("记录信息响应:", response.responseText); try { const responseData = JSON.parse(response.responseText); if (responseData.code === 0) { // console.log("成功记录信息:", responseData.data); } else { // console.error("记录信息失败或数据格式不正确"); } } catch (error) { // console.error("解析记录信息响应时出错:", error); } }, onerror: function (error) { //console.error("Error recording information:", error); }, }); } //获取飞书 tenant_access_token async function getTenantToken() { const req_url = `https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal`; const payload = { app_id: secureData.app_id, app_secret: secureData.secret, }; await post_api(req_url, payload); } //提交飞书 POST request async function post_api(req_url, payload) { const payloadJson = JSON.stringify(payload); let post_header = { "Content-Type": "application/json", }; // Send the POST request GM_xmlhttpRequest({ method: "POST", url: req_url, headers: post_header, data: payloadJson, onload: function (response) { console.log(req_url); console.log("响应:", response.responseText); try { const responseData = JSON.parse(response.responseText); if (responseData.tenant_access_token) { tenant_access_token = responseData.tenant_access_token; // Store tenant_access_token securely console.log("获取的 tenant_access_token:", tenant_access_token); } else { console.error("未能获取 tenant_access_token"); } } catch (error) { console.error("解析响应时出错:", error); } }, onerror: function (error) { console.error("Error fetching data:", error); }, }); } })();