Actualiser api.php
This commit is contained in:
@@ -115,31 +115,19 @@ function extractYear($dateStr) {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── DVDcover.com (avec vérification du titre) ──
|
// ── NOUVEAU SCRAPER : DVDFr (Refonte 2026) ──
|
||||||
function fetchDVDCover($title, $year = '', $format = 'bluray') {
|
function fetchDVDFrCover($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';
|
$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);
|
||||||
$cleanTitleLower = strtolower($cleanTitle);
|
|
||||||
|
|
||||||
// Mapping des formats
|
// 1. Simuler une recherche sur le nouveau site DVDFr
|
||||||
$formatMap = [
|
$searchUrl = "https://www.dvdfr.com/search/search.php?titre=" . urlencode($cleanTitle);
|
||||||
'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);
|
|
||||||
|
|
||||||
$html = httpGet($searchUrl, 8, $ua);
|
$html = httpGet($searchUrl, 8, $ua);
|
||||||
if (!$html) {
|
if (!$html) {
|
||||||
error_log("DVDCover: Échec recherche pour '$title'");
|
error_log("DVDFr Scraper: Échec de connexion pour '$title'");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,109 +137,67 @@ function fetchDVDCover($title, $year = '', $format = 'bluray') {
|
|||||||
'format' => $format,
|
'format' => $format,
|
||||||
];
|
];
|
||||||
|
|
||||||
// Chercher tous les articles/résultats
|
// 2. Parser le HTML de la recherche
|
||||||
preg_match_all('/<article[^>]*>(.*?)<\/article>/is', $html, $articles);
|
$dom = new DOMDocument();
|
||||||
|
@$dom->loadHTML($html);
|
||||||
|
$xpath = new DOMXPath($dom);
|
||||||
|
|
||||||
if (!empty($articles[1])) {
|
// 3. Chercher le lien vers la fiche de l'édition (les liens DVDFr commencent souvent par /dvd/f)
|
||||||
$bestMatch = null;
|
$links = $xpath->query('//a[contains(@href, "/dvd/f")]');
|
||||||
$bestScore = 0;
|
$ficheUrl = '';
|
||||||
|
|
||||||
foreach ($articles[1] as $article) {
|
if ($links->length > 0) {
|
||||||
// Extraire le lien vers la page
|
foreach ($links as $link) {
|
||||||
if (!preg_match('/<a[^>]+href=["\']([^"\']+)["\'][^>]*>/i', $article, $linkMatch)) {
|
$href = $link->getAttribute('href');
|
||||||
continue;
|
$ficheUrl = strpos($href, 'http') === 0 ? $href : "https://www.dvdfr.com" . (strpos($href, '/') === 0 ? '' : '/') . ltrim($href, '/');
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$coverPage = $linkMatch[1];
|
// Si la recherche nous a redirigé directement sur la fiche du film (1 seul résultat)
|
||||||
if (strpos($coverPage, 'http') !== 0) {
|
if (empty($ficheUrl) && stripos($html, 'jaquette') !== false) {
|
||||||
$coverPage = 'https://www.dvdcover.com' . $coverPage;
|
$ficheHtml = $html;
|
||||||
|
} elseif (!empty($ficheUrl)) {
|
||||||
|
// Sinon on charge la page de la fiche
|
||||||
|
$ficheHtml = httpGet($ficheUrl, 8, $ua);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extraire le titre de l'article
|
// 4. Extraire la jaquette de la fiche produit
|
||||||
$pageTitle = '';
|
if (!empty($ficheHtml)) {
|
||||||
if (preg_match('/<h2[^>]*class=["\'][^"\']*entry-title[^"\']*["\'][^>]*>([^<]+)<\/h2>/i', $article, $titleMatch)) {
|
$domFiche = new DOMDocument();
|
||||||
$pageTitle = trim(strip_tags($titleMatch[1]));
|
@$domFiche->loadHTML($ficheHtml);
|
||||||
} elseif (preg_match('/title=["\']([^"\']+)["\']/i', $article, $titleMatch)) {
|
$xpathFiche = new DOMXPath($domFiche);
|
||||||
$pageTitle = trim($titleMatch[1]);
|
|
||||||
|
// 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($pageTitle)) continue;
|
// 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) {
|
||||||
|
|
||||||
// Calculer un score de correspondance
|
$imgUrl = strpos($src, 'http') === 0 ? $src : "https://www.dvdfr.com" . (strpos($src, '/') === 0 ? '' : '/') . ltrim($src, '/');
|
||||||
$pageTitleLower = strtolower($pageTitle);
|
|
||||||
$score = 0;
|
|
||||||
|
|
||||||
// Le titre recherché est-il dans le titre de la page ?
|
// Transformation de l'URL pour choper la haute résolution (retirer le "small" ou "medium")
|
||||||
if (strpos($pageTitleLower, $cleanTitleLower) !== false) {
|
$imgUrl = preg_replace('/_s\./i', '.', $imgUrl);
|
||||||
$score += 100;
|
$imgUrl = preg_replace('/_m\./i', '.', $imgUrl);
|
||||||
}
|
|
||||||
|
|
||||||
// L'année correspond-elle ?
|
$result['poster'] = $imgUrl;
|
||||||
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('/<div[^>]*class=["\'][^"\']*entry-content[^"\']*["\'][^>]*>.*?<img[^>]+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('/<img[^>]+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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($poster)) {
|
|
||||||
// Extraire le titre de la page
|
|
||||||
$finalTitle = '';
|
|
||||||
if (preg_match('/<h1[^>]*class=["\'][^"\']*entry-title[^"\']*["\'][^>]*>([^<]+)<\/h1>/i', $coverHtml, $titleMatch)) {
|
|
||||||
$finalTitle = trim(strip_tags($titleMatch[1]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Garder le meilleur résultat
|
return (!empty($result['poster'])) ? $result : null;
|
||||||
if ($score > $bestScore) {
|
|
||||||
$bestScore = $score;
|
|
||||||
$bestMatch = [
|
|
||||||
'poster' => $poster,
|
|
||||||
'title' => $finalTitle ?: $pageTitle,
|
|
||||||
'format' => $format,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($bestMatch) {
|
|
||||||
return $bestMatch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── API TMDB (uniquement pour les critiques) ──
|
// ── API TMDB (uniquement pour les critiques) ──
|
||||||
@@ -388,6 +334,15 @@ switch ($action) {
|
|||||||
ORDER BY id DESC
|
ORDER BY id DESC
|
||||||
";
|
";
|
||||||
$result = $pdo->query($sql)->fetchAll();
|
$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);
|
echo json_encode($result);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -401,12 +356,10 @@ switch ($action) {
|
|||||||
'length' => '', 'number_of_discs' => 1, 'aspect_ratio' => '', 'actors' => ''
|
'length' => '', 'number_of_discs' => 1, 'aspect_ratio' => '', 'actors' => ''
|
||||||
];
|
];
|
||||||
|
|
||||||
// Pour DVDcover, on a besoin d'un titre
|
|
||||||
$tmdbKey = getTmdbApiKey($pdo);
|
$tmdbKey = getTmdbApiKey($pdo);
|
||||||
$titleForSearch = '';
|
$titleForSearch = '';
|
||||||
|
|
||||||
if ($tmdbKey) {
|
if ($tmdbKey) {
|
||||||
// Essayer de trouver via TMDB d'abord
|
|
||||||
$searchUrl = "https://api.themoviedb.org/3/find/{$ean}?api_key={$tmdbKey}&external_source=imdb_id";
|
$searchUrl = "https://api.themoviedb.org/3/find/{$ean}?api_key={$tmdbKey}&external_source=imdb_id";
|
||||||
$searchRes = httpGet($searchUrl, 5);
|
$searchRes = httpGet($searchUrl, 5);
|
||||||
$searchData = $searchRes ? json_decode($searchRes, true) : [];
|
$searchData = $searchRes ? json_decode($searchRes, true) : [];
|
||||||
@@ -425,18 +378,16 @@ switch ($action) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Récupération jaquette
|
|
||||||
if ($type === 'videotheque') {
|
if ($type === 'videotheque') {
|
||||||
// DVDcover pour vidéothèque
|
// DVDFr pour vidéothèque
|
||||||
$format = $result['format'] ?: 'Blu-ray';
|
$format = $result['format'] ?: 'Blu-ray';
|
||||||
$dcData = fetchDVDCover($titleForSearch, $result['year'], $format);
|
$dcData = fetchDVDFrCover($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'];
|
||||||
$result['format'] = $format;
|
$result['format'] = $format;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TMDB pour critiques
|
|
||||||
if ($tmdbKey) {
|
if ($tmdbKey) {
|
||||||
$tmdbData = fetchTMDBFull($titleForSearch, $result['year'], $tmdbKey, $pdo);
|
$tmdbData = fetchTMDBFull($titleForSearch, $result['year'], $tmdbKey, $pdo);
|
||||||
if ($tmdbData) {
|
if ($tmdbData) {
|
||||||
@@ -458,7 +409,6 @@ switch ($action) {
|
|||||||
$type = $data['type'] ?? 'critique';
|
$type = $data['type'] ?? 'critique';
|
||||||
$id = !empty($data['id']) ? $data['id'] : makeStableId($type, $data['title'] ?? '', $data['year'] ?? '0000');
|
$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']))) {
|
if ($type === 'critique' && (empty($data['director']) || empty($data['poster']))) {
|
||||||
$tmdbData = fetchTMDBFull($data['title'] ?? '', $data['year'] ?? '', getTmdbApiKey($pdo), $pdo);
|
$tmdbData = fetchTMDBFull($data['title'] ?? '', $data['year'] ?? '', getTmdbApiKey($pdo), $pdo);
|
||||||
if ($tmdbData) {
|
if ($tmdbData) {
|
||||||
@@ -475,10 +425,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 : DVDcover pour la jaquette
|
// Vidéothèque : DVDFr 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 = fetchDVDCover($data['title'], $data['year'] ?? '', $format);
|
$dcData = fetchDVDFrCover($data['title'], $data['year'] ?? '', $format);
|
||||||
if (!empty($dcData['poster'])) {
|
if (!empty($dcData['poster'])) {
|
||||||
$data['poster'] = $dcData['poster'];
|
$data['poster'] = $dcData['poster'];
|
||||||
}
|
}
|
||||||
@@ -525,7 +475,7 @@ switch ($action) {
|
|||||||
$id = makeStableId($type, $title, $year);
|
$id = makeStableId($type, $title, $year);
|
||||||
|
|
||||||
if ($type === 'videotheque') {
|
if ($type === 'videotheque') {
|
||||||
// ── VIDÉOTHÈQUE : DVDcover pour jaquette HD ──
|
// ── VIDÉOTHÈQUE : DVDFr pour jaquette ──
|
||||||
$csvActors = $rowData['ensemble'] ?? $rowData['creators'] ?? '';
|
$csvActors = $rowData['ensemble'] ?? $rowData['creators'] ?? '';
|
||||||
$actors = '';
|
$actors = '';
|
||||||
if (!empty($csvActors)) {
|
if (!empty($csvActors)) {
|
||||||
@@ -557,10 +507,10 @@ switch ($action) {
|
|||||||
$poster = $rowData['poster'] ?? '';
|
$poster = $rowData['poster'] ?? '';
|
||||||
$director = '';
|
$director = '';
|
||||||
|
|
||||||
// Récupération jaquette via DVDcover
|
// Récupération jaquette via DVDFr
|
||||||
$cleanTitleForDC = cleanTitle($title);
|
$cleanTitleForDC = cleanTitle($title);
|
||||||
if (!empty($cleanTitleForDC)) {
|
if (!empty($cleanTitleForDC)) {
|
||||||
$dcData = fetchDVDCover($cleanTitleForDC, $year, $format);
|
$dcData = fetchDVDFrCover($cleanTitleForDC, $year, $format);
|
||||||
if (!empty($dcData)) {
|
if (!empty($dcData)) {
|
||||||
if (!empty($dcData['poster'])) {
|
if (!empty($dcData['poster'])) {
|
||||||
$poster = $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)
|
$sql = "INSERT INTO videotheque (id, title, year, director, poster, format, length, publisher, ean_isbn13, number_of_discs, aspect_ratio, description, actors)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
ON DUPLICATE KEY UPDATE
|
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]);
|
$stmt->execute([$id, $title, $year, $director, $poster, $format, $length, $publisher, $ean, $discs, $aspect, $description, $actors]);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// ── CRITIQUES : TMDB complet ──
|
// ── CRITIQUES : TMDB ──
|
||||||
$ratingRaw = $rowData['Rating'] ?? $rowData['rating'] ?? '';
|
$ratingRaw = $rowData['Rating'] ?? $rowData['rating'] ?? '';
|
||||||
$rating = ($ratingRaw !== '' && $ratingRaw !== null) ? (float)$ratingRaw : null;
|
$rating = ($ratingRaw !== '' && $ratingRaw !== null) ? (float)$ratingRaw : null;
|
||||||
$review = $rowData['Review'] ?? $rowData['review'] ?? '';
|
$review = $rowData['Review'] ?? $rowData['review'] ?? '';
|
||||||
@@ -636,7 +584,7 @@ switch ($action) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'debug_dvdcover':
|
case 'debug_scraper':
|
||||||
$title = $_GET['title'] ?? '';
|
$title = $_GET['title'] ?? '';
|
||||||
$year = $_GET['year'] ?? '';
|
$year = $_GET['year'] ?? '';
|
||||||
$format = $_GET['format'] ?? 'Blu-ray';
|
$format = $_GET['format'] ?? 'Blu-ray';
|
||||||
@@ -644,7 +592,7 @@ 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 = fetchDVDCover($title, $year, $format);
|
$data = fetchDVDFrCover($title, $year, $format);
|
||||||
$result['data'] = $data;
|
$result['data'] = $data;
|
||||||
$result['status'] = $data ? 'OK' : 'AUCUN_RÉSULTAT';
|
$result['status'] = $data ? 'OK' : 'AUCUN_RÉSULTAT';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user