适配星铁抽卡记录导入导出,修正“留影叙佳期”正则 (#274)
* 修正留影叙佳期正则,降低触发频率 * 适配星铁抽卡记录导出 * 适配Github - biuuu原神/星铁抽卡导出工具的抽卡记录导入 --------- Co-authored-by: James <qgj087388718@163.com> Co-authored-by: Kokomi <102026640+yoimiya-kokomi@users.noreply.github.com>
This commit is contained in:
parent
18e8a8efa1
commit
60a82526cd
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue