Files
mon-petit-cinema/api.php
T
2026-06-24 09:09:56 +02:00

560 lines
29 KiB
PHP

<?php
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization");
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
define('ENCRYPTION_KEY', 'MaCleSecreteSuperRobuste123!');
define('CACHE_TTL', 604800); // 7 jours
try {
$pdo = new PDO("mysql:host=localhost;dbname=mon_cinema;charset=utf8mb4", "root", "", [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]);
$pdo->exec("CREATE TABLE IF NOT EXISTS users (id INT PRIMARY KEY, username VARCHAR(50) NOT NULL, password_hash VARCHAR(255) NOT NULL)");
$pdo->exec("CREATE TABLE IF NOT EXISTS config (key_name VARCHAR(50) PRIMARY KEY, key_value TEXT NOT NULL)");
$pdo->exec("CREATE TABLE IF NOT EXISTS critiques (id BIGINT PRIMARY KEY, title VARCHAR(255) NOT NULL, year VARCHAR(10), director VARCHAR(255), poster TEXT, rating DECIMAL(3,1) DEFAULT 3.0, review TEXT, streaming VARCHAR(255))");
$pdo->exec("ALTER TABLE critiques MODIFY COLUMN rating DECIMAL(3,1) DEFAULT 3.0;");
// 🔥 CRÉATION DE LA TABLE VIDÉOTHÈQUE AVEC LA COLONNE ACTORS
$pdo->exec("CREATE TABLE IF NOT EXISTS videotheque (id BIGINT PRIMARY KEY, title VARCHAR(255) NOT NULL, year VARCHAR(10), director VARCHAR(255), poster TEXT, format VARCHAR(50), length VARCHAR(50), publisher VARCHAR(255), ean_isbn13 VARCHAR(50), number_of_discs INT DEFAULT 1, aspect_ratio VARCHAR(50), description TEXT, actors TEXT)");
try { $pdo->exec("ALTER TABLE videotheque ADD COLUMN actors TEXT AFTER description"); } catch (\Exception $e) {}
$pdo->exec("CREATE TABLE IF NOT EXISTS cache_api (cache_key VARCHAR(120) PRIMARY KEY, data TEXT NOT NULL, source VARCHAR(20) NOT NULL, created_at INT NOT NULL)");
} catch (\PDOException $e) { echo json_encode(["error" => "Erreur BDD : " . $e->getMessage()]); exit; }
// ── FONCTIONS UTILITAIRES ──
function makeStableId($type, $title, $year) {
// 🔥 Isolation stricte : le type est inclus dans le hash pour éviter les collisions entre les deux tables
return (abs(crc32(strtolower(trim($type ?? '')) . '|' . strtolower(trim($title ?? '')) . '|' . trim($year ?? ''))) % 2000000000) + 100000000;
}
function checkAuth($pdo) {
if ($pdo->query("SELECT COUNT(*) FROM users")->fetchColumn() == 0) return true;
$token = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
if (empty($token) && function_exists('apache_request_headers')) {
$headers = apache_request_headers();
$token = $headers['Authorization'] ?? $headers['authorization'] ?? '';
}
if ($token !== md5(ENCRYPTION_KEY . 'session')) { http_response_code(403); echo json_encode(["error" => "Accès interdit."]); exit; }
}
function encryptData($data) {
$iv = openssl_random_pseudo_bytes(16);
$key = hash('sha256', ENCRYPTION_KEY, true);
return base64_encode(openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv) . '::' . $iv);
}
function decryptData($str) {
$decoded = base64_decode($str);
if (strpos($decoded, '::') === false) return null;
list($enc, $iv) = explode('::', $decoded, 2);
return openssl_decrypt($enc, 'AES-256-CBC', hash('sha256', ENCRYPTION_KEY, true), OPENSSL_RAW_DATA, substr($iv, 0, 16));
}
function getTmdbApiKey($pdo) {
$stmt = $pdo->prepare("SELECT key_value FROM config WHERE key_name = 'tmdb_api_key'");
$stmt->execute();
$row = $stmt->fetch();
return $row ? decryptData($row['key_value']) : null;
}
function httpGet($url, $timeout = 5) {
if (!function_exists('curl_init')) {
$ctx = stream_context_create(['http' => ['timeout' => $timeout, 'user_agent' => 'MonCinema/5.0']]);
return @file_get_contents($url, false, $ctx);
}
$ch = curl_init($url);
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => $timeout, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_USERAGENT => 'MonCinema/5.0', CURLOPT_FOLLOWLOCATION => true]);
$res = curl_exec($ch);
curl_close($ch);
return $res ?: null;
}
function getCache($pdo, $key) {
try {
$stmt = $pdo->prepare("SELECT data FROM cache_api WHERE cache_key = ? AND created_at > ?");
$stmt->execute([$key, time() - CACHE_TTL]);
$row = $stmt->fetch();
return $row ? json_decode($row['data'], true) : null;
} catch (\Exception $e) { return null; }
}
function setCache($pdo, $key, $data, $source) {
try {
$stmt = $pdo->prepare("REPLACE INTO cache_api (cache_key, data, source, created_at) VALUES (?, ?, ?, ?)");
$stmt->execute([$key, json_encode($data), $source, time()]);
} catch (\Exception $e) { /* ignore */ }
}
function cleanTitle($title) {
$clean = preg_replace('/\s*[\[\(].*?[\]\)]\s*/', '', $title);
$clean = preg_replace('/\s*-\s*(Édition|Edition|Collector|Simple|Spéciale|Digibook|Ultimate|Intégrale|Combo|SteelBook|Boîtier).*$/i', '', $clean);
$clean = preg_replace('/(blu-ray|bluray|dvd|4k|ultra hd|combo|vhs|bdrip).*$/i', '', $clean);
return trim(preg_replace('/\s{2,}/', ' ', $clean));
}
function detectFormat($title, $desc = '') {
$t = strtoupper($title . ' ' . $desc);
if (strpos($t, '4K') !== false || strpos($t, 'UHD') !== false) return '4K Ultra HD';
if (strpos($t, 'BLU-RAY') !== false || strpos($t, 'BLURAY') !== false) return 'Blu-ray';
if (strpos($t, 'DVD') !== false) return 'DVD';
if (strpos($t, 'VHS') !== false) return 'VHS';
if (strpos($t, 'COFFRET') !== false || strpos($t, 'TRILOGIE') !== false) return 'Coffret';
return 'Blu-ray';
}
function extractYear($dateStr) {
if (preg_match('/(\d{4})/', $dateStr, $m)) return $m[1];
return '';
}
// ── 1. API UPCitemDB ──
function fetchUPCitemdb($ean, $pdo) {
if (empty($ean) || strlen($ean) < 8) return null;
$cacheKey = 'upc_full_' . md5($ean);
$cached = getCache($pdo, $cacheKey);
if ($cached) return $cached;
$url = "https://api.upcitemdb.com/prod/trial/lookup?upc=" . urlencode($ean);
$res = httpGet($url, 5);
if (!$res) return null;
$data = json_decode($res, true);
if (isset($data['code']) && $data['code'] === 'OK' && !empty($data['items'])) {
$item = $data['items'][0];
$result = [
'title' => $item['title'] ?? '',
'poster' => $item['images'][0] ?? '',
'publisher' => $item['brand'] ?? $item['publisher'] ?? '',
'format' => detectFormat($item['title'] ?? '', $item['description'] ?? '')
];
setCache($pdo, $cacheKey, $result, 'upc');
return $result;
}
return null;
}
// ── 1.5 API DVDFr (Uniquement Jaquettes FR) ──
function fetchDVDFr($ean, $pdo) {
if (empty($ean) || strlen($ean) < 8) return null;
$cacheKey = 'dvdfr_' . md5($ean); // On revient au cache simple
$cached = getCache($pdo, $cacheKey);
if ($cached) return $cached;
$url = "https://www.dvdfr.com/api/search.php?gencode=" . urlencode($ean);
$res = httpGet($url, 5);
if (!$res) return null;
try {
$xml = @simplexml_load_string($res);
if ($xml && isset($xml->dvd) && isset($xml->dvd[0]->cover)) {
$poster = (string)$xml->dvd[0]->cover;
if (!empty($poster)) {
setCache($pdo, $cacheKey, $poster, 'dvdfr');
return $poster;
}
}
} catch (\Exception $e) {
return null;
}
return null;
}
// ── 2. API TMDB (Full Extract avec Synopsis et Acteurs) ──
function fetchTMDBFull($title, $year, $apiKey, $pdo) {
if (empty($apiKey) || empty($title)) return null;
$cleanTitle = cleanTitle($title);
$cacheKey = 'tmdb_full_' . md5(strtolower($cleanTitle) . '|' . $year);
$cached = getCache($pdo, $cacheKey);
if ($cached) return $cached;
$searchUrl = "https://api.themoviedb.org/3/search/movie?api_key={$apiKey}&query=" . urlencode($cleanTitle) . "&year={$year}&language=fr-FR";
$searchRes = httpGet($searchUrl, 5);
if (!$searchRes) return null;
$searchData = json_decode($searchRes, true);
if (empty($searchData['results'])) {
$searchUrl2 = "https://api.themoviedb.org/3/search/movie?api_key={$apiKey}&query=" . urlencode($cleanTitle) . "&language=fr-FR";
$searchRes2 = httpGet($searchUrl2, 5);
if ($searchRes2) {
$searchData2 = json_decode($searchRes2, true);
if (!empty($searchData2['results'])) $searchData = $searchData2;
}
}
if (empty($searchData['results'])) return null;
$movieId = $searchData['results'][0]['id'];
$detailsUrl = "https://api.themoviedb.org/3/movie/{$movieId}?api_key={$apiKey}&append_to_response=credits,watch/providers&language=fr-FR";
$detailsRes = httpGet($detailsUrl, 5);
if (!$detailsRes) return null;
$details = json_decode($detailsRes, true);
// 🔥 Extraction de TOUS les Réalisateurs (pour les co-réalisations)
$director = '';
if (!empty($details['credits']['crew'])) {
$directorsList = [];
foreach ($details['credits']['crew'] as $crew) {
if ($crew['job'] === 'Director') {
$directorsList[] = $crew['name'];
}
}
$director = implode(', ', $directorsList);
}
// 🔥 Extraction des 4 premiers Acteurs
$cast = [];
if (!empty($details['credits']['cast'])) {
$topCast = array_slice($details['credits']['cast'], 0, 4);
foreach ($topCast as $actor) {
$cast[] = $actor['name'];
}
}
// 🔥 Extraction du Synopsis (Overview)
$overview = $details['overview'] ?? '';
// Extraction Streaming
$streaming = '';
$frProviders = $details['watch/providers']['results']['FR'] ?? [];
$platforms = [];
if (!empty($frProviders['flatrate'])) { foreach ($frProviders['flatrate'] as $p) $platforms[] = $p['provider_name']; }
if (empty($platforms)) {
if (!empty($frProviders['rent'])) { foreach ($frProviders['rent'] as $p) $platforms[] = $p['provider_name'] . ' (loc.)'; }
if (!empty($frProviders['buy'])) { foreach ($frProviders['buy'] as $p) $platforms[] = $p['provider_name'] . ' (achat)'; }
}
if (!empty($platforms)) $streaming = implode(', ', array_unique($platforms));
$result = [
'title' => $details['title'] ?? '',
'year' => !empty($details['release_date']) ? substr($details['release_date'], 0, 4) : '',
'director' => $director,
'poster' => !empty($details['poster_path']) ? "https://image.tmdb.org/t/p/w500" . $details['poster_path'] : '',
'length' => !empty($details['runtime']) ? $details['runtime'] . ' min' : '',
'streaming' => $streaming,
'overview' => $overview,
'cast' => $cast
];
setCache($pdo, $cacheKey, $result, 'tmdb');
return $result;
}
// ── ROUTEUR PRINCIPAL ──
$action = $_GET['action'] ?? '';
$data = json_decode(file_get_contents('php://input'), true) ?? [];
switch ($action) {
case 'check_security_status':
echo json_encode(["is_blank" => ($pdo->query("SELECT COUNT(*) FROM users")->fetchColumn() == 0)]);
break;
case 'login':
if ($pdo->query("SELECT COUNT(*) FROM users")->fetchColumn() == 0) {
echo json_encode(["success" => true, "token" => md5(ENCRYPTION_KEY . 'session'), "blank" => true]);
} else {
$stmt = $pdo->prepare("SELECT password_hash FROM users WHERE username = 'admin'");
$stmt->execute(); $user = $stmt->fetch();
if ($user && password_verify($data['password'] ?? '', $user['password_hash'])) {
echo json_encode(["success" => true, "token" => md5(ENCRYPTION_KEY . 'session'), "blank" => false]);
} else { http_response_code(401); echo json_encode(["error" => "Mot de passe incorrect."]); }
}
break;
case 'setup_admin': case 'update_password':
checkAuth($pdo);
$pwd = $data['password'] ?? $data['new_password'] ?? '';
$stmt = $pdo->prepare("REPLACE INTO users (id, username, password_hash) VALUES (1, 'admin', :pass)");
$stmt->execute([':pass' => password_hash($pwd, PASSWORD_BCRYPT)]);
echo json_encode(["success" => true]);
break;
case 'get_config_keys':
checkAuth($pdo);
$stmt = $pdo->prepare("SELECT key_value FROM config WHERE key_name = 'tmdb_api_key'");
$stmt->execute(); $row = $stmt->fetch();
echo json_encode(['tmdb_api_key' => $row ? '••••••••' : '']);
break;
case 'save_config':
checkAuth($pdo);
$keyName = $data['key_name'] ?? '';
$keyValue = $data['key_value'] ?? '';
if ($keyName === 'tmdb_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]);
} else {
http_response_code(400); echo json_encode(["error" => "Données invalides."]);
}
break;
case 'get_films':
// Fusion parfaite des deux tables avec des colonnes neutres (NULL) pour harmoniser le flux
$sql = "
SELECT id, title, year, director, poster, rating, review, NULL AS description, streaming, 'critique' AS type
FROM critiques
UNION ALL
SELECT id, title, year, director, poster, NULL AS rating, NULL AS review, description, NULL AS streaming, 'videotheque' AS type
FROM videotheque
ORDER BY id DESC
";
$result = $pdo->query($sql)->fetchAll();
echo json_encode($result);
break;
case 'search_ean_full':
$ean = $_GET['ean'] ?? '';
if (!$ean) { echo json_encode(['error' => 'EAN manquant']); exit; }
$result = [
'ean' => $ean, 'title' => '', 'director' => '', 'year' => '',
'poster' => '', 'publisher' => '', 'format' => '',
'length' => '', 'number_of_discs' => 1, 'aspect_ratio' => '', 'actors' => ''
];
$upcData = fetchUPCitemdb($ean, $pdo);
$tmdbQueryTitle = "";
if ($upcData) {
$tmdbQueryTitle = $upcData['title'];
$result['title'] = $upcData['title'];
$result['poster'] = $upcData['poster'];
$result['publisher'] = $upcData['publisher'];
$result['format'] = $upcData['format'];
}
// 🔥 NOUVEAU : DVDFr pour remplacer l'affiche lors d'un ajout manuel
$dvdfrCover = fetchDVDFr($ean, $pdo);
if (!empty($dvdfrCover)) {
$result['poster'] = $dvdfrCover;
}
$tmdbKey = getTmdbApiKey($pdo);
if ($tmdbKey && $tmdbQueryTitle) {
$tmdbData = fetchTMDBFull($tmdbQueryTitle, '', $tmdbKey, $pdo);
if ($tmdbData) {
if (!empty($tmdbData['title'])) $result['title'] = $tmdbData['title'];
if (empty($result['poster']) && !empty($tmdbData['poster'])) $result['poster'] = $tmdbData['poster'];
if (!empty($tmdbData['year'])) $result['year'] = $tmdbData['year'];
if (!empty($tmdbData['length'])) $result['length'] = $tmdbData['length'];
if (!empty($tmdbData['director'])) $result['director'] = $tmdbData['director'];
if (!empty($tmdbData['cast'])) $result['actors'] = implode(', ', $tmdbData['cast']);
}
}
echo json_encode(['success' => true, 'data' => $result]);
break;
case 'save_film':
checkAuth($pdo);
$type = $data['type'] ?? 'critique';
$id = !empty($data['id']) ? $data['id'] : makeStableId($type, $data['title'] ?? '', $data['year'] ?? '0000');
if (empty($data['director']) || empty($data['poster'])) {
$tmdbData = fetchTMDBFull($data['title'] ?? '', $data['year'] ?? '', getTmdbApiKey($pdo), $pdo);
if ($tmdbData) {
if (empty($data['director'])) $data['director'] = $tmdbData['director'];
if (empty($data['poster'])) $data['poster'] = $tmdbData['poster'];
if (empty($data['length']) && !empty($tmdbData['length'])) $data['length'] = $tmdbData['length'];
}
}
if ($type === 'critique') {
$streaming = $data['streaming'] ?? '';
if (empty($streaming)) $streaming = 'Support physique / Cinéma';
$sql = "INSERT INTO critiques (id, title, year, director, poster, rating, review, streaming) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE title=VALUES(title), year=VALUES(year), director=VALUES(director), poster=VALUES(poster), rating=VALUES(rating), review=VALUES(review), streaming=VALUES(streaming)";
$stmt = $pdo->prepare($sql);
$stmt->execute([$id, $data['title'] ?? '', $data['year'] ?? '', $data['director'] ?? '', $data['poster'] ?? '', $data['rating'] ?? 3.0, $data['review'] ?? '', $streaming]);
} else {
$sql = "INSERT INTO videotheque (id, title, year, director, poster, format, length, publisher, ean_isbn13, number_of_discs, aspect_ratio, description, actors) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE title=VALUES(title), year=VALUES(year), director=VALUES(director), poster=VALUES(poster), format=VALUES(format), length=VALUES(length), publisher=VALUES(publisher), ean_isbn13=VALUES(ean_isbn13), number_of_discs=VALUES(number_of_discs), aspect_ratio=VALUES(aspect_ratio), description=VALUES(description), actors=VALUES(actors)";
$stmt = $pdo->prepare($sql);
$stmt->execute([$id, $data['title'] ?? '', $data['year'] ?? '', $data['director'] ?? '', $data['poster'] ?? '', $data['format'] ?? '', $data['length'] ?? '', $data['publisher'] ?? '', $data['ean_isbn13'] ?? '', $data['number_of_discs'] ?? 1, $data['aspect_ratio'] ?? '', $data['description'] ?? '', $data['actors'] ?? '']);
}
echo json_encode(["success" => true]);
break;
case 'delete_film':
checkAuth($pdo);
$type = $_GET['type'] ?? 'critique'; $table = ($type === 'videotheque') ? 'videotheque' : 'critiques';
$id = $_GET['id'] ?? null;
if (!$id) { http_response_code(400); echo json_encode(["error" => "ID manquant."]); break; }
$stmt = $pdo->prepare("DELETE FROM $table WHERE id = ?"); $stmt->execute([$id]);
echo json_encode(["success" => true]);
break;
case 'bulk_delete':
checkAuth($pdo);
$ids = $data['ids'] ?? []; $type = $data['type'] ?? 'critique'; $table = ($type === 'videotheque') ? 'videotheque' : 'critiques';
if (!empty($ids)) { $placeholders = implode(',', array_fill(0, count($ids), '?')); $stmt = $pdo->prepare("DELETE FROM $table WHERE id IN ($placeholders)"); $stmt->execute($ids); echo json_encode(["success" => true]); }
else { http_response_code(400); echo json_encode(["success" => false, "error" => "Aucun élément sélectionné."]); }
break;
// ── IMPORT PAR LOTS CSV (CROISEMENT UPC + TMDB) ──
case 'import_batch':
checkAuth($pdo);
$items = $data['items'] ?? [];
$type = $data['type'] ?? 'videotheque';
$tmdbApiKey = getTmdbApiKey($pdo);
$imported = 0;
$pdo->beginTransaction();
foreach ($items as $rowData) {
$title = $rowData['title'] ?? $rowData['Name'] ?? $rowData['Title'] ?? 'Sans titre';
$publishDate = $rowData['publish_date'] ?? $rowData['Year'] ?? $rowData['year'] ?? $rowData['Date'] ?? '';
$year = extractYear($publishDate);
// 🔥 ID isolé par type pour éviter les collisions
$id = makeStableId($type, $title, $year);
if ($type === 'videotheque') {
$firstName = $rowData['first_name'] ?? '';
$lastName = $rowData['last_name'] ?? '';
$creators = $rowData['creators'] ?? '';
$director = '';
// Bug 4 : dans le format CSV vidéothèque (ex: CLZ/Collectorz), creators et
// first_name/last_name contiennent les ACTEURS, pas le réalisateur.
// On laisse $director vide pour laisser TMDB trouver le vrai réalisateur.
// Exception : si ensemble est vide, creators peut servir de fallback acteurs.
unset($firstName, $lastName); // non utilisés volontairement
$ean = $rowData['ean_isbn13'] ?? $rowData['EAN'] ?? '';
// Bug 1 : EAN peut arriver comme float "7321950374984.0", on normalise en entier string
if (!empty($ean)) {
$eanFloat = floatval($ean);
if ($eanFloat > 0) $ean = (string) round($eanFloat);
$ean = preg_replace('/[^0-9]/', '', $ean);
}
$description = $rowData['description'] ?? $rowData['Description'] ?? '';
$publisher = $rowData['publisher'] ?? '';
// Bug 2 : length peut être un float "245.0", on le convertit en entier
$lengthRaw = $rowData['length'] ?? '';
$length = '';
if ($lengthRaw !== '' && $lengthRaw !== null) {
$lengthVal = floatval($lengthRaw);
if ($lengthVal > 0) $length = (string) round($lengthVal);
}
// Bug 3 : number_of_discs peut être NaN ou vide, on sécurise à 1
$discsRaw = $rowData['number_of_discs'] ?? '';
$discs = (is_numeric($discsRaw) && floatval($discsRaw) > 0) ? (int) round(floatval($discsRaw)) : 1;
$aspect = $rowData['aspect_ratio'] ?? '';
$format = $rowData['format'] ?? detectFormat($title, $description);
$poster = $rowData['poster'] ?? '';
// 🔥 Extraction des acteurs depuis le CSV
$csvActors = $rowData['ensemble'] ?? $rowData['creators'] ?? '';
$actors = '';
if (!empty($csvActors)) {
$actorsArray = array_map('trim', explode(',', $csvActors));
$actors = implode(', ', array_slice($actorsArray, 0, 4));
}
// 1. UPCitemDB
if (!empty($ean)) {
$upcData = fetchUPCitemdb($ean, $pdo);
if ($upcData) {
if (empty($poster) && !empty($upcData['poster'])) $poster = $upcData['poster'];
if ($title === 'Sans titre') $title = $upcData['title'];
if (empty($publisher)) $publisher = $upcData['publisher'];
if (empty($format) || $format === 'Blu-ray') $format = $upcData['format'];
}
// 🔥 1.5 DVDFr (Récupère uniquement la vraie jaquette FR)
$dvdfrCover = fetchDVDFr($ean, $pdo);
if (!empty($dvdfrCover)) {
$poster = $dvdfrCover;
}
// 2. TMDB (Données Officielles & Synopsis)
if ($tmdbApiKey && !empty($title)) {
// Premier essai classique
$tmdbData = fetchTMDBFull($title, $year, $tmdbApiKey, $pdo);
// 🔥 NOUVEAU : Si TMDB ne trouve rien (cas des Coffrets ou titres multiples)
if (!$tmdbData || empty($tmdbData['overview'])) {
$cleanTitle = $title;
// A. Supprime les mots parasites
$cleanTitle = preg_ireplace(['coffret ', 'l\'intégrale ', 'intégrale ', 'trilogie ', 'quadrilogie ', 'collection '], '', $cleanTitle);
// B. Sépare les listes de films (ex: "Alien / Aliens" ou "Batman + Batman Le Défi")
$cleanTitle = preg_split('/(\/|\+)/', $cleanTitle)[0];
// C. Sépare les tirets longs (ex: "Le Parrain - L'intégrale")
$cleanTitle = explode(' - ', $cleanTitle)[0];
$cleanTitle = trim($cleanTitle);
// Si le titre a été nettoyé, on relance TMDB avec le titre du 1er film
if (!empty($cleanTitle) && $cleanTitle !== $title) {
// On omet volontairement l'année, car l'année du coffret n'est pas celle du 1er film
$tmdbFallback = fetchTMDBFull($cleanTitle, '', $tmdbApiKey, $pdo);
if ($tmdbFallback && !empty($tmdbFallback['overview'])) {
$tmdbData = $tmdbFallback;
}
}
}
if ($tmdbData) {
if (!empty($tmdbData['title'])) $title = $tmdbData['title'];
if (empty($director)) {
$director = $tmdbData['director'] ?? '';
} elseif (!empty($tmdbData['director']) && strpos($director, ',') === false && strpos($tmdbData['director'], ',') !== false) {
$director = $tmdbData['director'];
}
if (empty($year) && !empty($tmdbData['year'])) $year = $tmdbData['year'];
if (empty($length) && !empty($tmdbData['length'])) $length = $tmdbData['length'];
// LIGNE DÉSACTIVÉE : TMDB ne touche jamais à l'affiche de la vidéothèque
// if (empty($poster) && !empty($tmdbData['poster'])) $poster = $tmdbData['poster'];
// 🔥 Récupération du Synopsis via TMDB (Même pour le 1er film d'un coffret)
if (!empty($tmdbData['overview'])) {
$description = $tmdbData['overview'];
}
// Récupération des Acteurs officiels (Top 4)
if (!empty($tmdbData['cast'])) {
$actors = implode(', ', $tmdbData['cast']);
}
}
}
}
// 🔥 L'INSERT SQL DOIT ÊTRE ICI (EN DEHORS DU IF TMDB)
$sql = "INSERT INTO videotheque (id, title, year, director, poster, format, length, publisher, ean_isbn13, number_of_discs, aspect_ratio, description, actors) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE director=IF(VALUES(director)!='',VALUES(director),director), poster=IF(VALUES(poster)!='',VALUES(poster),poster), format=IF(VALUES(format)!='',VALUES(format),format), length=IF(VALUES(length)!='',VALUES(length),length), publisher=IF(VALUES(publisher)!='',VALUES(publisher),publisher), ean_isbn13=IF(VALUES(ean_isbn13)!='',VALUES(ean_isbn13),ean_isbn13), number_of_discs=IF(VALUES(number_of_discs)!=1,VALUES(number_of_discs),number_of_discs), aspect_ratio=IF(VALUES(aspect_ratio)!='',VALUES(aspect_ratio),aspect_ratio), description=IF(VALUES(description)!='',VALUES(description),description), actors=IF(VALUES(actors)!='',VALUES(actors),actors)";
$stmt = $pdo->prepare($sql);
$stmt->execute([$id, $title, $year, $director, $poster, $format, $length, $publisher, $ean, $discs, $aspect, $description, $actors]);
} else {
// Pour les critiques
$ratingRaw = $rowData['Rating'] ?? $rowData['rating'] ?? '';
$rating = ($ratingRaw !== '' && $ratingRaw !== null) ? (float)$ratingRaw : null;
$review = $rowData['Review'] ?? $rowData['review'] ?? '';
$director = ''; $poster = ''; $streaming = '';
if ($tmdbApiKey && !empty($title)) {
$tmdbData = fetchTMDBFull($title, $year, $tmdbApiKey, $pdo);
if ($tmdbData) {
$director = $tmdbData['director'];
$poster = $tmdbData['poster'];
$streaming = $tmdbData['streaming'];
if(empty($year)) $year = $tmdbData['year'];
}
}
// 🔥 Valeur par défaut pour le streaming
if (empty($streaming)) {
$streaming = 'Support physique / Cinéma';
}
$sql = "INSERT INTO critiques (id, title, year, director, poster, rating, review, streaming) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE rating=VALUES(rating), review=IF(VALUES(review)!='',VALUES(review),review), director=IF(VALUES(director)!='',VALUES(director),director), poster=IF(VALUES(poster)!='',VALUES(poster),poster), streaming=IF(VALUES(streaming)!='',VALUES(streaming),streaming)";
$stmt = $pdo->prepare($sql);
$stmt->execute([$id, $title, $year, $director, $poster, $rating, $review, $streaming]);
}
$imported++;
}
$pdo->commit();
echo json_encode(["success" => true, "imported" => $imported]);
break;
}