From ee33abc554cd6655dc320c194f435aaf79a8454f Mon Sep 17 00:00:00 2001 From: Kokomi <1379177109@qq.com> Date: Wed, 25 Oct 2023 03:34:37 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=AF=B9e.game=E7=9A=84?= =?UTF-8?q?=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/plugins/loader.js | 24 +++++++++++++++++++----- lib/plugins/runtime.js | 3 +-- lib/tools/log.js | 3 +-- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/lib/plugins/loader.js b/lib/plugins/loader.js index 9d5448f..e97484e 100644 --- a/lib/plugins/loader.js +++ b/lib/plugins/loader.js @@ -181,12 +181,13 @@ class PluginsLoader { }) /** 检查频道消息 */ if (this.checkGuildMsg(e)) return - /** 检查黑白名单 */ - if (!this.checkBlack(e)) return + /** 冷却 */ if (!this.checkLimit(e)) return /** 处理消息 */ this.dealMsg(e) + /** 检查黑白名单 */ + if (!this.checkBlack(e)) return /** 处理回复 */ this.reply(e) /** 过滤事件 */ @@ -233,8 +234,16 @@ class PluginsLoader { // 判断是否是星铁命令,若是星铁命令则标准化处理 // e.isSr = true,且命令标准化为 #星铁 开头 + Object.defineProperty(e, 'isSr', { + get: () => e.game === 'sr', + set: (v) => e.game = v ? 'sr' : 'gs' + }) + Object.defineProperty(e, 'isGs', { + get: () => e.game === 'gs', + set: (v) => e.game = v ? 'gs' : 'sr' + }) if (this.srReg.test(e.msg)) { - e.isSr = true + e.game = 'sr' e.msg = e.msg.replace(this.srReg, '#星铁') } @@ -717,8 +726,13 @@ class PluginsLoader { if (e.test) return true /** 黑名单qq */ - if (other.blackQQ && other.blackQQ.includes(Number(e.user_id) || e.user_id)) { - return false + if (other.blackQQ) { + if (other.blackQQ.includes(Number(e.user_id) || e.user_id)) { + return false + } + if (e.at && other.blackQQ.includes(Number(e.at) || e.at)) { + return false + } } if (e.group_id) { diff --git a/lib/plugins/runtime.js b/lib/plugins/runtime.js index a1f90c8..0cba154 100644 --- a/lib/plugins/runtime.js +++ b/lib/plugins/runtime.js @@ -77,7 +77,6 @@ export default class Runtime { await MysInfo.initCache() let runtime = new Runtime(e) e.runtime = runtime - e.game = e.isSr ? 'sr' : 'gs' await runtime.initUser() return runtime } @@ -88,7 +87,7 @@ export default class Runtime { if (user) { e.user = new Proxy(user, { get (self, key, receiver) { - let game = e.isSr ? 'sr' : 'gs' + let game = e.game let fnMap = { uid: 'getUid', uidList: 'getUidList', diff --git a/lib/tools/log.js b/lib/tools/log.js index d4ff2f2..33799aa 100644 --- a/lib/tools/log.js +++ b/lib/tools/log.js @@ -13,7 +13,6 @@ fs.readFile(`${_path}/config/pm2/pm2.json`, `utf8`, (err, data) => { const config = JSON.parse(data) if (config.apps && config.apps.length > 0 && config.apps[0].name) { const appName = config.apps[0].name - console.log(config.apps[0].name) runPm2Logs(appName) } else { console.log('读取失败:无法在pm2.json中找到name数组') @@ -32,4 +31,4 @@ function runPm2Logs(appName) { console.error(`pm2 logs process exited with code ${code}`) } }) -} \ No newline at end of file +} From 4ab0afac85564c1b7993efa24e13e93aab35f6da Mon Sep 17 00:00:00 2001 From: Rrrrrrray <28804884+Rrrrrrray@users.noreply.github.com> Date: Wed, 25 Oct 2023 17:32:57 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8A=BD=E5=8D=A1?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E5=AF=BC=E5=85=A5=E5=8F=8A=E5=AF=BC=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - fix:回滚导入导出,抽卡记录无法导入 - fix:可能需要发送两次文件才能导入的问题 - 导入记录支持游戏自识别 - 原神记录标准升为v2.3,适配导入到其他祈愿记录项目 - 星铁新增记录标准v1.0 --- plugins/genshin/apps/gcLog.js | 71 ++++++-------- plugins/genshin/model/exportLog.js | 145 +++++++++++++++++------------ 2 files changed, 110 insertions(+), 106 deletions(-) diff --git a/plugins/genshin/apps/gcLog.js b/plugins/genshin/apps/gcLog.js index 27038a5..71f832f 100644 --- a/plugins/genshin/apps/gcLog.js +++ b/plugins/genshin/apps/gcLog.js @@ -8,7 +8,7 @@ import LogCount from '../model/logCount.js' const _path = process.cwd() + '/plugins/genshin' export class gcLog extends plugin { - constructor() { + constructor () { super({ name: '抽卡记录', dsc: '抽卡记录数据统计', @@ -20,15 +20,15 @@ export class gcLog extends plugin { fnc: 'logUrl' }, { - reg: '^#txt(日志)?(文件)?导入记录$', + reg: '^#txt日志文件导入记录$', fnc: 'logFile' }, { - reg: '^#*(原神|星铁)?(xlsx|excel)(文件)?导入记录$', + reg: '^#xlsx文件导入记录$', fnc: 'logXlsx' }, { - reg: '^#*(原神|星铁)?json(文件)?导入记录$', + reg: '^#json文件导入记录$', fnc: 'logJson' }, { @@ -57,8 +57,8 @@ export class gcLog extends plugin { this.androidUrl = 'https://docs.qq.com/doc/DUWpYaXlvSklmVXlX' } - async init() { - let file = ['./data/gachaJson', './data/srJson', './temp/html/StarRail'] + async init () { + let file = ['./data/gachaJson', './data/srJson', './temp/html/StarRail', './temp/uigf'] for (let i of file) { if (!fs.existsSync(i)) { fs.mkdirSync(i) @@ -66,7 +66,7 @@ export class gcLog extends plugin { } } - accept() { + accept () { if (this.e.file && this.e.isPrivate) { let name = this.e.file?.name if (name.includes('txt')) { @@ -89,7 +89,7 @@ export class gcLog extends plugin { } /** 抽卡记录链接 */ - async logUrl() { + async logUrl () { if (!this.e.isPrivate) { this.e.reply('请私聊发送链接', false, { at: true }) return true @@ -103,7 +103,7 @@ export class gcLog extends plugin { } /** 发送output_log.txt日志文件 */ - async logFile() { + async logFile () { if (!this.e.isPrivate) { await this.e.reply('请私聊发送日志文件', false, { at: true }) return true @@ -126,7 +126,7 @@ export class gcLog extends plugin { } /** #抽卡记录 */ - async getLog() { + async getLog () { this.e.isAll = !!(this.e.msg.includes('全部')) let data = await new GachaLog(this.e).getLogData() if (!data) return @@ -139,7 +139,7 @@ export class gcLog extends plugin { } /** 导出记录 */ - async exportLog() { + async exportLog () { if (this.e.isGroup) { await this.reply('请私聊导出', false, { at: true }) return @@ -150,63 +150,44 @@ export class gcLog extends plugin { if (this.e.msg.includes('json')) { return await exportLog.exportJson() } else { + await this.e.reply('如需要将此记录导入到其他平台,请导出json格式文件') return await exportLog.exportXlsx() } } - async logXlsx() { + async logXlsx () { if (!this.e.isPrivate) { await this.e.reply('请私聊发送日志文件', false, { at: true }) return true } - const gsTips = `注:不支持https://github.com/biuuu/genshin-wish-export项目导出的excel文件,如果是该项目的文件请发送任意消息,取消excel导入后,使用【#json导入记录】`; - const srTips = `注:适配https://github.com/biuuu/star-rail-warp-export项目导出的excel文件`; - - await this.e.reply(`请发送xlsx文件,该文件需要以${this.e?.isSr ? '*' : '#'}的uid命名,如:100000000.xlsx\n否则可能无法正确识别,如果误触可发送任意消息取消导入\n${this.e?.isSr ? srTips : gsTips}`); - this.setContext('importLogXlsx'); - } - - async importLogXlsx() { if (!this.e.file) { - await this.e.reply(`未检测到excel文件,操作已取消,请重新发送【${this.e?.isSr ? '*' : '#'}excel导入记录】`); + await this.e.reply('请发送xlsx文件') + return true } - else { - this.e.isSr = this.getContext()?.importLogXlsx.isSr; - await new ExportLog(this.e).logXlsx(); - } - this.finish('importLogXlsx'); + await this.e.reply('如果是星铁记录,请在【原始数据】工作表复制【gacha_type】列,粘贴并把此标题重命名为【srgf_gacha_type】,否则可能无法正确识别') + await new ExportLog(this.e).logXlsx() } - async logJson() { + async logJson () { if (!this.e.isPrivate) { - await this.e.reply('请私聊发送日志文件', false, { at: true }) + await this.e.reply('请私聊发送Json文件', false, { at: true }) return true } - const gsTips = `注:适配https://github.com/biuuu/genshin-wish-export项目导出的json文件`; - const srTips = `注:适配https://github.com/biuuu/star-rail-warp-export项目导出的json文件`; - - await this.e.reply(`请发送json文件,该文件需要以${this.e?.isSr ? '*' : '#'}的uid命名\n如:100000000.json,否则可能无法正确识别,如果误触可发送任意消息取消导入\n${this.e?.isSr ? srTips : gsTips}`); - this.setContext('importLogJson'); - } - - async importLogJson() { - this.e.isSr = this.getContext()?.importLogJson.isSr; if (!this.e.file) { - await this.e.reply(`未检测到json文件,操作已取消,请重新发送【${this.e?.isSr ? '*' : '#'}json导入记录】`); + await this.e.reply('请发送Json文件') + return true } - else { - await new ExportLog(this.e).logJson(); - } - this.finish('importLogJson'); + + await new ExportLog(this.e).logJson() } - async help() { + async help () { await this.e.reply(segment.image(`file://${_path}/resources/logHelp/记录帮助.png`)) } - async helpPort() { + async helpPort () { let msg = this.e.msg.replace(/#|帮助/g, '') if (['电脑', 'pc'].includes(msg)) { @@ -218,7 +199,7 @@ export class gcLog extends plugin { } } - async logCount() { + async logCount () { let data = await new LogCount(this.e).count() if (!data) return let img = await puppeteer.screenshot(`${data.srtempFile}logCount`, data) diff --git a/plugins/genshin/model/exportLog.js b/plugins/genshin/model/exportLog.js index ecef881..edf5e1d 100644 --- a/plugins/genshin/model/exportLog.js +++ b/plugins/genshin/model/exportLog.js @@ -19,35 +19,41 @@ export default class ExportLog extends base { this.path = this.e.isSr ? `./data/srJson/${this.e.user_id}/` : `./data/gachaJson/${this.e.user_id}/` - const gsPool = [ - { type: 301, typeName: '角色活动' }, - { type: 302, typeName: '武器活动' }, - { type: 200, typeName: '常驻' } - ]; + this.game = this.e.game || this.e.isSr ? 'sr' : 'gs' - const srPool = [ - { type: 11, typeName: '角色活动' }, - { type: 12, typeName: '武器活动' }, - { type: 2, typeName: '新手活动' }, - { type: 1, typeName: '常驻' } - ]; + this.pool = (game = 'gs') => { + let pool = { + gs: [ + { type: 301, typeName: '角色活动' }, + { type: 302, typeName: '武器活动' }, + { type: 200, typeName: '常驻' } + ], + sr: [ + { type: 11, typeName: '角色活动' }, + { type: 12, typeName: '武器活动' }, + { type: 2, typeName: '新手活动' }, + { type: 1, typeName: '常驻' } + ] + } + return pool[game] + } - this.pool = this.e.isSr ? srPool : gsPool; - - const gsTypeName = { - 301: '角色', - 302: '武器', - 200: '常驻' - }; - - const srTypeName = { - 11: '角色', - 12: '武器', - 2: '新手', - 1: '常驻' - }; - - this.typeName = this.e.isSr ? srTypeName : gsTypeName; + this.typeName = (game = 'gs') => { + let type = { + gs: { + 301: '角色', + 302: '武器', + 200: '常驻' + }, + sr: { + 11: '角色', + 12: '武器', + 2: '新手', + 1: '常驻' + } + } + return type[game] + } } async initXlsx() { @@ -57,6 +63,9 @@ export default class ExportLog extends base { } async exportJson() { + if (!this.e.isSr) { + await common.downFile('https://api.uigf.org/dict/genshin/chs.json', './temp/uigf/genshin.json') + } await this.getUid() if (!this.uid) return false @@ -71,11 +80,17 @@ export default class ExportLog extends base { export_timestamp: moment().format('X'), export_app: 'Miao-Yunzai', export_app_version: cfg.package.version, - uigf_version: 'v2.2' }, list } + if (this.e.isSr) { + data.info.srgf_version = 'v1.0' + data.info.region_time_zone = moment(list[0].time).utcOffset() / 60 + } else { + data.info.uigf_version = 'v2.3' + } + let saveFile = `${this.path}${this.uid}/${this.uid}.json` fs.writeFileSync(saveFile, JSON.stringify(data, '', '\t')) @@ -141,11 +156,12 @@ export default class ExportLog extends base { } getAllList() { + let uigf = JSON.parse(fs.readFileSync('./temp/uigf/genshin.json', 'utf8')) let res = { list: [] } let tmpId = {} - for (let v of this.pool) { + for (let v of this.pool(this.game)) { let json = `${this.path}${this.uid}/${v.type}.json` if (fs.existsSync(json)) { json = JSON.parse(fs.readFileSync(json, 'utf8')) @@ -155,10 +171,16 @@ export default class ExportLog extends base { } res[v.type] = json for (let v of json) { - if (v.gacha_type == 301 || v.gacha_type == 400) { - v.uigf_gacha_type = '301' - } else { - v.uigf_gacha_type = v.gacha_type + // item_id必要字段 + if (!v.item_id) { + v.item_id = String(uigf[v.name]) + } + if (!this.e.isSr) { + if (v.gacha_type == 301 || v.gacha_type == 400) { + v.uigf_gacha_type = '301' + } else { + v.uigf_gacha_type = v.gacha_type + } } let id = v.id if (!id) { @@ -192,7 +214,7 @@ export default class ExportLog extends base { xlsxDataPool(data) { let xlsxData = [] - for (let v of this.pool) { + for (let v of this.pool(this.game)) { let poolData = [ [ '时间', '名称', '物品类型', '星级', '祈愿类型' @@ -214,15 +236,17 @@ export default class ExportLog extends base { } xlsxDataAll(data) { + let ui = this.e.isSr ? 'sr' : 'ui' let list = [ [ - 'count', 'gacha_type', 'id', 'item_id', 'item_type', 'lang', 'name', 'rank_type', 'time', 'uid', 'uigf_gacha_type' + 'count', 'gacha_type', 'id', 'item_id', 'item_type', 'lang', 'name', 'rank_type', 'time', 'uid', `${ui}gf_gacha_type` ] ] for (let v of data.list) { let tmp = [] + if (this.e.isSr) v.srgf_gacha_type = v.gacha_type for (let i of list[0]) { - if (i == 'id' || i == 'uigf_gacha_type') v[i] = String(v[i]) + if (i == 'id' || i == `${ui}gf_gacha_type`) v[i] = String(v[i]) tmp.push(v[i]) } list.push(tmp) @@ -280,6 +304,10 @@ export default class ExportLog extends base { return false } + if (rawData.data[0].includes('srgf_gacha_type')) { + this.e.isSr = true + this.game = 'sr' + } /** 处理xlsx数据 */ let data = this.dealXlsx(rawData.data); if (!data) return false @@ -287,24 +315,26 @@ export default class ExportLog extends base { /** 保存json */ let msg = [] for (let type in data) { - if (!this.typeName[type]) continue + let typeName = this.typeName(this.game) + if (!typeName[type]) continue let gachLog = new GachaLog(this.e) gachLog.uid = uid gachLog.type = type gachLog.writeJson(data[type]) - msg.push(`${this.typeName[type]}记录:${data[type].length}条`) + msg.push(`${typeName[type]}记录:${data[type].length}条`) } /** 删除文件 */ fs.unlink(textPath, () => { }) - await this.e.reply(`${this.e.file.name},导入成功\n${msg.join('\n')}`) + await this.e.reply(`${this.e.file.name},${this.e.isSr ? '星铁' : '原神'}记录导入成功\n${msg.join('\n')}`) } dealXlsx(list) { + let ui = this.e.isSr ? 'sr' : 'ui' /** 必要字段 */ - let reqField = ['uigf_gacha_type', 'gacha_type', 'item_type', 'name', 'time'] + let reqField = ['gacha_type', 'item_type', 'name', 'time', `${ui}gf_gacha_type`] /** 不是必要字段 */ let noReqField = ['id', 'uid', 'count', 'item_id', 'lang', 'rank_type'] @@ -313,15 +343,11 @@ export default class ExportLog extends base { field[list[0][i]] = i } - // 适配StarRailExport导出的xlsx,该xlsx没有uigf_gacha_type字段. - if (!field['uigf_gacha_type'] && field['gacha_type']) { - field['uigf_gacha_type'] = field['gacha_type'] - } - /** 判断字段 */ for (let v of reqField) { if (!field[v]) { - this.e.reply(`xlsx文件内容错误:缺少必要字段${v}`) + let tips = v === 'srgf_gacha_type' ? '\n请在【原始数据】工作表复制【gacha_type】列,粘贴并把此标题重命名为【srgf_gacha_type】' : '' + this.e.reply(`xlsx文件内容错误:缺少必要字段${v}${tips}`) return } } @@ -334,7 +360,7 @@ export default class ExportLog extends base { let data = {} for (let v of list) { if (v[field.name] == 'name') continue - if (!data[v[field.uigf_gacha_type]]) data[v[field.uigf_gacha_type]] = [] + if (!data[v[field[`${ui}gf_gacha_type`]]]) data[v[field[`${ui}gf_gacha_type`]]] = [] let tmp = {} /** 加入必要字段 */ @@ -351,7 +377,7 @@ export default class ExportLog extends base { } } - data[v[field.uigf_gacha_type]].push(tmp) + data[v[field[`${ui}gf_gacha_type`]]].push(tmp) } return data @@ -382,25 +408,31 @@ export default class ExportLog extends base { return false } + if (json.info.srgf_version) { + this.e.isSr = true + this.game = 'sr' + } + let data = this.dealJson(json.list) if (!data) return false /** 保存json */ let msg = [] for (let type in data) { - if (!this.typeName[type]) continue + let typeName = this.typeName(this.game) + if (!typeName[type]) continue let gachLog = new GachaLog(this.e) gachLog.uid = uid gachLog.type = type gachLog.writeJson(data[type]) - msg.push(`${this.typeName[type]}记录:${data[type].length}条`) + msg.push(`${typeName[type]}记录:${data[type].length}条`) } /** 删除文件 */ fs.unlink(textPath, () => { }) - await this.e.reply(`${this.e.file.name},导入成功\n${msg.join('\n')}`) + await this.e.reply(`${this.e.file.name},${this.e.isSr ? '星铁' : '原神'}记录导入成功\n${msg.join('\n')}`) } dealJson(list) { @@ -416,22 +448,13 @@ export default class ExportLog extends base { } } - // 对json进行排序(按照time字段) - list.sort((a, b) => { - return moment(a.time).format('x') - moment(b.time).format('x'); - }); - /** 倒序 */ if (moment(list[0].time).format('x') < moment(list[list.length - 1].time).format('x')) { list = list.reverse() } for (let v of list) { - // 适配StarRailExport导出的json,该json没有uigf_gacha_type字段. - if (!v['uigf_gacha_type'] && v['gacha_type']) { - v['uigf_gacha_type'] = v['gacha_type'] - } - + if (this.game === 'sr') v.uigf_gacha_type = v.gacha_type if (!data[v.uigf_gacha_type]) data[v.uigf_gacha_type] = [] data[v.uigf_gacha_type].push(v) }