UPDATE: Update readme and Next 16.07 (CVE-2025-66478)
This commit is contained in:
266
src/lib/api/api.ts
Normal file
266
src/lib/api/api.ts
Normal file
@@ -0,0 +1,266 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
import { AffixDetail, ASDetail, CharacterDetail, ConfigMaze, FreeSRJson, LightConeDetail, MocDetail, MonsterDetail, PeakDetail, PFDetail, PSResponse, RelicDetail } from "@/types";
|
||||
import axios from 'axios';
|
||||
import { psResponseSchema } from "@/zod";
|
||||
import { ExtraData } from "@/types";
|
||||
|
||||
export async function getConfigMazeApi(): Promise<ConfigMaze> {
|
||||
try {
|
||||
const res = await axios.get<ConfigMaze>(
|
||||
`/api/config-maze`,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return res.data as ConfigMaze;
|
||||
} catch (error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.log(`Error: ${error.response?.status} - ${error.message}`);
|
||||
} else {
|
||||
console.log(`Unexpected error: ${String(error)}`);
|
||||
}
|
||||
return {
|
||||
Avatar: {},
|
||||
MOC: {},
|
||||
AS: {},
|
||||
PF: {},
|
||||
Stage: {},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function getMainAffixApi(): Promise<Record<string, Record<string, AffixDetail>>> {
|
||||
try {
|
||||
const res = await axios.get<Record<string, Record<string, AffixDetail>>>(
|
||||
`/api/main-affixes`,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return res.data as Record<string, Record<string, AffixDetail>>;
|
||||
} catch (error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.log(`Error: ${error.response?.status} - ${error.message}`);
|
||||
} else {
|
||||
console.log(`Unexpected error: ${String(error)}`);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
export async function getSubAffixApi(): Promise<Record<string, Record<string, AffixDetail>>> {
|
||||
try {
|
||||
const res = await axios.get<Record<string, Record<string, AffixDetail>>>(
|
||||
`/api/sub-affixes`,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return res.data as Record<string, Record<string, AffixDetail>>;
|
||||
} catch (error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.log(`Error: ${error.response?.status} - ${error.message}`);
|
||||
} else {
|
||||
console.log(`Unexpected error: ${String(error)}`);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchCharacterByIdNative(id: string, locale: string): Promise<CharacterDetail | null> {
|
||||
try {
|
||||
const res = await axios.get<CharacterDetail>(`/api/${locale}/characters/${id}`);
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch character:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchCharactersByIdsNative(ids: string[], locale: string): Promise<Record<string, CharacterDetail>> {
|
||||
try {
|
||||
const res = await axios.post<Record<string, CharacterDetail>>(`/api/${locale}/characters`, { charIds: ids });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch characters:', error);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchLightconeByIdNative(id: string, locale: string): Promise<LightConeDetail | null> {
|
||||
try {
|
||||
const res = await axios.get<LightConeDetail>(`/api/${locale}/lightcones/${id}`);
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch lightcone:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchLightconesByIdsNative(ids: string[], locale: string): Promise<Record<string, LightConeDetail>> {
|
||||
try {
|
||||
const res = await axios.post<Record<string, LightConeDetail>>(`/api/${locale}/lightcones`, { lightconeIds: ids });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch lightcones:', error);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchRelicByIdNative(id: string, locale: string): Promise<RelicDetail | null> {
|
||||
try {
|
||||
const res = await axios.get<RelicDetail>(`/api/${locale}/relics/${id}`);
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch relic:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchRelicsByIdsNative(ids: string[], locale: string): Promise<Record<string, RelicDetail>> {
|
||||
try {
|
||||
const res = await axios.post<Record<string, RelicDetail>>(`/api/${locale}/relics`, { relicIds: ids });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch relics:', error);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchASByIdsNative(ids: string[], locale: string): Promise<Record<string, ASDetail> | null> {
|
||||
try {
|
||||
const res = await axios.post<Record<string, ASDetail>>(`/api/${locale}/as`, { asIds: ids });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch AS:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchASByIdNative(ids: string, locale: string): Promise<ASDetail | null> {
|
||||
try {
|
||||
const res = await axios.get<ASDetail>(`/api/${locale}/as/${ids}`);
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch AS:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchPFByIdsNative(ids: string[], locale: string): Promise<Record<string, PFDetail> | null> {
|
||||
try {
|
||||
const res = await axios.post<Record<string, PFDetail>>(`/api/${locale}/pf`, { pfIds: ids });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch PF:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchPFByIdNative(ids: string, locale: string): Promise<PFDetail | null> {
|
||||
try {
|
||||
const res = await axios.get<PFDetail>(`/api/${locale}/pf/${ids}`);
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch PF:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchMOCByIdsNative(ids: string[], locale: string): Promise<Record<string, MocDetail[]> | null> {
|
||||
try {
|
||||
const res = await axios.post<Record<string, MocDetail[]>>(`/api/${locale}/moc`, { mocIds: ids });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch MOC:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchMOCByIdNative(ids: string, locale: string): Promise<MocDetail[] | null> {
|
||||
try {
|
||||
const res = await axios.get<MocDetail[]>(`/api/${locale}/moc/${ids}`);
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch MOC:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchPeakByIdsNative(ids: string[], locale: string): Promise<Record<string, PeakDetail> | null> {
|
||||
try {
|
||||
const res = await axios.post<Record<string, PeakDetail>>(`/api/${locale}/peak`, { peakIds: ids });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch peak:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchPeakByIdNative(ids: string, locale: string): Promise<PeakDetail | null> {
|
||||
try {
|
||||
const res = await axios.get<PeakDetail>(`/api/${locale}/peak/${ids}`);
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch peak:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchMonsterByIdsNative(ids: string[], locale: string): Promise<Record<string, MonsterDetail> | null> {
|
||||
try {
|
||||
const res = await axios.post<Record<string, MonsterDetail>>(`/api/${locale}/monster`, { monsterIds: ids });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch monster:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchMonsterByIdNative(ids: string, locale: string): Promise<MonsterDetail | null> {
|
||||
try {
|
||||
const res = await axios.get<MonsterDetail>(`/api/${locale}/monster/${ids}`);
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch monster:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function SendDataToServer(
|
||||
username: string,
|
||||
password: string,
|
||||
serverUrl: string,
|
||||
data: FreeSRJson | null,
|
||||
extraData?: ExtraData
|
||||
): Promise<PSResponse | string> {
|
||||
try {
|
||||
const response = await axios.post(`${serverUrl}`, { username, password, data, extra_data: extraData })
|
||||
const parsed = psResponseSchema.safeParse(response.data)
|
||||
if (!parsed.success) {
|
||||
return "Invalid response schema";
|
||||
}
|
||||
return parsed.data;
|
||||
} catch (error: any) {
|
||||
return error?.message || "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
export async function SendDataThroughProxy({ data }: { data: any }) {
|
||||
try {
|
||||
const response = await axios.post(`/api/proxy`, { ...data })
|
||||
return response.data;
|
||||
} catch (error: any) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
399
src/lib/api/hakushi.ts
Normal file
399
src/lib/api/hakushi.ts
Normal file
@@ -0,0 +1,399 @@
|
||||
import { convertAvatar, convertEvent, convertLightcone, convertMonster, convertRelicSet } from "@/helper";
|
||||
import { ASDetail, CharacterBasic, CharacterBasicRaw, CharacterDetail, EventBasic, EventBasicRaw, LightConeBasic, LightConeBasicRaw, LightConeDetail, MocDetail, MonsterBasic, MonsterBasicRaw, MonsterDetail, MonsterValue, PeakDetail, PFDetail, RelicBasic, RelicBasicRaw, RelicDetail } from "@/types";
|
||||
import axios from "axios";
|
||||
|
||||
export async function getLightconeInfoApi(lightconeId: number, locale: string): Promise<LightConeDetail | null> {
|
||||
try {
|
||||
const res = await axios.get<LightConeDetail>(
|
||||
`https://api.hakush.in/hsr/data/${locale}/lightcone/${lightconeId}.json`,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return res.data as LightConeDetail;
|
||||
} catch (error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.log(`Error: ${error.response?.status} - ${error.message}`);
|
||||
} else {
|
||||
console.log(`Unexpected error: ${String(error)}`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getRelicInfoApi(relicId: number, locale: string): Promise<RelicDetail | null> {
|
||||
try {
|
||||
const res = await axios.get<RelicDetail>(
|
||||
`https://api.hakush.in/hsr/data/${locale}/relicset/${relicId}.json`,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return res.data as RelicDetail;
|
||||
} catch (error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.log(`Error: ${error.response?.status} - ${error.message}`);
|
||||
} else {
|
||||
console.log(`Unexpected error: ${String(error)}`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getCharacterInfoApi(avatarId: number, locale: string): Promise<CharacterDetail | null> {
|
||||
try {
|
||||
const res = await axios.get<CharacterDetail>(
|
||||
`https://api.hakush.in/hsr/data/${locale}/character/${avatarId}.json`,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return res.data as CharacterDetail;
|
||||
} catch (error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.log(`Error: ${error.response?.status} - ${error.message}`);
|
||||
} else {
|
||||
console.log(`Unexpected error: ${String(error)}`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getMOCEventInfoApi(eventId: number, locale: string): Promise<MocDetail[] | null> {
|
||||
try {
|
||||
const res = await axios.get<MocDetail[]>(
|
||||
`https://api.hakush.in/hsr/data/${locale}/maze/${eventId}.json`,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return res.data as MocDetail[];
|
||||
} catch (error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.log(`Error: ${error.response?.status} - ${error.message}`);
|
||||
} else {
|
||||
console.log(`Unexpected error: ${String(error)}`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getASEventInfoApi(eventId: number, locale: string): Promise<ASDetail | null> {
|
||||
try {
|
||||
const res = await axios.get<ASDetail>(
|
||||
`https://api.hakush.in/hsr/data/${locale}/boss/${eventId}.json`,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return res.data as ASDetail;
|
||||
} catch (error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.log(`Error: ${error.response?.status} - ${error.message}`);
|
||||
} else {
|
||||
console.log(`Unexpected error: ${String(error)}`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getPFEventInfoApi(eventId: number, locale: string): Promise<PFDetail | null> {
|
||||
try {
|
||||
const res = await axios.get<PFDetail>(
|
||||
`https://api.hakush.in/hsr/data/${locale}/story/${eventId}.json`,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return res.data as PFDetail;
|
||||
} catch (error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.log(`Error: ${error.response?.status} - ${error.message}`);
|
||||
} else {
|
||||
console.log(`Unexpected error: ${String(error)}`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getPeakEventInfoApi(eventId: number, locale: string): Promise<PeakDetail | null> {
|
||||
try {
|
||||
const res = await axios.get<PeakDetail>(
|
||||
`https://api.hakush.in/hsr/data/${locale}/peak/${eventId}.json`,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return res.data as PeakDetail;
|
||||
} catch (error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.log(`Error: ${error.response?.status} - ${error.message}`);
|
||||
} else {
|
||||
console.log(`Unexpected error: ${String(error)}`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getCharacterListApi(): Promise<CharacterBasic[]> {
|
||||
try {
|
||||
const res = await axios.get<Record<string, CharacterBasicRaw>>(
|
||||
'https://api.hakush.in/hsr/data/character.json',
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const data = new Map(Object.entries(res.data));
|
||||
|
||||
return Array.from(data.entries()).map(([id, it]) => convertAvatar(id, it));
|
||||
} catch (error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.log(`Error: ${error.response?.status} - ${error.message}`);
|
||||
} else {
|
||||
console.log(`Unexpected error: ${String(error)}`);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function getLightconeListApi(): Promise<LightConeBasic[]> {
|
||||
try {
|
||||
const res = await axios.get<Record<string, LightConeBasicRaw>>(
|
||||
'https://api.hakush.in/hsr/data/lightcone.json',
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const data = new Map(Object.entries(res.data));
|
||||
|
||||
return Array.from(data.entries()).map(([id, it]) => convertLightcone(id, it));
|
||||
} catch (error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.log(`Error: ${error.response?.status} - ${error.message}`);
|
||||
} else {
|
||||
console.log(`Unexpected error: ${String(error)}`);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function getRelicSetListApi(): Promise<RelicBasic[]> {
|
||||
try {
|
||||
const res = await axios.get<Record<string, RelicBasicRaw>>(
|
||||
'https://api.hakush.in/hsr/data/relicset.json',
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const data = new Map(Object.entries(res.data));
|
||||
|
||||
return Array.from(data.entries()).map(([id, it]) => convertRelicSet(id, it));
|
||||
} catch (error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.log(`Error: ${error.response?.status} - ${error.message}`);
|
||||
} else {
|
||||
console.log(`Unexpected error: ${String(error)}`);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function getMOCEventListApi(): Promise<EventBasic[]> {
|
||||
try {
|
||||
const res = await axios.get<Record<string, EventBasicRaw>>(
|
||||
'https://api.hakush.in/hsr/data/maze.json',
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const data = new Map(Object.entries(res.data));
|
||||
|
||||
return Array.from(data.entries()).map(([id, it]) => convertEvent(id, it));
|
||||
} catch (error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.log(`Error: ${error.response?.status} - ${error.message}`);
|
||||
} else {
|
||||
console.log(`Unexpected error: ${String(error)}`);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function getASEventListApi(): Promise<EventBasic[]> {
|
||||
try {
|
||||
const res = await axios.get<Record<string, EventBasicRaw>>(
|
||||
'https://api.hakush.in/hsr/data/maze_boss.json',
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const data = new Map(Object.entries(res.data));
|
||||
|
||||
return Array.from(data.entries()).map(([id, it]) => convertEvent(id, it));
|
||||
} catch (error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.log(`Error: ${error.response?.status} - ${error.message}`);
|
||||
} else {
|
||||
console.log(`Unexpected error: ${String(error)}`);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function getPFEventListApi(): Promise<EventBasic[]> {
|
||||
try {
|
||||
const res = await axios.get<Record<string, EventBasicRaw>>(
|
||||
'https://api.hakush.in/hsr/data/maze_extra.json',
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const data = new Map(Object.entries(res.data));
|
||||
|
||||
return Array.from(data.entries()).map(([id, it]) => convertEvent(id, it));
|
||||
} catch (error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.log(`Error: ${error.response?.status} - ${error.message}`);
|
||||
} else {
|
||||
console.log(`Unexpected error: ${String(error)}`);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function getPEAKEventListApi(): Promise<EventBasic[]> {
|
||||
try {
|
||||
const res = await axios.get<Record<string, EventBasicRaw>>(
|
||||
'https://api.hakush.in/hsr/data/maze_peak.json',
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const data = new Map(Object.entries(res.data));
|
||||
|
||||
return Array.from(data.entries()).map(([id, it]) => convertEvent(id, it));
|
||||
} catch (error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.log(`Error: ${error.response?.status} - ${error.message}`);
|
||||
} else {
|
||||
console.log(`Unexpected error: ${String(error)}`);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function getMonsterListApi(): Promise<{list: MonsterBasic[], map: Record<string, MonsterBasic>}> {
|
||||
try {
|
||||
const res = await axios.get<Record<string, MonsterBasicRaw>>(
|
||||
'https://api.hakush.in/hsr/data/monster.json',
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const dataArr = Array.from(Object.entries(res.data)).map(([id, it]) => convertMonster(id, it));
|
||||
const dataMap = Object.fromEntries(Object.entries(res.data).map(([id, it]) => [id, convertMonster(id, it)]));
|
||||
|
||||
return {
|
||||
list: dataArr,
|
||||
map: dataMap
|
||||
};
|
||||
} catch (error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.log(`Error: ${error.response?.status} - ${error.message}`);
|
||||
} else {
|
||||
console.log(`Unexpected error: ${String(error)}`);
|
||||
}
|
||||
return {list: [], map: {}};
|
||||
}
|
||||
}
|
||||
|
||||
export async function getMonsterValueApi(): Promise<Record<string, MonsterValue> | null> {
|
||||
try {
|
||||
const res = await axios.get<Record<string, MonsterValue>>(
|
||||
`https://api.hakush.in/hsr/data/monstervalue.json`,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return res.data;
|
||||
} catch (error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.log(`Error: ${error.response?.status} - ${error.message}`);
|
||||
} else {
|
||||
console.log(`Unexpected error: ${String(error)}`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export async function getMonsterDetailApi(monsterId: number, locale: string): Promise<MonsterDetail | null> {
|
||||
try {
|
||||
const res = await axios.get<MonsterDetail>(
|
||||
`https://api.hakush.in/hsr/data/${locale}/monster/${monsterId}.json`,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return res.data;
|
||||
} catch (error: unknown) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.log(`Error: ${error.response?.status} - ${error.message}`);
|
||||
} else {
|
||||
console.log(`Unexpected error: ${String(error)}`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
2
src/lib/api/index.ts
Normal file
2
src/lib/api/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./api";
|
||||
export * from "./hakushi";
|
||||
32
src/lib/loader/affixLoader.ts
Normal file
32
src/lib/loader/affixLoader.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { AffixDetail } from '@/types';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
const DATA_DIR = path.join(process.cwd(), 'data');
|
||||
let mainAffixCache: Record<string, Record<string, AffixDetail>> = {};
|
||||
let subAffixCache: Record<string, Record<string, AffixDetail>> = {};
|
||||
|
||||
const mainAffixPath = path.join(DATA_DIR, `main_affixes.json`)
|
||||
const subAffixPath = path.join(DATA_DIR, `sub_affixes.json`)
|
||||
|
||||
function loadFromFileIfExists(filePath: string): Record<string, Record<string, AffixDetail>> {
|
||||
if (fs.existsSync(filePath)) {
|
||||
const data = JSON.parse(fs.readFileSync(filePath, 'utf-8')) as Record<string, Record<string, AffixDetail>>;
|
||||
return data;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
export async function loadMainAffix(): Promise<Record<string, Record<string, AffixDetail>>> {
|
||||
if (Object.keys(mainAffixCache).length > 0) return mainAffixCache;
|
||||
const fileData = loadFromFileIfExists(mainAffixPath);
|
||||
mainAffixCache = fileData;
|
||||
return fileData;
|
||||
}
|
||||
|
||||
export async function loadSubAffix(): Promise<Record<string, Record<string, AffixDetail>>> {
|
||||
if (Object.keys(subAffixCache).length > 0) return subAffixCache;
|
||||
const fileData = loadFromFileIfExists(subAffixPath);
|
||||
subAffixCache = fileData;
|
||||
return fileData;
|
||||
}
|
||||
52
src/lib/loader/asLoader.ts
Normal file
52
src/lib/loader/asLoader.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { ASDetail } from '@/types';
|
||||
import { getASEventInfoApi } from '../api';
|
||||
|
||||
const DATA_DIR = path.join(process.cwd(), 'data');
|
||||
const asFileCache: Record<string, Record<string, ASDetail>> = {};
|
||||
export let asMap: Record<string, ASDetail> = {};
|
||||
|
||||
function getJsonFilePath(locale: string): string {
|
||||
return path.join(DATA_DIR, `as.${locale}.json`);
|
||||
}
|
||||
|
||||
function loadFromFileIfExists(locale: string): Record<string, ASDetail> | null {
|
||||
if (asFileCache[locale]) return asFileCache[locale];
|
||||
|
||||
const filePath = getJsonFilePath(locale);
|
||||
if (fs.existsSync(filePath)) {
|
||||
const data = JSON.parse(fs.readFileSync(filePath, 'utf-8')) as Record<string, ASDetail>;
|
||||
asFileCache[locale] = data;
|
||||
return data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function loadAS(charIds: string[], locale: string): Promise<Record<string, ASDetail>> {
|
||||
const fileData = loadFromFileIfExists(locale);
|
||||
const fileIds = fileData ? Object.keys(fileData) : [];
|
||||
|
||||
if (fileData && charIds.every(id => fileIds.includes(id))) {
|
||||
asMap = fileData;
|
||||
return asMap;
|
||||
}
|
||||
|
||||
const result: Record<string, ASDetail> = {};
|
||||
|
||||
await Promise.all(
|
||||
charIds.map(async id => {
|
||||
const info = await getASEventInfoApi(Number(id), locale);
|
||||
if (info) result[id] = info;
|
||||
})
|
||||
);
|
||||
|
||||
fs.mkdirSync(DATA_DIR, { recursive: true });
|
||||
const filePath = getJsonFilePath(locale);
|
||||
fs.writeFileSync(filePath, JSON.stringify(result), 'utf-8');
|
||||
|
||||
|
||||
asFileCache[locale] = result;
|
||||
asMap = result;
|
||||
return result;
|
||||
}
|
||||
63
src/lib/loader/characterLoader.ts
Normal file
63
src/lib/loader/characterLoader.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { CharacterDetail } from '@/types/characterDetail';
|
||||
import { getCharacterInfoApi } from '../api';
|
||||
|
||||
const DATA_DIR = path.join(process.cwd(), 'data');
|
||||
const characterFileCache: Record<string, Record<string, CharacterDetail>> = {};
|
||||
export let characterMap: Record<string, CharacterDetail> = {};
|
||||
export let rankIconMap: Record<string, string[]> = {};
|
||||
function getJsonFilePath(locale: string): string {
|
||||
return path.join(DATA_DIR, `characters.${locale}.json`);
|
||||
}
|
||||
|
||||
function loadFromFileIfExists(locale: string): Record<string, CharacterDetail> | null {
|
||||
if (characterFileCache[locale]) return characterFileCache[locale];
|
||||
|
||||
const filePath = getJsonFilePath(locale);
|
||||
const fileRankIconPath = path.join(DATA_DIR, `rank_icon.json`);
|
||||
if (fs.existsSync(fileRankIconPath)) {
|
||||
const data = JSON.parse(fs.readFileSync(fileRankIconPath, 'utf-8')) as Record<string, string[]>;
|
||||
rankIconMap = data;
|
||||
}
|
||||
if (fs.existsSync(filePath)) {
|
||||
const data = JSON.parse(fs.readFileSync(filePath, 'utf-8')) as Record<string, CharacterDetail>;
|
||||
Object.keys(data).forEach((key) => {
|
||||
data[key].RankIcon = rankIconMap[key] || [];
|
||||
});
|
||||
characterFileCache[locale] = data;
|
||||
return data;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function loadCharacters(charIds: string[], locale: string): Promise<Record<string, CharacterDetail>> {
|
||||
const fileData = loadFromFileIfExists(locale);
|
||||
const fileIds = fileData ? Object.keys(fileData) : [];
|
||||
|
||||
if (fileData && charIds.every(id => fileIds.includes(id))) {
|
||||
characterMap = fileData;
|
||||
return characterMap;
|
||||
}
|
||||
|
||||
const result: Record<string, CharacterDetail> = {};
|
||||
|
||||
await Promise.all(
|
||||
charIds.map(async id => {
|
||||
const info = await getCharacterInfoApi(Number(id), locale);
|
||||
if (info){
|
||||
info.RankIcon = rankIconMap[id] || [];
|
||||
result[id] = info;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
fs.mkdirSync(DATA_DIR, { recursive: true });
|
||||
const filePath = getJsonFilePath(locale);
|
||||
fs.writeFileSync(filePath, JSON.stringify(result), 'utf-8');
|
||||
|
||||
characterFileCache[locale] = result;
|
||||
characterMap = result;
|
||||
return result;
|
||||
}
|
||||
23
src/lib/loader/configMazeLoader.ts
Normal file
23
src/lib/loader/configMazeLoader.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ConfigMaze } from "@/types";
|
||||
import fs from 'fs';
|
||||
import path from "path";
|
||||
|
||||
const DATA_DIR = path.join(process.cwd(), 'data');
|
||||
|
||||
export let configMazeMap: Record<string, ConfigMaze> = {};
|
||||
|
||||
function loadFromFileIfExists(): Record<string, ConfigMaze> | null {
|
||||
const filePath = path.join(DATA_DIR, 'config_maze.json');
|
||||
if (fs.existsSync(filePath)) {
|
||||
const data = JSON.parse(fs.readFileSync(filePath, 'utf-8')) as Record<string, ConfigMaze>;
|
||||
configMazeMap = data;
|
||||
return data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function loadConfigMaze(): Promise<Record<string, ConfigMaze>> {
|
||||
if (Object.keys(configMazeMap).length > 0) return configMazeMap;
|
||||
const fileData = loadFromFileIfExists();
|
||||
return fileData || {};
|
||||
}
|
||||
10
src/lib/loader/index.ts
Normal file
10
src/lib/loader/index.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export * from "./characterLoader";
|
||||
export * from "./lighconeLoader";
|
||||
export * from "./affixLoader";
|
||||
export * from "./configMazeLoader";
|
||||
export * from "./relicLoader";
|
||||
export * from "./asLoader";
|
||||
export * from "./pfLoader";
|
||||
export * from "./mocLoader";
|
||||
export * from "./peakLoader";
|
||||
export * from "./monsterLoader";
|
||||
64
src/lib/loader/lighconeLoader.ts
Normal file
64
src/lib/loader/lighconeLoader.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { getLightconeInfoApi } from '../api';
|
||||
import { LightConeDetail } from '@/types';
|
||||
|
||||
const DATA_DIR = path.join(process.cwd(), 'data');
|
||||
const lightconeFileCache: Record<string, Record<string, LightConeDetail>> = {};
|
||||
export let lightconeMap: Record<string, LightConeDetail> = {};
|
||||
export let lightconeBonusMap: Record<string, Record<string, { type: string, value: number }[]>> = {};
|
||||
|
||||
function getJsonFilePath(locale: string): string {
|
||||
return path.join(DATA_DIR, `lightcones.${locale}.json`);
|
||||
}
|
||||
|
||||
function loadLightconeFromFileIfExists(locale: string): Record<string, LightConeDetail> | null {
|
||||
if (lightconeFileCache[locale]) return lightconeFileCache[locale];
|
||||
|
||||
const filePath = getJsonFilePath(locale);
|
||||
const fileBonusPath = path.join(DATA_DIR, `lightcone_bonus.json`);
|
||||
if (fs.existsSync(fileBonusPath)) {
|
||||
const data = JSON.parse(fs.readFileSync(fileBonusPath, 'utf-8')) as Record<string, Record<string, { type: string, value: number }[]>>;
|
||||
lightconeBonusMap = data;
|
||||
}
|
||||
if (fs.existsSync(filePath)) {
|
||||
const data = JSON.parse(fs.readFileSync(filePath, 'utf-8')) as Record<string, LightConeDetail>;
|
||||
Object.keys(data).forEach((key) => {
|
||||
data[key].Bonus = lightconeBonusMap[key] || {};
|
||||
});
|
||||
lightconeFileCache[locale] = data;
|
||||
|
||||
return data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function loadLightcones(charIds: string[], locale: string): Promise<Record<string, LightConeDetail>> {
|
||||
const fileData = loadLightconeFromFileIfExists(locale);
|
||||
const fileIds = fileData ? Object.keys(fileData) : [];
|
||||
|
||||
if (fileData && charIds.every(id => fileIds.includes(id))) {
|
||||
lightconeMap = fileData;
|
||||
return lightconeMap;
|
||||
}
|
||||
|
||||
const result: Record<string, LightConeDetail> = {};
|
||||
|
||||
await Promise.all(
|
||||
charIds.map(async id => {
|
||||
const info = await getLightconeInfoApi(Number(id), locale);
|
||||
if (info) {
|
||||
info.Bonus = lightconeBonusMap[id] || {};
|
||||
result[id] = info;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
fs.mkdirSync(DATA_DIR, { recursive: true });
|
||||
const filePath = getJsonFilePath(locale);
|
||||
fs.writeFileSync(filePath, JSON.stringify(result), 'utf-8');
|
||||
|
||||
lightconeFileCache[locale] = result;
|
||||
lightconeMap = result;
|
||||
return result;
|
||||
}
|
||||
51
src/lib/loader/mocLoader.ts
Normal file
51
src/lib/loader/mocLoader.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { MocDetail } from '@/types';
|
||||
import { getMOCEventInfoApi } from '../api';
|
||||
|
||||
const DATA_DIR = path.join(process.cwd(), 'data');
|
||||
const mocFileCache: Record<string, Record<string, MocDetail[]>> = {};
|
||||
export let mocMap: Record<string, MocDetail[]> = {};
|
||||
|
||||
function getJsonFilePath(locale: string): string {
|
||||
return path.join(DATA_DIR, `moc.${locale}.json`);
|
||||
}
|
||||
|
||||
function loadFromFileIfExists(locale: string): Record<string, MocDetail[]> | null {
|
||||
if (mocFileCache[locale]) return mocFileCache[locale];
|
||||
|
||||
const filePath = getJsonFilePath(locale);
|
||||
if (fs.existsSync(filePath)) {
|
||||
const data = JSON.parse(fs.readFileSync(filePath, 'utf-8')) as Record<string, MocDetail[]>;
|
||||
mocFileCache[locale] = data;
|
||||
return data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function loadMOC(charIds: string[], locale: string): Promise<Record<string, MocDetail[]>> {
|
||||
const fileData = loadFromFileIfExists(locale);
|
||||
const fileIds = fileData ? Object.keys(fileData) : [];
|
||||
|
||||
if (fileData && charIds.every(id => fileIds.includes(id))) {
|
||||
mocMap = fileData;
|
||||
return mocMap;
|
||||
}
|
||||
|
||||
const result: Record<string, MocDetail[]> = {};
|
||||
|
||||
await Promise.all(
|
||||
charIds.map(async id => {
|
||||
const info = await getMOCEventInfoApi(Number(id), locale);
|
||||
if (info) result[id] = info;
|
||||
})
|
||||
);
|
||||
|
||||
fs.mkdirSync(DATA_DIR, { recursive: true });
|
||||
const filePath = getJsonFilePath(locale);
|
||||
fs.writeFileSync(filePath, JSON.stringify(result), 'utf-8');
|
||||
|
||||
mocFileCache[locale] = result;
|
||||
mocMap = result;
|
||||
return result;
|
||||
}
|
||||
51
src/lib/loader/monsterLoader.ts
Normal file
51
src/lib/loader/monsterLoader.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { MonsterDetail } from '@/types';
|
||||
import { getMonsterDetailApi } from '../api';
|
||||
|
||||
const DATA_DIR = path.join(process.cwd(), 'data');
|
||||
const monsterFileCache: Record<string, Record<string, MonsterDetail>> = {};
|
||||
export let monsterMap: Record<string, MonsterDetail> = {};
|
||||
|
||||
function getJsonFilePath(locale: string): string {
|
||||
return path.join(DATA_DIR, `monster.${locale}.json`);
|
||||
}
|
||||
|
||||
function loadFromFileIfExists(locale: string): Record<string, MonsterDetail> | null {
|
||||
if (monsterFileCache[locale]) return monsterFileCache[locale];
|
||||
|
||||
const filePath = getJsonFilePath(locale);
|
||||
if (fs.existsSync(filePath)) {
|
||||
const data = JSON.parse(fs.readFileSync(filePath, 'utf-8')) as Record<string, MonsterDetail>;
|
||||
monsterFileCache[locale] = data;
|
||||
return data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function loadMonster(charIds: string[], locale: string): Promise<Record<string, MonsterDetail>> {
|
||||
const fileData = loadFromFileIfExists(locale);
|
||||
const fileIds = fileData ? Object.keys(fileData) : [];
|
||||
|
||||
if (fileData && charIds.every(id => fileIds.includes(id))) {
|
||||
monsterMap = fileData;
|
||||
return monsterMap;
|
||||
}
|
||||
|
||||
const result: Record<string, MonsterDetail> = {};
|
||||
|
||||
await Promise.all(
|
||||
charIds.map(async id => {
|
||||
const info = await getMonsterDetailApi(Number(id), locale);
|
||||
if (info) result[id] = info;
|
||||
})
|
||||
);
|
||||
|
||||
fs.mkdirSync(DATA_DIR, { recursive: true });
|
||||
const filePath = getJsonFilePath(locale);
|
||||
fs.writeFileSync(filePath, JSON.stringify(result), 'utf-8');
|
||||
|
||||
monsterFileCache[locale] = result;
|
||||
monsterMap = result;
|
||||
return result;
|
||||
}
|
||||
51
src/lib/loader/peakLoader.ts
Normal file
51
src/lib/loader/peakLoader.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { PeakDetail } from '@/types';
|
||||
import { getPeakEventInfoApi } from '../api';
|
||||
|
||||
const DATA_DIR = path.join(process.cwd(), 'data');
|
||||
const peakFileCache: Record<string, Record<string, PeakDetail>> = {};
|
||||
export let peakMap: Record<string, PeakDetail> = {};
|
||||
|
||||
function getJsonFilePath(locale: string): string {
|
||||
return path.join(DATA_DIR, `peak.${locale}.json`);
|
||||
}
|
||||
|
||||
function loadFromFileIfExists(locale: string): Record<string, PeakDetail> | null {
|
||||
if (peakFileCache[locale]) return peakFileCache[locale];
|
||||
|
||||
const filePath = getJsonFilePath(locale);
|
||||
if (fs.existsSync(filePath)) {
|
||||
const data = JSON.parse(fs.readFileSync(filePath, 'utf-8')) as Record<string, PeakDetail>;
|
||||
peakFileCache[locale] = data;
|
||||
return data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function loadPeak(charIds: string[], locale: string): Promise<Record<string, PeakDetail>> {
|
||||
const fileData = loadFromFileIfExists(locale);
|
||||
const fileIds = fileData ? Object.keys(fileData) : [];
|
||||
|
||||
if (fileData && charIds.every(id => fileIds.includes(id))) {
|
||||
peakMap = fileData;
|
||||
return peakMap;
|
||||
}
|
||||
|
||||
const result: Record<string, PeakDetail> = {};
|
||||
|
||||
await Promise.all(
|
||||
charIds.map(async id => {
|
||||
const info = await getPeakEventInfoApi(Number(id), locale);
|
||||
if (info) result[id] = info;
|
||||
})
|
||||
);
|
||||
|
||||
fs.mkdirSync(DATA_DIR, { recursive: true });
|
||||
const filePath = getJsonFilePath(locale);
|
||||
fs.writeFileSync(filePath, JSON.stringify(result), 'utf-8');
|
||||
|
||||
peakFileCache[locale] = result;
|
||||
peakMap = result;
|
||||
return result;
|
||||
}
|
||||
51
src/lib/loader/pfLoader.ts
Normal file
51
src/lib/loader/pfLoader.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { PFDetail } from '@/types';
|
||||
import { getPFEventInfoApi } from '../api';
|
||||
|
||||
const DATA_DIR = path.join(process.cwd(), 'data');
|
||||
const pfFileCache: Record<string, Record<string, PFDetail>> = {};
|
||||
export let pfMap: Record<string, PFDetail> = {};
|
||||
|
||||
function getJsonFilePath(locale: string): string {
|
||||
return path.join(DATA_DIR, `pf.${locale}.json`);
|
||||
}
|
||||
|
||||
function loadFromFileIfExists(locale: string): Record<string, PFDetail> | null {
|
||||
if (pfFileCache[locale]) return pfFileCache[locale];
|
||||
|
||||
const filePath = getJsonFilePath(locale);
|
||||
if (fs.existsSync(filePath)) {
|
||||
const data = JSON.parse(fs.readFileSync(filePath, 'utf-8')) as Record<string, PFDetail>;
|
||||
pfFileCache[locale] = data;
|
||||
return data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function loadPF(charIds: string[], locale: string): Promise<Record<string, PFDetail>> {
|
||||
const fileData = loadFromFileIfExists(locale);
|
||||
const fileIds = fileData ? Object.keys(fileData) : [];
|
||||
|
||||
if (fileData && charIds.every(id => fileIds.includes(id))) {
|
||||
pfMap = fileData;
|
||||
return pfMap;
|
||||
}
|
||||
|
||||
const result: Record<string, PFDetail> = {};
|
||||
|
||||
await Promise.all(
|
||||
charIds.map(async id => {
|
||||
const info = await getPFEventInfoApi(Number(id), locale);
|
||||
if (info) result[id] = info;
|
||||
})
|
||||
);
|
||||
|
||||
fs.mkdirSync(DATA_DIR, { recursive: true });
|
||||
const filePath = getJsonFilePath(locale);
|
||||
fs.writeFileSync(filePath, JSON.stringify(result), 'utf-8');
|
||||
|
||||
pfFileCache[locale] = result;
|
||||
pfMap = result;
|
||||
return result;
|
||||
}
|
||||
62
src/lib/loader/relicLoader.ts
Normal file
62
src/lib/loader/relicLoader.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { RelicDetail } from '@/types';
|
||||
import { getRelicInfoApi } from '../api';
|
||||
|
||||
const DATA_DIR = path.join(process.cwd(), 'data');
|
||||
const relicFileCache: Record<string, Record<string, RelicDetail>> = {};
|
||||
export let relicMap: Record<string, RelicDetail> = {};
|
||||
export let relicBonusMap: Record<string, Record<string, { type: string, value: number }[]>> = {};
|
||||
function getJsonFilePath(locale: string): string {
|
||||
return path.join(DATA_DIR, `relics.${locale}.json`);
|
||||
}
|
||||
|
||||
function loadRelicFromFileIfExists(locale: string): Record<string, RelicDetail> | null {
|
||||
if (relicFileCache[locale]) return relicFileCache[locale];
|
||||
|
||||
const filePath = getJsonFilePath(locale);
|
||||
const fileBonusPath = path.join(DATA_DIR, `relic_bonus.json`);
|
||||
if (fs.existsSync(fileBonusPath)) {
|
||||
const data = JSON.parse(fs.readFileSync(fileBonusPath, 'utf-8')) as Record<string, Record<string, { type: string, value: number }[]>>;
|
||||
relicBonusMap = data;
|
||||
}
|
||||
if (fs.existsSync(filePath)) {
|
||||
const data = JSON.parse(fs.readFileSync(filePath, 'utf-8')) as Record<string, RelicDetail>;
|
||||
Object.keys(data).forEach((key) => {
|
||||
data[key].Bonus = relicBonusMap[key] || {};
|
||||
});
|
||||
relicFileCache[locale] = data;
|
||||
return data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function loadRelics(charIds: string[], locale: string): Promise<Record<string, RelicDetail>> {
|
||||
const fileData = loadRelicFromFileIfExists(locale);
|
||||
const fileIds = fileData ? Object.keys(fileData) : [];
|
||||
|
||||
if (fileData && charIds.every(id => fileIds.includes(id))) {
|
||||
relicMap = fileData;
|
||||
return relicMap;
|
||||
}
|
||||
|
||||
const result: Record<string, RelicDetail> = {};
|
||||
|
||||
await Promise.all(
|
||||
charIds.map(async id => {
|
||||
const info = await getRelicInfoApi(Number(id), locale);
|
||||
if (info) {
|
||||
info.Bonus = relicBonusMap[id] || {};
|
||||
result[id] = info;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
fs.mkdirSync(DATA_DIR, { recursive: true });
|
||||
const filePath = getJsonFilePath(locale);
|
||||
fs.writeFileSync(filePath, JSON.stringify(result), 'utf-8');
|
||||
|
||||
relicFileCache[locale] = result;
|
||||
relicMap = result;
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user