From ed7c2454b4b647fa873f2ad9e22d8829c8737177 Mon Sep 17 00:00:00 2001 From: Cedric Date: Tue, 30 Jun 2026 16:25:54 +0200 Subject: [PATCH] Actualiser api.php --- api.php | 263 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 148 insertions(+), 115 deletions(-) diff --git a/api.php b/api.php index f9cd457..5ac8bb0 100644 --- a/api.php +++ b/api.php @@ -372,7 +372,7 @@ function fetchFromBlurayCom($ean) { static $lastRequest = 0; $empty = [ 'title' => '', 'year' => '', 'director' => '', 'actors' => '', - 'poster' => '', 'description' => '', 'length' => '', + 'poster' => '', 'description' => '', 'length' => '', 'publisher' => '', 'format' => 'Blu-ray', 'number_of_discs' => 1, 'aspect_ratio' => '' ]; @@ -394,9 +394,8 @@ function fetchFromBlurayCom($ean) { error_log("Blu-ray.com: 🔍 Recherche EAN $ean"); - // Recherche simple par EAN + // Recherche par EAN $searchUrl = "https://www.blu-ray.com/movies/search.php?ean=" . urlencode($ean) . "&action=search"; - $ch = curl_init($searchUrl); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, @@ -422,7 +421,7 @@ function fetchFromBlurayCom($ean) { return $empty; } - // Extraire l'URL du film + // Extraire l'URL du film - regex améliorée if (!preg_match('/href="(https:\/\/www\.blu-ray\.com\/movies\/[^"]+\/(\d+)\/)"/i', $searchHtml, $matches)) { error_log("Blu-ray.com: ❌ Film non trouvé pour EAN $ean"); return $empty; @@ -432,6 +431,9 @@ function fetchFromBlurayCom($ean) { $movieId = $matches[2]; error_log("Blu-ray.com: ✅ Film trouvé → $movieUrl"); + // Délai avant la 2ème requête + sleep(2); + // Récupérer la page du film $ch2 = curl_init($movieUrl); curl_setopt_array($ch2, [ @@ -455,28 +457,34 @@ function fetchFromBlurayCom($ean) { return $empty; } - // Extraction des données + // Extraction des données - regex améliorées + // Titre if (preg_match('/]*>([^<]+)<\/h1>/i', $movieHtml, $m)) { $rawTitle = trim(strip_tags($m[1])); $empty['title'] = trim(preg_replace('/\s*(Blu-ray|4K|3D|DVD|UHD).*$/i', '', $rawTitle)); } + // Année if (preg_match('/href="[^"]*year=(\d{4})[^"]*"[^>]*>(\d{4})<\/a>/i', $movieHtml, $m)) { $empty['year'] = $m[1]; } + // Studio/Éditeur if (preg_match('/href="[^"]*studioid=\d+[^"]*"[^>]*>([^<]+)<\/a>/i', $movieHtml, $m)) { $empty['publisher'] = trim($m[1]); } + // Durée if (preg_match('/]*id="runtime"[^>]*>(\d+)\s*min<\/span>/i', $movieHtml, $m)) { $empty['length'] = $m[1] . ' min'; } + // Aspect ratio if (preg_match('/Aspect[\s-]*ratio:\s*([\d\.]+:[\d\.]+)/i', $movieHtml, $m)) { $empty['aspect_ratio'] = trim($m[1]); } + // Nombre de disques - plusieurs patterns if (preg_match('/(\w+)-disc\s+set/i', $movieHtml, $m)) { $wordToNum = ['single' => 1, 'two' => 2, 'three' => 3, 'four' => 4, 'five' => 5, 'six' => 6]; $word = strtolower($m[1]); @@ -485,6 +493,7 @@ function fetchFromBlurayCom($ean) { $empty['number_of_discs'] = (int)$m[1]; } + // Format if (strpos($movieUrl, '/4k/') !== false || stripos($movieHtml, '4K Ultra HD') !== false) { $empty['format'] = '4K Ultra HD'; } elseif (strpos($movieUrl, '/3d/') !== false) { @@ -493,36 +502,42 @@ function fetchFromBlurayCom($ean) { $empty['format'] = 'Blu-ray'; } - // Affiche HD + // Affiche HD - plusieurs patterns if (preg_match('/src="(https:\/\/images\.static-bluray\.com\/movies\/covers\/\d+_front\.jpg[^"]*)"/i', $movieHtml, $m)) { $empty['poster'] = $m[1]; } elseif (preg_match('/]*class="coverfront"[^>]*src="([^"]+)"/i', $movieHtml, $m)) { - $empty['poster'] = $m[1]; + $posterUrl = $m[1]; + $posterUrl = preg_replace('/_large\.jpg/', '_front.jpg', $posterUrl); + $empty['poster'] = $posterUrl; } // Synopsis, Réalisateur, Acteurs if (preg_match('/]*id="movie_info"[^>]*>(.*?)]*id="movie_review_intro"/is', $movieHtml, $infoBlock)) { $infoHtml = $infoBlock[1]; + // Synopsis if (preg_match('/<\/center>
\s*(.*?)


Director:/is', $infoHtml, $m)) { $synopsis = trim(strip_tags($m[1])); $synopsis = preg_replace('/\s+/', ' ', $synopsis); $empty['description'] = $synopsis; } + // Réalisateur if (preg_match('/Director:\s*]*>([^<]+)<\/a>/i', $infoHtml, $m)) { $empty['director'] = trim($m[1]); } + // Acteurs if (preg_match('/Starring:\s*(.*?)(?:
|<\/div>)/is', $infoHtml, $m)) { - preg_match_all('/]*>([^<]+)<\/a>/i', $m[1], $actorMatches); + $actorsHtml = $m[1]; + preg_match_all('/]*>([^<]+)<\/a>/i', $actorsHtml, $actorMatches); if (!empty($actorMatches[1])) { $empty['actors'] = implode(', ', array_map('trim', array_slice($actorMatches[1], 0, 6))); } } } - error_log("Blu-ray.com: âś… DonnĂ©es rĂ©cupĂ©rĂ©es → " . $empty['title']); + error_log("Blu-ray.com: âś… DonnĂ©es rĂ©cupĂ©rĂ©es pour EAN $ean → " . $empty['title']); return $empty; } @@ -534,6 +549,8 @@ function fetchFromMovieCovers($title, $year = '') { 'aspect_ratio' => '' ]; + if (empty($title)) return $empty; + // Nettoyer le titre pour l'URL $urlTitle = strtoupper(str_replace(' ', '+', $title)); $url = "https://moviecovers.com/film/titre_{$urlTitle}.html"; @@ -546,13 +563,18 @@ function fetchFromMovieCovers($title, $year = '') { $empty['title'] = trim($m[1]); } - // Extraire l'affiche + // Extraire l'affiche - plusieurs patterns if (preg_match('/]*src="(https:\/\/moviecovers\.com\/DATA\/thumbs\/[^"]+)"[^>]*title="Recto/i', $html, $m)) { $empty['poster'] = $m[1]; } elseif (preg_match('/]*property="og:image"[^>]*content="([^"]+)"/i', $html, $m)) { $empty['poster'] = $m[1]; } + // Format haute qualitĂ© de l'affiche + if ($empty['poster']) { + $empty['poster'] = str_replace('/thumbs/', '/films-l/', $empty['poster']); + } + // Extraire le rĂ©alisateur if (preg_match('/Réalisateur<\/TH>\s*]*>.*?]*>([^<]+)<\/a>/is', $html, $m)) { $empty['director'] = trim($m[1]); @@ -578,11 +600,6 @@ function fetchFromMovieCovers($title, $year = '') { $empty['description'] = html_entity_decode($m[1]); } - // Format haute qualitĂ© de l'affiche - if ($empty['poster']) { - $empty['poster'] = str_replace('/thumbs/', '/films-l/', $empty['poster']); - } - return $empty; } @@ -725,109 +742,125 @@ case 'import_batch': $data = json_decode(file_get_contents("php://input"), true); $type = $data['type'] ?? ''; $items = $data['items'] ?? []; + $pdo->beginTransaction(); $imported = 0; $skipped = 0; - try { - if ($type === 'videotheque') { - $stmt = $pdo->prepare("INSERT INTO videotheque (id, title, year, format, poster, ean_isbn13, description, length, number_of_discs, aspect_ratio, actors, publisher, director) - VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE - title=VALUES(title), year=VALUES(year), format=VALUES(format), - poster=IF(VALUES(poster)!='assets/img/default_physical_media.jpg', VALUES(poster), poster), - ean_isbn13=IF(VALUES(ean_isbn13)!='', VALUES(ean_isbn13), ean_isbn13), - description=IF(VALUES(description)!='', VALUES(description), description), - length=IF(VALUES(length)!='', VALUES(length), length), - 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), - actors=IF(VALUES(actors)!='', VALUES(actors), actors), - publisher=IF(VALUES(publisher)!='', VALUES(publisher), publisher), - director=IF(VALUES(director)!='', VALUES(director), director)"); - foreach ($items as $item) { - $csvTitle = trim($item['title'] ?? ''); - $ean = preg_replace('/[^0-9]/', '', (string)($item['ean'] ?? '')); - - if (empty($csvTitle)) { - error_log("Import: ❌ Pas de titre pour EAN $ean - ignorĂ©"); - $skipped++; - continue; - } - - error_log("Import: 🎬 Traitement de '$csvTitle' (EAN: $ean)"); - - // 1. Essayer Blu-ray.com (peut Ă©chouer sans bloquer) - $blurayData = !empty($ean) ? fetchFromBlurayCom($ean) : []; - - // 2. Utiliser le titre du CSV comme base - $title = $csvTitle; - $year = $blurayData['year'] ?? ''; - $format = $blurayData['format'] ?: detectFormat($title); - $publisher = $blurayData['publisher'] ?? ''; - $discs = $blurayData['number_of_discs'] ?: 1; - $aspect = $blurayData['aspect_ratio'] ?? ''; - $length = $blurayData['length'] ?? ''; - $poster = $blurayData['poster'] ?? ''; - $desc = $blurayData['description'] ?? ''; - $director = $blurayData['director'] ?? ''; - $actors = $blurayData['actors'] ?? ''; - - // 3. COMPLÉTER avec TMDB (toujours appelĂ© pour garantir les donnĂ©es) - error_log("Import: 🔄 Appel TMDB pour '$title'"); - $tmdb = fetchTmdbPosterAndSynopsis($title, $year, $pdo); - - // TMDB complète ce qui manque - if (empty($poster) || $poster === 'assets/img/default_physical_media.jpg') { - $poster = $tmdb['poster']; - } - if (empty($director)) $director = $tmdb['director'] ?? ''; - if (empty($actors)) $actors = $tmdb['actors'] ?? ''; - if (empty($desc)) $desc = $tmdb['description'] ?? ''; - if (empty($length) && !empty($tmdb['length'])) $length = $tmdb['length']; - if (empty($year) && !empty($tmdb['year'])) $year = $tmdb['year']; - - $id = makeStableId('videotheque', $title, $year); - $stmt->execute([$id, $title, $year, $format, $poster, $ean, $desc, $length, $discs, $aspect, $actors, $publisher, $director]); - $imported++; - - error_log("Import: âś… ImportĂ© '$title' (ID: $id)"); - } - } else { // ── IMPORTATION CRITIQUES ── - $stmtCritiques = $pdo->prepare("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)"); - - foreach ($items as $rowData) { - $title = $rowData['Title'] ?? $rowData['title'] ?? ''; - if (empty($title)) continue; - - $year = $rowData['Year'] ?? $rowData['year'] ?? ''; - $id = makeStableId('critique', $title, $year); - - $ratingRaw = $rowData['Rating'] ?? $rowData['rating'] ?? ''; - $rating = ($ratingRaw !== '' && $ratingRaw !== null) ? (float)$ratingRaw : null; - $review = $rowData['Review'] ?? $rowData['review'] ?? ''; - $director = ''; $poster = 'assets/img/default_physical_media.jpg'; $streaming = 'Support physique / CinĂ©ma'; - - // ── CORRECTION ICI : Utilisation de la bonne fonction TMDB ── - $tmdbData = fetchTmdbPosterAndSynopsis($title, $year, $pdo); - if ($tmdbData) { - if (!empty($tmdbData['director'])) $director = $tmdbData['director']; - if ($tmdbData['poster'] !== 'assets/img/default_physical_media.jpg') $poster = $tmdbData['poster']; - if (empty($year) && !empty($tmdbData['year'])) $year = $tmdbData['year']; - } - - $stmtCritiques->execute([$id, $title, $year, $director, $poster, $rating, $review, $streaming]); - $imported++; - } - } - $pdo->commit(); - echo json_encode(["success" => true, "imported" => $imported, "skipped" => $skipped]); + try { + if ($type === 'videotheque') { + $stmt = $pdo->prepare("INSERT INTO videotheque (id, title, year, format, poster, ean_isbn13, description, length, number_of_discs, aspect_ratio, actors, publisher, director) + VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE + title=VALUES(title), year=VALUES(year), format=VALUES(format), + poster=IF(VALUES(poster)!='assets/img/default_physical_media.jpg', VALUES(poster), poster), + ean_isbn13=IF(VALUES(ean_isbn13)!='', VALUES(ean_isbn13), ean_isbn13), + description=IF(VALUES(description)!='', VALUES(description), description), + length=IF(VALUES(length)!='', VALUES(length), length), + 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), + actors=IF(VALUES(actors)!='', VALUES(actors), actors), + publisher=IF(VALUES(publisher)!='', VALUES(publisher), publisher), + director=IF(VALUES(director)!='', VALUES(director), director)"); - } catch (Throwable $e) { // ── CORRECTION ICI : Throwable capture les Crash Fatals PHP ── - $pdo->rollBack(); - error_log("import_batch error: " . $e->getMessage()); - http_response_code(500); - echo json_encode(["success" => false, "error" => $e->getMessage(), "line" => $e->getLine()]); + foreach ($items as $item) { + $ean = preg_replace('/[^0-9]/', '', (string)($item['ean'] ?? '')); + $csvTitle = trim($item['title'] ?? ''); + + if (strlen($ean) < 8 && empty($csvTitle)) { + $skipped++; + continue; + } + + // 1. Essayer Blu-ray.com (avec throttling) + $blurayData = !empty($ean) ? fetchFromBlurayCom($ean) : []; + + // 2. Si Blu-ray.com Ă©choue, essayer MovieCovers avec le titre CSV + if (empty($blurayData['title']) && !empty($csvTitle)) { + error_log("Import: 🔄 Blu-ray.com Ă©chouĂ©, essai MovieCovers pour '$csvTitle'"); + $blurayData = array_merge($blurayData, fetchFromMovieCovers($csvTitle, '')); + } + + // 3. Utiliser le titre trouvĂ© ou le titre CSV + $title = !empty($blurayData['title']) ? $blurayData['title'] : $csvTitle; + + if (empty($title)) { + error_log("Import: ❌ Pas de titre pour EAN $ean - ignorĂ©"); + $skipped++; + continue; + } + + $year = $blurayData['year'] ?? ''; + $format = $blurayData['format'] ?: detectFormat($title); + $publisher = $blurayData['publisher'] ?? ''; + $discs = $blurayData['number_of_discs'] ?: 1; + $aspect = $blurayData['aspect_ratio'] ?? ''; + $length = $blurayData['length'] ?? ''; + $poster = $blurayData['poster'] ?? ''; + $desc = $blurayData['description'] ?? ''; + $director = $blurayData['director'] ?? ''; + $actors = $blurayData['actors'] ?? ''; + + // 4. Fallback TMDB si donnĂ©es manquantes + if (empty($poster) || empty($director) || empty($actors) || empty($desc)) { + error_log("Import: 🔄 Fallback TMDB pour '$title'"); + $tmdb = fetchTmdbPosterAndSynopsis($title, $year, $pdo); + + if (empty($poster) || $poster === 'assets/img/default_physical_media.jpg') { + $poster = $tmdb['poster']; + } + if (empty($director)) $director = $tmdb['director'] ?? ''; + if (empty($actors)) $actors = $tmdb['actors'] ?? ''; + if (empty($desc)) $desc = $tmdb['description'] ?? ''; + if (empty($length) && !empty($tmdb['length'])) $length = $tmdb['length']; + if (empty($year) && !empty($tmdb['year'])) $year = $tmdb['year']; + } + + $id = makeStableId('videotheque', $title, $year); + $stmt->execute([$id, $title, $year, $format, $poster, $ean, $desc, $length, $discs, $aspect, $actors, $publisher, $director]); + $imported++; + + error_log("Import: âś… ImportĂ© '$title' ($ean) - Disques: $discs, Format: $format"); + } + } else { + // Import critiques (inchangĂ©) + $stmtCritiques = $pdo->prepare("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)"); + + foreach ($items as $rowData) { + $title = $rowData['Title'] ?? $rowData['title'] ?? ''; + if (empty($title)) continue; + + $year = $rowData['Year'] ?? $rowData['year'] ?? ''; + $id = makeStableId('critique', $title, $year); + $ratingRaw = $rowData['Rating'] ?? $rowData['rating'] ?? ''; + $rating = ($ratingRaw !== '' && $ratingRaw !== null) ? (float)$ratingRaw : null; + $review = $rowData['Review'] ?? $rowData['review'] ?? ''; + + $director = ''; + $poster = 'assets/img/default_physical_media.jpg'; + $streaming = 'Support physique / CinĂ©ma'; + + $tmdbData = fetchTmdbPosterAndSynopsis($title, $year, $pdo); + if ($tmdbData) { + if (!empty($tmdbData['director'])) $director = $tmdbData['director']; + if ($tmdbData['poster'] !== 'assets/img/default_physical_media.jpg') $poster = $tmdbData['poster']; + if (empty($year) && !empty($tmdbData['year'])) $year = $tmdbData['year']; + } + + $stmtCritiques->execute([$id, $title, $year, $director, $poster, $rating, $review, $streaming]); + $imported++; + } } - break; + + $pdo->commit(); + echo json_encode(["success" => true, "imported" => $imported, "skipped" => $skipped]); + + } catch (Throwable $e) { + $pdo->rollBack(); + error_log("import_batch error: " . $e->getMessage()); + http_response_code(500); + echo json_encode(["success" => false, "error" => $e->getMessage(), "line" => $e->getLine()]); + } + break; } \ No newline at end of file