2026-07-07 16:59:54 +02:00

126 lines
3.9 KiB
TypeScript

import { write } from "bun";
const API_BASE = "https://eldenring.fanapis.com/api";
async function fetchAll(endpoint: string) {
let allData: any[] = [];
let page = 0;
const limit = 100;
while (true) {
const res = await fetch(`${API_BASE}/${endpoint}?limit=${limit}&page=${page}`);
if (!res.ok) {
console.error(`Error fetching ${endpoint}:`, res.status);
break;
}
const data = await res.json();
if (!data.data || data.data.length === 0) {
break;
}
allData = allData.concat(data.data);
console.log(`Fetched ${allData.length} ${endpoint}...`);
if (data.data.length < limit) {
break;
}
page++;
}
return allData;
}
function extractRegion(entityRegion: string | null | undefined, locationStr: string | null | undefined, locationLookup: Map<string, string>, uniqueRegions: Set<string>): string | null {
// 1. If the entity has a region, use it (and clean up typos from API)
if (entityRegion) {
let r = entityRegion;
if (r === "Liunia of the Lakes") r = "Liurnia of the Lakes";
if (r === "Mountaintop of the Giants") r = "Mountaintops of the Giants";
if (r === "Altus Pleateau") r = "Altus Plateau";
uniqueRegions.add(r);
return r;
}
// 2. Lookup via locations map
if (locationStr) {
for (const [locName, regionName] of locationLookup.entries()) {
if (locationStr.toLowerCase().includes(locName.toLowerCase())) {
return regionName;
}
}
// 3. Fallback: check if the location string itself contains a known dynamic region
for (const region of uniqueRegions) {
if (locationStr.toLowerCase().includes(region.toLowerCase())) {
return region;
}
}
}
return null;
}
async function main() {
console.log("Fetching locations...");
const locations = await fetchAll("locations");
const uniqueRegions = new Set<string>();
const locationLookup = new Map<string, string>();
// Normalize regions and build a lookup map: LocationName -> Region
for (const loc of locations) {
if (loc.region) {
let r = loc.region;
if (r === "Liunia of the Lakes" || r === "Liurnia") r = "Liurnia of the Lakes";
if (r === "Mountaintop of the Giants") r = "Mountaintops of the Giants";
if (r === "Altus Pleateau") r = "Altus Plateau";
uniqueRegions.add(r);
locationLookup.set(loc.name, r);
}
}
console.log("Fetching bosses...");
const bosses = await fetchAll("bosses");
console.log("Fetching creatures...");
const creatures = await fetchAll("creatures");
console.log("Fetching npcs...");
const npcs = await fetchAll("npcs");
const livingEntities = [
...bosses.map(b => ({ ...b, _type: "boss" })),
...creatures.map(c => ({ ...c, _type: "creature" })),
...npcs.map(n => ({ ...n, _type: "npc" }))
];
const cleanedEntities = livingEntities.map(entity => {
// combine all possible location info
const cleanRegion = extractRegion(entity.region, entity.location, locationLookup, uniqueRegions);
return {
id: entity.id,
name: entity.name,
type: entity._type,
cleanRegion: cleanRegion || "Unknown",
originalLocation: entity.location,
drops: entity.drops || []
};
});
// Save regions based on what was dynamically found in the API
const regionsData = Array.from(uniqueRegions).map((r, i) => ({ id: i + 1, name: r }));
console.log("Fetching items...");
const items = await fetchAll("items");
// you might also want weapons, armors etc depending on what "items" means to the user.
// The fan API separates items, weapons, armors, etc. Let's just fetch items for now.
const output = {
regions: regionsData,
entities: cleanedEntities,
items: items.map(i => ({ id: i.id, name: i.name, type: i.type, effect: i.effect }))
};
await write("./db/fanapi_data.json", JSON.stringify(output, null, 2));
console.log("Saved to db/fanapi_data.json");
}
main().catch(console.error);