Files
whattoplay/scripts/fetch-blizzard.mjs

184 lines
4.8 KiB
JavaScript

import fs from "fs";
import path from "path";
/**
* Blizzard Account Library Importer
* Nutzt OAuth 2.0 für Authentifizierung
*
* Unterstützt:
* - World of Warcraft
* - Diablo
* - Overwatch
* - StarCraft
* - Warcraft III
* - Heroes of the Storm
* - Hearthstone
*/
const loadConfig = () => {
const configPath = path.join(process.cwd(), "config.local.json");
try {
if (fs.existsSync(configPath)) {
return JSON.parse(fs.readFileSync(configPath, "utf-8"));
}
} catch (error) {
console.log("⚠️ Config nicht lesbar, nutze Defaults");
}
return {
blizzard: {
clientId: "",
clientSecret: "",
accountName: "",
region: "eu",
},
};
};
const fetchBlizzardGames = async ({ clientId, clientSecret, region }) => {
// OAuth 2.0 Token Endpoint
const tokenUrl = `https://${region}.battle.net/oauth/token`;
const libraryUrl = `https://${region}.api.blizzard.com/d3/profile/${clientId}/hero`;
try {
// Schritt 1: Bearer Token holen (Client Credentials Flow)
const tokenResponse = await fetch(tokenUrl, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`,
},
body: new URLSearchParams({
grant_type: "client_credentials",
scope: "d3.profile.us",
}),
});
if (!tokenResponse.ok) {
throw new Error(
`Token-Fehler: ${tokenResponse.status} - ${await tokenResponse.text()}`,
);
}
const { access_token } = await tokenResponse.json();
// Schritt 2: Games/Accountinfo laden
const gamesResponse = await fetch(libraryUrl, {
headers: {
Authorization: `Bearer ${access_token}`,
"User-Agent": "WhatToPlay/1.0",
},
});
if (!gamesResponse.ok) {
console.warn(
`⚠️ Blizzard API: ${gamesResponse.status} - Möglicherweise falscher Region oder Credentials`,
);
return [];
}
const data = await gamesResponse.json();
// Blizzard gibt Heros statt Games zurück
// Wir extrahieren Informationen über verfügbare Spiele
return data.heroes || [];
} catch (error) {
console.error(`❌ Blizzard Fehler: ${error.message}`);
return [];
}
};
const buildBlizzardEntry = (hero, gameType = "Diablo III") => ({
id: `blizzard-${hero.id}`,
title: `${gameType} - ${hero.name}`,
platform: "Blizzard",
class: hero.class,
level: hero.level,
experience: hero.experience,
killed: hero.kills?.elites || 0,
hardcore: hero.hardcore || false,
lastPlayed: hero.lastUpdated
? new Date(hero.lastUpdated).toISOString()
: null,
url: `https://www.diablo3.com/en/profile/${hero.id}/`,
});
const buildTextFile = (game) => {
const lines = [
`# ${game.title}`,
"",
`**Plattform**: ${game.platform}`,
`**Charaktertyp**: ${game.class || "Unbekannt"}`,
`**Level**: ${game.level || "N/A"}`,
game.hardcore ? `**Hardcore**: Ja ⚔️` : "",
`**Elite-Kills**: ${game.killed || 0}`,
`**Erfahrung**: ${game.experience || 0}`,
game.lastPlayed
? `**Zuletzt gespielt**: ${new Date(game.lastPlayed).toLocaleDateString("de-DE")}`
: "",
"",
`[Im Profil anschauen](${game.url})`,
];
return lines.filter(Boolean).join("\n");
};
const writeBlizzardData = async (games) => {
const dataDir = path.join(process.cwd(), "public/data");
const textDir = path.join(dataDir, "blizzard-text");
// Stelle sicher dass Verzeichnisse existieren
if (!fs.existsSync(dataDir)) fs.mkdirSync(dataDir, { recursive: true });
if (!fs.existsSync(textDir)) fs.mkdirSync(textDir, { recursive: true });
// Schreibe JSON-Datei
fs.writeFileSync(
path.join(dataDir, "blizzard.json"),
JSON.stringify(games, null, 2),
"utf-8",
);
// Schreibe Text-Dateien für jeden Hero
games.forEach((game) => {
const textFile = `${game.id}.txt`;
const filePath = path.join(textDir, textFile);
const content = buildTextFile(game);
fs.writeFileSync(filePath, content, "utf-8");
});
return games.length;
};
const main = async () => {
const config = loadConfig();
const { clientId, clientSecret, region } = config.blizzard || {};
if (!clientId || !clientSecret) {
console.log(
"⚠️ Blizzard: Keine Credentials - Überspringe\n → Für iOS/Web: Backend mit OAuth benötigt\n → Siehe docs/BLIZZARD-SETUP.md für Development-Setup",
);
return;
}
console.log("⏳ Blizzard-Games laden...");
const games = await fetchBlizzardGames({
clientId,
clientSecret,
region: region || "eu",
});
if (games.length === 0) {
console.log(
"⚠️ Keine Blizzard-Games gefunden\n → Stelle sicher dass der Account mit Heros in Diablo III hat",
);
return;
}
// Verarbeite jeden Hero
const processedGames = games.map((hero) => buildBlizzardEntry(hero));
const count = await writeBlizzardData(processedGames);
console.log(`✓ Blizzard-Export fertig: ${count} Charaktere`);
};
main().catch(console.error);