Compare commits

..

2 Commits

Author SHA1 Message Date
f8e47879f1
user notifications 2023-10-20 22:33:34 +08:00
dd86b82e1c
format code 2023-10-20 21:57:43 +08:00
5 changed files with 255 additions and 168 deletions

@ -1,9 +1,10 @@
{ {
"token":"", "token": "",
"client_type":"", "client_type": "",
"device_name":"", "device_name": "",
"device_model":"", "device_model": "",
"device_id":"", "device_id": "",
"sys_version":"", "sys_version": "",
"channel":"" "channel": "",
"email": ""
} }

@ -3,11 +3,11 @@
"maxDelay": 5000, "maxDelay": 5000,
"sendMail": false, "sendMail": false,
"mailConfig": { "mailConfig": {
"user":"", "user": "",
"pass":"", "pass": "",
"mailto":"", "mailto": "",
"smtpServer":"", "smtpServer": "",
"smtpPort":"", "smtpPort": "",
"smtpSecure":true "smtpSecure": true
} }
} }

@ -1,140 +1,183 @@
const { exit } = require("process") const { exit } = require("process");
const fs = require("fs") const fs = require("fs");
const { default: axios } = require("axios") const { default: axios } = require("axios");
const { log } = require("./util") const { log } = require("./util");
exports.ListNotificationURL = 'https://api-cloudgame.mihoyo.com/hk4e_cg_cn/gamer/api/listNotifications?is_sort=true&source=NotificationSourceUnknown&status=NotificationStatusUnread&type=NotificationTypePopup' exports.ListNotificationURL =
exports.AckNotificationURL = 'https://api-cloudgame.mihoyo.com/hk4e_cg_cn/gamer/api/ackNotification' "https://api-cloudgame.mihoyo.com/hk4e_cg_cn/gamer/api/listNotifications?is_sort=true&source=NotificationSourceUnknown&status=NotificationStatusUnread&type=NotificationTypePopup";
exports.WalletURL = 'https://api-cloudgame.mihoyo.com/hk4e_cg_cn/wallet/wallet/get?cost_method=COST_METHOD_UNSPECIFIED' exports.AckNotificationURL =
exports.AnnouncementURL = 'https://api-cloudgame.mihoyo.com/hk4e_cg_cn/gamer/api/getAnnouncementInfo' "https://api-cloudgame.mihoyo.com/hk4e_cg_cn/gamer/api/ackNotification";
exports.WalletURL =
"https://api-cloudgame.mihoyo.com/hk4e_cg_cn/wallet/wallet/get?cost_method=COST_METHOD_UNSPECIFIED";
exports.AnnouncementURL =
"https://api-cloudgame.mihoyo.com/hk4e_cg_cn/gamer/api/getAnnouncementInfo";
// Here must be an earlier version so that the response won't be null // Here must be an earlier version so that the response won't be null
exports.AppVersionURL = 'https://api-takumi.mihoyo.com/ptolemaios/api/getLatestRelease?app_id=1953443910&app_version=3.8.0&channel=mihoyo' exports.AppVersionURL =
"https://api-takumi.mihoyo.com/ptolemaios/api/getLatestRelease?app_id=1953443910&app_version=3.8.0&channel=mihoyo";
exports.ListNotification = async function(header) { exports.ListNotification = async function (header) {
let tmp = (await axios(exports.ListNotificationURL,{ let tmp = (
headers:header await axios(exports.ListNotificationURL, {
})).data; headers: header,
})
).data;
tmp.StringVersion = JSON.stringify(tmp); tmp.StringVersion = JSON.stringify(tmp);
return tmp; return tmp;
} };
exports.AckNotification = async function(header, id) { exports.AckNotification = async function (header, id) {
let data = `{"id":"${id}"}`; let data = `{"id":"${id}"}`;
await axios.post(exports.AckNotificationURL, data,{ await axios.post(exports.AckNotificationURL, data, {
headers:header headers: header,
}); });
} };
exports.Wallet = async function(header) { exports.Wallet = async function (header) {
let tmp = (await axios(exports.WalletURL,{ let tmp = (
headers:header await axios(exports.WalletURL, {
})).data; headers: header,
})
).data;
tmp.StringVersion = JSON.stringify(tmp); tmp.StringVersion = JSON.stringify(tmp);
return tmp; return tmp;
} };
exports.Announcement = async function(header) { exports.Announcement = async function (header) {
let tmp = (await axios(exports.AnnouncementURL,{ let tmp = (
headers:header await axios(exports.AnnouncementURL, {
})).data; headers: header,
})
).data;
tmp.StringVersion = JSON.stringify(tmp); tmp.StringVersion = JSON.stringify(tmp);
return tmp; return tmp;
} };
exports.AppVersion = async function() { exports.AppVersion = async function () {
let tmp = (await axios(exports.AppVersionURL)).data; let tmp = (await axios(exports.AppVersionURL)).data;
tmp.StringVersion = JSON.stringify(tmp); tmp.StringVersion = JSON.stringify(tmp);
return tmp; return tmp;
} };
var configKeys = [ var configKeys = [
"token", "token",
"client_type", "client_type",
"device_name", "device_name",
"device_model", "device_model",
"sys_version", "sys_version",
"channel" "channel",
] ];
exports.getGlobalConfig = function() { exports.getGlobalConfig = function () {
try { try {
var globalConfig = fs.readFileSync("global.json") var globalConfig = fs.readFileSync("global.json");
} catch(e) { } catch (e) {
if(e.toString().includes("Error: ENOENT: no such file or directory")) { if (e.toString().includes("Error: ENOENT: no such file or directory")) {
log.error(`读取配置失败!找不到全局配置文件`) log.error(`读取配置失败!找不到全局配置文件`);
} else { } else {
log.error(`读取配置失败!错误信息:${e}`); log.error(`读取配置失败!错误信息:${e}`);
} }
exit() exit();
} }
return JSON.parse(globalConfig); return JSON.parse(globalConfig);
} };
exports.getConfigs = function(){ exports.getConfigs = function () {
try { try {
var configsList = fs.readdirSync("configs") var configsList = fs.readdirSync("configs");
} catch(e) { } catch (e) {
if(e == "Error: ENOENT: no such file or directory, scandir 'configs'") { if (
log.error(`读取配置失败!找不到configs文件夹`) e == "Error: ENOENT: no such file or directory, scandir 'configs'"
) {
log.error(`读取配置失败!找不到configs文件夹`);
} else { } else {
log.error(`读取配置失败!错误信息:${e}`); log.error(`读取配置失败!错误信息:${e}`);
} }
exit() exit();
} }
log.info(`检测到${configsList.length}个配置文件:`) log.info(`检测到${configsList.length}个配置文件:`);
configsList.forEach(file => { configsList.forEach((file) => {
log.info(`${file}`) log.info(`${file}`);
}) });
var configs = {} var configs = {};
configsList.forEach(file => { configsList.forEach((file) => {
configs[file] = JSON.parse(fs.readFileSync(`configs/${file}`)) configs[file] = JSON.parse(fs.readFileSync(`configs/${file}`));
}) });
return configs return configs;
} };
exports.checkConfigs = function(configs){ exports.checkConfigs = function (configs) {
for(file in configs) { for (file in configs) {
var configThis = configs[file]; var configThis = configs[file];
for(key in configKeys) { for (key in configKeys) {
if(configThis[configKeys[key]] == "" || configThis[configKeys[key]] == undefined || configThis[configKeys[key]] == null || configThis[configKeys[key]] == NaN) { if (
configThis[configKeys[key]] == "" ||
configThis[configKeys[key]] == undefined ||
configThis[configKeys[key]] == null ||
configThis[configKeys[key]] == NaN
) {
log.error(`配置文件 ${file} 异常:`); log.error(`配置文件 ${file} 异常:`);
log.error(` —— ${configKeys[key]}字段缺失`); log.error(` —— ${configKeys[key]}字段缺失`);
} }
} }
} }
} };
exports.makeHeader = function(data,appversion){ exports.makeHeader = function (data, appversion) {
return { return {
"x-rpc-combo_token": data.token, "x-rpc-combo_token": data.token,
"x-rpc-client_type": data.client_type, "x-rpc-client_type": data.client_type,
"x-rpc-app_version": appversion, "x-rpc-app_version": appversion,
"x-rpc-sys_version": data.sys_version, "x-rpc-sys_version": data.sys_version,
"x-rpc-channel": data.channel, "x-rpc-channel": data.channel,
"x-rpc-device_id": data.device_id, "x-rpc-device_id": data.device_id,
"x-rpc-device_name": data.device_name, "x-rpc-device_name": data.device_name,
"x-rpc-device_model": data.device_model, "x-rpc-device_model": data.device_model,
"x-rpc-app_id": 1953439974, "x-rpc-app_id": 1953439974,
"x-rpc-cg_game_biz": "hk4e_cn", "x-rpc-cg_game_biz": "hk4e_cn",
"x-rpc-preview": 0, "x-rpc-preview": 0,
"x-rpc-op_biz": "clgm_cn", "x-rpc-op_biz": "clgm_cn",
"x-rpc-language": "zh-cn", "x-rpc-language": "zh-cn",
"x-rpc-vendor_id": 2, "x-rpc-vendor_id": 2,
Referer: "https://app.mihoyo.com", Referer: "https://app.mihoyo.com",
Host: "api-cloudgame.mihoyo.com", Host: "api-cloudgame.mihoyo.com",
Connection: "Keep-Alive", Connection: "Keep-Alive",
"Accept-Encoding": "gzip, deflate", "Accept-Encoding": "gzip, deflate",
Accept: "*/*", Accept: "*/*",
} };
} };
exports.SendLog = function(transporter,mailfrom,mailto,successNum,totalNum,content) { exports.SendLog = function (
transporter.sendMail({ transporter,
from: `"Genshin Cloud Game Helper" <${mailfrom}>`, //邮件来源 mailfrom,
to: mailto, //邮件发送到哪里,多个邮箱使用逗号隔开 mailto,
subject: `今日已签到${successNum}/${totalNum}名用户`, // 邮件主题 successNum,
text: '', // 存文本类型的邮件正文 totalNum,
html: `${content}` // html类型的邮件正文 content
}, (error) => { ) {
if (error) { transporter.sendMail(
return console.log(error); {
from: `"Genshin Cloud Game Helper" <${mailfrom}>`, //邮件来源
to: mailto, //邮件发送到哪里,多个邮箱使用逗号隔开
subject: `今日已签到${successNum}/${totalNum}名用户`, // 邮件主题
text: "", // 存文本类型的邮件正文
html: `${content}`, // html类型的邮件正文
},
(error) => {
if (error) {
return console.log(error);
}
log.info("日志已丢出!");
} }
log.info("日志已丢出!") );
}); };
}
exports.SendResult = function (transporter, mailfrom, mailto, content) {
transporter.sendMail(
{
from: `"Genshin Cloud Game Helper" <${mailfrom}>`, //邮件来源
to: mailto, //邮件发送到哪里,多个邮箱使用逗号隔开
subject: `Genshin Cloud Game Helper`, // 邮件主题
text: `${content}`, // 存文本类型的邮件正文
},
(error) => {
if (error) {
return console.log(error);
}
log.info(`已发送通知至${mailto}`);
}
);
};

