From 60a82526cddf57a1b06e11ffa1ec6e4adeaf1674 Mon Sep 17 00:00:00 2001 From: 8852690 <59615518+8852690@users.noreply.github.com> Date: Fri, 13 Oct 2023 02:52:05 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=82=E9=85=8D=E6=98=9F=E9=93=81=E6=8A=BD?= =?UTF-8?q?=E5=8D=A1=E8=AE=B0=E5=BD=95=E5=AF=BC=E5=85=A5=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E6=AD=A3=E2=80=9C=E7=95=99=E5=BD=B1=E5=8F=99?= =?UTF-8?q?=E4=BD=B3=E6=9C=9F=E2=80=9D=E6=AD=A3=E5=88=99=20(#274)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 修正留影叙佳期正则,降低触发频率 * 适配星铁抽卡记录导出 * 适配Github - biuuu原神/星铁抽卡导出工具的抽卡记录导入 --------- Co-authored-by: James Co-authored-by: Kokomi <102026640+yoimiya-kokomi@users.noreply.github.com> --- plugins/genshin/apps/gcLog.js | 74 ++++++++++++-------- plugins/genshin/model/exportLog.js | 104 ++++++++++++++++++++++------- plugins/genshin/model/gachaLog.js | 32 ++++----- 3 files changed, 143 insertions(+), 67 deletions(-) diff --git a/plugins/genshin/apps/gcLog.js b/plugins/genshin/apps/gcLog.js index 0c81ba2..3c7b1d1 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文件导入记录$', + reg: '#*(原神|星铁)?(xlsx|excel)(文件)?导入记录', fnc: 'logXlsx' }, { - reg: '^#json文件导入记录$', + reg: '#*(原神|星铁)?json(文件)?导入记录', fnc: 'logJson' }, { @@ -36,7 +36,7 @@ export class gcLog extends plugin { fnc: 'getLog' }, { - reg: '^#*导出记录(excel|xlsx|json)*$', + reg: '^#*(原神|星铁)?导出记录(excel|xlsx|json)*$', fnc: 'exportLog' }, { @@ -57,7 +57,7 @@ export class gcLog extends plugin { this.androidUrl = 'https://docs.qq.com/doc/DUWpYaXlvSklmVXlX' } - async init () { + async init() { let file = ['./data/gachaJson', './data/srJson', './temp/html/StarRail'] for (let i of file) { if (!fs.existsSync(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 @@ -154,39 +154,59 @@ export class gcLog extends plugin { } } - async logXlsx () { + async logXlsx() { if (!this.e.isPrivate) { await this.e.reply('请私聊发送日志文件', false, { at: true }) return true } - if (!this.e.file) { - await this.e.reply('请发送xlsx文件') - 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 new ExportLog(this.e).logXlsx() + await this.e.reply(`请发送xlsx文件,该文件需要以${this.e?.isSr ? '*' : '#'}的uid命名,如:100000000.xlsx\n否则可能无法正确识别,如果误触可发送任意消息取消导入\n${this.e?.isSr ? srTips : gsTips}`); + this.setContext('importLogXlsx'); } - async logJson () { + async importLogXlsx() { + if (!this.e.file) { + await this.e.reply(`未检测到excel文件,操作已取消,请重新发送【${this.e?.isSr ? '*' : '#'}excel导入记录】`); + } + else { + this.e.isSr = this.getContext()?.importLogXlsx.isSr; + await new ExportLog(this.e).logXlsx(); + } + this.finish('importLogXlsx'); + } + + async logJson() { if (!this.e.isPrivate) { - await this.e.reply('请私聊发送Json文件', false, { at: true }) + await this.e.reply('请私聊发送日志文件', false, { at: true }) return true } - if (!this.e.file) { - await this.e.reply('请发送Json文件') - return true - } + const gsTips = `注:适配https://github.com/biuuu/genshin-wish-export项目导出的json文件`; + const srTips = `注:适配https://github.com/biuuu/star-rail-warp-export项目导出的json文件`; - await new ExportLog(this.e).logJson() + await this.e.reply(`请发送json文件,该文件需要以${this.e?.isSr ? '*' : '#'}的uid命名\n如:100000000.json,否则可能无法正确识别,如果误触可发送任意消息取消导入\n${this.e?.isSr ? srTips : gsTips}`); + this.setContext('importLogJson'); } - async help () { + async importLogJson() { + this.e.isSr = this.getContext()?.importLogJson.isSr; + if (!this.e.file) { + await this.e.reply(`未检测到json文件,操作已取消,请重新发送【${this.e?.isSr ? '*' : '#'}json导入记录】`); + } + else { + await new ExportLog(this.e).logJson(); + } + this.finish('importLogJson'); + } + + 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)) { @@ -198,7 +218,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 736f5bf..ecef881 100644 --- a/plugins/genshin/model/exportLog.js +++ b/plugins/genshin/model/exportLog.js @@ -9,7 +9,7 @@ import lodash from 'lodash' let xlsx = {} export default class ExportLog extends base { - constructor (e) { + constructor(e) { super(e) this.model = 'gachaLog' @@ -17,28 +17,46 @@ export default class ExportLog extends base { /** 绑定的uid */ this.uidKey = `Yz:genshin:mys:qq-uid:${this.userId}` - this.path = `./data/gachaJson/${this.e.user_id}/` + this.path = this.e.isSr ? `./data/srJson/${this.e.user_id}/` : `./data/gachaJson/${this.e.user_id}/` - this.pool = [ + const gsPool = [ { type: 301, typeName: '角色活动' }, { type: 302, typeName: '武器活动' }, { type: 200, typeName: '常驻' } - ] + ]; - this.typeName = { + const srPool = [ + { type: 11, typeName: '角色活动' }, + { type: 12, typeName: '武器活动' }, + { type: 2, typeName: '新手活动' }, + { type: 1, typeName: '常驻' } + ]; + + 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; } - async initXlsx () { + async initXlsx() { if (!lodash.isEmpty(xlsx)) return xlsx xlsx = await import('node-xlsx') } - async exportJson () { + async exportJson() { await this.getUid() if (!this.uid) return false @@ -71,10 +89,10 @@ export default class ExportLog extends base { }) /** 删除文件 */ - fs.unlink(saveFile, () => {}) + fs.unlink(saveFile, () => { }) } - async exportXlsx () { + async exportXlsx() { await this.getUid() if (!this.uid) return false @@ -109,10 +127,10 @@ export default class ExportLog extends base { if (res) this.e.reply(`${this.uid}.xlsx上传成功,共${line}条\n请接收文件`) /** 删除文件 */ - fs.unlink(saveFile, () => {}) + fs.unlink(saveFile, () => { }) } - async getUid () { + async getUid() { let gachLog = new GachaLog(this.e) let uid = await gachLog.getUid() @@ -122,7 +140,7 @@ export default class ExportLog extends base { return this.uid } - getAllList () { + getAllList() { let res = { list: [] } @@ -166,12 +184,12 @@ export default class ExportLog extends base { return res } - loadJson (json) { + loadJson(json) { if (!fs.existsSync(json)) return [] return JSON.parse(fs.readFileSync(json, 'utf8')) } - xlsxDataPool (data) { + xlsxDataPool(data) { let xlsxData = [] for (let v of this.pool) { @@ -195,7 +213,7 @@ export default class ExportLog extends base { return xlsxData } - xlsxDataAll (data) { + xlsxDataAll(data) { let list = [ [ 'count', 'gacha_type', 'id', 'item_id', 'item_type', 'lang', 'name', 'rank_type', 'time', 'uid', 'uigf_gacha_type' @@ -217,7 +235,7 @@ export default class ExportLog extends base { } /** xlsx导入抽卡记录 */ - async logXlsx () { + async logXlsx() { await this.initXlsx() let uid = /[1-9][0-9]{8}/g.exec(this.e.file.name)[0] @@ -234,13 +252,36 @@ export default class ExportLog extends base { let list = xlsx.parse(textPath) list = lodash.keyBy(list, 'name') - if (!list['原始数据']) { + // 适配StarRailExport导出的xlsx,该xlsx没有原始数据表. + let rawData = list['原始数据'] ? list['原始数据'] : list['rawData']; + if (!list['原始数据'] && list['rawData']) { + // 获取rawData的time字段(第9列)的索引 + const timeIndex = 8; + + // 对rawData进行排序(按照time字段,除第一行外) + const headerRow = rawData.data[0]; // 保存标题行 + const dataToSort = rawData.data.slice(1); // 除第一行外的数据 + + dataToSort.sort((a, b) => { + return moment(a[timeIndex]).format('x') - moment(b[timeIndex]).format('x'); + }); + + // 重新构建rawData的数据,包括标题行 + rawData.data = [headerRow, ...dataToSort]; + + // 将数据写回原文件,重新读取 + fs.writeFileSync(textPath, xlsx.build([rawData])); + list = lodash.keyBy(xlsx.parse(textPath), 'name'); + rawData = list['rawData']; + } + + if (!rawData) { this.e.reply('xlsx文件内容错误:非统一祈愿记录标准') return false } /** 处理xlsx数据 */ - let data = this.dealXlsx(list['原始数据'].data) + let data = this.dealXlsx(rawData.data); if (!data) return false /** 保存json */ @@ -256,12 +297,12 @@ export default class ExportLog extends base { } /** 删除文件 */ - fs.unlink(textPath, () => {}) + fs.unlink(textPath, () => { }) await this.e.reply(`${this.e.file.name},导入成功\n${msg.join('\n')}`) } - dealXlsx (list) { + dealXlsx(list) { /** 必要字段 */ let reqField = ['uigf_gacha_type', 'gacha_type', 'item_type', 'name', 'time'] /** 不是必要字段 */ @@ -272,6 +313,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]) { @@ -312,7 +358,7 @@ export default class ExportLog extends base { } /** json导入抽卡记录 */ - async logJson () { + async logJson() { let uid = /[1-9][0-9]{8}/g.exec(this.e.file.name)[0] let textPath = `${this.path}${this.e.file.name}` /** 获取文件下载链接 */ @@ -352,12 +398,12 @@ export default class ExportLog extends base { } /** 删除文件 */ - fs.unlink(textPath, () => {}) + fs.unlink(textPath, () => { }) await this.e.reply(`${this.e.file.name},导入成功\n${msg.join('\n')}`) } - dealJson (list) { + dealJson(list) { let data = {} /** 必要字段 */ @@ -370,12 +416,22 @@ 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 (!data[v.uigf_gacha_type]) data[v.uigf_gacha_type] = [] data[v.uigf_gacha_type].push(v) } diff --git a/plugins/genshin/model/gachaLog.js b/plugins/genshin/model/gachaLog.js index 9c41c0f..110d44f 100644 --- a/plugins/genshin/model/gachaLog.js +++ b/plugins/genshin/model/gachaLog.js @@ -10,27 +10,27 @@ export default class GachaLog extends base { super(e) this.model = 'gachaLog' + if (!e.isSr && e.msg) e.isSr = /\/(common|hkrpg)\//.test(e.msg) + this.urlKey = `${this.prefix}url:` /** 绑定的uid */ - this.uidKey = `Yz:genshin:mys:qq-uid:${this.userId}` - this.path = `./data/gachaJson/${this.e.user_id}/` - this.pool = [ + this.uidKey = this.e.isSr ? `Yz:srJson:mys:qq-uid:${this.userId}` : `Yz:genshin:mys:qq-uid:${this.userId}`; + 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: '常驻' } - ] + ]; - if (!e.isSr && e.msg) e.isSr = /\/(common|hkrpg)\//.test(e.msg) - if (e.isSr) { - this.uidKey = `Yz:srJson:mys:qq-uid:${this.userId}` - this.path = `./data/srJson/${this.e.user_id}/` - this.pool = [ - { type: 11, typeName: '角色' }, - { type: 12, typeName: '光锥' }, - { type: 1, typeName: '常驻' }, - { type: 2, typeName: '新手' } - ] - } + const srPool = [ + { type: 11, typeName: '角色' }, + { type: 12, typeName: '光锥' }, + { type: 1, typeName: '常驻' }, + { type: 2, typeName: '新手' } + ]; + + this.pool = e.isSr ? srPool : gsPool; } async logUrl () { @@ -409,7 +409,7 @@ export default class GachaLog extends base { logData.push(data) } if (logData.length === 0) { - this.e.reply('暂无抽卡记录\n#记录帮助,查看配置说明', false, { at: true }) + this.e.reply(`暂无抽卡记录\n${this.e?.isSr ? '*' : '#'}记录帮助,查看配置说明`, false, { at: true }) return true } for (let i of logData) {