From 19b9b245f6c1cc8008d8fb9ae4f5258f88232654 Mon Sep 17 00:00:00 2001 From: Cedric Date: Thu, 25 Jun 2026 12:07:16 +0200 Subject: [PATCH] Actualiser api.php --- api.php | 214 +++++++++++++++++++++----------------------------------- 1 file changed, 81 insertions(+), 133 deletions(-) diff --git a/api.php b/api.php index 4dc1279..19cc9bd 100644 --- a/api.php +++ b/api.php @@ -115,31 +115,19 @@ function extractYear($dateStr) { return ''; } -// ── DVDcover.com (avec vérification du titre) ── -function fetchDVDCover($title, $year = '', $format = 'bluray') { +// ── NOUVEAU SCRAPER : DVDFr (Refonte 2026) ── +function fetchDVDFrCover($title, $year = '', $format = 'bluray') { if (empty($title)) return null; $ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'; $cleanTitle = cleanTitle($title); - $cleanTitleLower = strtolower($cleanTitle); - // Mapping des formats - $formatMap = [ - '4k ultra hd' => '4k-ultra-hd', - '4k' => '4k-ultra-hd', - 'blu-ray' => 'blu-ray', - 'bluray' => 'blu-ray', - 'dvd' => 'dvd', - ]; - - $dcFormat = $formatMap[strtolower($format)] ?? 'blu-ray'; - - // URL de recherche DVDcover - $searchUrl = "https://www.dvdcover.com/?s=" . urlencode($cleanTitle); + // 1. Simuler une recherche sur le nouveau site DVDFr + $searchUrl = "https://www.dvdfr.com/search/search.php?titre=" . urlencode($cleanTitle); $html = httpGet($searchUrl, 8, $ua); if (!$html) { - error_log("DVDCover: Échec recherche pour '$title'"); + error_log("DVDFr Scraper: Échec de connexion pour '$title'"); return null; } @@ -149,109 +137,67 @@ function fetchDVDCover($title, $year = '', $format = 'bluray') { 'format' => $format, ]; - // Chercher tous les articles/résultats - preg_match_all('/]*>(.*?)<\/article>/is', $html, $articles); + // 2. Parser le HTML de la recherche + $dom = new DOMDocument(); + @$dom->loadHTML($html); + $xpath = new DOMXPath($dom); - if (!empty($articles[1])) { - $bestMatch = null; - $bestScore = 0; - - foreach ($articles[1] as $article) { - // Extraire le lien vers la page - if (!preg_match('/]+href=["\']([^"\']+)["\'][^>]*>/i', $article, $linkMatch)) { - continue; - } - - $coverPage = $linkMatch[1]; - if (strpos($coverPage, 'http') !== 0) { - $coverPage = 'https://www.dvdcover.com' . $coverPage; - } - - // Extraire le titre de l'article - $pageTitle = ''; - if (preg_match('/]*class=["\'][^"\']*entry-title[^"\']*["\'][^>]*>([^<]+)<\/h2>/i', $article, $titleMatch)) { - $pageTitle = trim(strip_tags($titleMatch[1])); - } elseif (preg_match('/title=["\']([^"\']+)["\']/i', $article, $titleMatch)) { - $pageTitle = trim($titleMatch[1]); - } - - if (empty($pageTitle)) continue; - - // Calculer un score de correspondance - $pageTitleLower = strtolower($pageTitle); - $score = 0; - - // Le titre recherché est-il dans le titre de la page ? - if (strpos($pageTitleLower, $cleanTitleLower) !== false) { - $score += 100; - } - - // L'année correspond-elle ? - if (!empty($year) && strpos($pageTitle, $year) !== false) { - $score += 50; - } - - // Le format correspond-il ? - if (stripos($pageTitle, $format) !== false || - ($format === 'Blu-ray' && stripos($pageTitle, 'bluray') !== false) || - ($format === '4K Ultra HD' && (stripos($pageTitle, '4k') !== false || stripos($pageTitle, 'ultra') !== false))) { - $score += 25; - } - - // Si le score est suffisant, visiter la page - if ($score >= 50) { - $coverHtml = httpGet($coverPage, 8, $ua); - if ($coverHtml) { - // Chercher l'image principale - $poster = ''; - - // Méthode 1 : Chercher dans le contenu de l'article - if (preg_match('/]*class=["\'][^"\']*entry-content[^"\']*["\'][^>]*>.*?]+src=["\']([^"\']+\/wp-content\/uploads\/[^"\']+\.(?:jpg|jpeg|webp))["\'][^>]*>/is', $coverHtml, $imgMatch)) { - $poster = $imgMatch[1]; - } - // Méthode 2 : Chercher toutes les images uploads - elseif (preg_match_all('/]+src=["\']([^"\']+\/wp-content\/uploads\/[^"\']+\.(?:jpg|jpeg|webp))["\'][^>]*>/i', $coverHtml, $allImages)) { - foreach ($allImages[1] as $img) { - // Exclure les images non pertinentes - if (strpos($img, 'logo') === false && - strpos($img, 'icon') === false && - strpos($img, 'banner') === false && - strpos($img, 'bg') === false && - strpos($img, 'button') === false && - strpos($img, 'sidebar') === false) { - $poster = $img; - break; - } - } - } - - if (!empty($poster)) { - // Extraire le titre de la page - $finalTitle = ''; - if (preg_match('/]*class=["\'][^"\']*entry-title[^"\']*["\'][^>]*>([^<]+)<\/h1>/i', $coverHtml, $titleMatch)) { - $finalTitle = trim(strip_tags($titleMatch[1])); - } - - // Garder le meilleur résultat - if ($score > $bestScore) { - $bestScore = $score; - $bestMatch = [ - 'poster' => $poster, - 'title' => $finalTitle ?: $pageTitle, - 'format' => $format, - ]; - } - } - } - } - } - - if ($bestMatch) { - return $bestMatch; + // 3. Chercher le lien vers la fiche de l'édition (les liens DVDFr commencent souvent par /dvd/f) + $links = $xpath->query('//a[contains(@href, "/dvd/f")]'); + $ficheUrl = ''; + + if ($links->length > 0) { + foreach ($links as $link) { + $href = $link->getAttribute('href'); + $ficheUrl = strpos($href, 'http') === 0 ? $href : "https://www.dvdfr.com" . (strpos($href, '/') === 0 ? '' : '/') . ltrim($href, '/'); + break; } } - return null; + // Si la recherche nous a redirigé directement sur la fiche du film (1 seul résultat) + if (empty($ficheUrl) && stripos($html, 'jaquette') !== false) { + $ficheHtml = $html; + } elseif (!empty($ficheUrl)) { + // Sinon on charge la page de la fiche + $ficheHtml = httpGet($ficheUrl, 8, $ua); + } else { + return null; + } + + // 4. Extraire la jaquette de la fiche produit + if (!empty($ficheHtml)) { + $domFiche = new DOMDocument(); + @$domFiche->loadHTML($ficheHtml); + $xpathFiche = new DOMXPath($domFiche); + + // Récupération du titre exact de l'édition + $titles = $xpathFiche->query('//h1'); + if ($titles->length > 0) { + $result['title'] = trim(strip_tags($titles->item(0)->nodeValue)); + } + + // On cherche une image qui contient cover, jaquette, ou dans le répertoire des éditions + $images = $xpathFiche->query('//img'); + foreach ($images as $img) { + $src = $img->getAttribute('src'); + if (preg_match('/cover|jaquette|front|\/images\/dvd\//i', $src)) { + // On exclut les miniatures techniques ou de design + if (strpos($src, 'logo') === false && strpos($src, 'icon') === false && strpos($src, 'stars') === false) { + + $imgUrl = strpos($src, 'http') === 0 ? $src : "https://www.dvdfr.com" . (strpos($src, '/') === 0 ? '' : '/') . ltrim($src, '/'); + + // Transformation de l'URL pour choper la haute résolution (retirer le "small" ou "medium") + $imgUrl = preg_replace('/_s\./i', '.', $imgUrl); + $imgUrl = preg_replace('/_m\./i', '.', $imgUrl); + + $result['poster'] = $imgUrl; + break; + } + } + } + } + + return (!empty($result['poster'])) ? $result : null; } // ── API TMDB (uniquement pour les critiques) ── @@ -388,6 +334,15 @@ switch ($action) { ORDER BY id DESC "; $result = $pdo->query($sql)->fetchAll(); + + // Formatage des notes : suppression du .0 pour les comptes ronds + foreach ($result as &$row) { + if ($row['rating'] !== null) { + $ratingVal = (float)$row['rating']; + $row['rating'] = ($ratingVal == floor($ratingVal)) ? (int)$ratingVal : $ratingVal; + } + } + echo json_encode($result); break; @@ -401,12 +356,10 @@ switch ($action) { 'length' => '', 'number_of_discs' => 1, 'aspect_ratio' => '', 'actors' => '' ]; - // Pour DVDcover, on a besoin d'un titre $tmdbKey = getTmdbApiKey($pdo); $titleForSearch = ''; if ($tmdbKey) { - // Essayer de trouver via TMDB d'abord $searchUrl = "https://api.themoviedb.org/3/find/{$ean}?api_key={$tmdbKey}&external_source=imdb_id"; $searchRes = httpGet($searchUrl, 5); $searchData = $searchRes ? json_decode($searchRes, true) : []; @@ -425,18 +378,16 @@ switch ($action) { exit; } - // Récupération jaquette if ($type === 'videotheque') { - // DVDcover pour vidéothèque + // DVDFr pour vidéothèque $format = $result['format'] ?: 'Blu-ray'; - $dcData = fetchDVDCover($titleForSearch, $result['year'], $format); + $dcData = fetchDVDFrCover($titleForSearch, $result['year'], $format); if (!empty($dcData)) { if (!empty($dcData['poster'])) $result['poster'] = $dcData['poster']; if (!empty($dcData['title'])) $result['title'] = $dcData['title']; $result['format'] = $format; } } else { - // TMDB pour critiques if ($tmdbKey) { $tmdbData = fetchTMDBFull($titleForSearch, $result['year'], $tmdbKey, $pdo); if ($tmdbData) { @@ -458,7 +409,6 @@ switch ($action) { $type = $data['type'] ?? 'critique'; $id = !empty($data['id']) ? $data['id'] : makeStableId($type, $data['title'] ?? '', $data['year'] ?? '0000'); - // TMDB uniquement pour les critiques if ($type === 'critique' && (empty($data['director']) || empty($data['poster']))) { $tmdbData = fetchTMDBFull($data['title'] ?? '', $data['year'] ?? '', getTmdbApiKey($pdo), $pdo); if ($tmdbData) { @@ -475,10 +425,10 @@ switch ($action) { $stmt = $pdo->prepare($sql); $stmt->execute([$id, $data['title'] ?? '', $data['year'] ?? '', $data['director'] ?? '', $data['poster'] ?? '', $data['rating'] ?? 3.0, $data['review'] ?? '', $streaming]); } else { - // Vidéothèque : DVDcover pour la jaquette + // Vidéothèque : DVDFr pour la jaquette if (empty($data['poster']) && !empty($data['title'])) { $format = $data['format'] ?: 'Blu-ray'; - $dcData = fetchDVDCover($data['title'], $data['year'] ?? '', $format); + $dcData = fetchDVDFrCover($data['title'], $data['year'] ?? '', $format); if (!empty($dcData['poster'])) { $data['poster'] = $dcData['poster']; } @@ -525,7 +475,7 @@ switch ($action) { $id = makeStableId($type, $title, $year); if ($type === 'videotheque') { - // ── VIDÉOTHÈQUE : DVDcover pour jaquette HD ── + // ── VIDÉOTHÈQUE : DVDFr pour jaquette ── $csvActors = $rowData['ensemble'] ?? $rowData['creators'] ?? ''; $actors = ''; if (!empty($csvActors)) { @@ -557,10 +507,10 @@ switch ($action) { $poster = $rowData['poster'] ?? ''; $director = ''; - // Récupération jaquette via DVDcover + // Récupération jaquette via DVDFr $cleanTitleForDC = cleanTitle($title); if (!empty($cleanTitleForDC)) { - $dcData = fetchDVDCover($cleanTitleForDC, $year, $format); + $dcData = fetchDVDFrCover($cleanTitleForDC, $year, $format); if (!empty($dcData)) { if (!empty($dcData['poster'])) { $poster = $dcData['poster']; @@ -571,8 +521,6 @@ switch ($action) { } } - // PAS DE TMDB POUR VIDÉOTHÈQUE - $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 @@ -591,7 +539,7 @@ switch ($action) { $stmt->execute([$id, $title, $year, $director, $poster, $format, $length, $publisher, $ean, $discs, $aspect, $description, $actors]); } else { - // ── CRITIQUES : TMDB complet ── + // ── CRITIQUES : TMDB ── $ratingRaw = $rowData['Rating'] ?? $rowData['rating'] ?? ''; $rating = ($ratingRaw !== '' && $ratingRaw !== null) ? (float)$ratingRaw : null; $review = $rowData['Review'] ?? $rowData['review'] ?? ''; @@ -636,7 +584,7 @@ switch ($action) { } break; - case 'debug_dvdcover': + case 'debug_scraper': $title = $_GET['title'] ?? ''; $year = $_GET['year'] ?? ''; $format = $_GET['format'] ?? 'Blu-ray'; @@ -644,7 +592,7 @@ switch ($action) { if (!$title) { echo json_encode(['error' => 'Titre manquant']); exit; } $result = ['title' => $title, 'year' => $year, 'format' => $format]; - $data = fetchDVDCover($title, $year, $format); + $data = fetchDVDFrCover($title, $year, $format); $result['data'] = $data; $result['status'] = $data ? 'OK' : 'AUCUN_RÉSULTAT';