2
0
mirror of https://github.com/ctrlcvs/xiaoyao-cvs-plugin.git synced 2024-12-22 19:10:53 +08:00

格式化代码、优化接口文件

This commit is contained in:
Ctrlcvs 2022-10-12 16:51:51 +08:00
parent 50faef4e65
commit 745cd85253
14 changed files with 1331 additions and 1607 deletions

View File

@ -1,4 +1,7 @@
# 1.2.1 # 1.2.1
* 重写接口文件去除`promise-retry`跟 `superagent`依赖
* 自动签到增加推送签到信息以及成功信息
# 1.2.1
* 新增指令`获取(抽卡记录|ck` 导出cookie或者抽卡链接供用户操作到其他bot或app上面 * 新增指令`获取(抽卡记录|ck` 导出cookie或者抽卡链接供用户操作到其他bot或app上面
* 增加国际服 `stoken` 绑定 (功能目前仅支持V3) * 增加国际服 `stoken` 绑定 (功能目前仅支持V3)
* 支持国际服`刷新ck` * 支持国际服`刷新ck`

View File

@ -27,28 +27,7 @@ git clone https://github.com/Ctrlcvs/xiaoyao-cvs-plugin.git ./plugins/xiaoyao-cv
#### 使用说明 #### 使用说明
配合云崽使用, https://gitee.com/Le-niao/Yunzai-Bot
1. 配合云崽使用, https://gitee.com/Le-niao/Yunzai-Bot
2. V3版本安装报错的话请用指令引入包
```
pnpm add superagent -w
```
```
pnpm add promise-retry -w
```
3. V2版本安装报错指令引入包
```
cnpm i yaml
```
```
cnpm i superagent
```
```
cnpm i promise-retry
```
#### 命令说明 #### 命令说明
1. 发送 【#图鉴更新】 获取最新的图鉴记录。(必须) 1. 发送 【#图鉴更新】 获取最新的图鉴记录。(必须)
2. 发送 【#**图鉴】 进行触发,例如发送 #刻晴图鉴,即可返回对应的图片信息。 2. 发送 【#**图鉴】 进行触发,例如发送 #刻晴图鉴,即可返回对应的图片信息。
@ -62,7 +41,6 @@ cnpm i promise-retry
10. 发送 #崩坏3签到 可签到崩坏3游戏模块 具体支持【崩坏3、崩坏2、未定义事件】 10. 发送 #崩坏3签到 可签到崩坏3游戏模块 具体支持【崩坏3、崩坏2、未定义事件】
11. 发送 #云原神签到 可签到云原神游戏 11. 发送 #云原神签到 可签到云原神游戏
12. 默认配置文件位于 ./plugins/xiaoyao-cvs-plugin/defSet/config/config.yaml 12. 默认配置文件位于 ./plugins/xiaoyao-cvs-plugin/defSet/config/config.yaml
## 其他 ## 其他
<!--- <!---
- 有什么问题、Bug或有其它建议欢迎提 [issue](https://github.com/Ctrlcvs/xiaoyao-cvs-plugin/issues) - 有什么问题、Bug或有其它建议欢迎提 [issue](https://github.com/Ctrlcvs/xiaoyao-cvs-plugin/issues)

View File

@ -6,38 +6,44 @@ const plugin = 'xiaoyao-cvs-plugin'
const _path = process.cwd() const _path = process.cwd()
export async function render (app = '', tpl = '', data = {}, imgType = 'jpeg') { export async function render(app = '', tpl = '', data = {}, imgType = 'jpeg') {
// 在data中保存plugin信息 // 在data中保存plugin信息
data._plugin = plugin data._plugin = plugin
if (lodash.isUndefined(data._res_path)) { if (lodash.isUndefined(data._res_path)) {
data._res_path = `../../../../../plugins/${plugin}/resources/` data._res_path = `../../../../../plugins/${plugin}/resources/`
} }
if(imgType == "png"){ if (imgType == "png") {
data.omitBackground=true; data.omitBackground = true;
} }
data.imgType=imgType; data.imgType = imgType;
Data.createDir(_path + '/data/', `html/${plugin}/${app}/${tpl}`) Data.createDir(_path + '/data/', `html/${plugin}/${app}/${tpl}`)
data.saveId = data.saveId || data.save_id || tpl data.saveId = data.saveId || data.save_id || tpl
data.tplFile = `./plugins/${plugin}/resources/${app}/${tpl}.html` data.tplFile = `./plugins/${plugin}/resources/${app}/${tpl}.html`
data.pluResPath = data._res_path data.pluResPath = data._res_path
return await puppeteer.screenshot(`${plugin}/${app}/${tpl}`, data) data.pageGotoParams = {
waitUntil: 'networkidle0'
}
return await puppeteer.screenshot(`${plugin}/${app}/${tpl}`, data)
} }
export function getRender () { export function getRender() {
return async function render (app = '', tpl = '', data = {}, imgType = 'jpeg') { return async function render(app = '', tpl = '', data = {}, imgType = 'jpeg') {
// 在data中保存plugin信息 // 在data中保存plugin信息
data._plugin = plugin data._plugin = plugin
if (lodash.isUndefined(data._res_path)) { if (lodash.isUndefined(data._res_path)) {
data._res_path = `../../../../../plugins/${plugin}/resources/` data._res_path = `../../../../../plugins/${plugin}/resources/`
} }
if(imgType == "png"){ if (imgType == "png") {
data.omitBackground=true; data.omitBackground = true;
} }
data.imgType=imgType; data.imgType = imgType;
Data.createDir(_path + '/data/', `html/${plugin}/${app}/${tpl}`) Data.createDir(_path + '/data/', `html/${plugin}/${app}/${tpl}`)
data.saveId = data.saveId || data.save_id || tpl data.saveId = data.saveId || data.save_id || tpl
data.tplFile = `./plugins/${plugin}/resources/${app}/${tpl}.html` data.tplFile = `./plugins/${plugin}/resources/${app}/${tpl}.html`
data.pluResPath = data._res_path data.pluResPath = data._res_path
return await puppeteer.screenshot(`${plugin}/${app}/${tpl}`, data) data.pageGotoParams = {
waitUntil: 'networkidle0'
}
return await puppeteer.screenshot(`${plugin}/${app}/${tpl}`, data)
}
} }
}

View File

@ -14,7 +14,6 @@ import {
Data Data
} from "../components/index.js"; } from "../components/index.js";
import moment from 'moment'; import moment from 'moment';
import MysApi from "../model/mys/mysApi.js";
import utils from "../model/mys/utils.js"; import utils from "../model/mys/utils.js";
const _path = process.cwd(); const _path = process.cwd();
let role_user = Data.readJSON(`${_path}/plugins/xiaoyao-cvs-plugin/resources/dailyNote/json/`, "dispatch_time"); let role_user = Data.readJSON(`${_path}/plugins/xiaoyao-cvs-plugin/resources/dailyNote/json/`, "dispatch_time");
@ -28,7 +27,6 @@ init()
function init() { function init() {
Data.createDir("", tempDataUrl, false); Data.createDir("", tempDataUrl, false);
tempData = Data.readJSON(tempDataUrl, "tempData") tempData = Data.readJSON(tempDataUrl, "tempData")
// console.log(tempData)
} }
//#体力 //#体力
export async function Note(e, { export async function Note(e, {
@ -39,7 +37,7 @@ export async function Note(e, {
} }
let cookie, uid, res; let cookie, uid, res;
if (isV3) { if (isV3) {
let MysInfo =await import(`file://${_path}/plugins/genshin/model/mys/mysInfo.js`); let MysInfo = await import(`file://${_path}/plugins/genshin/model/mys/mysInfo.js`);
res = await MysInfo.default.get(e, 'dailyNote') res = await MysInfo.default.get(e, 'dailyNote')
if (!res || res.retcode !== 0) return true if (!res || res.retcode !== 0) return true
uid = e.uid; uid = e.uid;
@ -118,7 +116,6 @@ export async function Note(e, {
resinMaxTime = moment(maxDate).format("HH:mm"); resinMaxTime = moment(maxDate).format("HH:mm");
let Time_day = await dateTime_(maxDate) let Time_day = await dateTime_(maxDate)
resinMaxTime_mb2 = Time_day + moment(maxDate).format("hh:mm"); resinMaxTime_mb2 = Time_day + moment(maxDate).format("hh:mm");
// console.log(format("dd", maxDate))
if (moment(maxDate).format("DD") != nowDay) { if (moment(maxDate).format("DD") != nowDay) {
resinMaxTime_mb2Day = `明天`; resinMaxTime_mb2Day = `明天`;
resinMaxTime = `明天 ${resinMaxTime}`; resinMaxTime = `明天 ${resinMaxTime}`;
@ -127,7 +124,6 @@ export async function Note(e, {
resinMaxTime = ` ${resinMaxTime}`; resinMaxTime = ` ${resinMaxTime}`;
} }
} }
// console.log(data.expeditions)
for (let val of data.expeditions) { for (let val of data.expeditions) {
if (val.remained_time <= 0) { if (val.remained_time <= 0) {
val.percentage = 0; val.percentage = 0;
@ -265,13 +261,13 @@ export async function Note(e, {
uid: uid, uid: uid,
coinTime_mb2Day, coinTime_mb2Day,
coinTime_mb2, coinTime_mb2,
urlType:encodeURIComponent(urlType), urlType: encodeURIComponent(urlType),
resinMaxTime_mb2Day, resinMaxTime_mb2Day,
resinMaxTime, resinMaxTime,
resinMaxTime_mb2, resinMaxTime_mb2,
remained_time, remained_time,
coinTime, coinTime,
imgs:encodeURIComponent(imgs), imgs: encodeURIComponent(imgs),
day_mb2, day_mb2,
day, day,
...data, ...data,
@ -285,7 +281,7 @@ export async function Note(e, {
async function dateTime_(time) { async function dateTime_(time) {
return moment(time).format("HH") < 6 ? "凌晨" : moment(time).format("HH") < 12 ? "上午" : moment(time).format( return moment(time).format("HH") < 6 ? "凌晨" : moment(time).format("HH") < 12 ? "上午" : moment(time).format(
"HH") < 17.5 ? "下午" : moment(time).format("HH") < 19.5 ? "傍晚" : moment(time).format("HH") < 22 ? "晚上" : "HH") < 17.5 ? "下午" : moment(time).format("HH") < 19.5 ? "傍晚" : moment(time).format("HH") < 22 ? "晚上" :
"深夜"; "深夜";
} }
async function getDailyNote(uid, cookie) { async function getDailyNote(uid, cookie) {
@ -315,7 +311,7 @@ export async function DailyNoteTask() {
let sendResin = 120; let sendResin = 120;
//推送cd12小时一次 //推送cd12小时一次
let sendCD = 12 * 3600; let sendCD = 12 * 3600;
if(isV3){ if (isV3) {
return true; return true;
} }
//获取需要推送的用户 //获取需要推送的用户
@ -352,23 +348,35 @@ export async function DailyNoteTask() {
redis.set(sendkey, "1", { redis.set(sendkey, "1", {
EX: sendCD EX: sendCD
}); });
if(isV3){ if (isV3) {
let {getRender} = await import(`file://${_path}/plugins/xiaoyao-cvs-plugin/render.js`); let {
await Note(e, {render:await getRender()}); getRender
}else{ } = await import(`file://${_path}/plugins/xiaoyao-cvs-plugin/render.js`);
let {getPluginRender} = await import(`file://${_path}/lib/render.js`); await Note(e, {
await Note(e, {render:await getPluginRender()}); render: await getRender()
});
} else {
let {
getPluginRender
} = await import(`file://${_path}/lib/render.js`);
await Note(e, {
render: await getPluginRender()
});
} }
} }
} }
} }
export async function pokeNote(e,{render}) { export async function pokeNote(e, {
render
}) {
if (!Cfg.get("note.poke")) { if (!Cfg.get("note.poke")) {
return false; return false;
} }
return await Note(e,{render}, "poke"); return await Note(e, {
render
}, "poke");
} }
@ -387,12 +395,12 @@ export async function Note_appoint(e) {
} }
let type = 0; let type = 0;
if (msg.includes("列表")) { if (msg.includes("列表")) {
let xlmsg=msg.replace("列表","")*1 || 1 let xlmsg = msg.replace("列表", "") * 1 || 1
let sumCount=(urlType.length/80+0.49).toFixed(0); let sumCount = (urlType.length / 80 + 0.49).toFixed(0);
xlmsg=sumCount-xlmsg>-1?xlmsg:sumCount==0?1:sumCount; xlmsg = sumCount - xlmsg > -1 ? xlmsg : sumCount == 0 ? 1 : sumCount;
let xxmsg=(xlmsg-1)<=0?0:80*(xlmsg-1) let xxmsg = (xlmsg - 1) <= 0 ? 0 : 80 * (xlmsg - 1)
let count=0; let count = 0;
let msgData=[`模板列表共,第${xlmsg}页,共${urlType.length}张,\n您可通过【#体力模板设置1】来绑定你需要的体力模板~\n请选择序号~~\n当前支持选择的模板有:`]; let msgData = [`模板列表共,第${xlmsg}页,共${urlType.length}张,\n您可通过【#体力模板设置1】来绑定你需要的体力模板~\n请选择序号~~\n当前支持选择的模板有:`];
for (let [index, item] of urlType.entries()) { for (let [index, item] of urlType.entries()) {
let msg_pass = []; let msg_pass = [];
let imgurl; let imgurl;
@ -404,12 +412,12 @@ export async function Note_appoint(e) {
`file:///${mbPath}Template/${item}/icon/bg/${fs.readdirSync(`${mbPath}/Template/${item}/icon/bg/`)[0]}` `file:///${mbPath}Template/${item}/icon/bg/${fs.readdirSync(`${mbPath}/Template/${item}/icon/bg/`)[0]}`
) )
} }
item = index+1 + "." + item item = index + 1 + "." + item
count++; count++;
if(msgData.length==81){ if (msgData.length == 81) {
break; break;
} }
if(index<xxmsg){ if (index < xxmsg) {
continue; continue;
} }
msg_pass.push(item) msg_pass.push(item)
@ -418,18 +426,18 @@ export async function Note_appoint(e) {
} }
msgData.push(msg_pass) msgData.push(msg_pass)
} }
let endMsg=""; let endMsg = "";
if(count<urlType.length){ if (count < urlType.length) {
endMsg= `更多内容请翻页查看\n如:#体力模板列表2` endMsg = `更多内容请翻页查看\n如:#体力模板列表2`
}else{ } else {
endMsg= `已经到底了~~` endMsg = `已经到底了~~`
} }
msgData.push(endMsg) msgData.push(endMsg)
await utils.replyMake(e, msgData, 0) await utils.replyMake(e, msgData, 0)
return true; return true;
} }
if(urlType.includes(msg+".png")){ if (urlType.includes(msg + ".png")) {
msg=msg+".png"; msg = msg + ".png";
} }
if (!urlType.includes(msg) && !All.includes(msg)) { if (!urlType.includes(msg) && !All.includes(msg)) {
e.reply("没有找到你想要的模板昵!可输入 【#体力模板列表】 查询当前支持的模板哦~~") e.reply("没有找到你想要的模板昵!可输入 【#体力模板列表】 查询当前支持的模板哦~~")
@ -459,7 +467,7 @@ const note_file = function(xiaoyao) {
if (val.includes(".")) continue; if (val.includes(".")) continue;
urlType.push(val) urlType.push(val)
} }
if(!xiaoyao){ if (!xiaoyao) {
var urlFileOne = fs.readdirSync(`./plugins/xiaoyao-cvs-plugin/resources/dailyNote/background_image/`); var urlFileOne = fs.readdirSync(`./plugins/xiaoyao-cvs-plugin/resources/dailyNote/background_image/`);
for (let val of urlFileOne) { for (let val of urlFileOne) {
if (!val.includes(".")) continue; if (!val.includes(".")) continue;

View File

@ -24,34 +24,27 @@ import {
} from "../components/Changelog.js"; } from "../components/Changelog.js";
import { import {
rule as userRule,delSign,updCookie, rule as userRule,delSign,updCookie,
userInfo,gclog,mytoken,bindStoken userInfo,gclog,mytoken,bindStoken,cloudToken
} from "./user.js" } from "./user.js"
import { import {
rule as signRule, rule as signRule,
sign, sign,bbsSign,cloudSign,seach,cookiesDocHelp,signTask
mysSign,
cookiesDocHelp,
signlist,yunSignlist,yunAllSign,
allMysSign,yunSign,sendyunTime,yuntoken,yunHelp,
allSign,bbsSeach
} from "./sign.js" } from "./sign.js"
export { export {
updateRes,yunSignlist,delSign, updateRes,delSign,cloudSign,seach,bbsSign,
signlist,gclog,mytoken,bindStoken, gclog,mytoken,bindStoken,
updateMiaoPlugin,userInfo, updateMiaoPlugin,userInfo,
sign,bbsSeach, sign,
versionInfo,yunAllSign, versionInfo,cloudToken,
Note_appoint, Note_appoint,signTask,
pokeNote,yunSign,sendyunTime,yuntoken, pokeNote,
cookiesDocHelp,yunHelp, cookiesDocHelp,
sysCfg, sysCfg,
help,updCookie, help,updCookie,
DailyNoteTask, DailyNoteTask,
allMysSign,
allSign,
AtlasAlias, AtlasAlias,
Note, Note,
mysSign
}; };
import gsCfg from '../model/gsCfg.js'; import gsCfg from '../model/gsCfg.js';
const _path = process.cwd(); const _path = process.cwd();
@ -98,18 +91,18 @@ async function task() {
let set = gsCfg.getfileYaml(`${_path}/plugins/xiaoyao-cvs-plugin/config/`, "config") let set = gsCfg.getfileYaml(`${_path}/plugins/xiaoyao-cvs-plugin/config/`, "config")
schedule.scheduleJob(set.mysBbsTime, function() { schedule.scheduleJob(set.mysBbsTime, function() {
if (set.ismysSign) { if (set.ismysSign) {
allMysSign() signTask('bbs')
} }
} }
); );
schedule.scheduleJob(set.allSignTime, function() { schedule.scheduleJob(set.allSignTime, function() {
if (set.isSign) { if (set.isSign) {
allSign() signTask('mys')
} }
}); });
schedule.scheduleJob(set.YunSignTime, function() { schedule.scheduleJob(set.YunSignTime, function() {
if (set.isYunSign) { if (set.isYunSign) {
yunSignlist() signTask('cloud')
} }
}); });
} }

View File

@ -1,287 +1,105 @@
import MihoYoApi from "../model/mys/mihoyo-api.js" import miHoYoApi from "../model/mys/mihoyoApi.js"
import utils from '../model/mys/utils.js'; import utils from '../model/mys/utils.js';
import promiseRetry from 'promise-retry'; import User from "../model/user.js"
import moment from 'moment';
import { import {
Cfg, Cfg,
Data Data
} from "../components/index.js"; } from "../components/index.js";
import moment from 'moment';
import {
isV3
} from '../components/Changelog.js';
import gsCfg from '../model/gsCfg.js';
import fs from "fs";
import { import {
segment segment
} from "oicq"; } from "oicq";
import YAML from 'yaml' import user from "../model/user.js";
const _path = process.cwd();
let START = moment().unix();
const TODAY_DATE = moment().format('YYYY-MM-DD');
const RETRY_OPTIONS = {
retries: 3,
minTimeout: 5000,
maxTimeout: 10000
};
let YamlDataUrl = `${_path}/plugins/xiaoyao-cvs-plugin/data/yaml`;
let yunpath = `${_path}/plugins/xiaoyao-cvs-plugin/data/yunToken/`;
let configSign = gsCfg.getfileYaml(`${_path}/plugins/xiaoyao-cvs-plugin/config/`, "config");
configSign.signlist = configSign.signlist || "原神|崩坏3|崩坏2|未定事件簿".split("|")
export const rule = { export const rule = {
mysSign: { sign: {
reg: `^#*(原神|崩坏3|崩坏2|未定事件簿)签到$`,
describe: "米社规则签到"
},
bbsSign: {
reg: `^#*(米游社|mys|社区)(原神|崩坏3|崩坏2|未定事件簿|大别野|崩坏星穹铁道|绝区零|全部)签到$`, reg: `^#*(米游社|mys|社区)(原神|崩坏3|崩坏2|未定事件簿|大别野|崩坏星穹铁道|绝区零|全部)签到$`,
describe: "米游社米游币签到(理论上会签到全部所以区分开了)" describe: "米游社米游币签到(理论上会签到全部所以区分开了)"
}, },
bbsSeach: { cloudSign:{
reg: "^#*(米游币|米币)查询$",
describe: "米币查询"
},
sign: {
reg: `^#*(${configSign.signlist.join("|")})签到$`,
describe: "米社规则签到"
},
signlist: {
reg: "^#(米游币|米社(原神|崩坏3|崩坏2|未定事件簿)*)全部签到$",
describe: "米游币全部签到"
},
sendyunTime: {
reg: "^#*云原神(时间|剩余时间|剩余|还有多久|还剩多少分钟|查询)$",
describe: "查询当前云原神剩余时间"
},
yunSign: {
reg: "^#*云原神签到$", reg: "^#*云原神签到$",
describe: "云原神签到" describe: "云原神签到"
}, },
yunAllSign: { seach: {
reg: "^#云原神全部签到$", reg: `^#*(米游币|米币|云原神)查询$`,
describe: "云原神全部签到" describe: "米游币、云原神查询"
},
yuntoken: {
reg: "^(.*)ct(.*)$",
describe: "云原神签到token获取"
}, },
cookiesDocHelp: { cookiesDocHelp: {
reg: "^#*(米游社|cookies|米游币|stoken|Stoken)(帮助|教程|绑定)$", reg: "^#*(米游社|cookies|米游币|stoken|Stoken|云原神|云)(帮助|教程|绑定)$",
describe: "cookies获取帮助" describe: "cookies获取帮助"
}, },
yunHelp: { signTask:{
reg: "^#*(云原神|云)帮助$", reg: `^#((米游币|云原神|米社(原神|崩坏3|崩坏2|未定事件簿)*))全部签到$`,
describe: "cookies获取帮助" describe: "米游币、云原神查询"
} },
};
init()
function init() {
Data.createDir("", yunpath, false);
} }
export async function sign(e) { export async function cloudSign(e){
let { let user = new User(e);
skuid, let res= await user.cloudSeach()
cookie await replyMsg(e, "云原神签到成功\n当前"+res.message);
} = await getCookie(e);
if (!cookie) {
e.reply("请先绑定cookie~\n发送【cookie帮助】获取教程")
return true;
}
START = moment().unix();
let miHoYoApi = new MihoYoApi(e);
let resultMessage = "";
let msg = e.msg.replace(/#|签到|井|米游社|mys|社区/g, "");
let ForumData = await getDataList(msg);
e.reply(`开始尝试${msg}签到预计${msg=='全部'?"60":"5-10"}秒~`)
for (let forum of ForumData) {
if (!(configSign.signlist.includes(forum.name))) {
continue;
}
resultMessage += `**${forum.name}**\n`
try {
// 1 BBS Sign
let resObj = await promiseRetry((retry, number) => {
// Bot.logger.info(`开始签到: [${forum.name}] 尝试次数: ${number}`);
return miHoYoApi.honkai3rdSignTask(forum.name).catch((e) => {
Bot.logger.error(`${forum.name} 签到失败: [${e.message}] 尝试次数: ${number}`);
return retry(e);
});
}, RETRY_OPTIONS);
Bot.logger.info(`${forum.name} 签到结果: [${resObj.message}]`);
resultMessage += `签到: \n${resObj.message}\n`;
} catch (e) {
Bot.logger.error(`${forum.name} 签到失败 [${e.message}]`);
resultMessage += `签到失败: [${e.message}]\n`;
}
await utils.randomSleepAsync();
}
await replyMsg(e, resultMessage);
return true
}
export async function mysSign(e) {
let isck = await cookie(e);
if (!isck) {
return true;
}
let iscount = "";
let miHoYoApi = new MihoYoApi(e);
let stokens = await miHoYoApi.getStoken(e.user_id)
if (Object.keys(stokens).length == 0) {
e.reply("未读取到stoken\n请发送【stoken帮助】查看配置教程配置~")
return true;
}
if (e.uid[0] * 1 > 5) {
e.reply("暂不支持hoyolab社区签到~")
return true;
}
START = moment().unix();
let resultMessage = "";
let resObj=await mysSeach(e)
if(resObj?.data?.can_get_points===0){
resultMessage+=`今日米游币任务已完成~\n请勿重复操作\n当前米游币总持有数量为:${resObj.data.total_points}`;
await replyMsg(e, resultMessage);
return true
}else if(!resObj?.data){
resultMessage+=`登录Stoken失效\n请发送【stoken帮助】查看配置教程重新配置~`;
await replyMsg(e, resultMessage);
fs.unlink(`${YamlDataUrl}/${e.user_id}.yaml`,function(error){
if(error){
return ""
}
})
return true;
}
// Execute task
let msg = e.msg.replace(/#|签到|井|米游社|mys|社区/g, "");
let ForumData = await getDataList(msg);
e.reply(`开始尝试${msg}社区签到预计${msg=='全部'?"10-20":"1-3"}分钟~`)
for (let forum of ForumData) {
resultMessage += `**${forum.name}**\n`
try {
// 1 BBS Sign
let resObj = await promiseRetry((retry, number) => {
// Bot.logger.info(`开始签到: [${forum.name}] 尝试次数: ${number}`);
return miHoYoApi.forumSign(forum.forumId).catch((e) => {
Bot.logger.error(`${forum.name} 签到失败: [${e.message}] 尝试次数: ${number}`);
return retry(e);
});
}, RETRY_OPTIONS);
Bot.logger.mark(`${e.user_id}:${e.uid}:${forum.name} 签到结果: [${resObj.message}]`);
resultMessage += `签到: [${resObj.message}]\n`;
} catch (e) {
Bot.logger.error(`${forum.name} 签到失败 [${e.message}]`);
resultMessage += `签到失败: [${e.message}]\n`;
}
await utils.randomSleepAsync();
}
for (let forum of ForumData) {
let trueDetail = 0;
let Vote = 0;
let Share = 0;
let sumcount = 0;
resultMessage += `\n**${forum.name}**\n`
try {
// 2 BBS list post
let resObj = await promiseRetry((retry, number) => {
// Bot.logger.info(`读取帖子列表: [${forum.name}] 尝试次数: ${number}`);
return miHoYoApi.forumPostList(forum.forumId).catch((e) => {
Bot.logger.error(`${forum.name} 读取帖子列表失败: [${e.message}] 尝试次数: ${number}`);
return retry(e);
});
}, RETRY_OPTIONS);
sumcount++;
// Bot.logger.info(`${forum.name} 读取列表成功 [${resObj.message}],读取到 [${resObj.data.list.length}] 条记录`);
let postList = resObj.data.list;
for (let post of postList) {
post = post.post;
// 2.1 BBS read post
let resObj = await promiseRetry((retry, number) => {
// Bot.logger.mark(`读取帖子: [${post.subject}] 尝试次数: ${number}`);
return miHoYoApi.forumPostDetail(post['post_id']).catch((e) => {
Bot.logger.error(`${forum.name} 读取帖子失败: [${e.message}] 尝试次数: ${number}`);
return retry(e);
});
}, RETRY_OPTIONS);
if (resObj?.message) {
trueDetail++;
}
// Bot.logger.info(`${forum.name} [${post.subject}] 读取成功 [${resObj.message}]`);
await utils.randomSleepAsync();
// 2.2 BBS vote post
resObj = await promiseRetry((retry, number) => {
// Bot.logger.mark(`点赞帖子: [${post.subject}] 尝试次数: ${number}`);
return miHoYoApi.forumPostVote(post['post_id']).catch((e) => {
Bot.logger.error(`${forum.name} 点赞帖子失败: [${e.message}] 尝试次数: ${number}`);
return retry(e);
});
}, RETRY_OPTIONS);
if (resObj?.message) {
Vote++;
}
// Bot.logger.mark(`${forum.name} [${post.subject}] 点赞成功 [${resObj.message}]`);
await utils.randomSleepAsync();
}
// 2.3 BBS share post
let sharePost = postList[0].post;
resObj = await promiseRetry((retry, number) => {
// Bot.logger.mark(`分享帖子: [${sharePost.subject}] 尝试次数: ${number}`);
return miHoYoApi.forumPostShare(sharePost['post_id']).catch((e) => {
Bot.logger.error(`${forum.name} 分享帖子失败: [${e.message}] 尝试次数: ${number}`);
return retry(e);
});
}, RETRY_OPTIONS);
if (resObj?.message) {
Share++;
}
} catch (e) {
Bot.logger.error(`${forum.name} 读帖点赞分享失败 [${e.message}]`);
resultMessage += `读帖点赞分享: 失败 [${e.message}]\n`;
}
resultMessage += `共读取帖子记录${20*sumcount}\n浏览成功:${trueDetail}\n点赞成功:${Vote}\n分享成功:${Share}`;
await utils.randomSleepAsync();
}
Bot.logger.mark(`用户qq${e.user_id}:${e.uid}:${resultMessage}`);
await replyMsg(e, resultMessage);
return true
}
export async function bbsSeach(e) {
START = moment().unix();
let isck = await cookie(e);
if (!isck) {
return true;
}
let miHoYoApi = new MihoYoApi(e);
let stokens = await miHoYoApi.getStoken(e.user_id)
if (Object.keys(stokens).length == 0) {
let cookiesDoc = await getcookiesDoc()
await replyMsg(e, "未读取到stoken请检查cookies是否包含login_ticket请先绑定stoken再查询~\n" + cookiesDoc);
return true;
}
let resObj = await mysSeach(e)
if (!resObj?.data) {
await replyMsg(e, `登录Stoken失效请重新获取cookies或stoken保存~`);
fs.unlink(`${YamlDataUrl}/${e.user_id}.yaml`, function(error) {
if (error) {
return ""
}
})
return true;
}
await replyMsg(e, `当前米游币数量为:${resObj.data.total_points},今日剩余可获取:${resObj.data.can_get_points}`);
return true; return true;
} }
async function mysSeach(e) { export async function signTask(e){
let miHoYoApi = new MihoYoApi(e); let user = new User(e);
try { let task=e?.msg?.includes("米游币")?'bbs':e.msg.includes("云原神")?'cloud':'mys'
let resObj = await promiseRetry((retry, number) => { if(!task){
return miHoYoApi.getTasksList().catch((e) => { task=e;
return retry(e); e='';
});
}, RETRY_OPTIONS);
return resObj
} catch (e) {
} }
if(task==="bbs"){
await user.bbsTask(e)
}
if(task==="cloud"){
await user.cloudTask(e)
}
if(task==="mys"){
await user.signTask(e)
}
return true;
}
export async function cookiesDocHelp(e){
let user = new User(e);
e.reply(`${e.msg.replace(/帮助|教程|绑定/g,"")}帮助】${await user.docHelp(e.msg)}\ncookies必须包含login_ticket获取后请私发机器人`);
return true;
}
export async function seach(e){
let user = new User(e);
START = moment().unix();
let res
if(e.msg.includes('币')){
res= await user.bbsSeachSign()
}else{
res= await user.cloudSeach()
}
await replyMsg(e, res.message);
return true;
}
export async function bbsSign(e) {
let user = new User(e);
START = moment().unix();
let res = await user.bbsSeachSign()
if(res.isOk&&res?.data?.can_get_points!==0){
let forumData = await user.getDataList(e.msg);
e.reply(`开始尝试${e.msg}社区签到预计${e.msg=='全部'?"10-20":"1-3"}分钟~`)
res=await user.getbbsSign(forumData)
}
await replyMsg(e, res.message);
return true;
}
const _path = process.cwd();
let START;
export async function sign(e) {
let user = new User(e);
START = moment().unix();
let msg = e.msg.replace(/#|签到|井|米游社|mys|社区/g, "");
let ForumData = await user.getDataList(msg);
e.reply(`开始尝试${msg}签到\n预计${msg=='全部'?"60":"5-10"}秒~`)
let res = await user.multiSign(ForumData);
await replyMsg(e, res.message);
return true;
} }
async function replyMsg(e, resultMessage) { async function replyMsg(e, resultMessage) {
const END = moment().unix(); const END = moment().unix();
@ -289,315 +107,3 @@ async function replyMsg(e, resultMessage) {
resultMessage += `\n用时 ${END - START}`; resultMessage += `\n用时 ${END - START}`;
e.reply([segment.at(e.user_id), "\n" + resultMessage]); e.reply([segment.at(e.user_id), "\n" + resultMessage]);
} }
async function getDataList(name) {
let ForumData = Data.readJSON(`${_path}/plugins/xiaoyao-cvs-plugin/defSet/json`, "mys")
for (let item of ForumData) {
if (item.name == name) { //循环结束未找到的时候返回原数组签到全部
return [item]
}
}
return ForumData;
}
async function cookie(e) {
let {
cookie,
uid,
skuid
} = await getCookie(e);
let miHoYoApi = new MihoYoApi(e);
let cookiesDoc = await getcookiesDoc();
if (!cookie) {
e.reply("cookie失效请重新绑定~【教程】\n" + cookiesDoc)
return false;
}
let stokens = miHoYoApi.getStoken(e.user_id)
if (Object.keys(stokens).length > 0) {
return true;
}
if (!cookie.includes("login_ticket") && (isV3 && !skuid?.login_ticket)) {
e.reply("米游社登录cookie不完整请前往米游社通行证处重新获取cookie~\ncookies必须包含login_ticket【教程】 " + cookiesDoc)
return false;
}
let flot = (await miHoYoApi.stoken(cookie, e));
await utils.sleepAsync(1000); //延迟加载防止文件未生成
if (!flot) {
e.reply("登录失效请重新登录获取cookie发送机器人~")
return false;
}
return true;
}
async function getCookie(e) {
let skuid, cookie, uid
if (isV3) {
skuid = await gsCfg.getBingCookie(e.user_id);
cookie = skuid?.ck;
uid = skuid?.item;
} else {
if (NoteCookie[e.user_id]) {
cookie = NoteCookie[e.user_id].cookie;
uid = NoteCookie[e.user_id].uid;
skuid = NoteCookie[e.user_id];
} else if (BotConfig.dailyNote && BotConfig.dailyNote[e.user_id]) {
cookie = BotConfig.dailyNote[e.user_id].cookie;
uid = BotConfig.dailyNote[e.user_id].uid;
skuid = BotConfig.NoteCookie[e.user_id];
}
}
e.uid = uid;
e.cookie = cookie;
return {
cookie,
uid,
skuid
}
}
export async function cookiesDocHelp(e) {
let cookiesDoc = await getcookiesDoc()
e.reply(`${e.msg.replace(/帮助|教程|绑定/g,"")}帮助】${cookiesDoc}\ncookies必须包含login_ticket获取后请私发机器人`);
return true
}
async function getcookiesDoc() {
return await gsCfg.getfileYaml(`${_path}/plugins/xiaoyao-cvs-plugin/config/`, "config").cookiesDoc
}
//定时米社米币签到任务
export async function allMysSign() {
Bot.logger.mark(`开始米社米币签到任务`);
let stoken = await gsCfg.getBingStoken();
let isPushSign = await gsCfg.getfileYaml(`${_path}/plugins/xiaoyao-cvs-plugin/config/`, "config").isPushSign
//获取需要签到的用户
for (let dataUid of stoken) {
for (let uuId in dataUid) {
if (uuId[0] * 1 > 5) {
continue;
}
let data = dataUid[uuId]
let user_id = data.userId * 1;
let e = {
user_id,
isTask: true
};
e.cookie = `stuid=${data.stuid};stoken=${data.stoken};ltoken=${data.ltoken};`;
Bot.logger.mark(`正在为qq${user_id}uid:${uuId}进行米游币签到中...`);
e.msg = "全部"
e.reply = (msg) => {
//关闭签到消息推送
if (!isPushSign || ismysbool) {
return;
}
if (msg.includes("OK")) { //签到成功并且不是已签到的才推送
// msg = msg.replace("签到成功", "自动签到成功");
utils.relpyPrivate(user_id, msg + "uid:" + uuId + "\n自动签到成功");
}
};
await mysSign(e);
await utils.sleepAsync(10000);
}
}
Bot.logger.mark(`米社米币签到任务完成`);
return true
}
//定时签到任务
export async function allSign(e = "") {
Bot.logger.mark(`开始米社签到任务`);
let isAllSign = await gsCfg.getfileYaml(`${_path}/plugins/xiaoyao-cvs-plugin/config/`, "config").isAllSign
let userIdList = [];
if (isV3) {
let dir = './data/MysCookie/'
let files = fs.readdirSync(dir).filter(file => file.endsWith('.yaml'))
userIdList = (files.join(",").replace(/.yaml/g, "").split(","))
} else {
for (let [user_id, cookie] of Object.entries(NoteCookie)) {
userIdList.push(user_id)
}
}
let msg = e?.msg;
for (let qq of userIdList) {
let user_id = qq;
let e = {
user_id,
qq,
isTask: true
};
if (msg) {
e.msg = msg.replace(/全部|签到|米社/g, "");
} else {
e.msg = "全部"
}
Bot.logger.mark(`正在为qq${user_id}米社签到中...`);
e.reply = (msg) => {
if (!isAllSign || isbool) {
return;
}
if (msg.includes("OK")) {
utils.relpyPrivate(qq, msg + "\n自动签到成功");
}
};
await sign(e);
await utils.sleepAsync(10000);
}
Bot.logger.mark(`米社签到任务完成`);
}
const checkAuth = async function(e) {
return await e.checkAuth({
auth: "master",
replyMsg: `只有主人才能命令我哦~
(*/ω*)`
});
}
let isbool = false;
let ismysbool = false;
export async function signlist(e) {
if (!await checkAuth(e)) {
return true;
}
if (isbool) {
e.reply(`米社签到中请勿重复执行`)
return true;
}
if (ismysbool) {
e.reply(`米游币签到中请勿重复执行`)
return true;
}
let msg = e.msg.replace(/#|全部签到/g, "")
e.reply(`开始执行${msg}签到中,请勿重复执行`);
if (msg == "米游币") {
if (!fs.existsSync(YamlDataUrl)) {
Data.createDir("", YamlDataUrl, false);
e.reply("未读取到可签到文件")
return true;
}
ismysbool = true;
await allMysSign()
} else {
isbool = true;
await allSign(e)
}
e.reply(`${msg}签到任务已完成`);
ismysbool = false;
isbool = false;
return true;
}
let isYun = false;
export async function yunAllSign(e) {
if (!await checkAuth(e)) {
return true;
}
e.reply(`开始执行云原神签到中,请勿重复执行`);
if (isYun) {
e.reply(`云原神签到中请勿重复执行`)
return true;
}
isYun = true;
await yunSignlist(e);
e.reply(`云原神签到任务已完成`);
}
export async function yunSignlist(e) {
Bot.logger.mark(`云原神签到任务开始`);
let files = fs.readdirSync(yunpath).filter(file => file.endsWith('.yaml'))
let isYunSignMsg = await gsCfg.getfileYaml(`${_path}/plugins/xiaoyao-cvs-plugin/config/`, "config").isYunSignMsg
let userIdList = (files.join(",").replace(/.yaml/g, "").split(","))
for (let qq of userIdList) {
let user_id = qq;
let e = {
user_id,
qq,
isTask: true
};
Bot.logger.mark(`正在为qq${user_id}云原神签到中...`);
e.msg = "全部"
e.reply = (msg) => {
if (!isYunSignMsg || isYun) {
return;
}
if (msg.includes("领取奖励")) {
utils.relpyPrivate(qq, msg + "\n云原神自动签到成功");
}
};
await yunSign(e);
await utils.sleepAsync(10000);
}
Bot.logger.mark(`云原神签到任务完成`);
}
export async function yunSign(e) {
if (!(await getyunToken(e))) {
e.reply("尚未绑定云原神token\n" + await yunDoc())
return true;
}
let miHoYoApi = new MihoYoApi(e);
e.reply((await miHoYoApi.yunGenshen()).sendMSg)
return;
}
const getyunToken = async function(e) {
let file = `${yunpath}/${e.user_id}.yaml`
try {
let ck = fs.readFileSync(file, 'utf-8')
ck = YAML.parse(ck)
e.devId = ck.devId;
e.yuntoken = ck.yuntoken;
return ck
} catch (error) {
return ""
}
}
export async function sendyunTime(e) {
if (!(await getyunToken(e))) {
e.reply("尚未绑定云原神token\n" + await yunDoc())
return true;
}
let miHoYoApi = new MihoYoApi(e);
e.reply((await miHoYoApi.logyunGenshen()).log_msg)
return;
}
export async function yuntoken(e) {
if (e.msg.includes("ltoken") || e.msg.includes("_MHYUUID")) { //防止拦截米社cookie
return false;
}
if (["ct", "si", "devId"].includes(e.msg)) {
e.reply(`格式支持\nai=*;ci=*;oi=*;ct=***********;si=**************;bi=***********;devId=***********`)
return false;
}
let msg = e.msg.split("devId")
if (msg.length < 2) {
return false;
}
let devId = msg[1].replace(/=/, "")
let yuntoken = msg[0];
e.devId = devId;
e.yuntoken = yuntoken;
let miHoYoApi = new MihoYoApi(e);
let objData = (await miHoYoApi.logyunGenshen()) //校验token是否有效
if (objData.retcode != 0) {
e.reply(objData.message)
return true;
}
let datalist = {
devId: devId,
yuntoken: yuntoken,
qq: e.user_id,
uid: e.uid,
sign: true
}
let yamlStr = YAML.stringify(datalist);
fs.writeFileSync(`${yunpath}${e.user_id}.yaml`, yamlStr, 'utf8');
e.reply("云原神cookie保存成功~\n您后续可发送【#云原神查询】获取使用时间~")
return true;
}
export async function yunHelp(e) {
e.reply("云原神帮助:\n" + await yunDoc())
return true;
}
const yunDoc = async function() {
return await gsCfg.getfileYaml(`${_path}/plugins/xiaoyao-cvs-plugin/config/`, "config").yunDoc
}

View File

@ -1,6 +1,4 @@
import MihoYoApi from "../model/mys/mihoyo-api.js"
import utils from '../model/mys/utils.js'; import utils from '../model/mys/utils.js';
import promiseRetry from 'promise-retry';
import { import {
Cfg, Cfg,
Data Data
@ -18,6 +16,7 @@ import {
} from "oicq"; } from "oicq";
import YAML from 'yaml' import YAML from 'yaml'
import User from "../model/user.js" import User from "../model/user.js"
import user from '../model/user.js';
export const rule = { export const rule = {
userInfo: { userInfo: {
@ -36,6 +35,10 @@ export const rule = {
reg: "^(.*)stoken=(.*)$", reg: "^(.*)stoken=(.*)$",
describe: "绑定stoken" describe: "绑定stoken"
}, },
cloudToken: {
reg: "^(.*)ct(.*)$",
describe: "云原神签到token获取"
},
delSign: { delSign: {
reg: "^#*删除(我的)*(stoken|(云原神|云ck))$", reg: "^#*删除(我的)*(stoken|(云原神|云ck))$",
describe: "删除云原神、stoken数据" describe: "删除云原神、stoken数据"
@ -57,6 +60,7 @@ export async function userInfo(e, {
let week = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"]; let week = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
let day = moment(new Date()).format("yyyy年MM月DD日 HH:mm") + " " + week[new Date().getDay()]; let day = moment(new Date()).format("yyyy年MM月DD日 HH:mm") + " " + week[new Date().getDay()];
if (Object.keys(sumData).length == 0) { if (Object.keys(sumData).length == 0) {
e.reply("未获取到角色信息~")
return true; return true;
} }
let ck = ""; let ck = "";
@ -92,44 +96,15 @@ export async function gclog(e) {
e.reply("请私聊发送") e.reply("请私聊发送")
return true; return true;
} }
let miHoYoApi = new MihoYoApi(e);
if (!e.cookies || e.cookies.includes("undefined")) {
e.reply(`请先绑定stoken\n发送【stoken帮助】查看配置教程`)
return true;
}
// let kkbody = await miHoYoApi.getbody("原神");
e.region = getServer(e.uid) e.region = getServer(e.uid)
// const objData = await miHoYoApi.getUserInfo(kkbody) let authkeyrow = await user.getData("authKey");
// let data = objData.data
let authkeyrow = await miHoYoApi.authkey(e);
if (!authkeyrow?.data) { if (!authkeyrow?.data) {
e.reply("authkey获取失败" + authkeyrow.message) e.reply("authkey获取失败" + authkeyrow.message)
return true; return true;
} }
let authkey = authkeyrow.data["authkey"] let authkey = authkeyrow.data["authkey"]
let postdata = { let url = `https://hk4e-api.mihoyo.com/event/gacha_info/api/getGachaLog?authkey_ver=1&sign_type=2&auth_appid=webview_gacha&init_type=301&gacha_id=fecafa7b6560db5f3182222395d88aaa6aaac1bc&timestamp=${Math.floor(Date.now() / 1000)}&lang=zh-cn&device_type=mobile&plat_type=ios&region=${e.region}&authkey=${encodeURIComponent(authkey)}&game_biz=hk4e_cn&gacha_type=301&page=1&size=5&end_id=0`
'authkey_ver': '1', e.msg = url
'sign_type': '2',
'auth_appid': 'webview_gacha',
'init_type': '301',
'gacha_id': 'fecafa7b6560db5f3182222395d88aaa6aaac1bc',
'timestamp': Math.floor(Date.now() / 1000), //当前时间搓
'lang': 'zh-cn',
'device_type': 'mobile',
'plat_type': 'ios',
'region': e.region,
'authkey': encodeURIComponent(authkey),
'game_biz': 'hk4e_cn',
'gacha_type': "301",
'page': 1,
'size': 5,
'end_id': 0,
}
let url = `https://hk4e-api.mihoyo.com/event/gacha_info/api/getGachaLog?`
for (let item of Object.keys(postdata)) {
url += `${item}=${postdata[item]}&`
}
e.msg = url.substring(0, url.length - 1);
// e.reply(e.msg) // e.reply(e.msg)
let sendMsg = []; let sendMsg = [];
e.reply("抽卡记录获取中请稍等...") e.reply("抽卡记录获取中请稍等...")
@ -138,7 +113,6 @@ export async function gclog(e) {
sendMsg.push(msg) sendMsg.push(msg)
} }
if(isGet){ if(isGet){
sendMsg=[...sendMsg,...[1,`uid:${e.uid}`,e.msg]] sendMsg=[...sendMsg,...[1,`uid:${e.uid}`,e.msg]]
}else { }else {
if (isV3) { if (isV3) {
@ -190,12 +164,10 @@ export async function bindStoken(e) {
let msg = e.msg; let msg = e.msg;
let user = new User(e); let user = new User(e);
await user.cookie(e) await user.cookie(e)
let miHoYoApi = new MihoYoApi(e);
e.region = getServer(e.uid) e.region = getServer(e.uid)
miHoYoApi.cookies = msg; let res= await user.getData("bbsGetCookie",{cookies:msg.replace(/;/g,'&').replace(/stuid/,"uid")} )
let resObj = await miHoYoApi.updCookie(); if (!res?.data) {
if (!resObj?.data) { await e.reply(`绑定Stoken失败异常${res?.message}\n请发送【stoken帮助】查看配置教程重新配置~`);
await e.reply(`绑定Stoken失败异常${resObj?.message}\n请发送【stoken帮助】查看配置教程重新配置~`);
return true; return true;
} }
await user.getCookie(e) await user.getCookie(e)
@ -220,6 +192,40 @@ export async function bindStoken(e) {
await e.reply(msg); await e.reply(msg);
return true; return true;
} }
export async function cloudToken(e) {
if (e.msg.includes("ltoken") || e.msg.includes("_MHYUUID")) { //防止拦截米社cookie
return false;
}
if (["ct", "si", "devId"].includes(e.msg)) {
e.reply(`格式支持\nai=*;ci=*;oi=*;ct=***********;si=**************;bi=***********;devId=***********`)
return false;
}
let msg = e.msg.split("devId")
if (msg.length < 2) {
return false;
}
let devId = msg[1].replace(/=/, "")
let user = new User(e);
let yuntoken = msg[0];
e.devId = devId;
e.yuntoken = yuntoken;
let res=await user.cloudSeach()
if (res.retcode != 0) {
e.reply(objData.message)
return true;
}
let datalist = {
devId: devId,
yuntoken: yuntoken,
qq: e.user_id,
uid: e.uid,
sign: true
}
let yamlStr = YAML.stringify(datalist);
fs.writeFileSync(`${yunpath}${e.user_id}.yaml`, yamlStr, 'utf8');
e.reply("云原神cookie保存成功~\n您后续可发送【#云原神查询】获取使用时间~")
return true;
}
export async function delSign(e) { export async function delSign(e) {
let user = new User(e); let user = new User(e);
@ -239,7 +245,7 @@ export async function updCookie(e) {
e.reply("请私聊发送") e.reply("请私聊发送")
return true; return true;
} }
let miHoYoApi = new MihoYoApi(e); let user = new User(e);
let sendMsg = []; let sendMsg = [];
e._reply = e.reply; e._reply = e.reply;
e.reply = (msg) => { e.reply = (msg) => {
@ -247,15 +253,13 @@ export async function updCookie(e) {
} }
for(let item of Object.keys(stoken)){ for(let item of Object.keys(stoken)){
e.region = getServer(stoken[item].uid) e.region = getServer(stoken[item].uid)
miHoYoApi.cookies= `stuid=${stoken[item].stuid};stoken=${stoken[item].stoken};ltoken=${stoken[item].ltoken};`; let res= await user.getData("bbsGetCookie",{cookies:`uid=${stoken[item].stuid}&stoken=${stoken[item].stoken}`})
let resObj = await miHoYoApi.updCookie(); if (!res?.data) {
if (!resObj?.data) { e.reply(`uid:${stoken[item].uid},请求异常:${res.message}`)
e.reply(`uid:${stoken[item].uid},请求异常:${resObj.message}`)
continue; continue;
} }
let sk = await utils.getCookieMap(miHoYoApi.cookies) let ck = res["data"]["cookie_token"];
let ck = resObj["data"]["cookie_token"]; e.msg = `ltoken=${stoken[item].ltoken};ltuid=${stoken[item].stuid};cookie_token=${ck}; account_id=${stoken[item].stuid};`
e.msg = `ltoken=${sk.get("ltoken")};ltuid=${sk.get("stuid")};cookie_token=${ck}; account_id=${sk.get("stuid")};`
if(isGet){ if(isGet){
sendMsg=[...sendMsg,...[`uid:${stoken[item].uid}`,e.msg]] sendMsg=[...sendMsg,...[`uid:${stoken[item].uid}`,e.msg]]
}else { }else {

View File

@ -29,6 +29,16 @@ class GsCfg {
fs.readFileSync(path + name + ".yaml", 'utf8') fs.readFileSync(path + name + ".yaml", 'utf8')
) )
} }
async getMasterQQ(){
let qq;
if(isV3){
let config=(await import(`file://${_path}/plugins/genshin/model/gsCfg.js`)).default
qq=config.masterQQ[0]
}else{
qq=BotConfig.masterQQ[0]
}
return qq
}
/** 读取用户绑定的ck */ /** 读取用户绑定的ck */
async getBingCk() { async getBingCk() {
let ck = {} let ck = {}

View File

@ -1,601 +0,0 @@
import utils from './utils.js';
import md5 from 'md5';
import _ from 'lodash';
import superagent from 'superagent';
import fs from "fs";
import YAML from 'yaml'
import {
Data
} from "../../components/index.js";
import gsCfg from '../gsCfg.js'
import {
isV3
} from '../../components/Changelog.js';
import fetch from "node-fetch"
const APP_VERSION = "2.38.1";
const mhyVersion = "2.11.1";
const salt = "PVeGWIZACpxXZ1ibMVJPi9inCY4Nd4y2";
const salt2 = "t0qEgfub6cvueAPgR5m9aQWWVciEer7v";
const saltWeb = "yUZ3s0Sna1IrSNfk29Vo6vRapdOyqyhB";
const oldsalt = "z8DRIUjNDT7IT5IZXvrUAxyupA1peND9";
const osSaltWeb=''; //os 浏览帖子需要用到的salt
const DEVICE_ID = utils.randomString(32).toUpperCase();
const DEVICE_NAME = utils.randomString(_.random(1, 10));
const _path = process.cwd();
const YamlDataUrl = `${_path}/plugins/xiaoyao-cvs-plugin/data/yaml`;
const web_api = `https://api-takumi.mihoyo.com`
const os_web_api = `https://api-os-takumi.mihoyo.com`
const os_hk4_api=`https://hk4e-api-os.hoyoverse.com`;
const hk4_api = `https://hk4e-api.mihoyo.com`;
const bbs_api = `https://bbs-api.mihoyo.com`;
let HttpsProxyAgent = ''
// 米游社的版块
const boards = {
honkai3rd: {
forumid: 1,
key: 'honkai3rd',
biz: 'bh3_cn',
actid: 'e202207181446311',
name: '崩坏3',
url: "https://bbs.mihoyo.com/bh3/",
getReferer() {
return `https://webstatic.mihoyo.com/bh3/event/euthenia/index.html?bbs_presentation_style=fullscreen&bbs_game_role_required=${this.biz}&bbs_auth_required=true&act_id=${this.actid}&utm_source=bbs&utm_medium=mys&utm_campaign=icon`
}
},
genshin: {
forumid: 26,
key: 'genshin',
biz: 'hk4e_cn',
actid: 'e202009291139501',
name: '原神',
url: "https://bbs.mihoyo.com/ys/",
getReferer() {
return `https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html?bbs_auth_required=true&act_id=${this.actid}&utm_source=bbs&utm_medium=mys&utm_campaign=icon`
}
},
honkai2: {
forumid: 30,
biz: 'bh2_cn',
actid: 'e202203291431091',
name: '崩坏2',
url: "https://bbs.mihoyo.com/bh2/",
getReferer() {
return `https://webstatic.mihoyo.com/bbs/event/signin/bh2/index.html?bbs_auth_required=true&act_id=${this.actid}&bbs_presentation_style=fullscreen&utm_source=bbs&utm_medium=mys&utm_campaign=icon`
}
},
tears: {
forumid: 37,
biz: 'nxx_cn',
name: '未定事件簿',
actid: 'e202202251749321',
url: "https://bbs.mihoyo.com/wd/",
getReferer() {
return `https://webstatic.mihoyo.com/bbs/event/signin/nxx/index.html?bbs_auth_required=true&bbs_presentation_style=fullscreen&act_id=${this.actid}`
}
},
/** 以下数据待定 由于并未有存在签到入口可能后续会开放*/
house: {
forumid: 34,
name: '大别野',
url: "https://bbs.mihoyo.com/dby/"
},
honkaisr: {
forumid: 52,
name: '崩坏星穹铁道',
url: "https://bbs.mihoyo.com/sr/"
},
jql: {
forumid: 57,
name: "绝区零",
url: "https://bbs.mihoyo.com/zzz/"
}
}
export default class MihoYoApi {
constructor(e) {
if (e) {
this.e = e
this.cookie = e.cookie
this.userId = String(e.user_id)
this.yuntoken = e.yuntoken
this.devId = e.devId
this.e.region=utils.getServer(e.uid)
this.isOs= this.e.region>5
// //初始化配置文件
let data = this.getStoken(this.e.user_id);
if (data) {
this.cookies = `stuid=${data.stuid};stoken=${data.stoken};ltoken=${data.ltoken};`;
this.e.cookies = this.cookies
}
}
Data.createDir("", YamlDataUrl, false);
}
getbody(name) {
for (let item in boards) {
if (boards[item]?.name === name) {
return boards[item]
}
}
}
async honkai3rdSignTask(name) {
let kkbody = this.getbody(name);
try {
// 获取账号信息
const objData = await this.getUserInfo(kkbody)
let data = objData.data
if (data?.list?.length == 0 || !data?.list) {
return {
message: `未绑定${name}信息`
}
}
let message = `\n${name}共计${data.list.length}个账号\n`;
let upData = [];
for (let item of data.list) {
item.upName = name
let objshuj = await this.isPostSign(kkbody, item.game_uid, item.region)
item.total_sign_day = objshuj?.data?.total_sign_day
if (objshuj?.data?.is_sign) {
item.is_sign = true;
// console.log(objshuj)
message += `游戏id${item.nickname}-${item.game_uid}:今日已签到~\n`;
} else {
objshuj = (await this.postSign(kkbody, item.game_uid, item.region))
if (objshuj?.data?.gt) {
item.is_sign = false;
message += `游戏id${item.nickname}-${item.game_uid}:签到出现验证码~\n请晚点后重试,或者手动上米游社签到`;
} else {
item.total_sign_day++;
item.is_sign = true;
message +=
`游戏id${item.nickname}-${item.game_uid}${objshuj.message=="OK"?"签到成功":objshuj.message}\n`
}
}
//获取签到信息和奖励信息
const SignInfo = await this.getSignInfo(kkbody)
if (SignInfo) {
let awards = SignInfo.data.awards[item.total_sign_day - 1];
item.awards = awards?.name + "*" + awards?.cnt
}
upData.push(item)
await utils.randomSleepAsync();
}
// 签到操作
return {
message,
upData
}
} catch (error) {
Bot.logger.mark(`error.message`, error.message)
}
}
async forumSign(forumId) {
const url = `https://bbs-api.mihoyo.com/apihub/app/api/signIn`;
this.forumId = forumId;
let res = await superagent.post(url).set(this._getHeader()).send(JSON.stringify({
gids: forumId * 1
})).timeout(10000);
let resObj = JSON.parse(res.text);
// Bot.logger.mark(`ForumSign: ${res.text}`);
return resObj;
}
async getTasksList() {
let res = await superagent.get(`https://bbs-api.mihoyo.com/apihub/sapi/getUserMissionsState`).set(this
._getHeader()).timeout(10000);
let resObj = JSON.parse(res.text);
return resObj
}
// 获取签到状态和奖励信息
async getSignInfo(board) {
let url = `${web_api}/event/luna/home?lang=zh-cn&`
if (board?.name == "原神") {
url = `${web_api}/event/bbs_sign_reward/home?`
}
// if (board.name == "崩坏2" || board.name == "未定事件簿") {
// url = `${web_api}/event/luna/home?lang=zh-cn`
// }
let res = await superagent.get(
`${url}act_id=${board.actid}`
).set(this
.getpubHeaders(board)).timeout(10000);
let resObj = JSON.parse(res.text);
// logger.mark(`getSignInfo: ${res.text}`);
return resObj;
}
async forumPostList(forumId) {
const url =
`${web_api}/post/api/getForumPostList?forum_id=${forumId}&is_good=false&is_hot=false&page_size=20&sort_type=1`;
let res = await superagent.get(url).set(this._getHeader()).timeout(10000);
let resObj = JSON.parse(res.text);
return resObj;
}
async forumPostDetail(postId) {
const url = `${bbs_api}/post/api/getPostFull?post_id=${postId}`;
let res = await superagent.get(url).set(this._getHeader()).timeout(10000);
let resObj = JSON.parse(res.text);
return resObj;
}
async forumPostShare(postId) {
const url =
`${bbs_api}/apihub/api/getShareConf?entity_id=${postId}&entity_type=1`;
let res = await superagent.get(url).set(this._getHeader()).timeout(10000);
let resObj = JSON.parse(res.text);
return resObj;
}
async forumPostVote(postId) {
const url = `${bbs_api}/apihub/sapi/upvotePost`;
const upvotePostData = {
"post_id": postId,
"is_cancel": false
}
let res = await superagent.post(url).set(this._getHeader()).send(JSON.stringify(upvotePostData));
let resObj = JSON.parse(res.text);
return resObj;
}
async yunGenshen() {
let url = `https://api-cloudgame.mihoyo.com/hk4e_cg_cn/gamer/api/login`;
let res = await superagent.post(url).set(this.getyunHeader()).timeout(10000);
let sendMSg = "";
let log_msg = (await this.logyunGenshen()).log_msg
sendMSg += log_msg
Bot.logger.info(log_msg)
url =
`https://api-cloudgame.mihoyo.com/hk4e_cg_cn/gamer/api/listNotifications?status=NotificationStatusUnread&type=NotificationTypePopup&is_sort=true`;
res = await superagent.get(url).set(this.getyunHeader()).timeout(10000);
let resObj = JSON.parse(res.text);
let list = resObj.data.list;
if (Object.keys(list).length == 0) {
resObj.sendMSg = "您今天的奖励已经领取了啦~";
return resObj;
}
for (let item of list) {
let reward_id = item.id;
let reward_msg = item.msg;
url = `https://api-cloudgame.mihoyo.com/hk4e_cg_cn/gamer/api/ackNotification?id=${reward_id}`;
res = await superagent.post(url).set(this.getyunHeader()).timeout(10000);
let log_msg = `\n领取奖励,ID:${reward_id},Msg:${reward_msg}`;
Bot.logger.info(log_msg)
sendMSg += log_msg
}
resObj.sendMSg = sendMSg;
return resObj;
}
async logyunGenshen() {
let url = `https://api-cloudgame.mihoyo.com/hk4e_cg_cn/wallet/wallet/get`;
let res = await superagent.get(url).set(this.getyunHeader()).timeout(10000);
let resObj = JSON.parse(res.text);
let data = resObj.data
let log_msg = `米云币:${data?.coin?.coin_num},免费时长:${data?.free_time?.free_time}分钟,总时长:${data.total_time}分钟`;
resObj.log_msg = log_msg
return resObj
}
async updCookie() {
let url = `${web_api}/auth/api/getCookieAccountInfoBySToken?game_biz=hk4e_cn`;
if (this.e.region.includes("os")) {
url = `${os_web_api}/auth/api/getCookieAccountInfoBySToken?game_biz=hk4e_global`;
}
let map = this.getCookieMap(this.cookies)
url += `&stoken=${map.get("stoken")}&uid=${map.get("stuid")}`;
let param = {
agent: await this.getAgent(),
timeout: 10000,
method:'get'
}
let res = await fetch(url, param);
let resObj = await res.json()
return resObj;
}
async stoken(cookie, e) {
this.e = e;
let datalist = this.getStoken(e.user_id) || {}
if (Object.keys(datalist).length > 0) {
return true;
}
const map = this.getCookieMap(cookie);
let loginTicket = map.get("login_ticket");
const loginUid = map.get("login_uid") ? map.get("login_uid") : map.get("ltuid");
if (isV3) {
loginTicket = gsCfg.getBingCookie(e.user_id).login_ticket
}
const url = "https://api-takumi.mihoyo.com/auth/api/getMultiTokenByLoginTicket?login_ticket=" +
loginTicket + "&token_types=3&uid=" + loginUid;
fetch(url, {
"headers": {
"x-rpc-device_id": "zxcvbnmasadfghjk123456",
"Content-Type": "application/json;charset=UTF-8",
"x-rpc-client_type": "",
"x-rpc-app_version": "",
"DS": "",
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/%s",
"Referer": "cors",
"Accept-Encoding": "gzip, deflate, br",
"x-rpc-channel": "appstore",
},
"method": "GET"
}).then(
function(response) {
if (response.status !== 200) {
return false;
}
response.json().then(function(data) {
if (!data.data) {
return false;
}
datalist[e.uid] = {
stuid: map.get("account_id"),
stoken: data.data.list[0].token,
ltoken: data.data.list[1].token,
uid: e.uid,
userId: e.user_id,
is_sign: true
}
gsCfg.saveBingStoken(e.user_id, datalist)
return true;
});
}
).catch(function(err) {
return false;
});
return true;
}
/** 米游社 api headers */
// 签到的 headers
getpubHeaders(board) {
const randomStr = utils.randomString(6);
const timestamp = Math.floor(Date.now() / 1000)
let sign = md5(`salt=${saltWeb}&t=${timestamp}&r=${randomStr}`);
return {
'accept-language': 'zh-CN,zh;q=0.9,ja-JP;q=0.8,ja;q=0.7,en-US;q=0.6,en;q=0.5',
'x-rpc-device_id': DEVICE_ID,
'User-Agent': `Mozilla/5.0 (iPhone; CPU iPhone OS 14_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/${APP_VERSION}`,
Referer: board.getReferer(),
Host: 'api-takumi.mihoyo.com',
'x-rpc-channel': 'appstore',
'x-rpc-app_version': APP_VERSION,
'x-requested-with': 'com.mihoyo.hyperion',
'x-rpc-client_type': '5',
'Content-Type': 'application/json;charset=UTF-8',
DS: `${timestamp},${randomStr},${sign}`,
'Cookie': this.cookie
}
}
//社区签到ds
get_ds2(q = "", b) {
let n = salt2
// n ="6cqshh5dhw73bzxn20oexa9k516chk7s"
let i = Math.floor(Date.now() / 1000)
let r = _.random(100001, 200000)
let add = `&b=${b}&q=${q}`
let c = md5("salt=" + n + "&t=" + i + "&r=" + r + add)
// this.e.reply("md5"+c)
return `${i},${r},${c}`
}
// 米游币任务的 headers
_getHeader() {
const randomStr = utils.randomString(6);
const timestamp = Math.floor(Date.now() / 1000)
let sign = md5(`salt=${salt}&t=${timestamp}&r=${randomStr}`);
let ds = `${timestamp},${randomStr},${sign}`
if (this.forumId) {
ds = this.get_ds2("", JSON.stringify({
gids: this.forumId * 1
}));
this.forumId = "";
}
return {
'Cookie': this.cookies,
"x-rpc-channel": "miyousheluodi",
'x-rpc-device_id': DEVICE_ID,
'x-rpc-app_version': APP_VERSION,
"x-rpc-device_model": "Mi 10",
'x-rpc-device_name': DEVICE_NAME,
'x-rpc-client_type': '2', // 1 - iOS, 2 - Android, 4 - Web
'DS': ds,
"Referer": "https://app.mihoyo.com",
"x-rpc-sys_version": "12",
"Host": "bbs-api.mihoyo.com",
"User-Agent": "okhttp/4.8.0",
// 'DS': `1602569298,k0xfEh,07f4545f5d88eac59cb1257aef74a570`
}
}
//云原神签到头
getyunHeader() {
return {
"x-rpc-combo_token": this.yuntoken, //这里填你的ck
"x-rpc-client_type": "2",
"x-rpc-app_version": "1.3.0",
"x-rpc-sys_version": "11",
"x-rpc-channel": "mihoyo",
"x-rpc-device_id": this.devId, //这里填获取到的设备Id
"x-rpc-device_name": "Xiaomi Mi 10 Pro",
"x-rpc-device_model": "Mi 10 Pro",
"x-rpc-app_id": "1953439974",
"Referer": "https://app.mihoyo.com",
"Content-Length": "0",
"Host": "api-cloudgame.mihoyo.com",
"Connection": "Keep-Alive",
"Accept-Encoding": "gzip",
"User-Agent": "okhttp/3.14.9"
}
}
//一个奇怪的请求头
getHeader() {
return {
'x-rpc-app_version': mhyVersion,
'User-Agent': `Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1`,
'x-rpc-client_type': '5',
'Referer': 'https://webstatic.mihoyo.com/',
'Origin': 'https://webstatic.mihoyo.com',
}
}
old_version_get_ds_token() {
// 1 测试过的salt很显然都不是 也可能是header参数错误导致无法使用的 另外一个salt加密方法 get_ds
// xV8v4Qu44lUKrEYFZkJhB8cuOh9Asafs
// 2
// t0qEgfub6cvueAPgR5m9aQWWVciEer7v
// 3
// 599uqkwc0dlqu3h6epzjzfhgyyrd44PR
// 4
// rk4xg2hakoi26nljpr099fv9fck1ah10
// 5 6cqshh5dhw73bzxn20oexa9k516chk7s 签到salt?? 6s25p5ox5y14umn1p61aqyyvbvvl3lrt
let n = this.e.region.startsWith('os')?osSaltWeb:'N50pqm7FSy2AkFz2B3TqtuZMJ5TOl3Ep'
let i = Math.floor(Date.now() / 1000)
let r =utils.randomString(6)
let c = md5('salt=' + n + '&t=' + i + '&r=' + r )
// this.e.reply("md5"+c)
return i + ',' + r + ',' + c
}
async authkey(e) {
let isos=this.e.region.startsWith('os')?true:false;
let url = `${(isos?os_web_api:web_api)}/binding/api/genAuthKey`;
let HEADER = this.getHeader();
HEADER['Cookie'] = this.cookies
HEADER['DS'] =this.old_version_get_ds_token()
HEADER['User-Agent'] = 'okhttp/4.8.0'
HEADER['x-rpc-app_version'] =isos? '2.18.1':'2.35.2'
HEADER['x-rpc-sys_version'] = '12'
HEADER['x-rpc-client_type'] = '5'
HEADER['x-rpc-channel'] =isos?'hoyolab':'mihoyo'
HEADER['x-rpc-device_id'] = utils.randomString(32).toUpperCase();
HEADER['x-rpc-device_name'] = utils.randomString(_.random(1, 10));
HEADER['x-rpc-device_model'] = 'Mi 10'
// HEADER['Referer'] = 'https://app.mihoyo.com'
// HEADER['Host'] = 'api-takumi.mihoyo.com'
HEADER['Referer'] = isos?'https://app.hoyolab.com':'https://app.mihoyo.com'
HEADER['Host'] = (isos?os_web_api:web_api).replace(/https:\/\//,"")
HEADER['Origin']=(isos?'https://webstatic-sea.hoyolab.com':'https://webstatic.mihoyo.com')
let data = {
'auth_appid': 'webview_gacha',
'game_biz': isos?'hk4e_global':'hk4e_cn',
'game_uid': this.e.uid * 1,
'region': this.e.region,
}
let param = {
headers:HEADER,
agent: await this.getAgent(),
timeout: 10000,
body:JSON.stringify(data),
method:'post'
}
let res = await fetch(url, param);
// console.log(res)
let resObj = await res.json()
// headers
// let res = await superagent.post(url).set(HEADER).send(JSON.stringify(data));
// let resObj = JSON.parse(res.text);
return resObj
}
getCookieMap(cookie) {
let cookieArray = cookie.replace(/\s*/g, "").split(";");
let cookieMap = new Map();
for (let item of cookieArray) {
let entry = item.split("=");
if (!entry[0]) continue;
cookieMap.set(entry[0], entry[1]);
}
return cookieMap;
}
getStoken(userId) {
let file = `${YamlDataUrl}/${userId}.yaml`
try {
let ck = fs.readFileSync(file, 'utf-8')
ck = YAML.parse(ck)
if (ck?.uid) {
let datalist = {};
ck.userId = this.e.user_id
datalist[ck.uid] = ck;
ck = datalist
gsCfg.saveBingStoken(this.e.user_id, datalist)
}
return ck[this.e.uid] || {}
} catch (error) {
return {}
}
}
//==== 签到任务 ====
// @todo 签到任务大概率是接口通用的, 只是部分参数不一样, 可以构造通用方法, 方便后续整合崩2, 事件簿, 铁道等
// 获取账号信息 通用
async getUserInfo(board) {
let url = `${web_api}/binding/api/getUserGameRolesByCookie?game_biz=${board.biz}`
// if(this.e.region.includes("os")){
// 暂时先不接入
// url=`${os_web_api}/binding/api/getUserGameRolesByCookie?game_biz=hk4e_global`;
// }
let res = await superagent.get(url)
.set(this
.getpubHeaders(board)).timeout(10000);
let resObj = JSON.parse(res.text);
// console.log(resObj)
if (resObj.retcode != 0) {
return resObj
}
// const game_uid = data?.list?. [0]?.game_uid
// const region = data?.list?. [0]?.region
// const nickname = data?.list?. [0]?.nickname
return resObj
}
// 游戏签到操作查询
async isPostSign(board, game_uid, region) {
let url =
`${web_api}/event/luna/info?lang=zh-cn`
if (board?.name == "原神") {
url = `${web_api}/event/bbs_sign_reward/info`
}
if (board?.name == "崩坏2" || board.name == "未定事件簿") {
url = `${web_api}/event/luna/info?lang=zh-cn`
}
url += `${board?.name == "原神"?"?":"&"}region=${region}&act_id=${board.actid}&uid=${game_uid}`
let res = await superagent.get(url).set(this.getpubHeaders(board)).timeout(10000);
let resObj = JSON.parse(res.text);
return resObj
}
// 游戏签到操作
async postSign(board, game_uid, region) {
let url =
`${web_api}/event/luna/sign`
if (board?.name == "原神") {
url = `${web_api}/event/bbs_sign_reward/sign`
}
if (board?.name == "崩坏2" || board?.name == "未定事件簿") {
url = `${web_api}/event/luna/sign`
}
url += `?region=${region}&act_id=${board.actid}&uid=${game_uid}`
let res = await superagent.post(url).set(this.getpubHeaders(board)).timeout(10000);
let resObj = JSON.parse(res.text);
return resObj
}
async getAgent() {
if (isV3) {
let cfg = await import(`file://${_path}/lib/config/config.js`);
let proxyAddress = cfg.default.bot.proxyAddress
if (!proxyAddress) return null
if (proxyAddress === 'http://0.0.0.0:0') return null
if (!this.e.region.startsWith('os')) return null
if (HttpsProxyAgent === '') {
HttpsProxyAgent = await import('https-proxy-agent').catch((err) => {
logger.error(err)
})
HttpsProxyAgent = HttpsProxyAgent ? HttpsProxyAgent.default : undefined
}
if (HttpsProxyAgent) {
return new HttpsProxyAgent(proxyAddress)
}
}
return null
}
}

402
model/mys/mihoyoApi.js Normal file
View File

@ -0,0 +1,402 @@
import utils from './utils.js';
import md5 from 'md5';
import _ from 'lodash';
import fs from "fs";
import YAML from 'yaml'
import {
Data
} from "../../components/index.js";
import gsCfg from '../gsCfg.js'
import {
isV3
} from '../../components/Changelog.js';
import fetch from "node-fetch"
import mys from "./mysTool.js"
const _path = process.cwd();
// const APP_VERSION = "2.37.1";
// const mhyVersion = "2.11.1";
// const salt = "6J1hde1Wu02eF1DFlLpMjeg2dMloAytL";
// const salt2 = "t0qEgfub6cvueAPgR5m9aQWWVciEer7v";
// const saltWeb = "Qqx8cyv7kuyD8fTw11SmvXSFHp7iZD29";
// const oldsalt = "z8DRIUjNDT7IT5IZXvrUAxyupA1peND9";
// const osSaltWeb = ''; //os 浏览帖子需要用到的salt
const DEVICE_ID = utils.randomString(32).toUpperCase();
const DEVICE_NAME = utils.randomString(_.random(1, 10));
const yamlDataUrl = `${_path}/plugins/xiaoyao-cvs-plugin/data/yaml`;
// const web_api = `https://api-takumi.mihoyo.com`
// const os_web_api = `https://api-os-takumi.mihoyo.com`
// const os_hk4_api = `https://hk4e-api-os.hoyoverse.com`;
// const hk4_api = `https://hk4e-api.mihoyo.com`;
// const bbs_api = `https://bbs-api.mihoyo.com`;
let HttpsProxyAgent = ''
// 米游社的版块
export default class miHoYoApi {
constructor(e) {
if (e) {
this.e = e
this.cookie = e.cookie
this.userId = String(e.user_id)
this.yuntoken = e.yuntoken
this.devId = e.devId
this.isOs= this.e?.uid[0]*1>5
this.apiMap={
apiWeb:mys.web_api,
saltweb:mys.saltWeb,
saltSign:mys.salt
}
if(this.isOs){
this.apiMap={
apiWeb:mys.os_web_api,
saltweb:mys.saltWeb, //os websalt待定中
saltSign:mys.salt
}
}
// //初始化配置文件
let data = this.getStoken(this.e.user_id);
if (data) {
this.cookies = `stuid=${data.stuid};stoken=${data.stoken};ltoken=${data.ltoken};`;
this.e.cookies = this.cookies
}
}
Data.createDir("", yamlDataUrl, false);
}
getBody(name) {
for (let item in mys.boards) {
if (mys.boards[item].name === name) {
return mys.boards[item]
}
}
}
async getData(type, data = {}) {
let gameBody = this.getBody(data.name);
let {
url,
headers,
body
} = this.getUrl(type, gameBody, data)
if (!url) return false
if (data.headers) {
headers = {
...headers,
...data.headers
}
delete data.headers
}
let param = {
headers,
agent: await this.getAgent(),
timeout: 10000
}
if (body) {
param.method = 'post'
param.body = body
} else {
param.method = 'get'
}
let response = {}
let start = Date.now()
try {
response = await fetch(url, param)
} catch (error) {
logger.error(error.toString())
return false
}
if (!response.ok) {
Bot.logger.error(`[接口][${type}][${this.e.uid}] ${response.status} ${response.statusText}`)
return false
}
Bot.logger.mark(`[接口][${type}][${this.e.uid}] ${Date.now() - start}ms`)
const res = await response.json()
if (!res) {
Bot.logger.mark('mys接口没有返回')
return false
}
if (res.retcode !== 0) {
Bot.logger.debug(`[米游社接口][请求参数] ${url} ${JSON.stringify(param)}`)
}
res.api = type
return res
}
getUrl(type, board, data) {
let urlMap = {
userGameInfo: { //通用查询
url: `${this.apiMap.apiWeb}/binding/api/getUserGameRolesByCookie`,
query: `game_biz=${board?.biz}`,
types: 'sign'
},
isSign: board?.signUrl(data, "isSign",this.apiMap.apiWeb)||{},
sign: board?.signUrl(data, "sign",this.apiMap.apiWeb)||{},
home: board?.signUrl(data, "home",this.apiMap.apiWeb)||{},
//bbs接口 hoyolab那边不是很需要 这边不进行优化处理
bbsisSign: { //bbs 签到 (状态查询 米游币查询)
url: `${mys.bbs_api}/apihub/sapi/getUserMissionsState`,
types: 'bbs'
},
bbsSign: { //bbs讨论区签到
url: `${mys.bbs_api}/apihub/app/api/signIn`,
body: {
gids: data.forumId*1
},
sign: true,
types: 'bbs'
},
//人啊不能总想着跳脸 ~~这块给你们留个念想
bbsGetCaptcha:{
url:`???????????????????????????????????????????????????`,
},
bbsValidate:{
url:`???????????????????????????????????????????????????`,
},
bbsCaptchaVerify:{
url:`???????????????????????????????????????????????????`
},
bbs_Businesses_url:{
url:`${mys.bbs_api}/user/api/getUserBusinesses`,
query:`uid={}` //????
},
bbsPostList: { //bbs讨论区签到
url: `${mys.bbs_api}/post/api/getForumPostList`,
query: `forum_id=${data.forumId}&is_good=false&is_hot=false&page_size=20&sort_type=1`,
types: 'bbs'
},
bbsPostFull: { //bbs讨论区签到
url: `${mys.bbs_api}/post/api/getPostFull`,
query: `post_id=${data.postId}`,
types: 'bbs'
},
bbsShareConf: { //bbs讨论区签到
url: `${mys.bbs_api}/apihub/api/getShareConf`,
query: `entity_id=${data.postId}&entity_type=1`,
types: 'bbs'
},
bbsVotePost: { //bbs讨论区签到
url: `${mys.bbs_api}/apihub/sapi/upvotePost`,
body: {
"post_id": data.postId,
"is_cancel": false
},
types: 'bbs'
},
bbsGetCookie: {
url: `${this.apiMap.apiWeb}/auth/api/getCookieAccountInfoBySToken`,
query: `game_biz=hk4e_cn&${data.cookies}`,
types: ''
},
bbsStoken: {
url: `${this.apiMap.apiWeb}/auth/api/getMultiTokenByLoginTicket`,
query: `login_ticket=${data.loginTicket}&token_types=3&uid=${data.loginUid}`,
types: 'stoken'
},
cloudLogin: {
url: `${mys.cloud_api}/hk4e_cg_cn/gamer/api/login`,
types: 'cloud'
},
cloudReward: {
url: `${mys.cloud_api}/hk4e_cg_cn/gamer/api/listNotifications`,
query: `status=NotificationStatusUnread&type=NotificationTypePopup&is_sort=true`,
types: 'cloud'
},
cloudGamer: {
url: `${mys.cloud_api}/hk4e_cg_cn/gamer/api/ackNotification`,
query: `id=${data.reward_id}`,
types: 'cloud'
},
cloudGet: {
url: `${mys.cloud_api}/hk4e_cg_cn/wallet/wallet/get`,
types: 'cloud'
},
authKey: {
url: `${this.apiMap.apiWeb}/binding/api/genAuthKey`,
body:{
'auth_appid': 'webview_gacha',
'game_biz': this.isOs?'hk4e_global':'hk4e_cn',
'game_uid': this.e.uid * 1,
'region': this.e.region,
},
types: 'authKey'
},
}
if (!urlMap[type]) return false
let {
url,
query = '',
body ='',
types = '',
sign = ''
} = urlMap[type]
if (query) url += `?${query}`
if (body) body = JSON.stringify(body)
let headers = this.getHeaders(board, types, sign)
return {
url,
headers,
body
}
}
// 签到的 headers
getHeaders(board, type = "bbs", sign) {
let header = {};
switch (type) {
case "bbs":
header = {
'Cookie': this.cookies,
"x-rpc-channel": "miyousheluodi",
'x-rpc-device_id': DEVICE_ID,
'x-rpc-app_version': mys.APP_VERSION,
"x-rpc-device_model": "Mi 10",
'x-rpc-device_name': DEVICE_NAME,
'x-rpc-client_type': '2', // 1 - iOS, 2 - Android, 4 - Web
'DS': (sign ? this.getDs2("", JSON.stringify({
gids: board.forumid*1
}), mys.salt2) : this.getDs(mys.salt)),
"Referer": "https://app.mihoyo.com",
"x-rpc-sys_version": "12",
"Host": "bbs-api.mihoyo.com",
"User-Agent": "okhttp/4.8.0",
// 'DS': `1602569298,k0xfEh,07f4545f5d88eac59cb1257aef74a570`
}
break;
case "sign":
header = {
'accept-language': 'zh-CN,zh;q=0.9,ja-JP;q=0.8,ja;q=0.7,en-US;q=0.6,en;q=0.5',
'x-rpc-device_id': DEVICE_ID,
'User-Agent': `Mozilla/5.0 (iPhone; CPU iPhone OS 14_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/${mys.APP_VERSION}`,
Referer: board.getReferer(),
Host: 'api-takumi.mihoyo.com',
'x-rpc-channel': 'appstore',
'x-rpc-app_version': mys.APP_VERSION,
'x-requested-with': 'com.mihoyo.hyperion',
'x-rpc-client_type': '5',
'Content-Type': 'application/json;charset=UTF-8',
DS: this.getDs(),
'Cookie': this.cookie
}
if(this.isOs){
let os_Header={
app_version: '2.9.0',
User_Agent: `Mozilla/5.0 (Linux; Android 9.0; SAMSUNG SM-F900U Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.73 Mobile Safari/537.36 miHoYoBBSOversea/2.9.0`,
client_type: '2',
Origin: 'https://webstatic-sea.hoyolab.com',
X_Requested_With: 'com.mihoyo.hoyolab',
Referer: 'https://webstatic-sea.hoyolab.com'
}
header=Object.assign({},header,os_Header)
}
break;
case "cloud":
header = {
"x-rpc-combo_token": this.yuntoken, //云原神签到ck
"x-rpc-client_type": "2",
"x-rpc-app_version": "1.3.0",
"x-rpc-sys_version": "11",
"x-rpc-channel": "mihoyo",
"x-rpc-device_id": this.devId, //设备Id
"x-rpc-device_name": "Xiaomi Mi 10 Pro",
"x-rpc-device_model": "Mi 10 Pro",
"x-rpc-app_id": "1953439974",
"Referer": "https://app.mihoyo.com",
"Content-Length": "0",
"Host": "api-cloudgame.mihoyo.com",
"Connection": "Keep-Alive",
"Accept-Encoding": "gzip",
"User-Agent": "okhttp/3.14.9"
}
break;
case "authKey":
header = {
'x-rpc-app_version': mys.APP_VERSION,
'User-Agent': 'okhttp/4.8.0',
'x-rpc-client_type': '5',
Referer: 'https://app.mihoyo.com',
Origin: 'https://webstatic.mihoyo.com',
Cookie: this.cookies,
DS: this.getDs(mys.saltWeb),
'x-rpc-sys_version': '12',
'x-rpc-channel': 'mihoyo',
'x-rpc-device_id': 'HX6J7YCE7H1C9W5UQXTS6OYCLIYK5HTL',
'x-rpc-device_name': 'gsy4dp',
'x-rpc-device_model': 'Mi 10',
Host: 'api-takumi.mihoyo.com'
}
break;
case "stoken":
header = {
"x-rpc-device_id": "zxcvbnmasadfghjk123456",
"Content-Type": "application/json;charset=UTF-8",
"x-rpc-client_type": "",
"x-rpc-app_version": "",
"DS": "",
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/%s",
"Referer": "cors",
"Accept-Encoding": "gzip, deflate, br",
"x-rpc-channel": "appstore",
}
break;
default:
header = {}
break;
}
return header;
}
getStoken(userId) {
let file = `${yamlDataUrl}/${userId}.yaml`
try {
let ck = fs.readFileSync(file, 'utf-8')
ck = YAML.parse(ck)
if (ck?.uid) {
let datalist = {};
ck.userId = this.e.user_id
datalist[ck.uid] = ck;
ck = datalist
gsCfg.saveBingStoken(this.e.user_id, datalist)
}
return ck[this.e.uid] || {}
} catch (error) {
return {}
}
}
//社区签到ds
getDs2(q = "", b, salt) {
let i = Math.floor(Date.now() / 1000)
let r = _.random(100001, 200000)
let add = `&b=${b}&q=${q}`
let c = md5("salt=" + salt + "&t=" + i + "&r=" + r + add)
return `${i},${r},${c}`
}
getDs(salt = mys.saltWeb) {
const randomStr = utils.randomString(6);
const timestamp = Math.floor(Date.now() / 1000)
let sign = md5(`salt=${salt}&t=${timestamp}&r=${randomStr}`);
return `${timestamp},${randomStr},${sign}`
}
async getAgent() {
if (isV3) {
let cfg = await import(`file://${_path}/lib/config/config.js`);
let proxyAddress = cfg.default.bot.proxyAddress
if (!proxyAddress) return null
if (proxyAddress === 'http://0.0.0.0:0') return null
if (!this.isOs) return null
if (HttpsProxyAgent === '') {
HttpsProxyAgent = await import('https-proxy-agent').catch((err) => {
logger.error(err)
})
HttpsProxyAgent = HttpsProxyAgent ? HttpsProxyAgent.default : undefined
}
if (HttpsProxyAgent) {
return new HttpsProxyAgent(proxyAddress)
}
}
return null
}
}

View File

@ -1,219 +0,0 @@
import md5 from 'md5'
import lodash from 'lodash'
import fetch from 'node-fetch'
export default class MysApi {
/**
* @param uid 游戏uid
* @param cookie 米游社cookie
* @param option 其他参数
* @param option.log 是否显示日志
*/
constructor (uid, cookie, option = {}) {
this.uid = uid
this.cookie = cookie
this.server = this.getServer()
let op = {
log: true,
...option
}
this.option = op
}
getUrl (type, data = {}) {
let host, hostRecord
if (['cn_gf01', 'cn_qd01'].includes(this.server)) {
host = 'https://api-takumi.mihoyo.com/'
hostRecord = 'https://api-takumi-record.mihoyo.com/'
}
let urlMap = {
/** 首页宝箱 */
index: {
url: `${hostRecord}game_record/app/genshin/api/index`,
query: `role_id=${this.uid}&server=${this.server}`
},
/** 深渊 */
spiralAbyss: {
url: `${hostRecord}game_record/app/genshin/api/spiralAbyss`,
query: `role_id=${this.uid}&schedule_type=${data.schedule_type || 1}&server=${this.server}`
},
/** 角色详情 */
character: {
url: `${hostRecord}game_record/app/genshin/api/character`,
body: { role_id: this.uid, server: this.server }
},
/** 树脂 */
dailyNote: {
url: `${hostRecord}game_record/app/genshin/api/dailyNote`,
query: `role_id=${this.uid}&server=${this.server}`
},
/** 签到信息 */
bbs_sign_info: {
url: `${host}event/bbs_sign_reward/info`,
query: `act_id=e202009291139501&region=${this.server}&uid=${this.uid}`,
sign: true
},
/** 签到奖励 */
bbs_sign_home: {
url: `${host}event/bbs_sign_reward/home`,
query: `act_id=e202009291139501&region=${this.server}&uid=${this.uid}`,
sign: true
},
/** 签到 */
bbs_sign: {
url: `${host}event/bbs_sign_reward/sign`,
body: { act_id: 'e202009291139501', region: this.server, uid: this.uid },
sign: true
},
/** 详情 */
detail: {
url: `${host}event/e20200928calculate/v1/sync/avatar/detail`,
query: `uid=${this.uid}&region=${this.server}&avatar_id=${data.avatar_id}`
},
/** 札记 */
ys_ledger: {
url: 'https://hk4e-api.mihoyo.com/event/ys_ledger/monthInfo',
query: `month=${data.month}&bind_uid=${this.uid}&bind_region=${this.server}`
},
/** 养成计算器 */
compute: {
url: `${host}event/e20200928calculate/v2/compute`,
body: data
},
/** 角色技能 */
avatarSkill: {
url: `${host}event/e20200928calculate/v1/avatarSkill/list`,
query: `avatar_id=${data.avatar_id}`
}
}
if (!urlMap[type]) return false
let { url, query = '', body = '', sign = '' } = urlMap[type]
if (query) url += `?${query}`
if (body) body = JSON.stringify(body)
let headers = this.getHeaders(query, body, sign)
return { url, headers, body }
}
getServer () {
let uid = this.uid
switch (String(uid)[0]) {
case '1':
case '2':
return 'cn_gf01' // 官服
case '5':
return 'cn_qd01' // B服
}
return 'cn_gf01'
}
async getData (type, data = {}, isForce = true) {
let { url, headers, body } = this.getUrl(type, data)
if (!url) return false
let cahce = await redis.get(`Yz:genshin:mys:cache:${type}:${this.uid}`)
if (cahce && !isForce) return JSON.parse(cahce)
headers.Cookie = this.cookie
let param = {
headers,
timeout: 10000
}
if (body) {
param.method = 'post'
param.body = body
} else {
param.method = 'get'
}
let response = {}
let start = Date.now()
try {
response = await fetch(url, param)
} catch (error) {
logger.error(error)
return false
}
if (!response.ok) {
logger.error(response)
return false
}
if (this.option.log) {
logger.mark(`[米游社接口][${type}][${this.uid}] ${Date.now() - start}ms`)
}
const res = await response.json()
if (!res) {
logger.mark('mys接口没有返回')
return false
}
if (res.retcode !== 0) {
logger.debug(`[米游社接口][请求参数] ${url} ${JSON.stringify(param)}`)
}
res.api = type
this.cache(res, type)
return res
}
getHeaders (query = '', body = '', sign = false) {
if (sign) {
return {
'x-rpc-app_version': '2.3.0',
'x-rpc-client_type': 5,
'x-rpc-device_id': this.getGuid(),
'User-Agent': ' miHoYoBBS/2.3.0',
DS: this.getDsSign()
}
}
return {
'x-rpc-app_version': '2.31.1',
'x-rpc-client_type': 5,
DS: this.getDs(query, body)
}
}
getDs (q = '', b = '') {
let n = ''
if (['cn_gf01', 'cn_qd01'].includes(this.server)) {
n = 'xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs'
}
let t = Math.round(new Date().getTime() / 1000)
let r = Math.floor(Math.random() * 900000 + 100000)
let DS = md5(`salt=${n}&t=${t}&r=${r}&b=${b}&q=${q}`)
return `${t},${r},${DS}`
}
/** 签到ds */
getDsSign () {
const n = 'h8w582wxwgqvahcdkpvdhbh2w9casgfl'
const t = Math.round(new Date().getTime() / 1000)
const r = lodash.sampleSize('abcdefghijklmnopqrstuvwxyz0123456789', 6).join('')
const DS = md5(`salt=${n}&t=${t}&r=${r}`)
return `${t},${r},${DS}`
}
getGuid () {
function S4 () {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
}
return (S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4())
}
async cache (res, type) {
if (!res || res.retcode !== 0) return
redis.setEx(`Yz:genshin:mys:cache:${type}:${this.uid}`, 300, JSON.stringify(res))
}
}

220
model/mys/mysTool.js Normal file
View File

@ -0,0 +1,220 @@
const APP_VERSION = "2.38.1";
const mhyVersion = "2.11.1";
const salt = "PVeGWIZACpxXZ1ibMVJPi9inCY4Nd4y2";
const salt2 = "t0qEgfub6cvueAPgR5m9aQWWVciEer7v";
const saltWeb = "yUZ3s0Sna1IrSNfk29Vo6vRapdOyqyhB";
const oldsalt = "z8DRIUjNDT7IT5IZXvrUAxyupA1peND9";
const osSaltWeb = ''; //os 浏览帖子需要用到的salt
const web_api = `https://api-takumi.mihoyo.com`
const os_web_api = `https://api-os-takumi.mihoyo.com`
const os_hk4_api = `https://hk4e-api-os.hoyoverse.com`;
const hk4_api = `https://hk4e-api.mihoyo.com`;
const bbs_api = `https://bbs-api.mihoyo.com`;
const cloud_api = `https://api-cloudgame.mihoyo.com`
const boards = {
honkai3rd: {
forumid: 1,
key: 'honkai3rd',
biz: 'bh3_cn',
actid: 'e202207181446311',
name: '崩坏3',
url: "https://bbs.mihoyo.com/bh3/",
signUrl(data, type, api) {
let dataUrl = {}
switch (type) {
case "isSign":
dataUrl = {
url: `${api}/event/luna/info`,
query: `lang=zh-cn&region=${data.region}&act_id=${this.actid}&uid=${data.game_uid}`
}
break;
case "sign":
dataUrl = {
url: `${api}/event/luna/sign`,
body: {
lang:'zh-cn',
region: data.region,
act_id: this.actid,
uid: data.game_uid
}
}
break;
case "home":
dataUrl = {
url: `${api}/event/luna/home`,
query: `lang=zh-cn&act_id=${this.actid}`
}
break;
}
dataUrl['types'] = 'sign'
return dataUrl
},
getReferer() {
return `https://webstatic.mihoyo.com/bh3/event/euthenia/index.html?bbs_presentation_style=fullscreen&bbs_game_role_required=${this.biz}&bbs_auth_required=true&act_id=${this.actid}&utm_source=bbs&utm_medium=mys&utm_campaign=icon`
}
},
genShin: {
forumid: 26,
key: 'genshin',
biz: 'hk4e_cn',
actid: 'e202009291139501',
name: '原神',
url: "https://bbs.mihoyo.com/ys/",
signUrl(data, type, api) {
let dataUrl = {}
switch (type) {
case "isSign":
dataUrl = {
url: `${api}/event/bbs_sign_reward/info`,
query: `region=${data.region}&act_id=${this.actid}&uid=${data.game_uid}`
}
break;
case "sign":
dataUrl = {
url: `${api}/event/bbs_sign_reward/sign`,
body: {
region: data.region,
act_id: this.actid,
uid: data.game_uid
}
}
break;
case "home":
dataUrl = {
url: `${api}/event/bbs_sign_reward/home`,
query: `act_id=${this.actid}`
}
break;
}
dataUrl['types'] = 'sign'
return dataUrl
},
getReferer() {
return `https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html?bbs_auth_required=true&act_id=${this.actid}&utm_source=bbs&utm_medium=mys&utm_campaign=icon`
}
},
honkai2: {
forumid: 30,
biz: 'bh2_cn',
actid: 'e202203291431091',
name: '崩坏2',
url: "https://bbs.mihoyo.com/bh2/",
signUrl(data, type, api) {
let dataUrl = {}
switch (type) {
case "isSign":
dataUrl = {
url: `${api}/event/luna/info`,
query: `lang=zh-cn&region=${data.region}&act_id=${this.actid}&uid=${data.game_uid}`
}
break;
case "sign":
dataUrl = {
url: `${api}/event/luna/sign`,
body: {
lang:'zh-cn',
region: data.region,
act_id: this.actid,
uid: data.game_uid
}
}
break;
case "home":
dataUrl = {
url: `${api}/event/luna/home`,
query: `lang=zh-cn&act_id=${this.actid}`
}
break;
}
dataUrl['types'] = 'sign'
return dataUrl
},
getReferer() {
return `https://webstatic.mihoyo.com/bbs/event/signin/bh2/index.html?bbs_auth_required=true&act_id=${this.actid}&bbs_presentation_style=fullscreen&utm_source=bbs&utm_medium=mys&utm_campaign=icon`
}
},
tears: {
forumid: 37,
biz: 'nxx_cn',
name: '未定事件簿',
actid: 'e202202251749321',
url: "https://bbs.mihoyo.com/wd/",
signUrl(data, type) {
let dataUrl = {}
switch (type) {
case "isSign":
dataUrl = {
url: `${web_api}/event/luna/info`,
query: `lang=zh-cn&region=${data.region}&act_id=${this.actid}&uid=${data.game_uid}`
}
break;
case "sign":
dataUrl = {
url: `${web_api}/event/luna/sign`,
body: {
lang: 'zh-cn',
region: data.region,
act_id: this.actid,
uid: data.game_uid
}
}
break;
case "home":
dataUrl = {
url: `${web_api}/event/luna/home`,
query: `lang=zh-cn&act_id=${this.actid}`
}
break;
}
dataUrl['types'] = 'sign'
return dataUrl
},
getReferer() {
return `https://webstatic.mihoyo.com/bbs/event/signin/nxx/index.html?bbs_auth_required=true&bbs_presentation_style=fullscreen&act_id=${this.actid}`
}
},
/** 以下数据待定 由于并未有存在签到入口可能后续会开放*/
house: {
forumid: 34,
name: '大别野',
url: "https://bbs.mihoyo.com/dby/",
signUrl(data, type, api) { //预留方法方便后续迭代
let dataUrl = {}
return dataUrl
},
},
honkaisr: {
forumid: 52,
name: '崩坏星穹铁道',
url: "https://bbs.mihoyo.com/sr/",
signUrl(data, type, api) { //预留方法方便后续迭代
let dataUrl = {}
return dataUrl
},
},
zzz: {
forumid: 57,
name: "绝区零",
url: "https://bbs.mihoyo.com/zzz/",
signUrl(data, type, api) { //预留方法方便后续迭代
let dataUrl = {}
return dataUrl
},
}
}
export default {
APP_VERSION,
mhyVersion,
salt,
salt2,
cloud_api,
saltWeb,
oldsalt,
osSaltWeb,
web_api,
os_web_api,
os_hk4_api,
hk4_api,
bbs_api,
boards
}

View File

@ -9,15 +9,14 @@ export async function sleepAsync(sleepms) {
} }
export async function randomSleepAsync() { export async function randomSleepAsync(end) {
let sleep = 3 * 1000 + _.random(5 * 1000); let sleep = 3 * 1000 + _.random((end||5) * 1000);
await sleepAsync(sleep); await sleepAsync(sleep);
} }
export function randomString(length,os=false) {
export function randomString(length) {
let randomStr = ''; let randomStr = '';
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
randomStr += _.sample('abcdefghijklmnopqrstuvwxyz0123456789'); randomStr += _.sample(os?'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz':'abcdefghijklmnopqrstuvwxyz0123456789');
} }
return randomStr; return randomStr;
} }

View File

@ -1,14 +1,18 @@
import YAML from 'yaml' import YAML from 'yaml'
import chokidar from 'chokidar' import chokidar from 'chokidar'
import MihoYoApi from "../model/mys/mihoyo-api.js" import miHoYoApi from "../model/mys/mihoyoApi.js"
import fs from 'node:fs' import fs from 'node:fs'
import promiseRetry from 'promise-retry';
import lodash from 'lodash' import lodash from 'lodash'
import utils from '../model/mys/utils.js'; import utils from '../model/mys/utils.js';
import gsCfg from './gsCfg.js'; import gsCfg from './gsCfg.js';
import { import {
isV3 isV3
} from '../components/Changelog.js'; } from '../components/Changelog.js';
import {
Cfg,
Data
} from "../components/index.js";
import moment from 'moment'
const _path = process.cwd(); const _path = process.cwd();
const plugin = "xiaoyao-cvs-plugin" const plugin = "xiaoyao-cvs-plugin"
const RETRY_OPTIONS = { const RETRY_OPTIONS = {
@ -17,65 +21,435 @@ const RETRY_OPTIONS = {
maxTimeout: 10000 maxTimeout: 10000
}; };
const nameData = ["原神", "崩坏3", "崩坏2", "未定事件簿"]; const nameData = ["原神", "崩坏3", "崩坏2", "未定事件簿"];
const YamlDataUrl = `${_path}/plugins/xiaoyao-cvs-plugin/data/yaml`; const yamlDataUrl = `${_path}/plugins/xiaoyao-cvs-plugin/data/yaml`;
const cloudDataUrl = `${_path}/plugins/xiaoyao-cvs-plugin/data/yunToken/`
let bbsTask = false;
let cloudTask = false;
let mysTask = false;
/** 配置文件 */ /** 配置文件 */
export default class user { export default class user {
constructor(e) { constructor(e) {
this.e = e; this.e = e;
this.stokenPath = `./plugins/${plugin}/data/yaml/` this.stokenPath = `./plugins/${plugin}/data/yaml/`
this.yunPath = `./plugins/${plugin}/data/yunToken/`; this.yunPath = `./plugins/${plugin}/data/yunToken/`;
this.ForumData = Data.readJSON(`${_path}/plugins/xiaoyao-cvs-plugin/defSet/json`, "mys")
this.configSign = gsCfg.getfileYaml(`${_path}/plugins/xiaoyao-cvs-plugin/config/`, "config");
this.configSign.signlist = this.configSign.signlist || "原神|崩坏3|崩坏2|未定事件簿".split("|")
this.getyunToken(this.e) this.getyunToken(this.e)
} }
async getCkData() { async getCkData() {
let sumData = {}; let sumData = {};
await this.cookie(this.e) let yunres = await this.cloudSeach();
this.miHoYoApi = new MihoYoApi(this.e); let yundata = yunres.data
if (this.e.yuntoken) { if (yunres.retcode === 0) {
let yunres = await this.miHoYoApi.logyunGenshen(); sumData["云原神"] = {
let yundata = yunres.data "今日可获取": yundata?.coin?.coin_num,
if (yunres.retcode === 0) { "免费时长": yundata?.free_time?.free_time,
sumData["云原神"] = { "总时长": yundata.total_time
"今日可获取": yundata?.coin?.coin_num,
"免费时长": yundata?.free_time?.free_time,
"总时长": yundata.total_time
}
} }
} }
if (this.e.cookies) { let mysres = await this.bbsSeachSign();
let mysres = await this.miHoYoApi.getTasksList(); if (mysres.retcode === 0) {
if (mysres.retcode === 0) { sumData["米游社"] = {
sumData["米游社"] = { "米游币任务": mysres.data.can_get_points != 0 ? "未完成" : "已完成",
"米游币任务": mysres.data.can_get_points != 0 ? "未完成" : "已完成", "米游币余额": mysres.data.total_points,
"米游币余额": mysres.data.total_points, "今日剩余可获取": mysres.data.can_get_points
"今日剩余可获取": mysres.data.can_get_points
}
} }
} }
if (this.e.cookie) { let resSign = await this.multiSign(this.ForumData);
for (let name of nameData) { if (resSign?.upData) {
let resSign = await this.miHoYoApi.honkai3rdSignTask(name); // console.log(resSign?.upData)
if (resSign?.upData) { for (let item of resSign?.upData) {
// console.log(resSign?.upData) let num = lodash.random(0, 9999);
for (let item of resSign?.upData) { item.upName = item.upName == "原神" ? "ys" : item.upName == "崩坏3" ? "bh3" : item.upName ==
let num = lodash.random(0, 9999); "崩坏2" ? "bh2" : item.upName == "未定事件簿" ? "wdy" : ""
item.upName = item.upName == "原神" ? "ys" : item.upName == "崩坏3" ? "bh3" : item.upName == sumData[item.upName + "" + num] = {
"崩坏2" ? "bh2" : item.upName == "未定事件簿" ? "wdy" : "" "uid": item.game_uid,
sumData[item.upName + "" + num] = { "游戏昵称": item.nickname,
"uid": item.game_uid, "等级": item.level,
"游戏昵称": item.nickname, "今日签到": item.is_sign ? "已签到" : "未签到",
"等级": item.level, "累计签到": item.total_sign_day + "天",
"今日签到": item.is_sign ? "已签到" : "未签到", "今天奖励": item.awards
"累计签到": item.total_sign_day + "天",
"今天奖励": item.awards
}
}
} }
} }
} }
return sumData; return sumData;
} }
async getData(type, data = {}) {
await this.cookie(this.e)
this.miHoYoApi = new miHoYoApi(this.e);
let res = await this.miHoYoApi.getData(type, data)
return res
}
async multiSign(forumData) {
let upData = [],
message = '';
for (let forum of forumData) {
if (!(this.configSign.signlist.includes(forum.name))) {
continue;
}
message += `**${forum.name}**\n`
let res
try {
res = await this.getData("userGameInfo", forum)
await utils.sleepAsync(300) //等几毫秒免得请求太频繁了
if (res?.data?.list?.length === 0 || !res?.data?.list) {
message += `签到: 未绑定${forum.name}信息\n`;
continue;
}
message += `${forum.name}共计${res?.data?.list.length}个账号\n`;
for (let item of res?.data?.list) {
let data = Object.assign({}, forum, item)
item.is_sign = true;
item.upName = forum.name
res = await this.getData("isSign", data)
item.total_sign_day = res?.data?.total_sign_day
if (res?.data?.is_sign) {
message += `${item.nickname}-${item.game_uid}:今日已签到~\n`;
} else {
res = await this.getData("sign", data)
if (res?.data?.gt) {
item.is_sign = false;
message += `${item.nickname}-${item.game_uid}:签到出现验证码~\n请晚点后重试,或者手动上米游社签到\n`;
} else {
item.total_sign_day++;
message +=
`${item.nickname}-${item.game_uid}${res.message=="OK"?"签到成功":res.message}\n`
}
}
//获取签到信息和奖励信息
const SignInfo = await this.getData("home", data)
if (SignInfo) {
let awards = SignInfo.data.awards[item.total_sign_day - 1];
item.awards = awards?.name + "*" + awards?.cnt
}
upData.push(item)
await utils.sleepAsync(500) //等几毫秒免得请求太频繁了
}
} catch (e) {
Bot.logger.error(`${forum.name} 签到失败 [${res?.message}]`);
message += `签到失败: [${res?.message}]\n`;
}
}
return {
message,
upData
}
}
async docHelp(type) {
return this.configSign[type.includes("云") ? "yunDoc" : "cookiesDoc"]
}
async cloudSeach() {
let res = await this.getData("cloudGet") //这样会算签到?具体待测试
if (res?.retcode == -100) {
res.message = "云原神token失效/防沉迷"
res.isOk = false;
} else {
res.isOk = true;
res.message =
`米云币:${res?.data?.coin?.coin_num},免费时长:${res?.data?.free_time?.free_time}分钟,总时长:${res?.data.total_time}分钟`;
}
return res;
}
async bbsSeachSign() {
let message = '';
let res = await this.getData("bbsisSign", {
name: "原神"
})
if (!res?.data) {
res.message = `登录Stoken失效请重新获取cookies或stoken保存~`;
res.isOk = false;
this.delSytk(yamlDataUrl, this.e)
} else {
res.message = `当前米游币数量为:${res.data.total_points},今日剩余可获取:${res.data.can_get_points}`
res.isOk = true;
}
return res;
}
async getbbsSign(forumData) {
let message = '',
res;
try {
if (bbsTask) {
this.e.reply(`米游币自动签到任务进行中、暂不支持手动签到`);
return false;
}
for (let forum of forumData) {
let trueDetail = 0;
let Vote = 0;
let Share = 0;
let sumcount = 0;
message += `\n**${forum.name}**\n`
res = await this.getData("bbsSign", forum)
if (res?.retcode == 1034) {
message += `社区签到: 验证码失败\n`;
} else {
message += `社区签到: ${res.message}\n`;
}
Bot.logger.mark(`${this.e.user_id}:${this.e.uid}:${forum.name} 社区签到结果: [${res.message}]`);
await utils.randomSleepAsync();
res = await this.getData("bbsPostList", forum)
sumcount++;
let postList = res.data.list;
let postId
for (let post of postList) {
post = post.post;
postId = post['post_id']
res = await this.getData("bbsPostFull", {
postId
})
if (res?.message && res?.retcode == 0) {
trueDetail++;
}
res = await this.getData("bbsVotePost", {
postId
})
if (res?.message && res?.retcode == 0) {
Vote++;
}
await utils.randomSleepAsync(2);
}
let sharePost = postList[0].post;
res = await this.getData("bbsShareConf", {
postId
})
if (res?.message && res?.retcode == 0) {
Share++;
}
message += `共读取帖子记录${20*sumcount}\n浏览成功:${trueDetail}\n点赞成功:${Vote}\n分享成功:${Share}`;
await utils.randomSleepAsync(3);
}
} catch (ex) {
Bot.logger.error(`出问题了:${ex}`);
message += `${this.e.user_id}获取米游币异常`;
}
return {
message
}
}
async signTask(e = "") {
let mul = e;
//暂不支持多个uid签到
Bot.logger.mark(`开始米社签到任务`);
let isAllSign = this.configSign.isAllSign
let userIdList = [];
let dir = './data/MysCookie/'
if (isV3) {
let files = fs.readdirSync(dir).filter(file => file.endsWith('.yaml'))
userIdList = (files.join(",").replace(/.yaml/g, "").split(","))
} else {
for (let [user_id, cookie] of Object.entries(NoteCookie)) {
userIdList.push(user_id)
}
}
if (mysTask) {
e.reply(`米社自动签到任务进行中,请勿重复触发指令`)
return false
}
mysTask = true;
let tips = ['开始米社签到任务']
let time = userIdList.length * 3.5 + 5
let finishTime = moment().add(time, 's').format('MM-DD HH:mm:ss')
tips.push(`\n签到用户:${userIdList.length}`)
tips.push(`\n预计需要:${this.countTime(time)}`)
if (time > 120) {
tips.push(`\n完成时间:${finishTime}`)
}
logger.mark(`签到用户:${userIdList.length}个,预计需要${this.countTime(time)} ${finishTime} 完成`)
if (mul) {
await this.e.reply(tips)
if (this.e.msg.includes('force')) this.force = true
} else {
await utils.relpyPrivate(await gsCfg.getMasterQQ(), tips)
await utils.sleepAsync(lodash.random(1, 20) * 1000)
}
let _reply = e.reply
let msg = e?.msg;
for (let qq of userIdList) {
let user_id = qq;
// let cklist={};
// if(isV3){
// let ck=`${dir}${qq*1}.yaml`
// let cklis=fs.readFileSync(ck, 'utf-8')
// cklist=YAML.parse(cklis)
// console.log(cklist)
// }else{
// cklist=NoteCookie[qq*1]
// }
// for(let uid in cklist){
// console.log(item)
// }
let e = {
user_id,
qq,
isTask: true
};
if (msg) {
e.msg = msg.replace(/全部|签到|米社/g, "");
} else {
e.msg = "全部"
}
Bot.logger.mark(`正在为qq${user_id}米社签到中...`);
e.reply = (msg) => {
if (!isAllSign || isbool) {
return;
}
if (msg.includes("OK")) {
utils.relpyPrivate(qq, msg + "\n自动签到成功");
}
};
this.e = e;
let res = await this.multiSign(this.getDataList(e.msg));
Bot.logger.mark(`${res.message}`)
await utils.sleepAsync(10000);
}
msg = `米社签到任务完成`
Bot.logger.mark(msg);
if (mul) {
_reply(msg)
} else {
await utils.relpyPrivate(await gsCfg.getMasterQQ(), msg)
}
mysTask = false;
}
async cloudTask(e = "") {
let mul = e;
Bot.logger.mark(`云原神签到任务开始`);
let files = fs.readdirSync(this.yunPath).filter(file => file.endsWith('.yaml'))
let isYunSignMsg = this.configSign.isYunSignMsg
let userIdList = (files.join(",").replace(/.yaml/g, "").split(","))
if (cloudTask) {
e.reply(`云原神自动签到任务进行中,请勿重复触发指令`)
return false
}
let tips = ['开始云原神签到任务']
let time = userIdList.length * 3.5 + 5
let finishTime = moment().add(time, 's').format('MM-DD HH:mm:ss')
tips.push(`\n签到用户:${userIdList.length}`)
tips.push(`\n预计需要:${this.countTime(time)}`)
if (time > 120) {
tips.push(`\n完成时间:${finishTime}`)
}
logger.mark(`签到用户:${userIdList.length}个,预计需要${this.countTime(time)} ${finishTime} 完成`)
if (mul) {
await this.e.reply(tips)
if (this.e.msg.includes('force')) this.force = true
} else {
await utils.relpyPrivate(await gsCfg.getMasterQQ(), tips)
await utils.sleepAsync(lodash.random(1, 20) * 1000)
}
cloudTask = true;
let _reply = e.reply
for (let qq of userIdList) {
let user_id = qq;
let e = {
user_id,
qq,
isTask: true
};
Bot.logger.mark(`正在为qq${user_id}云原神签到中...`);
e.msg = "全部"
e.reply = (msg) => {
if (!isYunSignMsg || isYun) {
return;
}
if (msg.includes("领取奖励")) {
utils.relpyPrivate(qq, msg + "\n云原神自动签到成功");
}
};
await this.cloudSeach(e);
await utils.sleepAsync(10000);
}
let msg = `云原神签到任务完成`
Bot.logger.mark(msg);
if (mul) {
_reply(msg)
} else {
await utils.relpyPrivate(await gsCfg.getMasterQQ(), msg)
}
cloudTask = false;
}
countTime(time) {
let hour = Math.floor((time / 3600) % 24)
let min = Math.floor((time / 60) % 60)
let sec = Math.floor(time % 60)
let msg = ''
if (hour > 0) msg += `${hour}小时`
if (min > 0) msg += `${min}分钟`
if (sec > 0) msg += `${sec}`
return msg
}
async bbsTask(e = "") {
let mul = e;
Bot.logger.mark(`开始米社米币签到任务`);
let stoken = await gsCfg.getBingStoken();
let isPushSign = this.configSign.isPushSign
let userIdList = Object.keys(stoken)
if (bbsTask) {
e.reply(`云原神自动签到任务进行中,请勿重复触发指令`)
return false
}
let tips = ['开始米游币签到任务']
let time = userIdList.length * 3.5 + 5
let finishTime = moment().add(time, 's').format('MM-DD HH:mm:ss')
tips.push(`\n签到用户:${userIdList.length}`)
tips.push(`\n预计需要:${this.countTime(time)}`)
if (time > 120) {
tips.push(`\n完成时间:${finishTime}`)
}
logger.mark(`签到用户:${userIdList.length}个,预计需要${this.countTime(time)} ${finishTime} 完成`)
if (mul) {
await this.e.reply(tips)
if (this.e.msg.includes('force')) this.force = true
} else {
await utils.relpyPrivate(await gsCfg.getMasterQQ(), tips)
await utils.sleepAsync(lodash.random(1, 20) * 1000)
}
bbsTask = true;
let _reply = e.reply
//获取需要签到的用户
for (let dataUid of stoken) {
for (let uuId in dataUid) {
if (uuId[0] * 1 > 5) {
continue;
}
let data = dataUid[uuId]
let user_id = data.userId * 1;
let e = {
user_id,
isTask: true
};
e.cookie = `stuid=${data.stuid};stoken=${data.stoken};ltoken=${data.ltoken};`;
Bot.logger.mark(`正在为qq${user_id}uid:${uuId}进行米游币签到中...`);
e.msg = "全部"
e.reply = (msg) => {
//关闭签到消息推送
if (!isPushSign || ismysbool) {
return;
}
if (msg.includes("OK")) { //签到成功并且不是已签到的才推送
utils.relpyPrivate(user_id, msg + "uid:" + uuId + "\n自动签到成功");
}
};
this.e = e;
await this.getbbsSign(this.ForumData);
await utils.sleepAsync(10000);
}
}
let msg = `米社米币签到任务完成`
Bot.logger.mark(msg);
if (mul) {
_reply(msg)
} else {
await utils.relpyPrivate(await gsCfg.getMasterQQ(), msg)
}
bbsTask = false;
}
async bbsGeetest(){
let res=await this.getData('bbsGetCaptcha')//?????????????????????????????
}
getyunToken(e) { getyunToken(e) {
let file = `${this.yunPath}${e.user_id}.yaml` let file = `${this.yunPath}${e.user_id}.yaml`
try { try {
@ -95,7 +469,7 @@ export default class user {
skuid skuid
} = await this.getCookie(e); } = await this.getCookie(e);
let cookiesDoc = await this.getcookiesDoc(); let cookiesDoc = await this.getcookiesDoc();
let miHoYoApi = new MihoYoApi(this.e); // let miHoYoApi = new MihoYoApi(this.e);
if (!cookie) { if (!cookie) {
e.reply("请先#绑定cookie\n发送【体力帮助】查看配置教程") e.reply("请先#绑定cookie\n发送【体力帮助】查看配置教程")
return false; return false;
@ -108,7 +482,7 @@ export default class user {
// e.reply("米游社登录cookie不完整请前往米游社通行证处重新获取cookie~\ncookies必须包含login_ticket【教程】 " + cookiesDoc) // e.reply("米游社登录cookie不完整请前往米游社通行证处重新获取cookie~\ncookies必须包含login_ticket【教程】 " + cookiesDoc)
return false; return false;
} }
let flot = (await miHoYoApi.stoken(cookie, e)); // let flot = (await miHoYoApi.stoken(cookie, e));
// console.log(flot) // console.log(flot)
await utils.sleepAsync(1000); //延迟加载防止文件未生成 await utils.sleepAsync(1000); //延迟加载防止文件未生成
if (!flot) { if (!flot) {
@ -145,8 +519,38 @@ export default class user {
skuid skuid
} }
} }
async stoken(cookie, e) {
this.e = e;
let datalist = this.getStoken(e.user_id) || {}
if (Object.keys(datalist).length > 0) {
return true;
}
const map = this.getCookieMap(cookie);
let loginTicket = map.get("login_ticket");
const loginUid = map.get("login_uid") ? map.get("login_uid") : map.get("ltuid");
if (isV3) {
loginTicket = gsCfg.getBingCookie(e.user_id).login_ticket
}
let res = this.getData("bbsStoken", {
loginUid,
loginTicket
})
if (res?.data) {
datalist[e.uid] = {
stuid: map.get("account_id"),
stoken: data.data.list[0].token,
ltoken: data.data.list[1].token,
uid: e.uid,
userId: e.user_id,
is_sign: true
}
gsCfg.saveBingStoken(e.user_id, datalist)
}
return true;
}
getStoken(userId) { getStoken(userId) {
let file = `${YamlDataUrl}/${userId}.yaml` let file = `${yamlDataUrl}/${userId}.yaml`
try { try {
let ck = fs.readFileSync(file, 'utf-8') let ck = fs.readFileSync(file, 'utf-8')
ck = YAML.parse(ck) ck = YAML.parse(ck)
@ -162,8 +566,11 @@ export default class user {
return {} return {}
} }
} }
async delSytk(path,e){ async delSytk(path = yamlDataUrl, e, type = "stoken") {
await this.getCookie(e); await this.getCookie(e);
if (type != "stoken") {
path = cloudDataUrl
}
let file = `${path}/${e.user_id}.yaml` let file = `${path}/${e.user_id}.yaml`
fs.exists(file, (exists) => { fs.exists(file, (exists) => {
if (!exists) { if (!exists) {
@ -171,16 +578,16 @@ export default class user {
} }
let ck = fs.readFileSync(file, 'utf-8') let ck = fs.readFileSync(file, 'utf-8')
ck = YAML.parse(ck) ck = YAML.parse(ck)
if(ck?.yuntoken){ if (ck?.yuntoken) {
fs.unlinkSync(file); fs.unlinkSync(file);
}else if(ck){ } else if (ck) {
if(!ck[e.uid]) { if (!ck[e.uid]) {
return true; return true;
} }
delete ck[e.uid]; delete ck[e.uid];
if(Object.keys(ck)==0){ if (Object.keys(ck) == 0) {
fs.unlinkSync(file); fs.unlinkSync(file);
}else{ } else {
ck = YAML.stringify(ck) ck = YAML.stringify(ck)
fs.writeFileSync(file, ck, 'utf8') fs.writeFileSync(file, ck, 'utf8')
} }
@ -189,4 +596,12 @@ export default class user {
return true; return true;
}) })
} }
getDataList(name) {
for (let item of this.ForumData) {
if (item.name == name) { //循环结束未找到的时候返回原数组签到全部
return [item]
}
}
return this.ForumData;
}
} }