// ==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
// ==/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 =`<use href="/static/media/skills_sprite.2f50e113.svg#magic"></use>`;
}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);
},
});
}
})();