mirror of
https://github.com/ZZZure/ZZZ-Plugin.git
synced 2025-12-16 13:17:32 +00:00
feat: base panel
This commit is contained in:
parent
cbef7478c2
commit
ac0c3d0d6c
12 changed files with 361 additions and 149 deletions
105
lib/avatar.js
Normal file
105
lib/avatar.js
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
import { ZZZAvatarBasic, ZZZAvatarInfo } from '../model/avatar.js';
|
||||
import MysZZZApi from './mysapi.js';
|
||||
import { getPanelData, savePanelData } from './db.js';
|
||||
import { char } from './convert.js';
|
||||
|
||||
/**
|
||||
* 获取角色基础信息列表
|
||||
* @param {*} e 消息事件
|
||||
* @param {MysZZZApi} api
|
||||
* @param {string} deviceFp
|
||||
* @param {boolean} origin 是否返回原始数据
|
||||
* @returns {Promise<ZZZAvatarBasic[] | null>}
|
||||
*/
|
||||
export async function getAvatarBasicList(e, api, deviceFp, origin = false) {
|
||||
const avatarBaseListData = await api.getFinalData(e, 'zzzAvatarList', {
|
||||
deviceFp,
|
||||
});
|
||||
if (!avatarBaseListData) return null;
|
||||
if (origin) return avatarBaseListData.avatar_list;
|
||||
const result = avatarBaseListData.avatar_list.map(
|
||||
item => new ZZZAvatarBasic(item)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色详细信息列表
|
||||
* @param {*} e 消息事件
|
||||
* @param {MysZZZApi} api
|
||||
* @returns {Promise<ZZZAvatarInfo[] | null>}
|
||||
* @param {string} deviceFp
|
||||
* @param {boolean} origin 是否返回原始数据
|
||||
*/
|
||||
export async function getAvatarInfoList(e, api, deviceFp, origin = false) {
|
||||
const avatarBaseList = await getAvatarBasicList(e, api, deviceFp, origin);
|
||||
if (!avatarBaseList) return null;
|
||||
const avatarInfoList = await api.getFinalData(e, 'zzzAvatarInfo', {
|
||||
deviceFp,
|
||||
query: {
|
||||
id_list: avatarBaseList.map(item => item.id),
|
||||
},
|
||||
});
|
||||
if (!avatarInfoList) return null;
|
||||
if (origin) return avatarInfoList.avatar_list;
|
||||
const result = avatarInfoList.avatar_list.map(
|
||||
item => new ZZZAvatarInfo(item)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新面板
|
||||
* @param {*} e 消息事件
|
||||
* @param {MysZZZApi} api
|
||||
* @param {string} uid
|
||||
* @param {string} deviceFp
|
||||
* @returns {Promise<ZZZAvatarInfo[] | null>}
|
||||
*/
|
||||
export async function refreshPanel(e, api, uid, deviceFp) {
|
||||
const originData = getPanelData(uid);
|
||||
const newData = await getAvatarInfoList(e, api, deviceFp, true);
|
||||
if (!newData) return null;
|
||||
const finalData = [...newData];
|
||||
if (originData) {
|
||||
for (const item of originData) {
|
||||
if (!finalData.find(i => i.id === item.id)) {
|
||||
finalData.push(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
savePanelData(uid, finalData);
|
||||
finalData.forEach(item => {
|
||||
item.isNew = newData.find(i => i.id === item.id);
|
||||
});
|
||||
const formattedData = finalData.map(item => new ZZZAvatarInfo(item));
|
||||
for (const item of formattedData) {
|
||||
await item.get_basic_assets();
|
||||
}
|
||||
return formattedData;
|
||||
}
|
||||
|
||||
/**
|
||||
*获取面板数据
|
||||
* @param {string} uid
|
||||
* @returns {ZZZAvatarInfo[]}
|
||||
*/
|
||||
export function getPanelList(uid) {
|
||||
const data = getPanelData(uid);
|
||||
return data.map(item => new ZZZAvatarInfo(item));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某个角色的面板数据
|
||||
* @param {string} uid
|
||||
* @param {string} name
|
||||
* @returns {ZZZAvatarInfo | null}
|
||||
*/
|
||||
export function getPanel(uid, name) {
|
||||
logger.debug('获取面板数据', uid, name);
|
||||
const data = getPanelData(uid).map(item => new ZZZAvatarInfo(item));
|
||||
const id = char.atlasToID(name);
|
||||
logger.debug('获取角色ID', id);
|
||||
if (!id) return null;
|
||||
return data.find(item => item.id === id) || null;
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ const PartnerId2SpriteId = getMapData('PartnerId2Data');
|
|||
|
||||
/**
|
||||
*
|
||||
* @param {string} id
|
||||
* @param {string | number} id
|
||||
* @param {boolean} full 显示全称
|
||||
* @param {boolean} en 是否为英文
|
||||
* @returns string | null
|
||||
|
|
@ -21,7 +21,7 @@ export const IDToCharName = (id, full = true, en = false) => {
|
|||
|
||||
/**
|
||||
*
|
||||
* @param {string} id
|
||||
* @param {string | number} id
|
||||
* @returns string | null
|
||||
*/
|
||||
export const IDToCharSprite = id => {
|
||||
|
|
@ -32,11 +32,11 @@ export const IDToCharSprite = id => {
|
|||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @returns string | null
|
||||
* @returns number | null
|
||||
*/
|
||||
export const charNameToID = name => {
|
||||
for (const [id, data] of Object.entries(PartnerId2SpriteId)) {
|
||||
if (data['full_name'] === name) return id;
|
||||
if (data['name'] === name) return Number(id);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
|
@ -47,7 +47,7 @@ export const charNameToID = name => {
|
|||
*/
|
||||
export const charNameToSprite = name => {
|
||||
for (const [_id, data] of Object.entries(PartnerId2SpriteId)) {
|
||||
if (data['full_name'] === name) return data['sprite'];
|
||||
if (data['name'] === name) return data['sprite'];
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
|
@ -70,21 +70,16 @@ export const atlasToName = _atlas => {
|
|||
* @returns string | null
|
||||
*/
|
||||
export const atlasToSprite = _atlas => {
|
||||
const atlas = settings.getConfig('atlas');
|
||||
for (const [_id, data] of Object.entries(atlas)) {
|
||||
if (data.includes(_atlas)) return data['sprite'];
|
||||
}
|
||||
return null;
|
||||
const name = atlasToName(name);
|
||||
return charNameToSprite(name);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @returns string | null
|
||||
* @returns number | null
|
||||
*/
|
||||
export const atlasToID = name => {
|
||||
const atlas = settings.getConfig('atlas');
|
||||
for (const [id, data] of Object.entries(atlas)) {
|
||||
if (data.includes(name)) return charNameToID(id);
|
||||
}
|
||||
return null;
|
||||
const _name = atlasToName(name);
|
||||
const id = charNameToID(_name);
|
||||
return id;
|
||||
};
|
||||
|
|
|
|||
19
lib/db.js
19
lib/db.js
|
|
@ -4,13 +4,14 @@ import { checkFolderExistAndCreate } from '../utils/file.js';
|
|||
import { dataPath } from './path.js';
|
||||
const dbPath = {
|
||||
gacha: 'gacha',
|
||||
panel: 'panel',
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} dbName
|
||||
* @param {string} dbFile
|
||||
* @returns {object}
|
||||
* @returns {object | Array<object> | null}
|
||||
*/
|
||||
export function getDB(dbName, dbFile) {
|
||||
const db = dbPath[dbName];
|
||||
|
|
@ -57,3 +58,19 @@ export function getGachaLog(uid) {
|
|||
export function saveGachaLog(uid, data) {
|
||||
setDB('gacha', uid, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} uid
|
||||
* @returns {Array<object>}
|
||||
*/
|
||||
export function getPanelData(uid) {
|
||||
return getDB('panel', uid) || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} uid
|
||||
* @param {Array<object>} data
|
||||
*/
|
||||
export function savePanelData(uid, data) {
|
||||
setDB('panel', uid, data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,24 @@ export default class MysZZZApi extends MysApi {
|
|||
dsSalt = '',
|
||||
} = urlMap[type];
|
||||
if (query) url += `?${query}`;
|
||||
if (data.query) {
|
||||
let str = '';
|
||||
for (let key in data.query) {
|
||||
if (data.query[key] === undefined) continue;
|
||||
else if (data.query[key] === null) str += `${key}&`;
|
||||
else if (Array.isArray(data.query[key])) {
|
||||
data.query[key].forEach(item => {
|
||||
str += `${key}[]=${item}&`;
|
||||
});
|
||||
} else str += `${key}=${data.query[key]}&`;
|
||||
}
|
||||
str = str.slice(0, -1);
|
||||
if (url.includes('?')) {
|
||||
url += `&${str}`;
|
||||
} else {
|
||||
url += `?${str}`;
|
||||
}
|
||||
}
|
||||
if (body) body = JSON.stringify(body);
|
||||
|
||||
let headers = this.getHeaders(query, body);
|
||||
|
|
@ -96,6 +114,7 @@ export default class MysZZZApi extends MysApi {
|
|||
body = JSON.stringify(body);
|
||||
}
|
||||
}
|
||||
logger.debug(`[mysapi]请求url:${url}`);
|
||||
return { url, headers, body };
|
||||
}
|
||||
|
||||
|
|
@ -168,7 +187,7 @@ export default class MysZZZApi extends MysApi {
|
|||
*/
|
||||
async checkCode(e, res, type, data = {}) {
|
||||
if (!res || !e) {
|
||||
this.e.reply('米游社接口请求失败,暂时无法查询');
|
||||
e.reply('米游社接口请求失败,暂时无法查询');
|
||||
return false;
|
||||
}
|
||||
this.e = e;
|
||||
|
|
@ -221,6 +240,20 @@ export default class MysZZZApi extends MysApi {
|
|||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取米游社数据
|
||||
* @param {*} e 消息e
|
||||
* @param {keyof ZZZApiTool['zzzUrlMap']} type 请求类型
|
||||
* @param {{deviceFp: string; query: Record<string, any>; headers: object;}} data
|
||||
* @param {boolean} cached
|
||||
*/
|
||||
async getFinalData(e, type, data = {}, cached = false) {
|
||||
const result = await this.getData(type, data, cached);
|
||||
const _data = await this.checkCode(e, result, type, {});
|
||||
if (!_data || _data.retcode !== 0) return false;
|
||||
return _data.data;
|
||||
}
|
||||
}
|
||||
|
||||
export function randomString(length) {
|
||||
|
|
|
|||
|
|
@ -15,29 +15,60 @@ export default class ZZZApiTool {
|
|||
this.server = server;
|
||||
this.game = 'zzz';
|
||||
this.uuid = crypto.randomUUID();
|
||||
if (['prod_gf_cn'].includes(this.server)) {
|
||||
this.host = 'https://api-takumi.mihoyo.com/';
|
||||
this.hostRecord = 'https://api-takumi-record.mihoyo.com/';
|
||||
this.hostPublicData = 'https://public-data-api.mihoyo.com/';
|
||||
} else {
|
||||
this.host = 'https://sg-public-api.hoyolab.com/';
|
||||
this.hostRecord = 'https://bbs-api-os.hoyolab.com/';
|
||||
this.hostPublicData = 'https://sg-public-data-api.hoyoverse.com/';
|
||||
}
|
||||
this.zzzUrlMap = {
|
||||
zzzUser: {
|
||||
url: `${this.host}binding/api/getUserGameRolesByCookie`,
|
||||
query: `game_biz=nap_cn®ion=${this.server}&game_uid=${this.uid}`,
|
||||
},
|
||||
zzzNote: {
|
||||
url: `${this.hostRecord}event/game_record_zzz/api/zzz/note`,
|
||||
query: `role_id=${this.uid}&server=${this.server}`,
|
||||
},
|
||||
zzzIndex: {
|
||||
url: `${this.hostRecord}event/game_record_zzz/api/zzz/index`,
|
||||
query: `role_id=${this.uid}&server=${this.server}`,
|
||||
},
|
||||
zzzAvatarList: {
|
||||
url: `${this.hostRecord}event/game_record_zzz/api/zzz/avatar/basic`,
|
||||
query: `role_id=${this.uid}&server=${this.server}`,
|
||||
},
|
||||
zzzAvatarInfo: {
|
||||
url: `${this.hostRecord}event/game_record_zzz/api/zzz/avatar/info`,
|
||||
query: `role_id=${this.uid}&server=${this.server}&need_wiki=false`,
|
||||
},
|
||||
zzzBuddyList: {
|
||||
url: `${this.hostRecord}event/game_record_zzz/api/zzz/buddy/info`,
|
||||
query: `role_id=${this.uid}&server=${this.server}`,
|
||||
},
|
||||
zzzAuthKey: {
|
||||
url: `${this.host}binding/api/genAuthKey`,
|
||||
body: {
|
||||
auth_appid: 'webview_gacha',
|
||||
game_biz: 'nap_cn',
|
||||
game_uid: this.uid * 1,
|
||||
region: this.server,
|
||||
},
|
||||
dsSalt: 'web',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
getUrlMap = (data = {}) => {
|
||||
let host, hostRecord, hostPublicData;
|
||||
if (['prod_gf_cn'].includes(this.server)) {
|
||||
host = 'https://api-takumi.mihoyo.com/';
|
||||
hostRecord = 'https://api-takumi-record.mihoyo.com/';
|
||||
hostPublicData = 'https://public-data-api.mihoyo.com/';
|
||||
} else {
|
||||
host = 'https://sg-public-api.hoyolab.com/';
|
||||
hostRecord = 'https://bbs-api-os.hoyolab.com/';
|
||||
hostPublicData = 'https://sg-public-data-api.hoyoverse.com/';
|
||||
}
|
||||
let urlMap = {
|
||||
zzz: {
|
||||
...(['prod_gf_cn'].includes(this.server)
|
||||
? {
|
||||
zzzUser: {
|
||||
url: `${host}binding/api/getUserGameRolesByCookie`,
|
||||
query: `game_biz=nap_cn®ion=${this.server}&game_uid=${this.uid}`,
|
||||
},
|
||||
getFp: {
|
||||
url: `${hostPublicData}device-fp/api/getFp`,
|
||||
url: `${this.hostPublicData}device-fp/api/getFp`,
|
||||
body: {
|
||||
seed_id: `${generateSeed(16)}`,
|
||||
device_id: data.deviceId,
|
||||
|
|
@ -51,12 +82,8 @@ export default class ZZZApiTool {
|
|||
},
|
||||
}
|
||||
: {
|
||||
zzzUser: {
|
||||
url: `${host}binding/api/getUserGameRolesByCookie`,
|
||||
query: `game_biz=nap_global®ion=${this.server}&game_uid=${this.uid}`,
|
||||
},
|
||||
getFp: {
|
||||
url: `${hostPublicData}device-fp/api/getFp`,
|
||||
url: `${this.hostPublicData}device-fp/api/getFp`,
|
||||
body: {
|
||||
seed_id: `${this.uuid}`,
|
||||
device_id: '35315696b7071100',
|
||||
|
|
@ -70,45 +97,29 @@ export default class ZZZApiTool {
|
|||
noDs: true,
|
||||
},
|
||||
}),
|
||||
zzzNote: {
|
||||
url: `${hostRecord}event/game_record_zzz/api/zzz/note`,
|
||||
query: `role_id=${this.uid}&server=${this.server}`,
|
||||
},
|
||||
zzzIndex: {
|
||||
url: `${hostRecord}event/game_record_zzz/api/zzz/index`,
|
||||
query: `role_id=${this.uid}&server=${this.server}`,
|
||||
},
|
||||
zzzAvatarList: {
|
||||
url: `${hostRecord}event/game_record_zzz/api/zzz/avatar/basic`,
|
||||
query: `role_id=${this.uid}&server=${this.server}`,
|
||||
},
|
||||
zzzBuddyList: {
|
||||
url: `${hostRecord}event/game_record_zzz/api/zzz/buddy/info`,
|
||||
query: `role_id=${this.uid}&server=${this.server}`,
|
||||
},
|
||||
zzzAuthKey: {
|
||||
url: `${host}binding/api/genAuthKey`,
|
||||
body: {
|
||||
auth_appid: 'webview_gacha',
|
||||
game_biz: 'nap_cn',
|
||||
game_uid: this.uid * 1,
|
||||
region: this.server,
|
||||
},
|
||||
dsSalt: 'web',
|
||||
},
|
||||
...this.zzzUrlMap,
|
||||
},
|
||||
};
|
||||
|
||||
if (/_us|_eu|_jp|_sg/.test(this.server)) {
|
||||
urlMap.zzz.zzzNote.url = 'https://sg-act-nap-api.hoyolab.com/event/game_record_zzz/api/zzz/note'
|
||||
urlMap.zzz.zzzNote.query = `role_id=${this.uid}&server=${this.server}`
|
||||
urlMap.zzz.zzzIndex.url = 'https://sg-act-nap-api.hoyolab.com/event/game_record_zzz/api/zzz/index'
|
||||
urlMap.zzz.zzzIndex.query = `lang=zh-cn&role_id=${this.uid}&server=${this.server}`
|
||||
urlMap.zzz.zzzAvatarList.url = 'https://sg-act-nap-api.hoyolab.com/event/game_record_zzz/api/zzz/avatar/basic'
|
||||
urlMap.zzz.zzzAvatarList.query = `role_id=${this.uid}&server=${this.server}`
|
||||
urlMap.zzz.zzzBuddyList.url = 'https://sg-act-nap-api.hoyolab.com/event/game_record_zzz/api/zzz/buddy/info'
|
||||
urlMap.zzz.zzzBuddyList.query = `role_id=${this.uid}&server=${this.server}`
|
||||
};
|
||||
urlMap.zzz.zzzNote.url =
|
||||
'https://sg-act-nap-api.hoyolab.com/event/game_record_zzz/api/zzz/note';
|
||||
urlMap.zzz.zzzNote.query = `role_id=${this.uid}&server=${this.server}`;
|
||||
urlMap.zzz.zzzIndex.url =
|
||||
'https://sg-act-nap-api.hoyolab.com/event/game_record_zzz/api/zzz/index';
|
||||
urlMap.zzz.zzzIndex.query = `lang=zh-cn&role_id=${this.uid}&server=${this.server}`;
|
||||
urlMap.zzz.zzzAvatarList.url =
|
||||
'https://sg-act-nap-api.hoyolab.com/event/game_record_zzz/api/zzz/avatar/basic';
|
||||
urlMap.zzz.zzzAvatarList.query = `role_id=${this.uid}&server=${this.server}`;
|
||||
urlMap.zzz.zzzAvatarInfo.url =
|
||||
'https://sg-act-nap-api.hoyolab.com/event/game_record_zzz/api/zzz/avatar/info';
|
||||
urlMap.zzz.zzzAvatarInfo.query = `role_id=${this.uid}&server=${this.server}&need_wiki=false`;
|
||||
urlMap.zzz.zzzBuddyList.url =
|
||||
'https://sg-act-nap-api.hoyolab.com/event/game_record_zzz/api/zzz/buddy/info';
|
||||
urlMap.zzz.zzzBuddyList.query = `role_id=${this.uid}&server=${this.server}`;
|
||||
urlMap.zzzUser.url = `${this.host}binding/api/getUserGameRolesByCookie`;
|
||||
urlMap.zzzUser.query = `game_biz=nap_global®ion=${this.server}&game_uid=${this.uid}`;
|
||||
}
|
||||
return urlMap[this.game];
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,20 +4,28 @@ import _ from 'lodash';
|
|||
import NoteUser from '../../genshin/model/mys/NoteUser.js';
|
||||
|
||||
export class ZZZPlugin extends plugin {
|
||||
/**
|
||||
*
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async getUID() {
|
||||
let user = this.e;
|
||||
if (this.e.at) {
|
||||
user = this.e.at;
|
||||
}
|
||||
this.User = await NoteUser.create(user);
|
||||
let uid = this.e.msg.match(/\d+/)?.[0];
|
||||
uid = uid || this.User?.getUid('zzz');
|
||||
// let uid = this.e.msg.match(/\d+/)?.[0];
|
||||
const uid = this.User?.getUid('zzz');
|
||||
if (!uid) {
|
||||
await this.reply('uid为空,米游社查询请先绑定cookie,其他查询请携带uid');
|
||||
return false;
|
||||
}
|
||||
return uid;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @returns {Promise<{api: MysZZZApi, uid: string, deviceFp: string}>}
|
||||
*/
|
||||
async getAPI() {
|
||||
let uid = await this.getUID();
|
||||
if (!uid) return false;
|
||||
|
|
@ -47,15 +55,17 @@ export class ZZZPlugin extends plugin {
|
|||
}
|
||||
return { api, uid, deviceFp };
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {Promise<boolean | object>}
|
||||
*/
|
||||
async getPlayerInfo() {
|
||||
const { api } = await this.getAPI();
|
||||
if (!api) return false;
|
||||
let userData = await api.getData('zzzUser');
|
||||
if (!userData?.data || _.isEmpty(userData.data.list)) {
|
||||
await this.reply('[zzznote]玩家信息获取失败');
|
||||
return false;
|
||||
}
|
||||
userData = userData?.data?.list[0];
|
||||
let userData = await api.getFinalData(this.e, 'zzzUser');
|
||||
if (!userData) return false;
|
||||
userData = userData?.list[0];
|
||||
let avatar = this.e.bot.avatar;
|
||||
// 头像
|
||||
if (this.e.member?.getAvatarUrl) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue