merge multimedia.php with igdb.php
parent
eb3419aea6
commit
975b704553
@ -0,0 +1,891 @@
|
||||
<?php
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', '1');
|
||||
|
||||
// igdb.php
|
||||
|
||||
require_once __DIR__ . '/igdb-settings.php';
|
||||
|
||||
if (!defined('WIKI_DE_API_URL')) {
|
||||
define('WIKI_DE_API_URL', 'https://de.wikipedia.org/w/api.php');
|
||||
}
|
||||
|
||||
if (!defined('WIKI_USER_AGENT')) {
|
||||
define('WIKI_USER_AGENT', 'MultimediaFlutter/1.0 (https://windesign.at; Herwig.Birke@windesign.at)');
|
||||
}
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
// =====================================================
|
||||
// CORS HANDLING
|
||||
// =====================================================
|
||||
|
||||
function origin_allowed(string $origin): bool
|
||||
{
|
||||
if (!defined('IGDB_ALLOWED_ORIGINS')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (IGDB_ALLOWED_ORIGINS as $allowed) {
|
||||
|
||||
// Wildcards verarbeiten: *.domain.tld oder localhost:*
|
||||
if (strpos($allowed, '*') !== false) {
|
||||
$pattern = '#^' . str_replace(
|
||||
['*', '.', ':'],
|
||||
['.*', '\.', '\:'],
|
||||
$allowed
|
||||
) . '$#i';
|
||||
|
||||
if (preg_match($pattern, $origin)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (strcasecmp($allowed, $origin) === 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set CORS headers if origin matches
|
||||
$origin = $_SERVER['HTTP_ORIGIN'] ?? null;
|
||||
if ($origin && origin_allowed($origin)) {
|
||||
header('Access-Control-Allow-Origin: ' . $origin);
|
||||
header('Vary: Origin');
|
||||
}
|
||||
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
|
||||
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');
|
||||
|
||||
// Preflight
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||
http_response_code(204);
|
||||
exit;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// HELPERS
|
||||
// =====================================================
|
||||
|
||||
function respond($data, int $status = 200): void
|
||||
{
|
||||
http_response_code($status);
|
||||
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||
exit;
|
||||
}
|
||||
|
||||
function error_response($msg, int $status = 400): void
|
||||
{
|
||||
if (is_string($msg)) {
|
||||
$msg = ['error' => $msg];
|
||||
}
|
||||
respond($msg, $status);
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// DATABASE
|
||||
// =====================================================
|
||||
|
||||
function getDb(): PDO
|
||||
{
|
||||
static $pdo = null;
|
||||
if ($pdo !== null) {
|
||||
return $pdo;
|
||||
}
|
||||
|
||||
$dsn = sprintf(
|
||||
'mysql:host=%s;dbname=%s;charset=utf8mb4',
|
||||
DATABASE_HOST,
|
||||
DATABASE_NAME
|
||||
);
|
||||
|
||||
try {
|
||||
$pdo = new PDO($dsn, DATABASE_USER, DATABASE_PASSWORD, [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
]);
|
||||
} catch (PDOException $e) {
|
||||
error_response('DB connection failed: ' . $e->getMessage(), 500);
|
||||
}
|
||||
|
||||
return $pdo;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// LOCALIZATION SUPPORT (Tabelle igdb_localizations)
|
||||
// =====================================================
|
||||
|
||||
function getLocalization(int $igdbId, string $lang = 'de'): ?array
|
||||
{
|
||||
$pdo = getDb();
|
||||
$stmt = $pdo->prepare(
|
||||
'SELECT * FROM igdb_localizations WHERE igdb_id = :id AND lang = :lang LIMIT 1'
|
||||
);
|
||||
$stmt->execute([
|
||||
':id' => $igdbId,
|
||||
':lang' => $lang,
|
||||
]);
|
||||
$row = $stmt->fetch();
|
||||
return $row ?: null;
|
||||
}
|
||||
|
||||
function saveLocalization(
|
||||
int $igdbId,
|
||||
string $lang,
|
||||
?string $title,
|
||||
?string $summary,
|
||||
?string $storyline,
|
||||
?int $userId
|
||||
): array {
|
||||
$pdo = getDb();
|
||||
|
||||
$sql = '
|
||||
INSERT INTO igdb_localizations (igdb_id, lang, title, summary, storyline, user_id)
|
||||
VALUES (:id, :lang, :title, :summary, :storyline, :user_id)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
title = VALUES(title),
|
||||
summary = VALUES(summary),
|
||||
storyline = VALUES(storyline),
|
||||
user_id = VALUES(user_id),
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
';
|
||||
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([
|
||||
':id' => $igdbId,
|
||||
':lang' => $lang,
|
||||
':title' => $title,
|
||||
':summary' => $summary,
|
||||
':storyline' => $storyline,
|
||||
':user_id' => $userId,
|
||||
]);
|
||||
|
||||
return getLocalization($igdbId, $lang);
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// GAMES IN MULTIMEDIAFLUTTER (Tabelle games)
|
||||
// =====================================================
|
||||
|
||||
function saveGameStatus(
|
||||
int $igdbId,
|
||||
string $name,
|
||||
?string $originalName,
|
||||
int $status,
|
||||
?string $note = null
|
||||
): array {
|
||||
$pdo = getDb();
|
||||
|
||||
$sql = '
|
||||
INSERT INTO games (igdb_id, name, original_name, status, note)
|
||||
VALUES (:igdb_id, :name, :original_name, :status, :note)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
name = VALUES(name),
|
||||
original_name = VALUES(original_name),
|
||||
status = VALUES(status),
|
||||
note = VALUES(note),
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
';
|
||||
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([
|
||||
':igdb_id' => $igdbId,
|
||||
':name' => $name,
|
||||
':original_name'=> $originalName,
|
||||
':status' => $status,
|
||||
':note' => $note,
|
||||
]);
|
||||
|
||||
$stmt = $pdo->prepare('SELECT * FROM games WHERE igdb_id = :id LIMIT 1');
|
||||
$stmt->execute([':id' => $igdbId]);
|
||||
return $stmt->fetch() ?: [];
|
||||
}
|
||||
|
||||
function getGameByIgdbId(int $igdbId): ?array
|
||||
{
|
||||
$pdo = getDb();
|
||||
$stmt = $pdo->prepare('SELECT * FROM games WHERE igdb_id = :id LIMIT 1');
|
||||
$stmt->execute([':id' => $igdbId]);
|
||||
return $stmt->fetch() ?: null;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// IMAGE URL BUILDER
|
||||
// =====================================================
|
||||
|
||||
function igdbImageUrl(?string $imageId, string $sizeTag = 't_cover_big'): ?string
|
||||
{
|
||||
if (!$imageId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'https://images.igdb.com/igdb/image/upload/%s/%s.jpg',
|
||||
$sizeTag,
|
||||
$imageId
|
||||
);
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// TWITCH TOKEN + IGDB REQUEST
|
||||
// =====================================================
|
||||
|
||||
function getCachedToken(): ?array
|
||||
{
|
||||
if (!file_exists(IGDB_TOKEN_CACHE_FILE)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$json = file_get_contents(IGDB_TOKEN_CACHE_FILE);
|
||||
$data = json_decode($json, true);
|
||||
|
||||
if (!$data || time() >= ($data['expires_at'] ?? 0)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
function saveToken(array $tokenData): void
|
||||
{
|
||||
$expiresIn = (int)($tokenData['expires_in'] ?? 0);
|
||||
$tokenData['expires_at'] = time() + $expiresIn - 60; // 60s Puffer
|
||||
|
||||
file_put_contents(
|
||||
IGDB_TOKEN_CACHE_FILE,
|
||||
json_encode($tokenData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
|
||||
);
|
||||
}
|
||||
|
||||
function fetchNewToken(): array
|
||||
{
|
||||
$postFields = [
|
||||
'client_id' => TWITCH_CLIENT_ID,
|
||||
'client_secret' => TWITCH_CLIENT_SECRET,
|
||||
'grant_type' => 'client_credentials',
|
||||
];
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => TWITCH_TOKEN_URL,
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => http_build_query($postFields),
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
$data = json_decode($response, true);
|
||||
|
||||
if ($status !== 200) {
|
||||
error_response([
|
||||
'message' => 'Failed to fetch token from Twitch',
|
||||
'status' => $status,
|
||||
'body' => $data,
|
||||
], 500);
|
||||
}
|
||||
|
||||
saveToken($data);
|
||||
return $data;
|
||||
}
|
||||
|
||||
function getAccessToken(): string
|
||||
{
|
||||
$cached = getCachedToken();
|
||||
if ($cached) {
|
||||
return $cached['access_token'];
|
||||
}
|
||||
|
||||
$new = fetchNewToken();
|
||||
return $new['access_token'];
|
||||
}
|
||||
|
||||
function igdbRequest(string $endpoint, string $body)
|
||||
{
|
||||
$accessToken = getAccessToken();
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => IGDB_BASE_URL . $endpoint,
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => $body,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Client-ID: ' . TWITCH_CLIENT_ID,
|
||||
'Authorization: Bearer ' . $accessToken,
|
||||
'Accept: application/json',
|
||||
],
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
$data = json_decode($response, true);
|
||||
|
||||
if ($status !== 200) {
|
||||
error_response([
|
||||
'message' => 'IGDB returned error',
|
||||
'status' => $status,
|
||||
'body' => $data,
|
||||
], 500);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interne Hilfsfunktion: macht einen Wikipedia-API-Call mit einem Suchstring
|
||||
* und gibt das erste Page-Objekt (inkl. extract) zurück.
|
||||
*/
|
||||
function wikiApiSearchWithExtract(string $searchQuery): ?array
|
||||
{
|
||||
$params = [
|
||||
'action' => 'query',
|
||||
'generator' => 'search',
|
||||
'gsrsearch' => $searchQuery,
|
||||
'gsrlimit' => 1,
|
||||
'prop' => 'extracts',
|
||||
'exintro' => 1,
|
||||
'explaintext' => 1,
|
||||
'format' => 'json',
|
||||
'utf8' => 1,
|
||||
];
|
||||
|
||||
$url = WIKI_DE_API_URL . '?' . http_build_query($params, '', '&');
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => 5,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'User-Agent: ' . WIKI_USER_AGENT,
|
||||
],
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
if ($response === false) {
|
||||
curl_close($ch);
|
||||
return null;
|
||||
}
|
||||
|
||||
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
if ($status !== 200) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$data = json_decode($response, true);
|
||||
if (!is_array($data) || empty($data['query']['pages'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$pages = $data['query']['pages'];
|
||||
$page = reset($pages);
|
||||
|
||||
if (empty($page['extract'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// debug_url zum leichteren Debuggen
|
||||
$page['debug_url'] = $url;
|
||||
|
||||
return $page;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hochwertige DE-Zusammenfassung für einen Spieltitel holen.
|
||||
*
|
||||
* - Probiert mehrere Suchvarianten (Videospiel, Computerspiel, etc.)
|
||||
* - Schneidet den Text auf ~600 Zeichen
|
||||
* - Liefert Titel, Extract, URL + debug_url
|
||||
*/
|
||||
function wikiFetchGermanSummaryForTitle(string $gameTitle): ?array
|
||||
{
|
||||
$gameTitleTrimmed = trim($gameTitle);
|
||||
|
||||
// Verschiedene Suchmuster, um Spiele sauber zu treffen
|
||||
$patterns = [
|
||||
$gameTitleTrimmed . ' (Computerspiel)',
|
||||
$gameTitleTrimmed . ' (Videospiel)',
|
||||
$gameTitleTrimmed . ' Videospiel',
|
||||
$gameTitleTrimmed, // Fallback: purer Titel
|
||||
];
|
||||
|
||||
foreach ($patterns as $pattern) {
|
||||
$page = wikiApiSearchWithExtract($pattern);
|
||||
if ($page === null || empty($page['extract'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$pageTitle = $page['title'] ?? $gameTitleTrimmed;
|
||||
|
||||
// einfache Heuristik: Title ohne Klammern vergleichen
|
||||
$canonicalPageTitle = mb_strtolower(preg_replace('/\s*\(.*?\)\s*/u', '', $pageTitle), 'UTF-8');
|
||||
$canonicalGameTitle = mb_strtolower($gameTitleTrimmed, 'UTF-8');
|
||||
|
||||
// Wenn der Titel gar nicht passt, nächsten Versuch → verbessert Qualität
|
||||
if (mb_strpos($canonicalPageTitle, $canonicalGameTitle) === false &&
|
||||
mb_strpos($canonicalGameTitle, $canonicalPageTitle) === false) {
|
||||
// könnte z.B. „Zelda (Band)“ sein → skip
|
||||
continue;
|
||||
}
|
||||
|
||||
$extract = $page['extract'];
|
||||
$short = mb_substr($extract, 0, 600, 'UTF-8');
|
||||
|
||||
return [
|
||||
'pageid' => (int)($page['pageid'] ?? 0),
|
||||
'title' => $pageTitle,
|
||||
'extract' => $short,
|
||||
'url' => 'https://de.wikipedia.org/?curid=' . (int)($page['pageid'] ?? 0),
|
||||
'debug_url' => $page['debug_url'] ?? null,
|
||||
];
|
||||
}
|
||||
|
||||
// Keine passende Seite gefunden
|
||||
return null;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// ROUTING
|
||||
// =====================================================
|
||||
|
||||
$action = $_GET['action'] ?? 'ping';
|
||||
|
||||
switch ($action) {
|
||||
|
||||
// ---------------------------------------
|
||||
case 'ping':
|
||||
respond(['status' => 'ok']);
|
||||
break;
|
||||
|
||||
// ---------------------------------------
|
||||
case 'search':
|
||||
$query = $_GET['query'] ?? '';
|
||||
$limit = (int)($_GET['limit'] ?? 10);
|
||||
$page = (int)($_GET['page'] ?? 1);
|
||||
$lang = $_GET['lang'] ?? 'en';
|
||||
|
||||
$checkExternal = isset($_GET['check_external'])
|
||||
? ((int)$_GET['check_external'] === 1)
|
||||
: false;
|
||||
|
||||
$debug = isset($_GET['debug'])
|
||||
? ((int)$_GET['debug'] === 1)
|
||||
: false;
|
||||
|
||||
if ($query === '') {
|
||||
error_response('Missing "query"', 400);
|
||||
}
|
||||
|
||||
if ($limit < 1 || $limit > 50) {
|
||||
$limit = 10;
|
||||
}
|
||||
if ($page < 1) {
|
||||
$page = 1;
|
||||
}
|
||||
|
||||
$offset = ($page - 1) * $limit;
|
||||
|
||||
$body = sprintf(
|
||||
'fields id,name,summary,first_release_date,cover.image_id; ' .
|
||||
'limit %d; offset %d; search "%s";',
|
||||
$limit,
|
||||
$offset,
|
||||
addslashes($query)
|
||||
);
|
||||
|
||||
$results = igdbRequest('/games', $body);
|
||||
|
||||
foreach ($results as &$g) {
|
||||
// Cover-URL
|
||||
$g['cover_url'] = isset($g['cover']['image_id'])
|
||||
? igdbImageUrl($g['cover']['image_id'], 't_cover_big')
|
||||
: null;
|
||||
|
||||
// eigener Status aus games
|
||||
$localGame = getGameByIgdbId($g['id']);
|
||||
$g['my_status'] = $localGame['status'] ?? null;
|
||||
|
||||
// eig. Lokalisierung aus DB (z.B. de)
|
||||
$hasLoc = false;
|
||||
if ($lang !== 'en') {
|
||||
$loc = getLocalization($g['id'], $lang);
|
||||
if ($loc !== null) {
|
||||
$hasLoc = true;
|
||||
|
||||
if (!empty($loc['title'])) {
|
||||
$g['name'] = $loc['title'];
|
||||
}
|
||||
if (!empty($loc['summary'])) {
|
||||
$g['summary'] = $loc['summary'];
|
||||
}
|
||||
}
|
||||
}
|
||||
$g['has_localization'] = $hasLoc;
|
||||
|
||||
// Wikipedia-Felder vorbereiten
|
||||
$g['has_external_de'] = false;
|
||||
$g['external_de_source'] = null;
|
||||
$g['external_de_summary'] = null;
|
||||
$g['external_de_url'] = null;
|
||||
|
||||
if ($debug) {
|
||||
$g['wiki_debug'] = [];
|
||||
}
|
||||
|
||||
// Wikipedia nur bei lang=de, wenn keine eigene Lokalisierung da ist
|
||||
if ($checkExternal && $lang === 'de' && !$hasLoc) {
|
||||
$wiki = wikiFetchGermanSummaryForTitle($g['name']);
|
||||
|
||||
if ($debug) {
|
||||
$g['wiki_debug']['used_title'] = $g['name'];
|
||||
$g['wiki_debug']['wiki_result'] = $wiki;
|
||||
}
|
||||
|
||||
if ($wiki !== null && !empty($wiki['extract'])) {
|
||||
$g['has_external_de'] = true;
|
||||
$g['external_de_source'] = 'wikipedia';
|
||||
$g['external_de_summary'] = $wiki['extract'];
|
||||
$g['external_de_url'] = $wiki['url'];
|
||||
|
||||
// Direkt als Summary verwenden (Qualitäts-Boost)
|
||||
$g['summary'] = $wiki['extract'];
|
||||
|
||||
// OPTIONAL: den Titel auf Wikipedia-Titel setzen:
|
||||
// $g['name'] = $wiki['title'];
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($g);
|
||||
|
||||
respond([
|
||||
'source' => 'igdb',
|
||||
'mode' => 'search',
|
||||
'lang' => $lang,
|
||||
'query' => $query,
|
||||
'page' => $page,
|
||||
'limit' => $limit,
|
||||
'offset' => $offset,
|
||||
'results_count' => count($results),
|
||||
'results' => $results,
|
||||
]);
|
||||
break;
|
||||
|
||||
// ---------------------------------------
|
||||
case 'details':
|
||||
$idParam = $_GET['id'] ?? '';
|
||||
$lang = $_GET['lang'] ?? 'en';
|
||||
|
||||
$checkExternal = isset($_GET['check_external'])
|
||||
? ((int)$_GET['check_external'] === 1)
|
||||
: false;
|
||||
|
||||
if ($idParam === '') {
|
||||
error_response('Missing "id"', 400);
|
||||
}
|
||||
|
||||
$id = (int)$idParam;
|
||||
if ($id <= 0) {
|
||||
error_response('Invalid "id"', 400);
|
||||
}
|
||||
|
||||
$body = sprintf(
|
||||
'fields ' .
|
||||
'id,' .
|
||||
'name,' .
|
||||
'summary,' .
|
||||
'storyline,' .
|
||||
'first_release_date,' .
|
||||
'genres.name,' .
|
||||
'platforms.name,' .
|
||||
'cover.image_id,' .
|
||||
'screenshots.image_id,' .
|
||||
'involved_companies.company.name,' .
|
||||
'websites.url,' .
|
||||
'websites.category,' .
|
||||
'age_ratings.rating,' .
|
||||
'age_ratings.category,' .
|
||||
'language_supports.language;' .
|
||||
' where id = %d;',
|
||||
$id
|
||||
);
|
||||
|
||||
$results = igdbRequest('/games', $body);
|
||||
|
||||
if (empty($results)) {
|
||||
error_response('Game not found', 404);
|
||||
}
|
||||
|
||||
$game = $results[0];
|
||||
|
||||
// Cover-URL
|
||||
$game['cover_url'] = isset($game['cover']['image_id'])
|
||||
? igdbImageUrl($game['cover']['image_id'], 't_cover_big')
|
||||
: null;
|
||||
|
||||
// Screenshot-URLs
|
||||
$game['screenshot_urls'] = [];
|
||||
if (!empty($game['screenshots']) && is_array($game['screenshots'])) {
|
||||
foreach ($game['screenshots'] as $s) {
|
||||
if (!empty($s['image_id'])) {
|
||||
$game['screenshot_urls'][] =
|
||||
igdbImageUrl($s['image_id'], 't_screenshot_big');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// eigener Status / Notiz
|
||||
$localGame = getGameByIgdbId($id);
|
||||
if ($localGame !== null) {
|
||||
$game['my_status'] = (int)$localGame['status'];
|
||||
$game['my_note'] = $localGame['note'];
|
||||
} else {
|
||||
$game['my_status'] = null;
|
||||
$game['my_note'] = null;
|
||||
}
|
||||
|
||||
// eigene Lokalisierung (DB)
|
||||
$hasLoc = false;
|
||||
if ($lang !== 'en') {
|
||||
$loc = getLocalization($id, $lang);
|
||||
if ($loc !== null) {
|
||||
$hasLoc = true;
|
||||
|
||||
if (!empty($loc['title'])) {
|
||||
$game['name'] = $loc['title'];
|
||||
}
|
||||
if (!empty($loc['summary'])) {
|
||||
$game['summary'] = $loc['summary'];
|
||||
}
|
||||
if (!empty($loc['storyline'])) {
|
||||
$game['storyline'] = $loc['storyline'];
|
||||
}
|
||||
|
||||
$game['localization'] = [
|
||||
'lang' => $lang,
|
||||
'source' => 'custom',
|
||||
'id' => $loc['id'],
|
||||
];
|
||||
}
|
||||
}
|
||||
$game['has_localization'] = $hasLoc;
|
||||
|
||||
// Wikipedia-Fallback (DE), wenn keine eigene Lokalisierung existiert
|
||||
$game['has_external_de'] = false;
|
||||
$game['external_de_source'] = null;
|
||||
$game['external_de_summary'] = null;
|
||||
$game['external_de_url'] = null;
|
||||
|
||||
if ($checkExternal && $lang === 'de' && !$hasLoc) {
|
||||
$wiki = wikiFetchGermanSummaryForTitle($game['name']);
|
||||
|
||||
if ($wiki !== null && !empty($wiki['extract'])) {
|
||||
$game['has_external_de'] = true;
|
||||
$game['external_de_source'] = 'wikipedia';
|
||||
$game['external_de_summary'] = $wiki['extract'];
|
||||
$game['external_de_url'] = $wiki['url'];
|
||||
|
||||
// Summary-Fallback auf DE-Text
|
||||
$game['summary'] = $wiki['extract'];
|
||||
|
||||
// OPTIONAL: Name anpassen
|
||||
// $game['name'] = $wiki['title'];
|
||||
}
|
||||
}
|
||||
|
||||
respond([
|
||||
'source' => 'igdb',
|
||||
'mode' => 'details',
|
||||
'lang' => $lang,
|
||||
'id' => $id,
|
||||
'game' => $game,
|
||||
]);
|
||||
break;
|
||||
|
||||
// ---------------------------------------
|
||||
case 'get_localization':
|
||||
$idParam = $_GET['id'] ?? '';
|
||||
$lang = $_GET['lang'] ?? 'de';
|
||||
|
||||
if ($idParam === '') {
|
||||
error_response('Missing "id"', 400);
|
||||
}
|
||||
|
||||
$igdbId = (int)$idParam;
|
||||
if ($igdbId <= 0) {
|
||||
error_response('Invalid "id"', 400);
|
||||
}
|
||||
|
||||
$loc = getLocalization($igdbId, $lang);
|
||||
|
||||
respond([
|
||||
'found' => (bool)$loc,
|
||||
'localization' => $loc,
|
||||
]);
|
||||
break;
|
||||
|
||||
// ---------------------------------------
|
||||
case 'submit_localization':
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
error_response('Use POST', 405);
|
||||
}
|
||||
|
||||
$raw = file_get_contents('php://input');
|
||||
$data = json_decode($raw, true);
|
||||
if (!is_array($data)) {
|
||||
error_response('Invalid JSON body', 400);
|
||||
}
|
||||
|
||||
$igdbId = (int)($data['igdb_id'] ?? 0);
|
||||
$lang = trim($data['lang'] ?? 'de');
|
||||
$title = isset($data['title']) ? trim($data['title']) : '';
|
||||
$summary= isset($data['summary']) ? trim($data['summary']) : '';
|
||||
$story = isset($data['storyline']) ? trim($data['storyline']) : '';
|
||||
$userId = isset($data['user_id']) ? (int)$data['user_id'] : null;
|
||||
|
||||
if ($igdbId <= 0) {
|
||||
error_response('Invalid "igdb_id"', 400);
|
||||
}
|
||||
|
||||
if ($lang === '') {
|
||||
$lang = 'de';
|
||||
}
|
||||
|
||||
$loc = saveLocalization(
|
||||
$igdbId,
|
||||
$lang,
|
||||
$title ?: null,
|
||||
$summary ?: null,
|
||||
$story ?: null,
|
||||
$userId
|
||||
);
|
||||
|
||||
respond([
|
||||
'success' => true,
|
||||
'localization' => $loc,
|
||||
]);
|
||||
break;
|
||||
|
||||
// ---------------------------------------
|
||||
case 'set_game_status':
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
error_response('Use POST', 405);
|
||||
}
|
||||
|
||||
$raw = file_get_contents('php://input');
|
||||
$data = json_decode($raw, true);
|
||||
if (!is_array($data)) {
|
||||
error_response('Invalid JSON body', 400);
|
||||
}
|
||||
|
||||
$igdbId = (int)($data['igdb_id'] ?? 0);
|
||||
$name = isset($data['name']) ? trim($data['name']) : '';
|
||||
$orig = isset($data['original_name']) ? trim($data['original_name']) : '';
|
||||
$status = (int)($data['status'] ?? 0);
|
||||
$note = isset($data['note']) ? trim($data['note']) : '';
|
||||
|
||||
if ($igdbId <= 0) {
|
||||
error_response('Invalid "igdb_id"', 400);
|
||||
}
|
||||
if ($name === '') {
|
||||
error_response('Missing "name"', 400);
|
||||
}
|
||||
if ($status < 0 || $status > 2) {
|
||||
error_response('Invalid "status" (0, 1, 2 allowed)', 400);
|
||||
}
|
||||
|
||||
$game = saveGameStatus(
|
||||
$igdbId,
|
||||
$name,
|
||||
$orig !== '' ? $orig : null,
|
||||
$status,
|
||||
$note !== '' ? $note : null
|
||||
);
|
||||
|
||||
respond([
|
||||
'success' => true,
|
||||
'game' => $game,
|
||||
]);
|
||||
break;
|
||||
|
||||
// ---------------------------------------
|
||||
case 'get_game':
|
||||
$idParam = $_GET['igdb_id'] ?? '';
|
||||
if ($idParam === '') {
|
||||
error_response('Missing "igdb_id"', 400);
|
||||
}
|
||||
|
||||
$igdbId = (int)$idParam;
|
||||
if ($igdbId <= 0) {
|
||||
error_response('Invalid "igdb_id"', 400);
|
||||
}
|
||||
|
||||
$game = getGameByIgdbId($igdbId);
|
||||
|
||||
respond([
|
||||
'found' => (bool)$game,
|
||||
'game' => $game,
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'wiki_test':
|
||||
$title = $_GET['title'] ?? '';
|
||||
if ($title === '') {
|
||||
error_response('Missing "title"', 400);
|
||||
}
|
||||
|
||||
// Wir bauen die URL sichtbar zusammen
|
||||
$params = [
|
||||
'action' => 'query',
|
||||
'generator' => 'search',
|
||||
'gsrsearch' => $title . ' Videospiel',
|
||||
'gsrlimit' => 1,
|
||||
'prop' => 'extracts',
|
||||
'exintro' => 1,
|
||||
'explaintext' => 1,
|
||||
'format' => 'json',
|
||||
'utf8' => 1,
|
||||
];
|
||||
|
||||
$url = WIKI_DE_API_URL . '?' . http_build_query($params, '', '&');
|
||||
|
||||
// Wikipedia anfragen
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => 5,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'User-Agent: ' . WIKI_USER_AGENT,
|
||||
],
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$curlErr = curl_error($ch);
|
||||
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
// Parse versuchen
|
||||
$json = json_decode($response, true);
|
||||
|
||||
respond([
|
||||
'title' => $title,
|
||||
'used_url' => $url, // <- DIE WICHTIGE URL
|
||||
'http_status' => $status,
|
||||
'curl_error' => $curlErr,
|
||||
'raw_response' => $response, // <- Rohdaten
|
||||
'parsed_json' => $json, // <- Versuch zu decodieren
|
||||
]);
|
||||
break;
|
||||
|
||||
// ---------------------------------------
|
||||
default:
|
||||
error_response('Unknown action: ' . $action, 404);
|
||||
}
|
||||
Loading…
Reference in New Issue