From 33d303923dc190f06997f9baf5f359f343e7cb23 Mon Sep 17 00:00:00 2001 From: Cedric Date: Thu, 25 Jun 2026 13:06:51 +0200 Subject: [PATCH] Actualiser api.php --- api.php | 203 ++++++++++++++++++++++++-------------------------------- 1 file changed, 86 insertions(+), 117 deletions(-) diff --git a/api.php b/api.php index 062efe0..46bd9a8 100644 --- a/api.php +++ b/api.php @@ -115,33 +115,19 @@ function extractYear($dateStr) { return ''; } -// ── NOUVEAU SCRAPER : DVDFr (Version corrigée avec débogage) ── -function fetchDVDFrCover($title, $year = '', $format = 'bluray') { +// ── DVDCover.com Scraper ── +function fetchDVDCover($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); - // Essayer différentes URLs de recherche - $searchUrls = [ - "https://www.dvdfr.com/search?q=" . urlencode($cleanTitle), - "https://www.dvdfr.com/dvd/recherche.html?search=" . urlencode($cleanTitle), - "https://www.dvdfr.com/catalogue/recherche?query=" . urlencode($cleanTitle), - ]; - - $html = null; - $usedUrl = ''; - - foreach ($searchUrls as $url) { - $html = httpGet($url, 10, $ua); - if ($html && strlen($html) > 1000) { - $usedUrl = $url; - break; - } - } + // URL de recherche DVDCover + $searchUrl = "https://www.dvdcover.com/?s=" . urlencode($cleanTitle); + $html = httpGet($searchUrl, 8, $ua); if (!$html) { - error_log("DVDFr: Impossible de récupérer la page de recherche pour '$title'"); + error_log("DVDCover: Échec recherche pour '$title'"); return null; } @@ -149,101 +135,87 @@ function fetchDVDFrCover($title, $year = '', $format = 'bluray') { 'poster' => '', 'title' => '', 'format' => $format, - 'debug_url' => $usedUrl, ]; - // Méthode 1 : Chercher les liens vers les fiches produits (pattern /dvd/f ou /dvd/ suivi de chiffres) - $ficheUrl = ''; - if (preg_match('/href=["\']([^"\']*\/dvd\/f?\d+[^"\']*\.html)["\']/i', $html, $matches)) { - $ficheUrl = $matches[1]; - if (strpos($ficheUrl, 'http') !== 0) { - $ficheUrl = 'https://www.dvdfr.com' . $ficheUrl; - } - } + // DVDCover est un site WordPress - les articles ont la classe "post" + // Chercher les liens vers les pages individuelles de covers + preg_match_all('/]*class=["\'][^"\']*post[^"\']*["\'][^>]*>.*?]+href=["\']([^"\']+)["\'][^>]*>.*?<\/article>/is', $html, $articles); - // Méthode 2 : Chercher dans les données JSON-LD ou scripts - if (empty($ficheUrl) && preg_match('/"url"\s*:\s*"([^"]*\/dvd\/[^"]+)"/i', $html, $matches)) { - $ficheUrl = $matches[1]; - if (strpos($ficheUrl, 'http') !== 0) { - $ficheUrl = 'https://www.dvdfr.com' . $ficheUrl; - } - } - - if (!empty($ficheUrl)) { - error_log("DVDFr: Fiche trouvée - $ficheUrl"); - $ficheHtml = httpGet($ficheUrl, 10, $ua); - - if ($ficheHtml) { - // Extraire le titre - if (preg_match('/]*>([^<]+)<\/h1>/i', $ficheHtml, $titleMatch)) { - $result['title'] = trim(strip_tags($titleMatch[1])); - } elseif (preg_match('/]*>([^<]+)<\/title>/i', $ficheHtml, $titleMatch)) { - $result['title'] = trim(strip_tags($titleMatch[1])); + if (!empty($articles[1])) { + foreach ($articles[1] as $coverPage) { + if (strpos($coverPage, 'http') !== 0) { + $coverPage = 'https://www.dvdcover.com' . $coverPage; } - // Chercher les images de jaquettes - // Pattern 1 : Images dans /images/dvd/ ou /covers/ - if (preg_match_all('/src=["\']([^"\']*(?:\/images\/dvd\/|\/covers\/|cover|jaquette)[^"\']*\.(?:jpg|jpeg|png|webp))["\']/i', $ficheHtml, $imgMatches)) { - foreach ($imgMatches[1] as $img) { - if (strpos($img, 'logo') === false && - strpos($img, 'icon') === false && - strpos($img, 'stars') === false && - strpos($img, 'bg-') === false) { - - $imgUrl = strpos($img, 'http') === 0 ? $img : 'https://www.dvdfr.com' . (strpos($img, '/') === 0 ? '' : '/') . ltrim($img, '/'); - - // Supprimer les suffixes de taille pour avoir la HD - $imgUrl = preg_replace('/[_-](?:small|medium|thumb|mini|s|m|t)\./i', '.', $imgUrl); - - $result['poster'] = $imgUrl; - break; + $coverHtml = httpGet($coverPage, 8, $ua); + if (!$coverHtml) continue; + + // Extraire le titre du cover + $coverTitle = ''; + if (preg_match('/]*class=["\'][^"\']*entry-title[^"\']*["\'][^>]*>([^<]+)<\/h1>/i', $coverHtml, $titleMatch)) { + $coverTitle = trim(strip_tags($titleMatch[1])); + } elseif (preg_match('/]*>([^<]+)<\/title>/i', $coverHtml, $titleMatch)) { + $coverTitle = trim(strip_tags($titleMatch[1])); + } + + // Vérifier que le titre correspond au film recherché + $coverTitleLower = strtolower($coverTitle); + $searchTitleLower = strtolower($cleanTitle); + + // Score de correspondance + $score = 0; + if (strpos($coverTitleLower, $searchTitleLower) !== false) { + $score += 50; + } + if (!empty($year) && strpos($coverTitle, $year) !== false) { + $score += 30; + } + if (stripos($coverTitle, $format) !== false) { + $score += 20; + } + + // Si le score est trop bas, on ignore ce résultat + if ($score < 30) { + continue; + } + + // Chercher l'image principale dans le contenu + $poster = ''; + + // Méthode 1 : Image dans entry-content + if (preg_match('/]*class=["\'][^"\']*entry-content[^"\']*["\'][^>]*>.*?]+src=["\']([^"\']+)["\'][^>]*>/is', $coverHtml, $imgMatch)) { + $poster = $imgMatch[1]; + } + + // Méthode 2 : Image dans figure + if (empty($poster) && preg_match('/]*>.*?]+src=["\']([^"\']+)["\'][^>]*>/is', $coverHtml, $imgMatch)) { + $poster = $imgMatch[1]; + } + + // Méthode 3 : Chercher toutes les images et prendre la première valide + if (empty($poster)) { + preg_match_all('/]+src=["\']([^"\']+\/wp-content\/uploads\/[^"\']+\.(?:jpg|jpeg|webp))["\'][^>]*>/i', $coverHtml, $allImages); + if (!empty($allImages[1])) { + foreach ($allImages[1] as $img) { + // Exclure les images de thème, logos, etc. + if (strpos($img, 'logo') === false && + strpos($img, 'icon') === false && + strpos($img, 'banner') === false && + strpos($img, 'bg') === false && + strpos($img, 'button') === false && + strpos($img, '300x200') === false && + strpos($img, '150x150') === false) { + $poster = $img; + break; + } } } } - // Pattern 2 : Meta Open Graph - if (empty($result['poster']) && preg_match('/]+property=["\']og:image["\'][^>]+content=["\']([^"\']+)["\']/i', $ficheHtml, $ogMatch)) { - $result['poster'] = $ogMatch[1]; - } - - // Pattern 3 : Chercher toutes les images et filtrer - if (empty($result['poster'])) { - preg_match_all('/]+src=["\']([^"\']+\.(?:jpg|jpeg|png|webp))["\'][^>]*>/i', $ficheHtml, $allImages); - foreach ($allImages[1] as $img) { - $imgLower = strtolower($img); - if (strpos($imgLower, 'dvdfr.com') !== false && - strpos($imgLower, 'logo') === false && - strpos($imgLower, 'icon') === false && - strpos($imgLower, 'banner') === false && - strpos($imgLower, 'bg') === false && - strpos($imgLower, 'button') === false && - strpos($imgLower, 'social') === false) { - - $imgUrl = strpos($img, 'http') === 0 ? $img : 'https://www.dvdfr.com' . (strpos($img, '/') === 0 ? '' : '/') . ltrim($img, '/'); - $imgUrl = preg_replace('/[_-](?:small|medium|thumb|mini|s|m|t)\./i', '.', $imgUrl); - - $result['poster'] = $imgUrl; - break; - } - } - } - } - } - - // Fallback : chercher directement dans la page de recherche - if (empty($result['poster'])) { - preg_match_all('/src=["\']([^"\']+\.(?:jpg|jpeg|png|webp))["\']/i', $html, $searchImages); - foreach ($searchImages[1] as $img) { - $imgLower = strtolower($img); - if (strpos($imgLower, 'dvdfr.com') !== false && - (strpos($imgLower, 'dvd') !== false || strpos($imgLower, 'cover') !== false) && - strpos($imgLower, 'logo') === false && - strpos($imgLower, 'icon') === false) { - - $imgUrl = strpos($img, 'http') === 0 ? $img : 'https://www.dvdfr.com' . (strpos($img, '/') === 0 ? '' : '/') . ltrim($img, '/'); - $imgUrl = preg_replace('/[_-](?:small|medium|thumb|mini|s|m|t)\./i', '.', $imgUrl); - - $result['poster'] = $imgUrl; + // Si on a une image valide, on la garde + if (!empty($poster)) { + $result['poster'] = $poster; + $result['title'] = $coverTitle; break; } } @@ -387,7 +359,6 @@ switch ($action) { "; $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']; @@ -431,9 +402,9 @@ switch ($action) { } if ($type === 'videotheque') { - // DVDFr pour vidéothèque + // DVDCover pour vidéothèque $format = $result['format'] ?: 'Blu-ray'; - $dcData = fetchDVDFrCover($titleForSearch, $result['year'], $format); + $dcData = fetchDVDCover($titleForSearch, $result['year'], $format); if (!empty($dcData)) { if (!empty($dcData['poster'])) $result['poster'] = $dcData['poster']; if (!empty($dcData['title'])) $result['title'] = $dcData['title']; @@ -477,10 +448,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 : DVDFr pour la jaquette + // Vidéothèque : DVDCover pour la jaquette if (empty($data['poster']) && !empty($data['title'])) { $format = $data['format'] ?: 'Blu-ray'; - $dcData = fetchDVDFrCover($data['title'], $data['year'] ?? '', $format); + $dcData = fetchDVDCover($data['title'], $data['year'] ?? '', $format); if (!empty($dcData['poster'])) { $data['poster'] = $dcData['poster']; } @@ -527,7 +498,6 @@ switch ($action) { $id = makeStableId($type, $title, $year); if ($type === 'videotheque') { - // ── VIDÉOTHÈQUE : DVDFr pour jaquette ── $csvActors = $rowData['ensemble'] ?? $rowData['creators'] ?? ''; $actors = ''; if (!empty($csvActors)) { @@ -559,10 +529,10 @@ switch ($action) { $poster = $rowData['poster'] ?? ''; $director = ''; - // Récupération jaquette via DVDFr + // Récupération jaquette via DVDCover $cleanTitleForDC = cleanTitle($title); if (!empty($cleanTitleForDC)) { - $dcData = fetchDVDFrCover($cleanTitleForDC, $year, $format); + $dcData = fetchDVDCover($cleanTitleForDC, $year, $format); if (!empty($dcData)) { if (!empty($dcData['poster'])) { $poster = $dcData['poster']; @@ -591,7 +561,6 @@ switch ($action) { $stmt->execute([$id, $title, $year, $director, $poster, $format, $length, $publisher, $ean, $discs, $aspect, $description, $actors]); } else { - // ── CRITIQUES : TMDB ── $ratingRaw = $rowData['Rating'] ?? $rowData['rating'] ?? ''; $rating = ($ratingRaw !== '' && $ratingRaw !== null) ? (float)$ratingRaw : null; $review = $rowData['Review'] ?? $rowData['review'] ?? ''; @@ -636,7 +605,7 @@ switch ($action) { } break; - case 'debug_scraper': + case 'debug_dvdcover': $title = $_GET['title'] ?? ''; $year = $_GET['year'] ?? ''; $format = $_GET['format'] ?? 'Blu-ray'; @@ -644,7 +613,7 @@ switch ($action) { if (!$title) { echo json_encode(['error' => 'Titre manquant']); exit; } $result = ['title' => $title, 'year' => $year, 'format' => $format]; - $data = fetchDVDFrCover($title, $year, $format); + $data = fetchDVDCover($title, $year, $format); $result['data'] = $data; $result['status'] = $data ? 'OK' : 'AUCUN_RÉSULTAT';