Actualiser api.php

This commit is contained in:
2026-06-24 13:01:28 +02:00
parent e6d0c99a07
commit b525ad6f76
+213 -262
View File
@@ -17,17 +17,18 @@ try {
$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 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 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("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;"); try { $pdo->exec("ALTER TABLE critiques MODIFY COLUMN rating DECIMAL(3,1) DEFAULT 3.0"); } catch (\Exception $e) {}
// 🔥 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)"); $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) {} try { $pdo->exec("ALTER TABLE videotheque ADD COLUMN actors TEXT AFTER description"); } catch (\Exception $e) {}
// 🔥 SUPPRESSION DE LA TABLE CACHE SI ELLE EXISTE ENCORE
try { $pdo->exec("DROP TABLE IF EXISTS cache_api"); } catch (\Exception $e) {}
} catch (\PDOException $e) { echo json_encode(["error" => "Erreur BDD : " . $e->getMessage()]); exit; } } catch (\PDOException $e) { echo json_encode(["error" => "Erreur BDD : " . $e->getMessage()]); exit; }
// ── FONCTIONS UTILITAIRES ── // ── FONCTIONS UTILITAIRES ──
function makeStableId($type, $title, $year) { 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; return (abs(crc32(strtolower(trim($type ?? '')) . '|' . strtolower(trim($title ?? '')) . '|' . trim($year ?? ''))) % 2000000000) + 100000000;
} }
@@ -61,13 +62,19 @@ function getTmdbApiKey($pdo) {
return $row ? decryptData($row['key_value']) : null; return $row ? decryptData($row['key_value']) : null;
} }
function httpGet($url, $timeout = 5) { function httpGet($url, $timeout = 3) {
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); $ch = curl_init($url);
curl_setopt_array($ch, [ curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $timeout, CURLOPT_TIMEOUT => $timeout,
CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', CURLOPT_CONNECTTIMEOUT => 2,
CURLOPT_SSL_VERIFYPEER => false CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) MonCinema/5.0',
CURLOPT_FOLLOWLOCATION => true
]); ]);
$res = curl_exec($ch); $res = curl_exec($ch);
curl_close($ch); curl_close($ch);
@@ -96,15 +103,29 @@ function extractYear($dateStr) {
return ''; return '';
} }
// ── 1. API UPCitemDB (SANS CACHE) ──
function fetchUPCitemdb($ean, $pdo) {
if (empty($ean) || strlen($ean) < 8) return null;
$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];
return [
'title' => $item['title'] ?? '',
'poster' => $item['images'][0] ?? '',
'publisher' => $item['brand'] ?? $item['publisher'] ?? '',
'format' => detectFormat($item['title'] ?? '', $item['description'] ?? '')
];
}
return null;
}
// ── 2. API DVDFr (SANS CACHE - Récupération complète) ──
function fetchDVDFr($ean, $pdo) { function fetchDVDFr($ean, $pdo) {
if (empty($ean) || strlen($ean) < 8) return null; if (empty($ean) || strlen($ean) < 8) return null;
$cacheKey = 'dvdfr_' . md5($ean);
$cached = getCache($pdo, $cacheKey);
if ($cached) return $cached;
// DVDFr exige un User-Agent propre
$ua = 'MonCinema/1.0 (collection privée; contact@moncineapp.fr)'; $ua = 'MonCinema/1.0 (collection privée; contact@moncineapp.fr)';
// Étape 1 : recherche par gencode → récupère l'id DVDFr // Étape 1 : recherche par gencode → récupère l'id DVDFr
@@ -154,90 +175,64 @@ function fetchDVDFr($ean, $pdo) {
$dvd = $fiche->dvd[0]; $dvd = $fiche->dvd[0];
// 🔥 Extraction de la jaquette (CORRECTION) // Extraction de la jaquette
$poster = ''; $poster = '';
// Méthode 1 : cover directe if (isset($dvd->cover)) $poster = (string)$dvd->cover;
if (isset($dvd->cover)) { if (empty($poster) && isset($dvd->covers->cover[0])) $poster = (string)$dvd->covers->cover[0];
$poster = (string)$dvd->cover; // ✅ CORRECTION ICI
}
// Méthode 2 : covers->cover[0]
if (empty($poster) && isset($dvd->covers->cover[0])) {
$poster = (string)$dvd->covers->cover[0];
}
// Méthode 3 : image directe
if (empty($poster) && isset($dvd->image)) {
$poster = (string)$dvd->image;
}
// Extraction des métadonnées techniques // Extraction des métadonnées techniques
$result = [ $result = [
'poster' => $poster, 'poster' => $poster,
'publisher' => isset($dvd->editeur) ? (string)$dvd->editeur : '', 'publisher' => isset($dvd->editeur) ? (string)$dvd->editeur : '',
'format' => isset($dvd->type) ? (string)$dvd->type : '', 'format' => isset($dvd->type) ? (string)$dvd->type : '',
'length' => isset($dvd->duree) ? (string)$dvd->duree : '', 'length' => isset($dvd->duree) ? (string)$dvd->duree : '',
'aspect' => isset($dvd->formatimage) ? (string)$dvd->formatimage : '', 'aspect' => isset($dvd->formatimage) ? (string)$dvd->formatimage : '',
'discs' => isset($dvd->nbdisques) ? (string)$dvd->nbdisques : '', 'discs' => isset($dvd->nbdisques) ? (string)$dvd->nbdisques : '',
]; ];
// Ne met en cache que si on a au moins une affiche ou un éditeur return (!empty($result['poster']) || !empty($result['publisher'])) ? $result : null;
if (!empty($result['poster']) || !empty($result['publisher'])) {
setCache($pdo, $cacheKey, $result, 'dvdfr');
}
return !empty($result['poster']) || !empty($result['publisher']) ? $result : null;
} }
// ── 3. API TMDB (SANS CACHE - Full Extract) ──
function fetchTMDBFull($title, $year, $apiKey, $pdo) { function fetchTMDBFull($title, $year, $apiKey, $pdo) {
if (empty($apiKey) || empty($title)) return null; if (empty($apiKey) || empty($title)) return null;
$cleanTitle = cleanTitle($title); $cleanTitle = cleanTitle($title);
// 1. Recherche avec l'année
$searchUrl = "https://api.themoviedb.org/3/search/movie?api_key={$apiKey}&query=" . urlencode($cleanTitle) . "&year={$year}&language=fr-FR"; $searchUrl = "https://api.themoviedb.org/3/search/movie?api_key={$apiKey}&query=" . urlencode($cleanTitle) . "&year={$year}&language=fr-FR";
$searchRes = httpGet($searchUrl, 5); $searchRes = httpGet($searchUrl, 5);
$searchData = $searchRes ? json_decode($searchRes, true) : []; $searchData = $searchRes ? json_decode($searchRes, true) : [];
// 2. Fallback sans l'année
if (empty($searchData['results'])) { if (empty($searchData['results'])) {
$searchUrl = "https://api.themoviedb.org/3/search/movie?api_key={$apiKey}&query=" . urlencode($cleanTitle) . "&language=fr-FR"; $searchUrl2 = "https://api.themoviedb.org/3/search/movie?api_key={$apiKey}&query=" . urlencode($cleanTitle) . "&language=fr-FR";
$searchRes = httpGet($searchUrl, 5); $searchRes2 = httpGet($searchUrl2, 5);
$searchData = $searchRes ? json_decode($searchRes, true) : []; $searchData = $searchRes2 ? json_decode($searchRes2, true) : [];
} }
if (empty($searchData['results'])) return null; if (empty($searchData['results'])) return null;
$movieId = $searchData['results'][0]['id']; $movieId = $searchData['results'][0]['id'];
// 3. Détails complets
$detailsUrl = "https://api.themoviedb.org/3/movie/{$movieId}?api_key={$apiKey}&append_to_response=credits,watch/providers&language=fr-FR"; $detailsUrl = "https://api.themoviedb.org/3/movie/{$movieId}?api_key={$apiKey}&append_to_response=credits,watch/providers&language=fr-FR";
$detailsRes = httpGet($detailsUrl, 5); $detailsRes = httpGet($detailsUrl, 5);
if (!$detailsRes) return null; if (!$detailsRes) return null;
$details = json_decode($detailsRes, true); $details = json_decode($detailsRes, true);
// Extraction Réalisateurs
$director = ''; $director = '';
if (!empty($details['credits']['crew'])) { if (!empty($details['credits']['crew'])) {
$directorsList = []; $directorsList = [];
foreach ($details['credits']['crew'] as $crew) { foreach ($details['credits']['crew'] as $crew) {
if ($crew['job'] === 'Director') { if ($crew['job'] === 'Director') $directorsList[] = $crew['name'];
$directorsList[] = $crew['name'];
}
} }
$director = implode(', ', $directorsList); $director = implode(', ', $directorsList);
} }
// Extraction Acteurs (Top 4)
$cast = []; $cast = [];
if (!empty($details['credits']['cast'])) { if (!empty($details['credits']['cast'])) {
$topCast = array_slice($details['credits']['cast'], 0, 4); $topCast = array_slice($details['credits']['cast'], 0, 4);
foreach ($topCast as $actor) { foreach ($topCast as $actor) $cast[] = $actor['name'];
$cast[] = $actor['name'];
}
} }
// Synopsis
$overview = $details['overview'] ?? ''; $overview = $details['overview'] ?? '';
// Streaming
$streaming = ''; $streaming = '';
$frProviders = $details['watch/providers']['results']['FR'] ?? []; $frProviders = $details['watch/providers']['results']['FR'] ?? [];
$platforms = []; $platforms = [];
@@ -310,7 +305,6 @@ switch ($action) {
break; break;
case 'get_films': case 'get_films':
// Fusion parfaite des deux tables avec des colonnes neutres (NULL) pour harmoniser le flux
$sql = " $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
FROM critiques FROM critiques
@@ -326,14 +320,13 @@ switch ($action) {
case 'search_ean_full': case 'search_ean_full':
$ean = $_GET['ean'] ?? ''; $ean = $_GET['ean'] ?? '';
if (!$ean) { echo json_encode(['error' => 'EAN manquant']); exit; } if (!$ean) { echo json_encode(['error' => 'EAN manquant']); exit; }
$result = [ $result = [
'ean' => $ean, 'title' => '', 'director' => '', 'year' => '', 'ean' => $ean, 'title' => '', 'director' => '', 'year' => '',
'poster' => '', 'publisher' => '', 'format' => '', 'poster' => '', 'publisher' => '', 'format' => '',
'length' => '', 'number_of_discs' => 1, 'aspect_ratio' => '', 'actors' => '' 'length' => '', 'number_of_discs' => 1, 'aspect_ratio' => '', 'actors' => ''
]; ];
// 🔥 UNIQUEMENT DVDFr // DVDFr en priorité
$dvdfrData = fetchDVDFr($ean, $pdo); $dvdfrData = fetchDVDFr($ean, $pdo);
if (!empty($dvdfrData)) { if (!empty($dvdfrData)) {
if (!empty($dvdfrData['poster'])) $result['poster'] = $dvdfrData['poster']; if (!empty($dvdfrData['poster'])) $result['poster'] = $dvdfrData['poster'];
@@ -344,7 +337,7 @@ switch ($action) {
if (!empty($dvdfrData['discs'])) $result['number_of_discs'] = (int)$dvdfrData['discs']; if (!empty($dvdfrData['discs'])) $result['number_of_discs'] = (int)$dvdfrData['discs'];
} }
// TMDB pour le titre, réalisateur, année et acteurs // TMDB pour le reste
$tmdbKey = getTmdbApiKey($pdo); $tmdbKey = getTmdbApiKey($pdo);
if ($tmdbKey && !empty($result['publisher'])) { if ($tmdbKey && !empty($result['publisher'])) {
$tmdbData = fetchTMDBFull($result['publisher'], '', $tmdbKey, $pdo); $tmdbData = fetchTMDBFull($result['publisher'], '', $tmdbKey, $pdo);
@@ -355,15 +348,14 @@ switch ($action) {
if (!empty($tmdbData['cast'])) $result['actors'] = implode(', ', $tmdbData['cast']); if (!empty($tmdbData['cast'])) $result['actors'] = implode(', ', $tmdbData['cast']);
} }
} }
echo json_encode(['success' => true, 'data' => $result]); echo json_encode(['success' => true, 'data' => $result]);
break; break;
case 'save_film': case 'save_film':
checkAuth($pdo); checkAuth($pdo);
$type = $data['type'] ?? 'critique'; $type = $data['type'] ?? 'critique';
$id = !empty($data['id']) ? $data['id'] : makeStableId($type, $data['title'] ?? '', $data['year'] ?? '0000'); $id = !empty($data['id']) ? $data['id'] : makeStableId($type, $data['title'] ?? '', $data['year'] ?? '0000');
// 🔥 Récupération des données manquantes via TMDB uniquement (plus de UPC)
if (empty($data['director']) || empty($data['poster'])) { if (empty($data['director']) || empty($data['poster'])) {
$tmdbData = fetchTMDBFull($data['title'] ?? '', $data['year'] ?? '', getTmdbApiKey($pdo), $pdo); $tmdbData = fetchTMDBFull($data['title'] ?? '', $data['year'] ?? '', getTmdbApiKey($pdo), $pdo);
if ($tmdbData) { if ($tmdbData) {
@@ -376,27 +368,11 @@ switch ($action) {
if ($type === 'critique') { if ($type === 'critique') {
$streaming = $data['streaming'] ?? ''; $streaming = $data['streaming'] ?? '';
if (empty($streaming)) $streaming = 'Support physique / Cinéma'; 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)"; $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 = $pdo->prepare($sql);
$stmt->execute([$id, $data['title'] ?? '', $data['year'] ?? '', $data['director'] ?? '', $data['poster'] ?? '', $data['rating'] ?? 3.0, $data['review'] ?? '', $streaming]); $stmt->execute([$id, $data['title'] ?? '', $data['year'] ?? '', $data['director'] ?? '', $data['poster'] ?? '', $data['rating'] ?? 3.0, $data['review'] ?? '', $streaming]);
} else { } else {
// Remplacez votre bloc SQL dans 'save_film' par celui-ci : $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=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)";
$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=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 = $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'] ?? '']); $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'] ?? '']);
} }
@@ -419,190 +395,165 @@ switch ($action) {
else { http_response_code(400); echo json_encode(["success" => false, "error" => "Aucun élément sélectionné."]); } else { http_response_code(400); echo json_encode(["success" => false, "error" => "Aucun élément sélectionné."]); }
break; break;
// ── IMPORT PAR LOTS CSV (CROISEMENT UPC + TMDB) ── // ── IMPORT PAR LOTS CSV (DVDfr + TMDB, SANS CACHE) ──
case 'import_batch': case 'import_batch':
checkAuth($pdo); checkAuth($pdo);
set_time_limit(0); set_time_limit(0);
$items = $data['items'] ?? []; $items = $data['items'] ?? [];
$type = $data['type'] ?? 'videotheque'; $type = $data['type'] ?? 'videotheque';
$tmdbApiKey = getTmdbApiKey($pdo); $tmdbApiKey = getTmdbApiKey($pdo);
$imported = 0; $imported = 0;
$debugLog = []; // 🔥 LOG DE DÉBOGAGE $debugLog = [];
try {
$pdo->beginTransaction();
foreach ($items as $index => $rowData) {
$title = $rowData['title'] ?? $rowData['Name'] ?? $rowData['Title'] ?? 'Sans titre';
$publishDate = $rowData['publish_date'] ?? $rowData['Year'] ?? $rowData['year'] ?? $rowData['Date'] ?? '';
$year = extractYear($publishDate);
$id = makeStableId($type, $title, $year);
if ($type === 'videotheque') {
// 🔥 EXTRACTION CORRECTE DES ACTEURS DEPUIS LE CSV
$csvActors = '';
if (!empty($rowData['ensemble'])) {
$csvActors = $rowData['ensemble'];
} elseif (!empty($rowData['creators'])) {
$csvActors = $rowData['creators'];
}
$actors = '';
if (!empty($csvActors)) {
$actorsArray = array_map('trim', explode(',', $csvActors));
$actors = implode(', ', array_slice($actorsArray, 0, 4));
}
// Normalisation EAN
$ean = $rowData['ean_isbn13'] ?? $rowData['EAN'] ?? '';
if (!empty($ean)) {
$eanFloat = floatval($ean);
if ($eanFloat > 0) $ean = (string) round($eanFloat);
$ean = preg_replace('/[^0-9]/', '', $ean);
}
$lengthRaw = $rowData['length'] ?? '';
$length = '';
if ($lengthRaw !== '' && $lengthRaw !== null) {
$lengthVal = floatval($lengthRaw);
if ($lengthVal > 0) $length = (string) round($lengthVal);
}
$discsRaw = $rowData['number_of_discs'] ?? '';
$discs = (is_numeric($discsRaw) && floatval($discsRaw) > 0) ? (int) round(floatval($discsRaw)) : 1;
$description = $rowData['description'] ?? $rowData['Description'] ?? '';
$publisher = $rowData['publisher'] ?? '';
$aspect = $rowData['aspect_ratio'] ?? '';
$format = $rowData['format'] ?? detectFormat($title, $description);
$poster = $rowData['poster'] ?? '';
$director = '';
// Remplacez votre bloc de gestion DVDFr actuel par ceci :
$dvdfrData = fetchDVDFr($ean, $pdo);
if (!empty($dvdfrData)) {
if (empty($poster) && !empty($dvdfrData['poster'])) $poster = $dvdfrData['poster'];
if (empty($format) && !empty($dvdfrData['format'])) $format = $dvdfrData['format'];
if (empty($publisher) && !empty($dvdfrData['publisher'])) $publisher = $dvdfrData['publisher'];
if (empty($length) && !empty($dvdfrData['length'])) $length = $dvdfrData['length'];
if (empty($aspect) && !empty($dvdfrData['aspect'])) $aspect = $dvdfrData['aspect'];
}
// 2. TMDB (Données Officielles & Synopsis)
if ($tmdbApiKey && !empty($title)) {
// 🔥 CRÉER UNE VERSION PROPRE DU TITRE POUR TMDB
$tmdbTitle = $title;
// Supprimer les suffixes d'édition
$tmdbTitle = preg_replace('/\s*[\[\(].*?[\]\)]\s*/', '', $tmdbTitle);
$tmdbTitle = preg_replace('/\s*-\s*(Édition|Edition|Collector|Simple|Spéciale|Digibook|Ultimate|Intégrale|Combo|SteelBook|Boîtier|Coffret).*$/i', '', $tmdbTitle);
$tmdbTitle = preg_replace('/\s*(Blu-ray|Bluray|DVD|4K|Ultra HD|Combo|VHS|BDRip|\[.*\]).*$/i', '', $tmdbTitle);
$tmdbTitle = preg_replace('/\s*(Coffret|Trilogie|Quadrilogie|Collection|Anthologie).*$/i', '', $tmdbTitle);
// Séparer les titres multiples (ex: "Alien / Aliens")
$tmdbTitle = preg_split('/\s*(\/|\+|:)\s*/', $tmdbTitle)[0];
// Séparer les sous-titres après tiret
$tmdbTitle = explode(' - ', $tmdbTitle)[0];
$tmdbTitle = trim($tmdbTitle);
// 🔥 LOG POUR DÉBOGAGE
if ($tmdbTitle !== $title) {
$debugLog[] = "Titre original: '$title' -> Titre TMDB: '$tmdbTitle'";
}
$tmdbData = fetchTMDBFull($tmdbTitle, $year, $tmdbApiKey, $pdo);
// Si TMDB ne trouve rien, essayer avec le titre original
if (!$tmdbData && $tmdbTitle !== $title) {
$tmdbData = fetchTMDBFull($title, $year, $tmdbApiKey, $pdo);
}
if ($tmdbData) {
if (!empty($tmdbData['title'])) $title = $tmdbData['title'];
if (empty($director)) $director = $tmdbData['director'] ?? '';
if (empty($year) && !empty($tmdbData['year'])) $year = $tmdbData['year'];
if (empty($length) && !empty($tmdbData['length'])) $length = $tmdbData['length'];
if (!empty($tmdbData['overview'])) $description = $tmdbData['overview'];
// 🔥 NE PAS ÉCRASER LES ACTEURS DU CSV SI TMDB N'A PAS D'ACTEURS
if (!empty($tmdbData['cast'])) {
$actors = implode(', ', $tmdbData['cast']);
}
} else {
$debugLog[] = "TMDB n'a pas trouvé: '$tmdbTitle' (année: $year)";
}
}
// 🔥 LOG FINAL
$debugLog[] = "Film #$id: '$title' | Réal: '$director' | Acteurs: '$actors' | Durée: '$length'";
// INSERT SQL
$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=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 (code inchangé)
$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'];
}
}
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),
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();
// 🔥 RENVOYER LES LOGS DE DÉBOGAGE try {
echo json_encode([ $pdo->beginTransaction(); // 🔥 UNE SEULE TRANSACTION
"success" => true,
"imported" => $imported, foreach ($items as $rowData) {
"debug" => $debugLog $title = $rowData['title'] ?? $rowData['Name'] ?? $rowData['Title'] ?? 'Sans titre';
]); $publishDate = $rowData['publish_date'] ?? $rowData['Year'] ?? $rowData['year'] ?? $rowData['Date'] ?? '';
} catch (\Throwable $e) { $year = extractYear($publishDate);
if ($pdo->inTransaction()) { $id = makeStableId($type, $title, $year);
$pdo->rollBack();
if ($type === 'videotheque') {
// Acteurs depuis CSV
$csvActors = $rowData['ensemble'] ?? $rowData['creators'] ?? '';
$actors = '';
if (!empty($csvActors)) {
$actorsArray = array_map('trim', explode(',', $csvActors));
$actors = implode(', ', array_slice($actorsArray, 0, 4));
}
// Normalisation EAN
$ean = $rowData['ean_isbn13'] ?? $rowData['EAN'] ?? '';
if (!empty($ean)) {
$eanFloat = floatval($ean);
if ($eanFloat > 0) $ean = (string) round($eanFloat);
$ean = preg_replace('/[^0-9]/', '', $ean);
}
$lengthRaw = $rowData['length'] ?? '';
$length = '';
if ($lengthRaw !== '' && $lengthRaw !== null) {
$lengthVal = floatval($lengthRaw);
if ($lengthVal > 0) $length = (string) round($lengthVal);
}
$discsRaw = $rowData['number_of_discs'] ?? '';
$discs = (is_numeric($discsRaw) && floatval($discsRaw) > 0) ? (int) round(floatval($discsRaw)) : 1;
$description = $rowData['description'] ?? $rowData['Description'] ?? '';
$publisher = $rowData['publisher'] ?? '';
$aspect = $rowData['aspect_ratio'] ?? '';
$format = $rowData['format'] ?? detectFormat($title, $description);
$poster = $rowData['poster'] ?? '';
$director = '';
// 🔥 1. DVDFr (priorité pour les métadonnées physiques)
if (!empty($ean)) {
$dvdfrData = fetchDVDFr($ean, $pdo);
if (!empty($dvdfrData)) {
if (!empty($dvdfrData['poster'])) $poster = $dvdfrData['poster'];
if (!empty($dvdfrData['publisher'])) $publisher = $dvdfrData['publisher'];
if (!empty($dvdfrData['format'])) $format = $dvdfrData['format'];
if (!empty($dvdfrData['length'])) $length = $dvdfrData['length'];
if (!empty($dvdfrData['aspect'])) $aspect = $dvdfrData['aspect'];
if (!empty($dvdfrData['discs'])) $discs = (int)$dvdfrData['discs'];
}
}
// 🔥 2. TMDB (réalisateur, acteurs, synopsis)
if ($tmdbApiKey && !empty($title)) {
$tmdbTitle = $title;
$tmdbTitle = preg_replace('/\s*[\[\(].*?[\]\)]\s*/', '', $tmdbTitle);
$tmdbTitle = preg_replace('/\s*-\s*(Édition|Edition|Collector|Simple|Spéciale|Digibook|Ultimate|Intégrale|Combo|SteelBook|Boîtier|Coffret).*$/i', '', $tmdbTitle);
$tmdbTitle = preg_replace('/\s*(Blu-ray|Bluray|DVD|4K|Ultra HD|Combo|VHS|BDRip|\[.*\]).*$/i', '', $tmdbTitle);
$tmdbTitle = preg_replace('/\s*(Coffret|Trilogie|Quadrilogie|Collection|Anthologie).*$/i', '', $tmdbTitle);
$tmdbTitle = preg_split('/\s*(\/|\+|:)\s*/', $tmdbTitle)[0];
$tmdbTitle = explode(' - ', $tmdbTitle)[0];
$tmdbTitle = trim($tmdbTitle);
if ($tmdbTitle !== $title) {
$debugLog[] = "Titre nettoyé: '$title' -> '$tmdbTitle'";
}
$tmdbData = fetchTMDBFull($tmdbTitle, $year, $tmdbApiKey, $pdo);
if (!$tmdbData && $tmdbTitle !== $title) {
$tmdbData = fetchTMDBFull($title, $year, $tmdbApiKey, $pdo);
}
if ($tmdbData) {
if (!empty($tmdbData['title'])) $title = $tmdbData['title'];
if (empty($director)) $director = $tmdbData['director'] ?? '';
if (empty($year) && !empty($tmdbData['year'])) $year = $tmdbData['year'];
if (empty($length) && !empty($tmdbData['length'])) $length = $tmdbData['length'];
if (!empty($tmdbData['overview'])) $description = $tmdbData['overview'];
if (!empty($tmdbData['cast'])) $actors = implode(', ', $tmdbData['cast']);
} else {
$debugLog[] = "TMDB non trouvé pour: '$tmdbTitle'";
}
}
$debugLog[] = "Film: '$title' | Réal: '$director' | Durée: '$length' | Éditeur: '$publisher'";
$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=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'];
}
}
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),
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, "debug" => $debugLog]);
} catch (\Throwable $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
http_response_code(500);
echo json_encode(["success" => false, "error" => "Erreur serveur : " . $e->getMessage(), "debug" => $debugLog]);
} }
http_response_code(500); break;
echo json_encode([
"success" => false,
"error" => "Erreur serveur : " . $e->getMessage(),
"debug" => $debugLog
]);
}
break;
} }