@ -1,67 +1,110 @@
const { getConfigs, checkConfigs, makeHeader, ListNotification, AckNotification, Wallet, SendLog, AppVersion, getGlobalConfig } = require("./config") const {
getConfigs,
checkConfigs,
makeHeader,
ListNotification,
AckNotification,
Wallet,
SendLog,
AppVersion,
getGlobalConfig,
SendResult,
} = require("./config");
const { log, addLogContent, getLogs, sleep } = require("./util"); const { log, addLogContent, getLogs, sleep } = require("./util");
const nodemailer = require("nodemailer"); const nodemailer = require("nodemailer");
(async () => { (async () => {
log.info("开始获取全局配置") log.info("开始获取全局配置");
var globalConfig = getGlobalConfig(); var globalConfig = getGlobalConfig();
log.info("获取成功") log.info("获取成功");
if (globalConfig.sendMail == true) { if (globalConfig.sendMail == true) {
log.info("组装邮件发射器") log.info("组装邮件发射器");
var transporter = nodemailer.createTransport({ var transporter = nodemailer.createTransport({
host: globalConfig.mailConfig.smtpServer, host: globalConfig.mailConfig.smtpServer,
port: globalConfig.mailConfig.smtpPort, port: globalConfig.mailConfig.smtpPort,
secure: globalConfig.mailConfig.smtpSecure, secure: globalConfig.mailConfig.smtpSecure,
auth: { auth: {
user: globalConfig.mailConfig.user, user: globalConfig.mailConfig.user,
pass: globalConfig.mailConfig.pass pass: globalConfig.mailConfig.pass,
} },
}); });
} }
var minDelay = globalConfig.minDelay var minDelay = globalConfig.minDelay;
var maxDelay = globalConfig.maxDelay var maxDelay = globalConfig.maxDelay;
var configs = getConfigs(); var configs = getConfigs();
log.info(`正在检测配置有效性`) log.info(`正在检测配置有效性`);
checkConfigs(configs) checkConfigs(configs);
log.info("检测完毕!") log.info("检测完毕!");
log.info("正在获取版本号") log.info("正在获取版本号");
var appversion = await AppVersion(); var appversion = await AppVersion();
appversion = appversion.data.package_version appversion = appversion.data.package_version;
log.info(`获取成功!当前版本号:${appversion}`) log.info(`获取成功!当前版本号:${appversion}`);
var successNum = 0,totalNum = 0; var successNum = 0,
totalNum = 0;
for (key in configs) { for (key in configs) {
totalNum ++; totalNum++;
log.info(`正在执行配置 ${key}`) log.info(`正在执行配置 ${key}`);
log.info("尝试签到……") log.info("尝试签到……");
var header = makeHeader(configs[key], appversion); var header = makeHeader(configs[key], appversion);
var WalletRespond = await Wallet(header); var WalletRespond = await Wallet(header);
addLogContent(`<span style="color: orange; font-weight: bold">${key} Wallet返回体</span> <br> <span style="color: orange">${JSON.stringify(WalletRespond)}</span><br>`); addLogContent(
if(WalletRespond.data != null) { `<span style="color: orange; font-weight: bold">${key} Wallet返回体</span> <br> <span style="color: orange">${JSON.stringify(
WalletRespond
)}</span><br>`
);
if (WalletRespond.data != null) {
var NotificationRespond = await ListNotification(header); var NotificationRespond = await ListNotification(header);
addLogContent(`<span style="color: orange; font-weight: bold">${key} Notification返回体</span> <br> <span style="color: orange">${JSON.stringify(NotificationRespond)}</span><br>`); addLogContent(
successNum ++; `<span style="color: orange; font-weight: bold">${key} Notification返回体</span> <br> <span style="color: orange">${JSON.stringify(
log.info(`签到完毕! 获得时长:${WalletRespond.data.free_time.send_freetime}分钟,总时长:${WalletRespond.data.free_time.free_time}分钟`); NotificationRespond
let NotificationLength = NotificationRespond.data.list.length )}</span><br>`
);
successNum++;
log.info(
`签到完毕! 获得时长:${WalletRespond.data.free_time.send_freetime}分钟,总时长:${WalletRespond.data.free_time.free_time}分钟`
);
if (configs[key].email != null) {
SendResult(
transporter,
globalConfig.mailConfig.user,
configs[key].email,
`签到完毕! 获得时长:${WalletRespond.data.free_time.send_freetime}分钟,总时长:${WalletRespond.data.free_time.free_time}分钟`
);
}
let NotificationLength = NotificationRespond.data.list.length;
let postHeader = header; let postHeader = header;
Object.assign(postHeader, { Object.assign(postHeader, {
"Content-Length": 28, "Content-Length": 28,
"Content-Type": "application/json", "Content-Type": "application/json",
}); });
for (var i = 0; i < NotificationLength; i++) { for (var i = 0; i < NotificationLength; i++) {
AckNotification(postHeader, NotificationRespond.data.list[i].id); AckNotification(
} postHeader,
NotificationRespond.data.list[i].id
);
}
} else { } else {
log.error("签到失败") log.error("签到失败");
if (configs[key].email != null) {
SendResult(
transporter,
globalConfig.mailConfig.user,
configs[key].email,
"签到失败"
);
}
} }
var delay = Math.round(Math.random() * (maxDelay - minDelay) + minDelay) var delay = Math.round(
log.info(`暂停:${delay}毫秒`) Math.random() * (maxDelay - minDelay) + minDelay
);
log.info(`暂停:${delay}毫秒`);
await sleep(delay); await sleep(delay);
} }
if (globalConfig.sendMail == true) { if (globalConfig.sendMail == true) {
log.info(`运行完毕!丢出日志`) log.info(`运行完毕!丢出日志`);
SendLog( SendLog(
transporter, transporter,
globalConfig.mailConfig.user, globalConfig.mailConfig.user,
@ -69,6 +112,6 @@ const nodemailer = require("nodemailer");
successNum, successNum,
totalNum, totalNum,
getLogs() getLogs()
) );
} }
})() })();

@ -1,26 +1,26 @@
const reggol = require("reggol") const reggol = require("reggol");
const baseLogger = new reggol("GenshinCloudGameHelper") const baseLogger = new reggol("GenshinCloudGameHelper");
let logContent = `` let logContent = ``;
exports.addLogContent = function(content) { exports.addLogContent = function (content) {
logContent += content logContent += content;
} };
exports.getLogs = function() { exports.getLogs = function () {
return logContent return logContent;
} };
exports.log = { exports.log = {
info(content) { info(content) {
logContent += `<strong style="color: green">[info]</strong> ${content}<br>` logContent += `<strong style="color: green">[info]</strong> ${content}<br>`;
baseLogger.info(content) baseLogger.info(content);
}, },
error(content) { error(content) {
logContent += `<strong style="color: red">[error]</strong> ${content}<br>` logContent += `<strong style="color: red">[error]</strong> ${content}<br>`;
baseLogger.error(content) baseLogger.error(content);
} },
} };
exports.sleep = function (delay) { exports.sleep = function (delay) {
return new Promise((resolve) => { return new Promise((resolve) => {
setTimeout(resolve, delay) setTimeout(resolve, delay);
}) });
} };