feat(guides): add team loadouts and element icons
This commit is contained in:
+16
-7
@@ -78,7 +78,7 @@ async function mapConcurrent<T, R>(items: T[], task: (item: T) => Promise<R>): P
|
||||
|
||||
async function uploadAssets(
|
||||
jobId: string,
|
||||
assets: Array<{ source: string; target: string }>,
|
||||
assets: Array<{ source: string; target: string; type?: string }>,
|
||||
): Promise<Set<string>> {
|
||||
const storage = await getMediaStorage();
|
||||
let next = 0;
|
||||
@@ -91,7 +91,7 @@ async function uploadAssets(
|
||||
const response = await fetch(asset.source, { signal: AbortSignal.timeout(30_000), cache: "no-store" });
|
||||
if (response.status === 404) missing.add(asset.target);
|
||||
else if (!response.ok) throw new Error(`Asset returned ${response.status}: ${asset.source}`);
|
||||
else await storage.write(asset.target, response, { type: "image/webp", acl: "public-read" });
|
||||
else await storage.write(asset.target, response, { type: asset.type ?? "image/webp", acl: "public-read" });
|
||||
completed += 1;
|
||||
if (completed % 10 === 0 || completed === assets.length) {
|
||||
await getDb().update(catalogSyncJobs).set({ progress: completed }).where(eq(catalogSyncJobs.id, jobId));
|
||||
@@ -129,9 +129,11 @@ export async function processCatalogSyncJob(jobId: string): Promise<void> {
|
||||
const detailRaw = await getOptionalJson(`${API_ROOT}/${version}/en/char/${encodeURIComponent(key)}.json`);
|
||||
const detail = detailRaw ? characterDetailSchema.parse(detailRaw) : null;
|
||||
const avatarIcon = webpName(avatarIconName(value.CardImg));
|
||||
const element = detail?.info?.element ?? value.element ?? null;
|
||||
return {
|
||||
version, key, name: value.enName, element: value.element ?? null, rarity: rarity(value.qualityType), weaponType: detail?.info?.weapon ?? value.weaponType ?? null,
|
||||
version, key, name: value.enName, element, rarity: rarity(value.qualityType), weaponType: detail?.info?.weapon ?? value.weaponType ?? null,
|
||||
imageKey: `catalog/${version}/characters/${avatarIcon}`,
|
||||
elementIconKey: element ? `catalog/${version}/elements/${element.toLowerCase()}.png` : null,
|
||||
sourceImage: `${API_ROOT}/assets/avataricon/${encodeURIComponent(avatarIcon)}`,
|
||||
constellations: detail ? constellationSnapshot(detail, (icon) => `catalog/${version}/constellations/${webpName(icon)}`) : [],
|
||||
};
|
||||
@@ -147,8 +149,15 @@ export async function processCatalogSyncJob(jobId: string): Promise<void> {
|
||||
imageKey: `catalog/${version}/artifacts/${webpName(value.setIcon)}`,
|
||||
sourceImage: `${API_ROOT}/assets/artifacts/${encodeURIComponent(webpName(value.setIcon))}`,
|
||||
}));
|
||||
const uniqueAssets = new Map<string, { source: string; target: string }>();
|
||||
const uniqueAssets = new Map<string, { source: string; target: string; type?: string }>();
|
||||
for (const item of [...characters, ...weapons, ...artifacts]) uniqueAssets.set(item.imageKey, { source: item.sourceImage, target: item.imageKey });
|
||||
for (const character of characters) {
|
||||
if (character.elementIconKey && character.element) uniqueAssets.set(character.elementIconKey, {
|
||||
source: `${API_ROOT}/assets/icons/${encodeURIComponent(character.element.toLowerCase())}.png`,
|
||||
target: character.elementIconKey,
|
||||
type: "image/png",
|
||||
});
|
||||
}
|
||||
for (const character of characters) {
|
||||
for (const constellation of character.constellations) {
|
||||
if (constellation.iconKey) uniqueAssets.set(constellation.iconKey, {
|
||||
@@ -159,13 +168,13 @@ export async function processCatalogSyncJob(jobId: string): Promise<void> {
|
||||
}
|
||||
const missingAssets = await uploadAssets(jobId, [...uniqueAssets.values()]);
|
||||
characters = characters.filter((item) => !missingAssets.has(item.imageKey));
|
||||
characters = characters.map((item) => ({ ...item, constellations: item.constellations.map((constellation) => ({ ...constellation, iconKey: constellation.iconKey && !missingAssets.has(constellation.iconKey) ? constellation.iconKey : null })) }));
|
||||
characters = characters.map((item) => ({ ...item, elementIconKey: item.elementIconKey && !missingAssets.has(item.elementIconKey) ? item.elementIconKey : null, constellations: item.constellations.map((constellation) => ({ ...constellation, iconKey: constellation.iconKey && !missingAssets.has(constellation.iconKey) ? constellation.iconKey : null })) }));
|
||||
weapons = weapons.filter((item) => !missingAssets.has(item.imageKey));
|
||||
artifacts = artifacts.filter((item) => !missingAssets.has(item.imageKey));
|
||||
|
||||
const storage = await getMediaStorage();
|
||||
await Promise.all([
|
||||
storage.write(`catalog/${version}/characters.json`, JSON.stringify(characters.map((item) => ({ version: item.version, key: item.key, name: item.name, element: item.element, rarity: item.rarity, weaponType: item.weaponType, imageKey: item.imageKey, constellations: item.constellations }))), { type: "application/json", acl: "public-read" }),
|
||||
storage.write(`catalog/${version}/characters.json`, JSON.stringify(characters.map((item) => ({ version: item.version, key: item.key, name: item.name, element: item.element, rarity: item.rarity, weaponType: item.weaponType, imageKey: item.imageKey, elementIconKey: item.elementIconKey, constellations: item.constellations }))), { type: "application/json", acl: "public-read" }),
|
||||
storage.write(`catalog/${version}/weapons.json`, JSON.stringify(weapons.map((item) => ({ version: item.version, key: item.key, name: item.name, rarity: item.rarity, weaponType: item.weaponType, imageKey: item.imageKey }))), { type: "application/json", acl: "public-read" }),
|
||||
storage.write(`catalog/${version}/artifacts.json`, JSON.stringify(artifacts.map((item) => ({ version: item.version, key: item.key, name: item.name, imageKey: item.imageKey }))), { type: "application/json", acl: "public-read" }),
|
||||
]);
|
||||
@@ -175,7 +184,7 @@ export async function processCatalogSyncJob(jobId: string): Promise<void> {
|
||||
await tx.delete(catalogCharacters).where(eq(catalogCharacters.version, version));
|
||||
await tx.delete(catalogWeapons).where(eq(catalogWeapons.version, version));
|
||||
await tx.delete(catalogArtifacts).where(eq(catalogArtifacts.version, version));
|
||||
if (characters.length) await tx.insert(catalogCharacters).values(characters.map((item) => ({ version: item.version, key: item.key, name: item.name, element: item.element, rarity: item.rarity, weaponType: item.weaponType, imageKey: item.imageKey, constellations: item.constellations })));
|
||||
if (characters.length) await tx.insert(catalogCharacters).values(characters.map((item) => ({ version: item.version, key: item.key, name: item.name, element: item.element, rarity: item.rarity, weaponType: item.weaponType, imageKey: item.imageKey, elementIconKey: item.elementIconKey, constellations: item.constellations })));
|
||||
if (weapons.length) await tx.insert(catalogWeapons).values(weapons.map((item) => ({ version: item.version, key: item.key, name: item.name, rarity: item.rarity, weaponType: item.weaponType, imageKey: item.imageKey })));
|
||||
if (artifacts.length) await tx.insert(catalogArtifacts).values(artifacts.map((item) => ({ version: item.version, key: item.key, name: item.name, imageKey: item.imageKey })));
|
||||
await tx.update(catalogVersions).set({ active: false });
|
||||
|
||||
Reference in New Issue
Block a user