Actualiser api.php

This commit is contained in:
2026-06-28 14:12:40 +02:00
parent d993260574
commit 62f4570d7c
+166 -31
View File
@@ -60,10 +60,22 @@ function getTmdbApiKey($pdo) {
return $row ? decryptData($row['key_value']) : null;
}
function httpGet($url, $timeout = 5, $ua = null) {
function getUpcmdbApiKey($pdo) {
$stmt = $pdo->prepare("SELECT key_value FROM config WHERE key_name = 'upcmdb_api_key'");
$stmt->execute();
$row = $stmt->fetch();
return $row ? decryptData($row['key_value']) : null;
}
function httpGet($url, $timeout = 5, $ua = null, $extraHeaders = []) {
if (!$ua) $ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36';
$headers = array_merge(
['Accept: application/json, text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language: fr-FR,fr;q=0.8'],
$extraHeaders
);
if (!function_exists('curl_init')) {
$ctx = stream_context_create(['http' => ['timeout' => $timeout, 'user_agent' => $ua]]);
$headerLines = implode("\r\n", $headers);
$ctx = stream_context_create(['http' => ['timeout' => $timeout, 'user_agent' => $ua, 'header' => $headerLines]]);
$res = @file_get_contents($url, false, $ctx);
return $res ?: null;
}
@@ -76,7 +88,7 @@ function httpGet($url, $timeout = 5, $ua = null) {
CURLOPT_USERAGENT => $ua,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_REFERER => 'https://www.cinemapassion.com/',
CURLOPT_HTTPHEADER => ['Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language: fr-FR,fr;q=0.8'],
CURLOPT_HTTPHEADER => $headers,
]);
$res = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
@@ -101,6 +113,125 @@ function detectFormat($title, $desc = '') {
return 'Blu-ray';
}
function parseDiscCountFromTitle($title) {
if (preg_match('/(\d+)\s*(?:dvd|blu-?ray|bluray|bd|disc|disque)/i', $title, $m)) {
return max(1, (int)$m[1]);
}
if (preg_match('/(?:coffret|pack|collection|trilogie|anthologie).*?(\d+)/i', $title, $m)) {
return max(1, (int)$m[1]);
}
if (preg_match('/\btrilogie\b/i', $title)) return 3;
return 1;
}
function cleanUpcTitle($title) {
$clean = trim($title);
$clean = preg_replace('/^[\s"]*(DVD|Blu-ray|Blu Ray|4K|UHD)[\s"]*/i', '', $clean);
$clean = preg_replace('/(blu-ray|bluray|dvd|4k|ultra hd|combo|vhs|blister pack|new blister).*$/i', '', $clean);
$clean = preg_replace('/[\s"]+New[\s"]*$/i', '', $clean);
return cleanTitle($clean);
}
function emptyPhysicalResult() {
return [
'title' => '', 'publisher' => '', 'format' => '', 'length' => '',
'number_of_discs' => 1, 'aspect_ratio' => '', 'year' => ''
];
}
function throttleUpcLookup() {
static $lastLookupAt = 0;
$elapsed = microtime(true) - $lastLookupAt;
if ($lastLookupAt > 0 && $elapsed < 2) {
usleep((int)((2 - $elapsed) * 1000000));
}
$lastLookupAt = microtime(true);
}
// ── API GRATUITE UPCitemdb : métadonnées physiques via EAN/UPC ──
function fetchPhysicalFromUpcitemdb($ean) {
$empty = emptyPhysicalResult();
$ean = preg_replace('/[^0-9]/', '', (string)$ean);
if (strlen($ean) < 8) return $empty;
throttleUpcLookup();
$url = 'https://api.upcitemdb.com/prod/trial/lookup?upc=' . urlencode($ean);
$res = httpGet($url, 10, 'MonPetitCinema/1.0');
if (!$res) return $empty;
$data = json_decode($res, true);
if (empty($data['items'][0])) return $empty;
$item = $data['items'][0];
$rawTitle = $item['title'] ?? '';
$title = cleanUpcTitle($rawTitle) ?: trim($rawTitle);
$publisher = trim($item['brand'] ?? '');
return [
'title' => $title,
'publisher' => $publisher,
'format' => detectFormat($rawTitle),
'length' => '',
'number_of_discs' => parseDiscCountFromTitle($rawTitle),
'aspect_ratio' => '',
'year' => ''
];
}
// ── API UPCMDB (clé gratuite) : fallback spécialisé DVD/Blu-ray/4K ──
function fetchPhysicalFromUpcmdb($ean, $pdo) {
$empty = emptyPhysicalResult();
$apiKey = getUpcmdbApiKey($pdo);
if (!$apiKey) return $empty;
$ean = preg_replace('/[^0-9]/', '', (string)$ean);
if (strlen($ean) < 8) return $empty;
$url = 'https://upcmdb.com/api/v1/lookup/' . urlencode($ean);
$res = httpGet($url, 10, 'MonPetitCinema/1.0', [
'Accept: application/json',
'X-API-Key: ' . $apiKey
]);
if (!$res || $res[0] === '<') return $empty;
$data = json_decode($res, true);
if (($data['status'] ?? '') !== 'success' || empty($data['data'])) return $empty;
$item = $data['data'];
$rawTitle = trim($item['title'] ?? '');
if ($rawTitle === '') return $empty;
$title = cleanUpcTitle($rawTitle) ?: $rawTitle;
$format = trim($item['format'] ?? '');
$runtime = trim($item['runtime'] ?? '');
return [
'title' => $title,
'publisher' => trim($item['studio'] ?? $item['publisher'] ?? ''),
'format' => $format !== '' ? $format : detectFormat($rawTitle),
'length' => $runtime,
'number_of_discs' => parseDiscCountFromTitle($rawTitle),
'aspect_ratio' => trim($item['aspect_ratio'] ?? ''),
'year' => trim($item['year'] ?? '')
];
}
function fetchPhysicalByEan($ean, $pdo = null) {
$result = fetchPhysicalFromUpcitemdb($ean);
if (!empty($result['title'])) return $result;
if ($pdo) {
$fallback = fetchPhysicalFromUpcmdb($ean, $pdo);
if (!empty($fallback['title'])) {
error_log("UPCMDB: ✅ Fallback trouvé pour EAN {$ean}{$fallback['title']}");
return $fallback;
}
}
return $result;
}
// ── FONCTION POUR RÉCUPÉRER LES AFFICHES DEPUIS TMDB ──
function fetchPosterTMDB($title, $year = '', $pdo = null) {
$defaultPoster = 'assets/img/default_physical_media.jpg';
@@ -291,7 +422,7 @@ switch ($action) {
case 'get_config_keys':
checkAuth($pdo);
$stmt = $pdo->prepare("SELECT key_name, key_value FROM config WHERE key_name IN ('tmdb_api_key', 'fanart_api_key')");
$stmt = $pdo->prepare("SELECT key_name, key_value FROM config WHERE key_name IN ('tmdb_api_key', 'fanart_api_key', 'upcmdb_api_key')");
$stmt->execute();
$rows = $stmt->fetchAll();
$config = [];
@@ -300,6 +431,7 @@ switch ($action) {
}
if (!isset($config['tmdb_api_key'])) $config['tmdb_api_key'] = '';
if (!isset($config['fanart_api_key'])) $config['fanart_api_key'] = '';
if (!isset($config['upcmdb_api_key'])) $config['upcmdb_api_key'] = '';
echo json_encode($config);
break;
@@ -307,7 +439,7 @@ switch ($action) {
checkAuth($pdo);
$keyName = $data['key_name'] ?? '';
$keyValue = $data['key_value'] ?? '';
if (in_array($keyName, ['tmdb_api_key', 'fanart_api_key']) && !empty($keyValue)) {
if (in_array($keyName, ['tmdb_api_key', 'fanart_api_key', 'upcmdb_api_key']) && !empty($keyValue)) {
$stmt = $pdo->prepare("REPLACE INTO config (key_name, key_value) VALUES (?, ?)");
$stmt->execute([$keyName, encryptData($keyValue)]);
echo json_encode(["success" => true]);
@@ -319,10 +451,10 @@ switch ($action) {
case 'get_films':
$sql = "
SELECT id, title, year, director, poster, rating, review, NULL AS description, streaming, 'critique' AS type
SELECT id, title, year, director, poster, rating, review, NULL AS description, streaming, 'critique' AS type, NULL AS format
FROM critiques
UNION ALL
SELECT id, title, year, director, poster, NULL AS rating, NULL AS review, description, NULL AS streaming, 'videotheque' AS type
SELECT id, title, year, director, poster, NULL AS rating, NULL AS review, description, NULL AS streaming, 'videotheque' AS type, format
FROM videotheque
ORDER BY id DESC
";
@@ -343,7 +475,7 @@ switch ($action) {
$id = !empty($data['id']) ? $data['id'] : makeStableId($type, $data['title'] ?? '', $data['year'] ?? '0000');
if ($type === 'critique' && (empty($data['director']) || empty($data['poster']))) {
$tmdbData = fetchTMDBFull($data['title'] ?? '', $data['year'] ?? '', getTmdbApiKey($pdo), $pdo);
$tmdbData = fetchTmdbPosterAndSynopsis($data['title'] ?? '', $data['year'] ?? '', $pdo);
if ($tmdbData) {
if (empty($data['director'])) $data['director'] = $tmdbData['director'];
if (empty($data['poster'])) $data['poster'] = $tmdbData['poster'];
@@ -401,6 +533,7 @@ $type = $data['type'] ?? 'critique';
$items = $data['items'] ?? [];
$pdo->beginTransaction();
$imported = 0;
$skipped = 0;
try {
if ($type === 'videotheque') {
$stmtVideo = $pdo->prepare("INSERT INTO videotheque (id, title, year, format, poster, ean_isbn13, description, length, number_of_discs, aspect_ratio, actors, publisher, director)
@@ -419,41 +552,43 @@ try {
year = VALUES(year)");
foreach ($items as $item) {
$title = $item['title'] ?? '';
if (empty($title)) continue;
$year = $item['year'] ?? '';
$id = makeStableId('videotheque', $title, $year);
// ── SOURCE 1 : CSV (Informations physiques uniquement) ──
$ean = $item['ean'] ?? '';
$format = $item['format'] ?? '';
$publisher = $item['publisher'] ?? '';
$discs = $item['number_of_discs'] ?? 1;
$aspect = $item['aspect_ratio'] ?? '';
$length = $item['length'] ?? '';
// On initialise avec le CSV, mais l'API TMDB va écraser ces valeurs si elle trouve mieux
$description = $item['description'] ?? '';
$director = $item['director'] ?? '';
$actors = $item['actors'] ?? '';
// ── SOURCE 1 : CSV → EAN uniquement ──
$ean = preg_replace('/[^0-9]/', '', (string)($item['ean'] ?? ''));
if (strlen($ean) < 8) { $skipped++; continue; }
// ── SOURCE 2 : UPCitemdb (gratuit) → métadonnées physiques ──
$physical = fetchPhysicalByEan($ean, $pdo);
$title = $physical['title'] ?? '';
if (empty($title)) { $skipped++; continue; }
$year = $physical['year'] ?? '';
$format = $physical['format'] ?? '';
$publisher = $physical['publisher'] ?? '';
$discs = $physical['number_of_discs'] ?? 1;
$aspect = $physical['aspect_ratio'] ?? '';
$length = $physical['length'] ?? '';
$id = makeStableId('videotheque', $ean, $title);
$description = '';
$director = '';
$actors = '';
$poster = 'assets/img/default_physical_media.jpg';
// ── SOURCE 2 : API TMDB (Priorité absolue pour les métadonnées) ──
// ── SOURCE 3 : TMDB → affiche, synopsis, réalisateur, acteurs ──
$tmdbData = fetchTmdbPosterAndSynopsis($title, $year, $pdo);
if ($tmdbData) {
if ($tmdbData['poster'] !== 'assets/img/default_physical_media.jpg') {
$poster = $tmdbData['poster'];
}
// Écrasement des données CSV par l'API TMDB si disponibles
if (!empty($tmdbData['description'])) $description = $tmdbData['description'];
if (!empty($tmdbData['director'])) $director = $tmdbData['director'];
if (!empty($tmdbData['actors'])) $actors = $tmdbData['actors'];
if (!empty($tmdbData['length'])) $length = $tmdbData['length'];
if (!empty($tmdbData['year'])) $year = $tmdbData['year'];
}
if (empty($format)) $format = detectFormat($title, $description);
$stmtVideo->execute([
$id, $title, $year, $format, $poster, $ean, $description,
$length, $discs, $aspect, $actors, $publisher, $director
@@ -491,7 +626,7 @@ try {
}
}
$pdo->commit();
echo json_encode(["success" => true, "imported" => $imported]);
echo json_encode(["success" => true, "imported" => $imported, "skipped" => $skipped]);
} catch (Throwable $e) { // ── CORRECTION ICI : Throwable capture les Crash Fatals PHP ──
$pdo->rollBack();