diff --git a/api.php b/api.php index bdc299f..4097aad 100644 --- a/api.php +++ b/api.php @@ -117,66 +117,96 @@ function extractYear($dateStr) { 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); - - // On encode proprement pour l'URL $searchUrl = "https://www.dvdcover.com/?s=" . urlencode($cleanTitle); - + $html = httpGet($searchUrl, 10, $ua); if (!$html) { error_log("DVDCover: Erreur réseau pour '$title'"); return null; } - // DEBUG : Sauvegarde le contenu pour vérifier si on est bloqué - file_put_contents(__DIR__ . '/debug_scrap.html', $html); - $dom = new DOMDocument(); @$dom->loadHTML($html); $xpath = new DOMXPath($dom); - - // On cherche les liens dans les articles (Standard WordPress) - $links = $xpath->query('//article[contains(@class, "post")]//a/@href'); - + + // Les résultats sont dans des

+ $links = $xpath->query('//h2//a'); if ($links->length === 0) { - error_log("DVDCover: Aucun article trouvé pour '$title' (structure changée ?)"); + error_log("DVDCover: Aucun lien H2 trouvé pour '$title'"); return null; } - - foreach ($links as $link) { - $coverPage = $link->nodeValue; - - $coverHtml = httpGet($coverPage, 10, $ua); - if (!$coverHtml) continue; - - $domFiche = new DOMDocument(); - @$domFiche->loadHTML($coverHtml); - $xpathFiche = new DOMXPath($domFiche); - - // On cherche toutes les images dans la zone de contenu - // WordPress utilise souvent la classe 'entry-content' ou 'post-content' - $imgs = $xpathFiche->query('//div[contains(@class, "entry-content")]//img | //article//img'); - - foreach ($imgs as $img) { - $src = $img->getAttribute('src'); - - // On filtre les images : on veut une jaquette, pas un logo ou une vignette 150x150 - if (strpos($src, 'wp-content/uploads') !== false && - strpos($src, 'logo') === false && - strpos($src, 'icon') === false && - strpos($src, '150x150') === false) { - - return [ - 'poster' => $src, - 'title' => $cleanTitle, - 'format' => $format - ]; - } + + // On cherche le meilleur lien : correspondance titre + année si possible + $bestUrl = null; + $cleanTitleLower = strtolower($cleanTitle); + + foreach ($links as $a) { + $text = strtolower(trim($a->textContent)); + $href = $a->getAttribute('href'); + + // Priorité : correspond au titre ET à l'année + if (!empty($year) && strpos($text, strtolower($cleanTitleLower)) !== false && strpos($text, $year) !== false) { + $bestUrl = $href; + break; + } + + // Fallback : correspond au titre seul (premier trouvé) + if ($bestUrl === null && strpos($text, $cleanTitleLower) !== false) { + $bestUrl = $href; } } - return null; + + // Dernier fallback : premier lien de la liste + if (!$bestUrl) { + $bestUrl = $links->item(0)->getAttribute('href'); + } + + if (!$bestUrl) return null; + + // On scrape la page de la fiche + $coverHtml = httpGet($bestUrl, 10, $ua); + if (!$coverHtml) return null; + + $domFiche = new DOMDocument(); + @$domFiche->loadHTML($coverHtml); + $xpathFiche = new DOMXPath($domFiche); + + // On cherche la plus grande image dans wp-content/uploads (pas les thumbnails -300x) + $imgs = $xpathFiche->query('//img[contains(@src,"wp-content/uploads")]'); + $bestSrc = null; + $bestSize = 0; + + foreach ($imgs as $img) { + $src = $img->getAttribute('src'); + + // Ignorer logos, icônes et thumbnails redimensionnés + if (strpos($src, 'logo') !== false) continue; + if (strpos($src, 'icon') !== false) continue; + + // Préférer les images sans suffixe de redimensionnement (ex: -300x201) + $isThumb = preg_match('/-\d+x\d+\./', $src); + + // Tenter de récupérer la version pleine taille (supprimer le suffixe -WxH) + $fullSrc = preg_replace('/-\d+x\d+(\.\w+)$/', '$1', $src); + + // Scorer : pleine taille > thumbnail + $score = $isThumb ? 1 : 10; + if ($score > $bestSize) { + $bestSize = $score; + $bestSrc = $fullSrc; + } + } + + if (!$bestSrc) return null; + + return [ + 'poster' => $bestSrc, + 'title' => $cleanTitle, + 'format' => $format + ]; } // ── API TMDB (uniquement pour les critiques) ──