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

409 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 MysUser from './mys/MysUser.js'
import MysInfo from './mys/mysInfo.js'
export default class User extends base {
constructor (e) {
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}`
}
}
// 获取当前user实例
async user () {
return await MysInfo.getNoteUser(this.e)
}
async resetCk () {
let user = await this.user()
await user.initCache()
}
/** 绑定ck */
async bing () {
let user = await this.user()
let set = gsCfg.getConfig('mys', 'set')
if (!this.e.ck) {
await this.e.reply(`请【私聊】发送米游社cookie获取教程\n${set.cookieDoc}`)
return
}
let ck = this.e.ck.replace(/#|'|"/g, '')
let param = {}
ck.split(';').forEach((v) => {
// 处理分割特殊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
}
this.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};`
let flagV2 = false
if (param.cookie_token_v2 && (param.account_mid_v2 || param.ltmid_v2)) { //
// account_mid_v2 为版本必须带的字段不带的话会一直提示绑定cookie失败 请重新登录
flagV2 = true
this.ck = `account_mid_v2=${param.account_mid_v2};cookie_token_v2=${param.cookie_token_v2};ltoken_v2=${param.ltoken_v2};ltmid_v2=${param.ltmid_v2};`
}
/** 拼接ck */
this.ltuid = param.ltuid || param.ltmid_v2
/** 米游币签到字段 */
this.login_ticket = param.login_ticket ?? ''
/** 检查ck是否失效 */
if (!await this.checkCk(param)) {
logger.mark(`绑定cookie错误1${this.checkMsg || 'cookie错误'}`)
await this.e.reply(`绑定cookie失败${this.checkMsg || 'cookie错误'}`)
return
}
if (flagV2) {
// 获取米游社通行证id
let userFullInfo = await this.getUserInfo()
if (userFullInfo?.data?.user_info) {
let userInfo = userFullInfo?.data?.user_info
this.ltuid = userInfo.uid
this.ck = `${this.ck}ltuid=${this.ltuid};`
} else {
logger.mark(`绑定cookie错误2${userFullInfo.message || 'cookie错误'}`)
await this.e.reply(`绑定cookie失败${userFullInfo.message || 'cookie错误'}`)
return
}
}
logger.mark(`${this.e.logFnc} 检查cookie正常 [uid:${this.uid}]`)
await user.addCk(this.getCk())
logger.mark(`${this.e.logFnc} 保存cookie成功 [uid:${this.uid}] [ltuid:${this.ltuid}]`)
let uidMsg = [`绑定cookie成功\n${this.region_name}${this.uid}`]
if (!lodash.isEmpty(this.allUid)) {
this.allUid.forEach(v => {
uidMsg.push(`${v.region_name}${v.uid}`)
})
}
await this.e.reply(uidMsg.join('\n'))
let msg = ''
this.region_name += lodash.map(this.allUid, 'region_name').join(',')
if (/天空岛|世界树|America Server|Europe Server|Asia Server/.test(this.region_name)) {
msg += '原神模块支持:\n【#体力】查询当前树脂'
msg += '\n【#签到】米游社原神自动签到'
msg += '\n【#关闭签到】开启或关闭原神自动签到'
msg += '\n【#原石】查看原石札记'
msg += '\n【#原石统计】原石统计数据'
msg += '\n【#练度统计】技能统计列表'
msg += '\n【#uid】当前绑定ck uid列表'
msg += '\n【#ck】检查当前用户ck是否有效'
msg += '\n【#我的ck】查看当前绑定ck'
msg += '\n【#删除ck】删除当前绑定ck'
}
if (/星穹列车/.test(this.region_name)) {
msg += '\n星穹铁道支持\n功能还在咕咕咕~'
}
msg += '\n 支持绑定多个ck'
msg = await common.makeForwardMsg(this.e, ['使用命令说明', msg], '绑定成功:使用命令说明')
await this.e.reply(msg)
}
/** 检查ck是否可用 */
async checkCk (param) {
let res
for (let type of ['mys', 'hoyolab']) {
let roleRes = await this.getGameRoles(type)
if (roleRes?.retcode === 0) {
res = roleRes
/** 国际服的标记 */
if (type === 'hoyolab' && typeof (param.mi18nLang) === 'string') {
this.ck += ` mi18nLang=${param.mi18nLang};`
}
break
}
if (roleRes.retcode === -100) {
this.checkMsg = '该ck已失效请重新登录获取'
} else {
this.checkMsg = roleRes.message || 'error'
}
}
if (!res) return false
if (!res.data.list || res.data.list.length <= 0) {
this.checkMsg = '该账号尚未绑定原神或星穹角色!'
return false
} else {
res.data.list = res.data.list.filter(v => ['hk4e_cn', 'hkrpg_cn', 'hk4e_global', 'hkrpg_global'].includes(v.game_biz))
}
//避免同时多个默认展示角色时候只绑定一个
let is_chosen = false
/** 米游社默认展示的角色 */
for (let val of res.data.list) {
if (val.is_chosen && !is_chosen) {
this.uid = val.game_uid
this.region_name = val.region_name
is_chosen = true
} else {
this.allUid.push({
uid: val.game_uid,
region_name: val.region_name
})
}
}
if (!this.uid && res.data?.list?.length > 0) {
this.uid = res.data.list[0].game_uid
this.region_name = res.data.list[0].region_name
if (this.allUid[0].uid == this.uid) delete this.allUid[0]
}
return this.uid
}
async getGameRoles (server = 'mys') {
return await MysUser.getGameRole(this.ck, server)
}
// 获取米游社通行证id
async getUserInfo (server = 'mys') {
return await MysUser.getUserFullInfo(this.ck, server)
}
/** 保存ck */
getCk () {
let ck = gsCfg.getBingCkSingle(this.e.user_id)
lodash.map(ck, o => {
o.isMain = false
return o
})
ck[this.uid] = {
uid: this.uid,
qq: this.e.user_id,
ck: this.ck,
ltuid: this.ltuid,
login_ticket: this.login_ticket,
region_name: this.region_name,
device_id: this.getGuid(),
isMain: true
}
this.allUid.forEach((v) => {
if (!v.uid) return
ck[v.uid] = {
uid: v.uid,
qq: this.e.user_id,
ck: this.ck,
ltuid: this.ltuid,
region_name: v.region_name,
device_id: this.getGuid(),
isMain: false
}
})
return ck
}
/** 删除绑定ck */
async delCk (uid = '') {
let user = await this.user()
let uids = await user.delCk()
return `绑定cookie已删除,uid:${uids.join(',')}`
}
/** 绑定uid若有ck的话优先使用ck-uid */
async bingUid () {
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()
await user.setRegUid(uid, true)
return await this.e.reply(`绑定成功uid:${uid}`, false, { at: true })
}
/** #uid */
async showUid () {
let user = await this.user()
if (!user.hasCk) {
await this.e.reply(`当前绑定uid${user.uid || '无'}`, false, { at: true })
return
}
let uids = user.ckUids
let ckData = user.ckData
let uid = user.uid * 1
let msg = [`当前uid${uid}`, '当前绑定cookie Uid列表', '通过【#uid+序号】来切换uid']
let region_name = []
Object.keys(ckData).forEach((v) => {
if (!region_name.includes(ckData[v].region_name)) {
region_name.push(ckData[v].region_name)
}
})
let count = 0
for (let n of region_name) {
msg.push(n)
for (let i in uids) {
if (ckData[uids[i]].region_name == n) {
let tmp = `${++count}: ${uids[i]}`
if (uids[i] * 1 === uid) {
tmp += ' ☑'
}
msg.push(tmp)
}
}
}
await this.e.reply(msg.join('\n'))
}
/** 切换uid */
async toggleUid (index) {
let user = await this.user()
let uidList = user.ckUids
if (index > uidList.length) {
return await this.e.reply('uid序号输入错误')
}
index = Number(index) - 1
await user.setMainUid(index)
return await this.e.reply(`切换成功当前uid${user.uid}`)
}
/** 加载旧ck */
async loadOldData () {
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,
device_id: this.getGuid()
}
})
lodash.forEach(arr, (ck, qq) => {
let saveFile = `./data/MysCookie/${qq}.yaml`
if (fs.existsSync(saveFile)) return
gsCfg.saveBingCk(qq, ck)
})
logger.mark(logger.green(`加载用户ck完成${lodash.size(arr)}`))
fs.unlinkSync(json)
}
/** 我的ck */
async myCk () {
let user = await this.user()
if (!user.hasCk) {
this.e.reply('当前尚未绑定cookie')
}
let ck = user.mainCk
if (!lodash.isEmpty(ck)) {
await this.e.reply(`当前绑定cookie\nuid${ck.uid}`)
await this.e.reply(ck.ck)
}
}
async checkCkStatus () {
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 })
}
getGuid () {
function S4 () {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
}
return (S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4())
}
async userAdmin () {
this.model = 'userAdmin'
await MysInfo.initCache()
let stat = await MysUser.getStatData()
return {
saveId: 'user-admin',
...stat,
_plugin: 'genshin',
...this.screenData
}
}
}