This commit is contained in:
bietiaop 2024-07-08 22:17:31 +08:00
parent 0c72964b12
commit 51fb65cdb4
11 changed files with 313 additions and 56 deletions

View file

@ -15,16 +15,15 @@ export async function getAuthKey(e, zzzUid, authAppid = 'csc') {
if (!User) {
throw new Error('未安装逍遥插件,无法自动刷新抽卡链接');
}
let user = new User(e);
// set genshin uid
const user = new User(e);
await user.getCookie(e);
let ck = await user.getStoken(e.user_id);
ck = `stuid=${ck.stuid};stoken=${ck.stoken};mid=${ck.mid};`;
let api = new MysZZZApi(zzzUid, ck);
let type = 'zzzPayAuthKey';
const api = new MysZZZApi(zzzUid, ck);
let type = 'zzzAuthKey';
switch (authAppid) {
case 'csc': {
type = 'zzzPayAuthKey';
type = 'zzzAuthKey';
break;
}
default:

59
lib/db.js Normal file
View file

@ -0,0 +1,59 @@
import { readFileSync, writeFileSync } from 'fs';
import path from 'path';
import { checkFolderExistAndCreate } from '../utils/file.js';
import { dataPath } from './path.js';
const dbPath = {
gacha: 'gacha',
};
/**
*
* @param {string} dbName
* @param {string} dbFile
* @returns {object}
*/
export function getDB(dbName, dbFile) {
const db = dbPath[dbName];
const dbFolder = path.join(dataPath, db);
try {
const dbPath = path.join(dbFolder, `${dbFile}.json`);
return JSON.parse(readFileSync(dbPath, 'utf-8'));
} catch (error) {
logger.mark(`读取数据库失败: ${error.message}`);
return null;
}
}
/**
*
* @param {string} dbName
* @param {string} dbFile
* @param {object} data
*/
export function setDB(dbName, dbFile, data) {
const db = dbPath[dbName];
const dbFolder = path.join(dataPath, db);
try {
checkFolderExistAndCreate(dbFolder);
const dbPath = path.join(dbFolder, `${dbFile}.json`);
writeFileSync(dbPath, JSON.stringify(data, null, 2));
} catch (error) {
logger.mark(`读取数据库失败: ${error.message}`);
}
}
/**
* @param {string} uid
* @returns {object}
*/
export function getGachaLog(uid) {
return getDB('gacha', uid);
}
/**
* @param {string} uid
* @param {object} data
*/
export function saveGachaLog(uid, data) {
setDB('gacha', uid, data);
}

129
lib/gacha.js Normal file
View file

@ -0,0 +1,129 @@
import { SingleGachaLog, ZZZGachaLogResp } from '../model/gacha.js';
import { sleep } from '../utils/time.js';
import { getGachaLog, saveGachaLog } from './db.js';
import { ZZZ_GET_GACHA_LOG_API } from './mysapi/api.js';
export const gacha_type_meta_data = {
音擎频段: ['3001'],
独家频段: ['2001'],
常驻频段: ['1001'],
邦布频段: ['5001'],
};
/**
*
* @param {string} authKey
* @param {*} gachaType
* @param {*} initLogGachaBaseType
* @param {number} page
* @param {string} endId
* @returns {Promise<ZZZGachaLogResp>}
*/
export async function getZZZGachaLogByAuthkey(
authKey,
gachaType = '2001',
initLogGachaBaseType = '2',
page = 1,
endId = '0'
) {
const serverId = 'prod_gf_cn';
const url = ZZZ_GET_GACHA_LOG_API;
const timestamp = Math.floor(Date.now() / 1000);
const params = new URLSearchParams({
authkey_ver: '1',
sign_type: '2',
auth_appid: 'webview_gacha',
init_log_gacha_type: gachaType,
init_log_gacha_base_type: initLogGachaBaseType,
gacha_id: '2c1f5692fdfbb733a08733f9eb69d32aed1d37',
timestamp: timestamp.toString(),
lang: 'zh-cn',
device_type: 'mobile',
plat_type: 'ios',
region: serverId,
authkey: authKey,
game_biz: 'nap_cn',
gacha_type: gachaType,
real_gacha_type: initLogGachaBaseType,
page: page,
size: '20',
end_id: endId,
});
const response = await fetch(`${url}?${params}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
const data = await response.json();
if (!data || !data?.data) return null;
return new ZZZGachaLogResp(data.data);
}
/**
*
* @param {string} authKey
* @param {string} uid
* @returns {Promise<{
* [x: string]: SingleGachaLog[];
* }>}
*/
export async function updateGachaLog(authKey, uid) {
let previousLog = getGachaLog(uid);
if (!previousLog) {
previousLog = {};
}
for (const name in gacha_type_meta_data) {
if (!previousLog[name]) {
previousLog[name] = [];
}
previousLog[name] = previousLog[name].map(
i =>
new SingleGachaLog(
i.uid,
i.gacha_id,
i.gacha_type,
i.item_id,
i.count,
i.time,
i.name,
i.lang,
i.item_type,
i.rank_type,
i.id
)
);
const lastSaved = previousLog[name]?.[0];
let page = 1;
let endId = '0';
for (const type of gacha_type_meta_data[name]) {
queryLabel: while (true) {
const log = await getZZZGachaLogByAuthkey(
authKey,
type,
type[0],
page,
endId
);
if (!log || !log?.list || log?.list?.length === 0) {
break;
}
for (const item of log.list) {
if (lastSaved && lastSaved.equals(item)) {
break queryLabel;
}
previousLog[name].push(item);
}
endId = log.list[log.list.length - 1]?.id || endId;
page++;
await sleep(400);
}
}
}
saveGachaLog(uid, previousLog);
return previousLog;
}

View file

@ -1,8 +1,9 @@
import MysApi from '../../genshin/model/mys/mysApi.js';
import md5 from 'md5';
import _ from 'lodash';
import crypto from 'crypto';
import ZZZApiTool from './mysapi/tool.js';
import MysApi from '../../genshin/model/mys/mysApi.js';
// const DEVICE_ID = randomString(32).toUpperCase()
const DEVICE_NAME = randomString(_.random(1, 10));
const game_region = [
@ -79,20 +80,9 @@ export default class MysZZZApi extends MysApi {
}
default:
}
if (type === 'zzzPayAuthKey') {
if (type === 'zzzAuthKey') {
let extra = {
'x-rpc-app_version': '2.40.1',
'User-Agent': 'okhttp/4.8.0',
'x-rpc-client_type': '5',
Referer: 'https://app.mihoyo.com',
Origin: 'https://webstatic.mihoyo.com',
// Cookie: this.cookies,
// DS: this.getDS2(),
'x-rpc-sys_version': '12',
'x-rpc-channel': 'mihoyo',
'x-rpc-device_id': this._device,
'x-rpc-device_name': DEVICE_NAME,
'x-rpc-device_model': 'Mi 10',
DS: this.getDS2(),
Host: 'api-takumi.mihoyo.com',
};
headers = Object.assign(headers, extra);
@ -114,7 +104,7 @@ export default class MysZZZApi extends MysApi {
let n = '';
if (['prod_gf_cn', 'prod_qd_cn'].includes(this.server)) {
n = 'xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs';
} else if (/official/.test(this.server)) {
} else if (/prod_gf_/.test(this.server)) {
n = 'okr4obncj8bw5a65hbnn5oo6ixjc3l9w';
}
let t = Math.round(new Date().getTime() / 1000);
@ -126,15 +116,15 @@ export default class MysZZZApi extends MysApi {
getDS2() {
let t = Math.round(new Date().getTime() / 1000);
let r = randomString(6);
let sign = md5(`salt=jEpJb9rRARU2rXDA9qYbZ3selxkuct9a&t=${t}&r=${r}`);
let sign = md5(`salt=BIPaooxbWZW02fGHZL1If26mYCljPgst&t=${t}&r=${r}`);
return `${t},${r},${sign}`;
}
getHeaders(query = '', body = '') {
const cn = {
app_version: '2.44.1',
app_version: '2.63.1',
User_Agent:
'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.44.1',
'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.63.1',
client_type: '5',
Origin: 'https://webstatic.mihoyo.com',
X_Requested_With: 'com.mihoyo.hyperion',
@ -158,7 +148,10 @@ export default class MysZZZApi extends MysApi {
return {
'x-rpc-app_version': client.app_version,
'x-rpc-client_type': client.client_type,
// 'x-rpc-page': '3.1.3_#/rpg',
'User-Agent': 'okhttp/4.8.0',
'x-rpc-sys_version': '12',
'x-rpc-client_type': '2',
'x-rpc-channel': 'mihoyo',
'User-Agent': client.User_Agent,
Referer: client.Referer,
DS: this.getDs(query, body),

View file

@ -11,7 +11,7 @@ export default class ZZZApiTool {
*/
constructor(uid, server) {
this.uid = uid;
this.isSr = true;
this.isZZZ = true;
this.server = server;
this.game = 'zzz';
this.uuid = crypto.randomUUID();
@ -19,18 +19,18 @@ export default class ZZZApiTool {
getUrlMap = (data = {}) => {
let host, hostRecord, hostPublicData;
if (['prod_gf_cn', 'prod_qd_cn'].includes(this.server)) {
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 if (/official/.test(this.server)) {
} else if (/prod_gf_/.test(this.server)) {
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', 'prod_qd_cn'].includes(this.server)
...(['prod_gf_cn'].includes(this.server)
? {
zzzUser: {
url: `${host}binding/api/getUserGameRolesByCookie`,
@ -78,6 +78,16 @@ export default class ZZZApiTool {
url: `${hostRecord}event/game_record_zzz/api/zzz/index`,
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',
},
},
};
return urlMap[this.game];