Actualiser api.php

This commit is contained in:
2026-06-25 15:24:37 +02:00
parent fd91b968fe
commit 0efc35bcf7
+156 -151
View File
@@ -69,7 +69,7 @@ function httpGet($url, $timeout = 3, $ua = null) {
$ctx = stream_context_create(['http' => [ $ctx = stream_context_create(['http' => [
'timeout' => $timeout, 'timeout' => $timeout,
'user_agent' => $ua, 'user_agent' => $ua,
'header' => "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Language: fr-FR,fr;q=0.9\r\n" 'header' => "Accept: application/json\r\nAccept-Language: fr-FR,fr;q=0.9\r\n"
]]); ]]);
return @file_get_contents($url, false, $ctx); return @file_get_contents($url, false, $ctx);
} }
@@ -82,10 +82,8 @@ function httpGet($url, $timeout = 3, $ua = null) {
CURLOPT_USERAGENT => $ua, CURLOPT_USERAGENT => $ua,
CURLOPT_FOLLOWLOCATION => true, CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTPHEADER => [ CURLOPT_HTTPHEADER => [
'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept: application/json',
'Accept-Language: fr-FR,fr;q=0.9,en;q=0.8', 'Accept-Language: fr-FR,fr;q=0.9,en;q=0.8',
'Accept-Encoding: identity',
'Connection: keep-alive',
], ],
]); ]);
$res = curl_exec($ch); $res = curl_exec($ch);
@@ -115,190 +113,152 @@ function extractYear($dateStr) {
return ''; return '';
} }
// ── DVDBlurayCovers.com Scraper ── // ── DVDCover.com via API REST WordPress ──
function fetchDVDBlurayCovers($title, $year = '', $format = 'bluray') { function fetchDVDCover($title, $year = '', $format = 'bluray') {
if (empty($title)) return null; 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); $cleanTitle = cleanTitle($title);
if (empty($cleanTitle)) return null;
// URL de recherche DVDBlurayCovers // API REST WordPress de DVDcover
$searchUrl = "https://www.dvdbluraycovers.com/?s=" . urlencode($cleanTitle); // Endpoint : /wp-json/wp/v2/posts?search=TITRE&_embed
$searchUrl = "https://www.dvdcover.com/wp-json/wp/v2/posts?search=" . urlencode($cleanTitle) . "&_embed&per_page=10";
$html = httpGet($searchUrl, 10, $ua); $json = httpGet($searchUrl, 10);
if (!$html) { if (!$json) {
error_log("DVDBlurayCovers: Échec recherche pour '$title'"); error_log("DVDCover API: Échec requête pour '$title'");
return null; return null;
} }
$result = [ $posts = json_decode($json, true);
'poster' => '', if (!is_array($posts) || empty($posts)) {
'title' => '', error_log("DVDCover API: Aucun résultat pour '$title'");
'format' => $format, return null;
];
// Parser le HTML avec DOMDocument
$dom = new DOMDocument();
@$dom->loadHTML($html);
$xpath = new DOMXPath($dom);
// Chercher les liens vers les pages de covers individuelles
// DVDBlurayCovers utilise des articles avec des liens vers les covers
$links = $xpath->query('//article[contains(@class,"post") or contains(@class,"entry")]//a/@href');
if ($links->length === 0) {
// Fallback : chercher tous les liens qui ressemblent à des pages de covers
$links = $xpath->query('//a[contains(@href,"/cover/") or contains(@href,"/covers/") or contains(@href,"/bluray/") or contains(@href,"/dvd/")]');
} }
$coverPages = []; $cleanTitleLower = strtolower($cleanTitle);
foreach ($links as $link) { $bestPost = null;
$href = $link->nodeValue; $bestScore = 0;
if (strpos($href, 'http') !== 0) {
$href = 'https://www.dvdbluraycovers.com' . $href;
}
// Éviter les doublons et les pages de catégories/tags
if (!in_array($href, $coverPages) &&
strpos($href, '/category/') === false &&
strpos($href, '/tag/') === false &&
strpos($href, '/page/') === false) {
$coverPages[] = $href;
}
if (count($coverPages) >= 5) break; // Limiter à 5 résultats max
}
// Parcourir les pages de covers trouvées // Parcourir les posts et scorer leur pertinence
foreach ($coverPages as $coverPage) { foreach ($posts as $post) {
$coverHtml = httpGet($coverPage, 10, $ua); $postTitle = $post['title']['rendered'] ?? '';
if (!$coverHtml) continue; $postTitleLower = strtolower($postTitle);
$domCover = new DOMDocument();
@$domCover->loadHTML($coverHtml);
$xpathCover = new DOMXPath($domCover);
// Extraire le titre de la page
$coverTitle = '';
$titleNodes = $xpathCover->query('//h1[contains(@class,"entry-title") or contains(@class,"post-title")]');
if ($titleNodes->length > 0) {
$coverTitle = trim($titleNodes->item(0)->textContent);
} else {
$titleNodes = $xpathCover->query('//title');
if ($titleNodes->length > 0) {
$coverTitle = trim($titleNodes->item(0)->textContent);
// Nettoyer le titre (enlever " - DVDBlurayCovers" etc.)
$coverTitle = preg_replace('/\s*[-|]\s*DVDBlurayCovers.*$/i', '', $coverTitle);
}
}
// Vérifier que le titre correspond au film recherché
$coverTitleLower = strtolower($coverTitle);
$searchTitleLower = strtolower($cleanTitle);
$score = 0; $score = 0;
if (strpos($coverTitleLower, $searchTitleLower) !== false) {
// Le titre du post contient-il le film recherché ?
if (strpos($postTitleLower, $cleanTitleLower) !== false) {
$score += 50; $score += 50;
} }
if (!empty($year) && strpos($coverTitle, $year) !== false) {
// Correspondance de l'année
if (!empty($year) && strpos($postTitle, $year) !== false) {
$score += 30; $score += 30;
} }
if (stripos($coverTitle, $format) !== false) {
// Correspondance du format
$formatLower = strtolower($format);
if (stripos($postTitle, $format) !== false ||
stripos($postTitle, str_replace('-', ' ', $format)) !== false) {
$score += 20; $score += 20;
} }
// Si le score est trop bas, on ignore ce résultat // Bonus si le titre contient "cover" ou "jaquette"
if ($score < 30) { if (stripos($postTitle, 'cover') !== false) {
continue; $score += 10;
} }
// Chercher l'image principale de la jaquette if ($score > $bestScore) {
$bestScore = $score;
$bestPost = $post;
}
// Score parfait, on arrête
if ($score >= 100) break;
}
// Si aucun post ne correspond assez bien, prendre le premier
if (!$bestPost && !empty($posts)) {
$bestPost = $posts[0];
}
if (!$bestPost) return null;
// Extraire l'image du post
$poster = ''; $poster = '';
// Méthode 1 : Chercher dans le contenu principal (entry-content) // Méthode 1 : Image mise en avant (_embedded.wp:featuredmedia)
$contentNodes = $xpathCover->query('//div[contains(@class,"entry-content") or contains(@class,"post-content")]//img'); if (isset($bestPost['_embedded']['wp:featuredmedia'][0])) {
if ($contentNodes->length > 0) { $featured = $bestPost['_embedded']['wp:featuredmedia'][0];
foreach ($contentNodes as $img) { // Chercher la plus grande taille disponible
$src = $img->getAttribute('src'); if (!empty($featured['media_details']['sizes'])) {
if (empty($src)) { $sizes = $featured['media_details']['sizes'];
$src = $img->getAttribute('data-src'); // Ordre de préférence : full > large > medium > thumbnail
} $preferredSizes = ['full', 'large', 'medium', 'thumbnail'];
if (empty($src)) { foreach ($preferredSizes as $size) {
$src = $img->getAttribute('data-lazy-src'); if (isset($sizes[$size]['source_url'])) {
} $poster = $sizes[$size]['source_url'];
// Vérifier que c'est une vraie image (pas un logo, icône, etc.)
if (!empty($src) &&
strpos($src, 'logo') === false &&
strpos($src, 'icon') === false &&
strpos($src, 'banner') === false &&
strpos($src, 'bg') === false &&
strpos($src, 'button') === false &&
strpos($src, 'social') === false &&
(strpos($src, '.jpg') !== false || strpos($src, '.jpeg') !== false || strpos($src, '.png') !== false || strpos($src, '.webp') !== false)) {
$poster = $src;
break; break;
} }
} }
} }
// Fallback : source_url direct
// Méthode 2 : Chercher dans les figures if (empty($poster) && !empty($featured['source_url'])) {
if (empty($poster)) { $poster = $featured['source_url'];
$figureNodes = $xpathCover->query('//figure//img');
if ($figureNodes->length > 0) {
foreach ($figureNodes as $img) {
$src = $img->getAttribute('src');
if (empty($src)) {
$src = $img->getAttribute('data-src');
} }
if (!empty($src) && }
strpos($src, 'logo') === false &&
strpos($src, 'icon') === false && // Méthode 2 : Images dans le contenu du post
(strpos($src, '.jpg') !== false || strpos($src, '.jpeg') !== false || strpos($src, '.png') !== false)) { if (empty($poster) && !empty($bestPost['content']['rendered'])) {
$poster = $src; $content = $bestPost['content']['rendered'];
// Chercher les balises img
if (preg_match_all('/<img[^>]+src=["\']([^"\']+)["\'][^>]*>/i', $content, $matches)) {
foreach ($matches[1] as $img) {
// Filtrer 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, 'social') === false &&
(strpos($img, '.jpg') !== false || strpos($img, '.jpeg') !== false || strpos($img, '.png') !== false || strpos($img, '.webp') !== false)) {
$poster = $img;
break; break;
} }
} }
} }
} }
// Méthode 3 : Meta Open Graph // Méthode 3 : Images embarquées dans _embedded.wp:embedded
if (empty($poster)) { if (empty($poster) && isset($bestPost['_embedded']['wp:embedded'])) {
$ogNodes = $xpathCover->query('//meta[@property="og:image"]/@content'); foreach ($bestPost['_embedded']['wp:embedded'] as $embedded) {
if ($ogNodes->length > 0) { if (!empty($embedded['source_url'])) {
$poster = $ogNodes->item(0)->nodeValue; $poster = $embedded['source_url'];
}
}
// Méthode 4 : Toutes les images dans wp-content/uploads
if (empty($poster)) {
$allImgs = $xpathCover->query('//img[contains(@src,"wp-content/uploads")]');
if ($allImgs->length > 0) {
foreach ($allImgs as $img) {
$src = $img->getAttribute('src');
if (strpos($src, 'logo') === false &&
strpos($src, 'icon') === false &&
strpos($src, '300x') === false &&
strpos($src, '150x') === false) {
$poster = $src;
break; break;
} }
} }
} }
if (empty($poster)) {
error_log("DVDCover API: Pas d'image trouvée pour le post ID " . ($bestPost['id'] ?? '?'));
return null;
} }
// Si on a trouvé une image, on la garde
if (!empty($poster)) {
// S'assurer que l'URL est absolue // S'assurer que l'URL est absolue
if (strpos($poster, 'http') !== 0) { if (strpos($poster, 'http') !== 0) {
$poster = 'https://www.dvdbluraycovers.com' . (strpos($poster, '/') === 0 ? '' : '/') . ltrim($poster, '/'); $poster = 'https://www.dvdcover.com' . (strpos($poster, '/') === 0 ? '' : '/') . ltrim($poster, '/');
} }
$result['poster'] = $poster; // Supprimer les suffixes de taille WordPress pour avoir la version originale
$result['title'] = $coverTitle; // Ex: image-300x200.jpg → image.jpg
break; $poster = preg_replace('/-\d+x\d+(\.\w+)$/', '$1', $poster);
}
}
return (!empty($result['poster'])) ? $result : null; return [
'poster' => $poster,
'title' => $bestPost['title']['rendered'] ?? $cleanTitle,
'format' => $format,
];
} }
// ── API TMDB (uniquement pour les critiques) ── // ── API TMDB (uniquement pour les critiques) ──
@@ -480,9 +440,9 @@ switch ($action) {
} }
if ($type === 'videotheque') { if ($type === 'videotheque') {
// DVDBlurayCovers pour vidéothèque // DVDCover API pour vidéothèque
$format = $result['format'] ?: 'Blu-ray'; $format = $result['format'] ?: 'Blu-ray';
$dcData = fetchDVDBlurayCovers($titleForSearch, $result['year'], $format); $dcData = fetchDVDCover($titleForSearch, $result['year'], $format);
if (!empty($dcData)) { if (!empty($dcData)) {
if (!empty($dcData['poster'])) $result['poster'] = $dcData['poster']; if (!empty($dcData['poster'])) $result['poster'] = $dcData['poster'];
if (!empty($dcData['title'])) $result['title'] = $dcData['title']; if (!empty($dcData['title'])) $result['title'] = $dcData['title'];
@@ -526,10 +486,10 @@ switch ($action) {
$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 {
// Vidéothèque : DVDBlurayCovers pour la jaquette // Vidéothèque : DVDCover API pour la jaquette
if (empty($data['poster']) && !empty($data['title'])) { if (empty($data['poster']) && !empty($data['title'])) {
$format = $data['format'] ?: 'Blu-ray'; $format = $data['format'] ?: 'Blu-ray';
$dcData = fetchDVDBlurayCovers($data['title'], $data['year'] ?? '', $format); $dcData = fetchDVDCover($data['title'], $data['year'] ?? '', $format);
if (!empty($dcData['poster'])) { if (!empty($dcData['poster'])) {
$data['poster'] = $dcData['poster']; $data['poster'] = $dcData['poster'];
} }
@@ -634,10 +594,10 @@ switch ($action) {
$poster = $rowData['poster'] ?? ''; $poster = $rowData['poster'] ?? '';
$director = ''; $director = '';
// Récupération jaquette via DVDBlurayCovers // Récupération jaquette via DVDCover API
$cleanTitleForDC = cleanTitle($title); $cleanTitleForDC = cleanTitle($title);
if (!empty($cleanTitleForDC)) { if (!empty($cleanTitleForDC)) {
$dcData = fetchDVDBlurayCovers($cleanTitleForDC, $year, $format); $dcData = fetchDVDCover($cleanTitleForDC, $year, $format);
if (!empty($dcData)) { if (!empty($dcData)) {
if (!empty($dcData['poster'])) { if (!empty($dcData['poster'])) {
$poster = $dcData['poster']; $poster = $dcData['poster'];
@@ -685,7 +645,7 @@ switch ($action) {
} }
break; break;
case 'debug_dvdbluraycovers': case 'debug_dvdcover':
$title = $_GET['title'] ?? ''; $title = $_GET['title'] ?? '';
$year = $_GET['year'] ?? ''; $year = $_GET['year'] ?? '';
$format = $_GET['format'] ?? 'Blu-ray'; $format = $_GET['format'] ?? 'Blu-ray';
@@ -693,8 +653,53 @@ switch ($action) {
if (!$title) { echo json_encode(['error' => 'Titre manquant']); exit; } if (!$title) { echo json_encode(['error' => 'Titre manquant']); exit; }
$result = ['title' => $title, 'year' => $year, 'format' => $format]; $result = ['title' => $title, 'year' => $year, 'format' => $format];
$data = fetchDVDBlurayCovers($title, $year, $format);
$result['data'] = $data; // Test direct de l'API
$cleanTitle = cleanTitle($title);
$apiUrl = "https://www.dvdcover.com/wp-json/wp/v2/posts?search=" . urlencode($cleanTitle) . "&_embed&per_page=5";
$result['api_url'] = $apiUrl;
$json = httpGet($apiUrl, 10);
if ($json) {
$posts = json_decode($json, true);
$result['posts_count'] = is_array($posts) ? count($posts) : 0;
$result['posts'] = [];
if (is_array($posts)) {
foreach ($posts as $post) {
$postData = [
'id' => $post['id'] ?? null,
'title' => $post['title']['rendered'] ?? '',
'link' => $post['link'] ?? '',
];
// Extraire les images
$imgs = [];
if (isset($post['_embedded']['wp:featuredmedia'][0])) {
$featured = $post['_embedded']['wp:featuredmedia'][0];
if (!empty($featured['source_url'])) {
$imgs[] = $featured['source_url'];
}
if (!empty($featured['media_details']['sizes'])) {
foreach ($featured['media_details']['sizes'] as $size => $data) {
if (!empty($data['source_url'])) {
$imgs[] = $data['source_url'] . " ($size)";
}
}
}
}
$postData['images'] = $imgs;
$result['posts'][] = $postData;
}
}
} else {
$result['api_error'] = 'Impossible de joindre l\'API';
}
// Test de la fonction complète
$data = fetchDVDCover($title, $year, $format);
$result['fetch_result'] = $data;
$result['status'] = $data ? 'OK' : 'AUCUN_RÉSULTAT'; $result['status'] = $data ? 'OK' : 'AUCUN_RÉSULTAT';
echo json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); echo json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);