Miao-Yunzai/plugins/genshin/model/user.js

498 lines
14 KiB
JavaScript
Raw Normal View History

2023-03-04 14:30:13 +08:00
import base from './base.js'
import gsCfg from './gsCfg.js'
import lodash from 'lodash'
import fs from 'node:fs'
import common from '../../../lib/common/common.js'
import MysInfo from './mys/mysInfo.js'
import NoteUser from './mys/NoteUser.js'
import MysUser from './mys/MysUser.js'
import { promisify } from 'node:util'
import YAML from 'yaml'
import { Data } from '#miao'
2023-06-01 03:28:35 +08:00
import { Player } from '#miao.models'
import { UserGameDB, sequelize } from './db/index.js'
2023-03-04 14:30:13 +08:00
export default class User extends base {
constructor (e) {
2023-03-04 14:30:13 +08:00
super(e)
this.model = 'bingCk'
/** 绑定的uid */
this.uidKey = `Yz:genshin:mys:qq-uid:${this.userId}`
/** 多角色uid */
this.allUid = []
if (this.e.isSr) {
/** 绑定的uid */
this.uidKey = `Yz:srJson:mys:qq-uid:${this.userId}`
}
2023-03-04 14:30:13 +08:00
}
// 获取当前user实例
async user () {
return await NoteUser.create(this.e)
2023-03-04 14:30:13 +08:00
}
async resetCk () {
2023-03-04 14:30:13 +08:00
let user = await this.user()
await user.initCache()
}
/** 绑定ck */
async bing () {
2023-03-04 14:30:13 +08:00
let user = await this.user()
let set = gsCfg.getConfig('mys', 'set')
2023-05-28 13:20:16 +08:00
if (this.ck && !this.e.ck) {
this.e.ck = this.ck
}
2023-03-04 14:30:13 +08:00
if (!this.e.ck) {
await this.e.reply(`请【私聊】发送米游社cookie获取教程\n${set.cookieDoc}`)
return
}
let ckStr = this.e.ck.replace(/#|'|"/g, '')
2023-03-04 14:30:13 +08:00
let param = {}
ckStr.split(';').forEach((v) => {
2023-03-04 14:30:13 +08:00
// 处理分割特殊cookie_token
let tmp = lodash.trim(v).replace('=', '~').split('~')
param[tmp[0]] = tmp[1]
})
if (!param.cookie_token && !param.cookie_token_v2) {
await this.e.reply('发送cookie不完整\n请退出米游社【重新登录】刷新完整cookie')
return
}
// TODO独立的mys数据不走缓存ltuid
2023-06-01 03:28:35 +08:00
let mys = await MysUser.create(param.ltuid || param.ltuid_v2 || param.ltmid_v2)
if (!mys) {
await this.e.reply('发送cookie不完整或数据错误')
return
}
let data = {}
data.ck = `ltoken=${param.ltoken};ltuid=${param.ltuid || param.login_uid};cookie_token=${param.cookie_token || param.cookie_token_v2}; account_id=${param.ltuid || param.login_uid};`
2023-03-04 14:30:13 +08:00
let flagV2 = false
2023-03-04 14:30:13 +08:00
if (param.cookie_token_v2 && (param.account_mid_v2 || param.ltmid_v2)) { //
// account_mid_v2 为版本必须带的字段不带的话会一直提示绑定cookie失败 请重新登录
flagV2 = true
data.ck = `ltuid=${param.ltuid || param.login_uid || param.ltuid_v2};account_mid_v2=${param.account_mid_v2};cookie_token_v2=${param.cookie_token_v2};ltoken_v2=${param.ltoken_v2};ltmid_v2=${param.ltmid_v2};`
2023-03-04 14:30:13 +08:00
}
2023-05-09 11:03:38 +08:00
if (param.mi18nLang) {
data.ck += ` mi18nLang=${param.mi18nLang};`
}
2023-03-04 14:30:13 +08:00
/** 拼接ck */
data.ltuid = param.ltuid || param.ltmid_v2
2023-03-04 14:30:13 +08:00
/** 米游币签到字段 */
data.login_ticket = param.login_ticket ?? ''
mys.setCkData(data)
2023-03-04 14:30:13 +08:00
/** 检查ck是否失效 */
2023-05-09 11:03:38 +08:00
let uidRet = await mys.reqMysUid()
if (uidRet.status !== 0) {
logger.mark(`绑定cookie错误1${this.checkMsg || 'cookie错误'}`)
// 清除mys数据
mys._delCache()
2023-05-09 11:03:38 +08:00
return await this.e.reply(`绑定cookie失败${this.checkMsg || 'cookie错误'}`)
2023-03-04 14:30:13 +08:00
}
if (flagV2) {
// 获取米游社通行证id
let userFullInfo = await mys.getUserFullInfo()
2023-03-04 14:30:13 +08:00
if (userFullInfo?.data?.user_info) {
let userInfo = userFullInfo?.data?.user_info
2023-06-01 03:28:35 +08:00
this.ltuid = userInfo.uid || this.ltuid
this.ck = `${this.ck}ltuid=${this.ltuid};`
2023-03-04 14:30:13 +08:00
} else {
logger.mark(`绑定cookie错误2${userFullInfo.message || 'cookie错误'}`)
2023-05-09 11:03:38 +08:00
return await this.e.reply(`绑定cookie失败${userFullInfo.message || 'cookie错误'}`)
2023-03-04 14:30:13 +08:00
}
}
logger.mark(`${this.e.logFnc} 检查cookie正常 [ltuid:${mys.ltuid}]`)
2023-03-04 14:30:13 +08:00
await user.addMysUser(mys)
await mys.initCache()
2023-05-09 11:03:38 +08:00
await user.save()
2023-03-04 14:30:13 +08:00
logger.mark(`${this.e.logFnc} 保存cookie成功 [ltuid:${mys.ltuid}]`)
2023-03-04 14:30:13 +08:00
2023-06-01 03:28:35 +08:00
let uidMsg = [`绑定cookie成功`, mys.getUidInfo()]
2023-03-04 14:30:13 +08:00
await this.e.reply(uidMsg.join('\n'))
2023-06-01 03:28:35 +08:00
let msg = []
if (mys.hasGame('gs')) {
2023-06-01 03:28:35 +08:00
msg.push(
'原神模块支持:',
'【#uid】当前绑定ck uid列表',
'【#我的ck】查看当前绑定ck',
'【#删除ck】删除当前绑定ck',
'【#体力】查询当前树脂',
'【#原石】查看原石札记',
'【#原石统计】原石统计数据',
'【#练度统计】技能统计列表',
'【#面板】【#更新面板】面板信息'
)
}
if (mys.hasGame('sr')) {
2023-06-01 03:28:35 +08:00
msg.push(
'星穹铁道支持:',
'【*uid】当前绑定ck uid列表',
'【*体力】体力信息',
'【*面板】【*更新面板】面板信息'
)
}
2023-06-01 03:28:35 +08:00
msg = await common.makeForwardMsg(this.e, ['使用命令说明', msg.join('\n')], '绑定成功:使用命令说明')
2023-03-04 14:30:13 +08:00
await this.e.reply(msg)
}
/** 删除绑定ck */
async delCk () {
2023-03-04 14:30:13 +08:00
let user = await this.user()
// 获取当前uid
2023-06-01 03:28:35 +08:00
let uidData = user.getUidData('', this.e)
if (!uidData || uidData.type !== 'ck' || !uidData.ltuid) {
2023-06-01 03:28:35 +08:00
return `删除失败当前的UID${uidData?.uid}无CK信息`
}
2023-06-01 03:28:35 +08:00
let mys = await MysUser.create(uidData.ltuid)
if (!mys) {
return `删除失败当前的UID${uidData?.uid}无CK信息`
}
let msg = [`绑定cookie已删除`, mys.getUidInfo()]
2023-05-11 06:08:03 +08:00
await user.delMysUser(uidData.ltuid)
2023-06-01 03:28:35 +08:00
return msg.join('\n')
2023-03-04 14:30:13 +08:00
}
/** 绑定uid若有ck的话优先使用ck-uid */
async bingUid () {
2023-03-04 14:30:13 +08:00
let uid = this.e.msg.match(/[1|2|5-9][0-9]{8}/g)
if (!uid) return
uid = uid[0]
let user = await this.user()
2023-05-28 15:25:23 +08:00
await user.addRegUid(uid, this.e)
return await this.showUid()
}
async delUid (index) {
let user = await this.user()
let game = this.e
let uidList = user.getUidList(game)
if (index > uidList.length) {
return await this.e.reply('uid序号输入错误')
}
index = Number(index) - 1
let uidObj = uidList[index]
if (uidObj.type === 'ck') {
return await this.e.reply('CK对应UID无法直接删除请通过【#删除ck】命令来删除')
}
await user.delRegUid(uidObj.uid, game)
return await this.showUid()
2023-03-04 14:30:13 +08:00
}
/** #uid */
async showUid () {
2023-03-04 14:30:13 +08:00
let user = await this.user()
let msg = []
2023-05-28 15:25:23 +08:00
let typeMap = { ck: 'CK Uid', reg: '绑定 Uid' }
lodash.forEach({ gs: '原神 (#uid)', sr: '星穹铁道 (*uid)' }, (gameName, game) => {
let uidList = user.getUidList(game)
let currUid = user.getUid(game)
2023-05-28 15:25:23 +08:00
msg.push(`${gameName}`)
if (uidList.length === 0) {
2023-05-28 15:25:23 +08:00
msg.push(`暂无,通过${game === 'gs' ? '#' : '*'}绑定123456789来绑定UID`)
return true
}
lodash.forEach(uidList, (ds, idx) => {
2023-05-28 15:25:23 +08:00
let tmp = `${++idx}: ${ds.uid} (${typeMap[ds.type]})`
if (currUid * 1 === ds.uid * 1) {
tmp += ' ☑'
}
msg.push(tmp)
})
})
2023-05-28 15:25:23 +08:00
msg.unshift('通过【#uid+序号】来切换uid【#删除uid+序号】删除uid')
await this.e.reply(msg.join('\n'))
2023-03-04 14:30:13 +08:00
}
2023-06-01 03:28:35 +08:00
/** #uid */
async showUid2 () {
let user = await this.user()
let uids = [{
key: 'gs',
name: '原神'
}, {
key: 'sr',
name: '星穹铁道'
}]
lodash.forEach(uids, (ds) => {
ds.uidList = user.getUidList(ds.key)
ds.uid = user.getUid(ds.key)
lodash.forEach(ds.uidList, (uidDs) => {
let player = Player.create(uidDs.uid, ds.key)
if (player) {
uidDs.name = player.name
uidDs.level = player.level
}
})
})
let e = this.e
return e.runtime.render('genshin', 'html/user/uid-list', {
uids
})
}
2023-03-04 14:30:13 +08:00
/** 切换uid */
async toggleUid (index) {
2023-03-04 14:30:13 +08:00
let user = await this.user()
let game = this.e
let uidList = user.getUidList(game)
2023-03-04 14:30:13 +08:00
if (index > uidList.length) {
return await this.e.reply('uid序号输入错误')
}
index = Number(index) - 1
user.setMainUid(index, game)
2023-05-09 11:03:38 +08:00
await user.save()
return await this.showUid()
2023-03-04 14:30:13 +08:00
}
/** 加载V2ck */
async loadOldDataV2 () {
2023-03-04 14:30:13 +08:00
let file = [
'./data/MysCookie/NoteCookie.json',
'./data/NoteCookie/NoteCookie.json',
'./data/NoteCookie.json'
]
let json = file.find(v => fs.existsSync(v))
if (!json) return
let list = JSON.parse(fs.readFileSync(json, 'utf8'))
let arr = {}
logger.mark(logger.green('加载用户ck...'))
lodash.forEach(list, (ck, qq) => {
if (ck.qq) qq = ck.qq
let isMain = false
if (!arr[qq]) {
arr[qq] = {}
isMain = true
}
let param = {}
ck.cookie.split(';').forEach((v) => {
let tmp = lodash.trim(v).split('=')
param[tmp[0]] = tmp[1]
})
let ltuid = param.ltuid
if (!param.cookie_token) return
arr[qq][String(ck.uid)] = {
uid: ck.uid,
qq,
ck: ck.cookie,
ltuid,
isMain
2023-03-04 14:30:13 +08:00
}
})
let count = await this.loadOldData(arr)
if (count > 0) {
logger.mark(logger.green(`DB导入V2用户ck${count}`))
}
fs.unlinkSync(json)
}
2023-03-04 14:30:13 +08:00
/** 加载V3ck */
async loadOldDataV3 () {
let dir = './data/MysCookie/'
if (!fs.existsSync(dir)) {
return false
}
2023-05-28 15:25:23 +08:00
Data.createDir('./temp/MysCookieBak')
let files = fs.readdirSync(dir).filter(file => file.endsWith('.yaml'))
const readFile = promisify(fs.readFile)
let promises = []
2023-05-28 15:25:23 +08:00
if (files.length === 0) {
fs.rmdirSync('./data/MysCookie/')
return
}
files.forEach((v) => promises.push(readFile(`${dir}${v}`, 'utf8')))
const res = await Promise.all(promises)
let ret = {}
for (let v of res) {
v = YAML.parse(v)
let qq
for (let k in v) {
qq = qq || v[k]?.qq
}
if (qq) {
ret[qq] = v
}
}
let count = await this.loadOldData(ret)
if (count > 0) {
logger.mark(logger.green(`DB导入V3用户ck${count}`))
}
}
2023-03-04 14:30:13 +08:00
async loadOldUid () {
// 从DB中导入
await sequelize.query(`delete from UserGames where userId is null or data is null`, {})
let games = await UserGameDB.findAll()
let count = 0
await Data.asyncPool(20, games, async (game) => {
if (!game.userId) {
game.destroy()
return true
}
count++
let user = await NoteUser.create(game.userId)
if (game.userId && game.data) {
lodash.forEach(game.data, (ds) => {
let { uid } = ds
user.addRegUid(uid, game.game, false)
})
}
if (game.uid) {
user.setMainUid(game.uid, game.game, false)
}
await user.save()
await game.destroy()
})
// 从Redis中导入
let keys = await redis.keys('Yz:genshin:mys:qq-uid:*')
for (let key of keys) {
let uid = await redis.get(key)
let qqRet = /Yz:genshin:mys:qq-uid:(\d{5,12})/.exec(key)
if (qqRet?.[1] && uid) {
let user = await NoteUser.create(qqRet[1])
if (!user.getUid('gs')) {
user.addRegUid(uid, 'gs')
}
}
redis.del(key)
}
await sequelize.query(`delete from Users where (ltuids is null or ltuids='') and games is null`, {})
console.log('load Uid Data Done...')
}
async loadOldData (data) {
let count = 0
if (!lodash.isPlainObject(data)) {
return
}
for (let u in data) {
let ltuids = {}
let v = data[u]
let qq
for (let k in v) {
let data = v[k]
qq = qq || data?.qq
let { uid, ck, ltuid, region_name: region, device_id: device } = data
ltuids[ltuid] = ltuids[ltuid] || {
ck,
device,
ltuid,
uids: {},
type: /America Server|Europe Server|Asia Server/.test(region) ? 'hoyolab' : 'mys'
}
let tmp = ltuids[ltuid]
let game = region === '星穹列车' ? 'sr' : 'gs'
tmp.uids[game] = tmp.uids[game] || []
let gameUids = tmp.uids[game]
if (!gameUids.includes(uid + '')) {
gameUids.push(uid + '')
}
}
if (!qq) {
continue
}
let user = await NoteUser.create(qq)
for (let ltuid in ltuids) {
let data = ltuids[ltuid]
let mys = await MysUser.create(data.ltuid)
if (mys) {
mys.setCkData(data)
2023-05-09 11:03:38 +08:00
await mys.save()
user.addMysUser(mys)
}
}
2023-05-09 11:03:38 +08:00
await user.save()
if (fs.existsSync(`./data/MysCookie/${qq}.yaml`)) {
try {
let src = `./data/MysCookie/${qq}.yaml`;
let dest = `./temp/MysCookieBak/${qq}.yaml`;
await fs.promises.unlink(dest).catch((_) => { });
await fs.promises.copyFile(src, dest);
await fs.promises.unlink(src);
} catch (err) {
console.log(err);
}
}
count++
}
2023-03-04 14:30:13 +08:00
}
/** 我的ck */
async myCk () {
2023-03-04 14:30:13 +08:00
let user = await this.user()
if (!user.hasCk) {
this.e.reply('当前尚未绑定cookie')
}
2023-05-11 06:08:03 +08:00
let mys = user.getMysUser(this.e)
if (mys) {
await this.e.reply(`当前绑定cookie\nuid${mys.getUid(this.e)}`)
await this.e.reply(mys.ck)
2023-03-04 14:30:13 +08:00
}
}
async checkCkStatus () {
2023-03-04 14:30:13 +08:00
let user = await this.user()
if (!user.hasCk) {
await this.e.reply(`\n未绑定CK当前绑定uid${user.uid || '无'}`, false, { at: true })
return true
}
let uid = user.uid * 1
let uids = user.ckUids
let checkRet = await user.checkCk()
let cks = []
lodash.forEach(checkRet, (ds, idx) => {
let tmp = [`\n#${idx + 1}: [CK:${ds.ltuid}] - 【${ds.status === 0 ? '正常' : '失效'}`]
if (ds.uids && ds.uids.length > 0) {
let dsUids = []
lodash.forEach(ds.uids, (u) => {
dsUids.push(u * 1 === uid ? `${u}` : u)
})
tmp.push(`绑定UID: [ ${dsUids.join(', ')} ]`)
}
if (ds.status !== 0) {
tmp.push(ds.msg)
}
cks.push(tmp.join('\n'))
})
if (uids.length > 1) {
cks.push(`当前生效uid${uid}\n通过【#uid】命令可查看并切换UID`)
}
await this.e.reply(cks.join('\n----\n'), false, { at: true })
}
async userAdmin () {
2023-03-04 14:30:13 +08:00
this.model = 'userAdmin'
await MysInfo.initCache()
let stat = await MysUser.getStatData()
return {
saveId: 'user-admin',
...stat,
_plugin: 'genshin',
...this.screenData
}
}
}