Actualiser api.php
This commit is contained in:
@@ -419,7 +419,6 @@ function fetchFromBlurayCom($ean) {
|
||||
'publisher' => '', 'format' => 'Blu-ray', 'number_of_discs' => 1,
|
||||
'aspect_ratio' => ''
|
||||
];
|
||||
|
||||
$ean = preg_replace('/[^0-9]/', '', (string)$ean);
|
||||
if (strlen($ean) < 8) {
|
||||
error_log("Blu-ray.com: ❌ EAN invalide: $ean");
|
||||
@@ -436,8 +435,6 @@ function fetchFromBlurayCom($ean) {
|
||||
$lastRequest = microtime(true);
|
||||
|
||||
error_log("Blu-ray.com: 🔍 Recherche EAN $ean");
|
||||
|
||||
// Recherche par EAN
|
||||
$searchUrl = "https://www.blu-ray.com/movies/search.php?ean=" . urlencode($ean) . "&action=search";
|
||||
$ch = curl_init($searchUrl);
|
||||
curl_setopt_array($ch, [
|
||||
@@ -453,7 +450,6 @@ function fetchFromBlurayCom($ean) {
|
||||
'Referer: https://www.blu-ray.com/'
|
||||
]
|
||||
]);
|
||||
|
||||
$searchHtml = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$curlError = curl_error($ch);
|
||||
@@ -464,20 +460,17 @@ function fetchFromBlurayCom($ean) {
|
||||
return $empty;
|
||||
}
|
||||
|
||||
// Extraire l'URL du film - regex améliorée
|
||||
// Extraire l'URL du film
|
||||
if (!preg_match('/href="(https:\/\/www\.blu-ray\.com\/movies\/[^"]+\/(\d+)\/)"/i', $searchHtml, $matches)) {
|
||||
error_log("Blu-ray.com: ❌ Film non trouvé pour EAN $ean");
|
||||
return $empty;
|
||||
}
|
||||
|
||||
$movieUrl = $matches[1];
|
||||
$movieId = $matches[2];
|
||||
error_log("Blu-ray.com: ✅ Film trouvé → $movieUrl");
|
||||
|
||||
// Délai avant la 2ème requête
|
||||
sleep(2);
|
||||
sleep(2); // Délai avant la 2ème requête
|
||||
|
||||
// Récupérer la page du film
|
||||
$ch2 = curl_init($movieUrl);
|
||||
curl_setopt_array($ch2, [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
@@ -491,7 +484,6 @@ function fetchFromBlurayCom($ean) {
|
||||
'Referer: https://www.blu-ray.com/'
|
||||
]
|
||||
]);
|
||||
|
||||
$movieHtml = curl_exec($ch2);
|
||||
curl_close($ch2);
|
||||
|
||||
@@ -500,26 +492,19 @@ function fetchFromBlurayCom($ean) {
|
||||
return $empty;
|
||||
}
|
||||
|
||||
// Extraction des données - regex robustes face à la refonte du site
|
||||
// (le site a été redesigné : le <h1> contient désormais un lien <a> imbriqué,
|
||||
// la div#movie_info / #movie_review_intro qui encadrait les infos a disparu,
|
||||
// et le span#runtime a été remplacé par du texte brut dans une cellule de tableau)
|
||||
|
||||
// Titre - le <h1> peut désormais contenir un <a>, donc on autorise les balises
|
||||
// imbriquées avec (.*?) puis on nettoie avec strip_tags
|
||||
if (preg_match('/<h1[^>]*>(.*?)<\/h1>/is', $movieHtml, $m)) {
|
||||
// ── EXTRACTION AVEC LES NOUVELLES REGEX ──
|
||||
|
||||
// Titre (dans <h3> inside #movie_info)
|
||||
if (preg_match('/<div[^>]*id="movie_info"[^>]*>.*?<h3>([^<]+)<\/h3>/is', $movieHtml, $m)) {
|
||||
$empty['title'] = trim($m[1]);
|
||||
} elseif (preg_match('/<h1[^>]*>([^<]+)<\/h1>/i', $movieHtml, $m)) {
|
||||
$rawTitle = trim(strip_tags($m[1]));
|
||||
$empty['title'] = trim(preg_replace('/\s*(Blu-ray|4K|3D|DVD|UHD).*$/i', '', $rawTitle));
|
||||
}
|
||||
if (empty($empty['title']) && preg_match('/<title>([^<]+)<\/title>/i', $movieHtml, $m)) {
|
||||
// Filet de sécurité : la balise <title> de la page contient toujours le nom du film
|
||||
$rawTitle = trim(html_entity_decode(strip_tags($m[1])));
|
||||
$empty['title'] = trim(preg_replace('/\s*(Blu-ray|4K|3D|DVD|UHD).*$/i', '', $rawTitle));
|
||||
}
|
||||
|
||||
// Année
|
||||
if (preg_match('/href="[^"]*year=(\d{4})[^"]*"[^>]*>(\d{4})<\/a>/i', $movieHtml, $m)) {
|
||||
$empty['year'] = $m[1];
|
||||
|
||||
// Année (juste après le <h3>)
|
||||
if (preg_match('/<h3[^>]*>([^<]+)<\/h3>\s*(?: )?\((\d{4})\)/i', $movieHtml, $m)) {
|
||||
$empty['year'] = $m[2];
|
||||
}
|
||||
|
||||
// Studio/Éditeur
|
||||
@@ -527,26 +512,21 @@ function fetchFromBlurayCom($ean) {
|
||||
$empty['publisher'] = trim($m[1]);
|
||||
}
|
||||
|
||||
// Durée - le span#runtime n'existe plus ; on cherche "NNN min" à proximité
|
||||
// du lien "année" déjà trouvé plus haut (ex: "... | 2012 | 123 min | Rated PG | ...")
|
||||
if (preg_match('/movies\.php\?year=\d{4}[^>]*>\d{4}<\/a>.{0,80}?(\d{2,3})\s*min\b/is', $movieHtml, $m)) {
|
||||
// Durée (dans un span avant "Rated")
|
||||
if (preg_match('/(\d+)\s*min<\/span>/i', $movieHtml, $m)) {
|
||||
$empty['length'] = $m[1] . ' min';
|
||||
} elseif (preg_match('/\b(\d{2,3})\s*min\b/i', $movieHtml, $m)) {
|
||||
// Filet de sécurité, moins précis
|
||||
} elseif (preg_match('/(\d+)\s*min\s*\|\s*Rated/i', $movieHtml, $m)) {
|
||||
$empty['length'] = $m[1] . ' min';
|
||||
}
|
||||
|
||||
// Aspect ratio - "Original aspect ratio: X.XX:1" est plus fiable que le premier
|
||||
// "Aspect ratio:" qui peut lister plusieurs valeurs (plans différents dans le film)
|
||||
if (preg_match('/Original aspect ratio:\s*([\d\.]+:[\d\.]+)/i', $movieHtml, $m)) {
|
||||
$empty['aspect_ratio'] = trim($m[1]);
|
||||
} elseif (preg_match('/Aspect[\s-]*ratio:\s*([\d\.]+:[\d\.]+)/i', $movieHtml, $m)) {
|
||||
// Aspect ratio
|
||||
if (preg_match('/Aspect[\s-]*ratio:\s*([\d\.]+:[\d\.]+)/i', $movieHtml, $m)) {
|
||||
$empty['aspect_ratio'] = trim($m[1]);
|
||||
}
|
||||
|
||||
// Nombre de disques - plusieurs patterns
|
||||
// Nombre de disques (gère "Three-disc set" en plus des chiffres)
|
||||
if (preg_match('/(\w+)-disc\s+set/i', $movieHtml, $m)) {
|
||||
$wordToNum = ['single' => 1, 'two' => 2, 'three' => 3, 'four' => 4, 'five' => 5, 'six' => 6];
|
||||
$wordToNum = ['single' => 1, 'one' => 1, 'two' => 2, 'three' => 3, 'four' => 4, 'five' => 5, 'six' => 6];
|
||||
$word = strtolower($m[1]);
|
||||
$empty['number_of_discs'] = $wordToNum[$word] ?? 1;
|
||||
} elseif (preg_match('/(\d+)-disc\s+set/i', $movieHtml, $m)) {
|
||||
@@ -562,67 +542,43 @@ function fetchFromBlurayCom($ean) {
|
||||
$empty['format'] = 'Blu-ray';
|
||||
}
|
||||
|
||||
// Affiche HD - le site charge désormais les jaquettes en JS (lazy-load,
|
||||
// le HTML statique ne contient qu'un visuel "Temporary cover art" en placeholder).
|
||||
// On essaie d'abord les anciens motifs (au cas où ils réapparaissent sur certaines
|
||||
// pages), puis on retombe sur l'URL CDN prévisible construite à partir de l'ID du
|
||||
// film, en la validant par une requête HEAD avant de l'utiliser.
|
||||
if (preg_match('/(?:src|data-src)="(https:\/\/images\d*\.static-bluray\.com\/movies\/covers\/\d+_(?:front|large)\.jpg[^"]*)"/i', $movieHtml, $m)) {
|
||||
// Affiche HD
|
||||
if (preg_match('/src="(https:\/\/images\.static-bluray\.com\/movies\/covers\/\d+_front\.jpg[^"]*)"/i', $movieHtml, $m)) {
|
||||
$empty['poster'] = $m[1];
|
||||
} elseif (preg_match('/<img[^>]*class="[^"]*coverfront[^"]*"[^>]*(?:src|data-src)="([^"]+)"/i', $movieHtml, $m)) {
|
||||
$posterUrl = preg_replace('/_large\.jpg/', '_front.jpg', $m[1]);
|
||||
} elseif (preg_match('/<img[^>]*class="coverfront"[^>]*src="([^"]+)"/i', $movieHtml, $m)) {
|
||||
$posterUrl = $m[1];
|
||||
$posterUrl = preg_replace('/_large\.jpg/', '_front.jpg', $posterUrl);
|
||||
$empty['poster'] = $posterUrl;
|
||||
} else {
|
||||
error_log("Blu-ray.com: ⚠️ Jaquette absente du HTML statique (lazy-load JS), tentative CDN prévisible pour ID $movieId");
|
||||
foreach (['_large.jpg', '_front.jpg'] as $suffix) {
|
||||
$candidate = "https://images.static-bluray.com/movies/covers/{$movieId}{$suffix}";
|
||||
if (urlExists($candidate)) {
|
||||
$empty['poster'] = $candidate;
|
||||
break;
|
||||
}
|
||||
|
||||
// Synopsis, Réalisateur, Acteurs (dans #movie_info)
|
||||
if (preg_match('/<div[^>]*id="movie_info"[^>]*>(.*?)<div[^>]*id="movie_review_intro"/is', $movieHtml, $infoBlock)) {
|
||||
$infoHtml = $infoBlock[1];
|
||||
|
||||
// Synopsis (après la balise <font> vide)
|
||||
if (preg_match('/<font[^>]*><br><\/font>\s*(.*?)<br><br><br>Directors:/is', $infoHtml, $m)) {
|
||||
$synopsis = trim(strip_tags($m[1]));
|
||||
$synopsis = preg_replace('/\s+/', ' ', $synopsis);
|
||||
$empty['description'] = $synopsis;
|
||||
}
|
||||
|
||||
// Réalisateur (extrait depuis les balises <a>)
|
||||
if (preg_match('/Directors?:\s*(.*?)(?:<br>|<\/div>)/is', $infoHtml, $m)) {
|
||||
preg_match_all('/<a[^>]*>([^<]+)<\/a>/i', $m[1], $dirMatches);
|
||||
if (!empty($dirMatches[1])) {
|
||||
$empty['director'] = implode(', ', array_map('trim', array_slice($dirMatches[1], 0, 2)));
|
||||
}
|
||||
}
|
||||
if (empty($empty['poster'])) {
|
||||
error_log("Blu-ray.com: ❌ Aucune URL de jaquette CDN valide trouvée pour ID $movieId (fallback TMDB attendu)");
|
||||
|
||||
// Acteurs (extrait depuis les balises <a>)
|
||||
if (preg_match('/Starring:\s*(.*?)(?:<br>|<\/div>)/is', $infoHtml, $m)) {
|
||||
preg_match_all('/<a[^>]*>([^<]+)<\/a>/i', $m[1], $actorMatches);
|
||||
if (!empty($actorMatches[1])) {
|
||||
$empty['actors'] = implode(', ', array_map('trim', array_slice($actorMatches[1], 0, 6)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Synopsis, Réalisateur, Acteurs
|
||||
// La div#movie_info / #movie_review_intro qui encadrait ces infos a disparu de la
|
||||
// refonte du site : "Director:" et "Starring:" apparaissent maintenant directement
|
||||
// dans le flux HTML de la page, donc on cherche sur $movieHtml en entier plutôt
|
||||
// que dans un sous-bloc délimité par ces anciens ID.
|
||||
|
||||
// Réalisateur
|
||||
if (preg_match('/Director:\s*<a[^>]*>([^<]+)<\/a>/i', $movieHtml, $m)) {
|
||||
$empty['director'] = trim(html_entity_decode($m[1]));
|
||||
} else {
|
||||
error_log("Blu-ray.com: ⚠️ Réalisateur non trouvé (structure HTML probablement changée)");
|
||||
}
|
||||
|
||||
// Acteurs
|
||||
if (preg_match('/Starring:\s*(.*?)(?:<br\s*\/?>|<\/(?:p|div|td)>)/is', $movieHtml, $m)) {
|
||||
preg_match_all('/<a[^>]*>([^<]+)<\/a>/i', $m[1], $actorMatches);
|
||||
if (!empty($actorMatches[1])) {
|
||||
$empty['actors'] = implode(', ', array_map(fn($a) => trim(html_entity_decode($a)), array_slice($actorMatches[1], 0, 6)));
|
||||
}
|
||||
} else {
|
||||
error_log("Blu-ray.com: ⚠️ Acteurs non trouvés (structure HTML probablement changée)");
|
||||
}
|
||||
|
||||
// Synopsis - on capture le dernier bloc de texte "libre" (hors balises) qui
|
||||
// précède immédiatement "Director:", en tolérant quelques balises intermédiaires
|
||||
if (preg_match('/>([^<]{60,900})<(?:[^>]*>){0,5}\s*Director:/is', $movieHtml, $m)) {
|
||||
$synopsis = trim(html_entity_decode(strip_tags($m[1])));
|
||||
$synopsis = preg_replace('/\s+/', ' ', $synopsis);
|
||||
$empty['description'] = $synopsis;
|
||||
} else {
|
||||
error_log("Blu-ray.com: ⚠️ Synopsis non trouvé (structure HTML probablement changée)");
|
||||
}
|
||||
|
||||
if (empty($empty['title'])) {
|
||||
error_log("Blu-ray.com: ⚠️ Titre non extrait malgré une page trouvée pour ID $movieId — vérifier la structure du <h1>/<title>");
|
||||
}
|
||||
|
||||
|
||||
error_log("Blu-ray.com: ✅ Données récupérées pour EAN $ean → " . $empty['title']);
|
||||
return $empty;
|
||||
}
|
||||
@@ -634,57 +590,55 @@ function fetchFromMovieCovers($title, $year = '') {
|
||||
'publisher' => '', 'format' => 'DVD', 'number_of_discs' => 1,
|
||||
'aspect_ratio' => ''
|
||||
];
|
||||
|
||||
if (empty($title)) return $empty;
|
||||
|
||||
// Nettoyer le titre pour l'URL : moviecovers.com attend un titre en MAJUSCULES
|
||||
// SANS accents ni apostrophes/ponctuation (ex: "L'Étrange Noël" -> "L+ETRANGE+NOEL").
|
||||
// C'est la cause principale des échecs silencieux : un titre accentué produit une
|
||||
// URL qui ne correspond à aucune fiche et retombe sur la page "non trouvé".
|
||||
$normalized = removeAccentsForUrl($title);
|
||||
$normalized = str_replace(['œ', 'Œ'], ['OE', 'OE'], $normalized);
|
||||
$normalized = preg_replace('/[^A-Za-z0-9 ]+/', ' ', $normalized); // apostrophes, ':', '-', etc. -> espace
|
||||
$normalized = preg_replace('/\s{2,}/', ' ', trim($normalized));
|
||||
$urlTitle = strtoupper(str_replace(' ', '+', $normalized));
|
||||
|
||||
if ($urlTitle === '') {
|
||||
error_log("MovieCovers: ❌ Titre vide après normalisation pour '$title'");
|
||||
return $empty;
|
||||
}
|
||||
|
||||
|
||||
// Nettoyer le titre pour l'URL (les espaces deviennent des +)
|
||||
$urlTitle = strtoupper(str_replace(' ', '+', $title));
|
||||
$url = "https://moviecovers.com/film/titre_{$urlTitle}.html";
|
||||
error_log("MovieCovers: 🔍 Recherche '$title' → $url");
|
||||
|
||||
$html = httpGet($url, 10);
|
||||
if (!$html) {
|
||||
error_log("MovieCovers: ❌ Échec HTTP pour $url");
|
||||
return $empty;
|
||||
}
|
||||
|
||||
// Le site répond en 200 même quand le film n'existe pas ("Je n'ai pas trouvé de film")
|
||||
if (stripos($html, "n'ai pas trouv") !== false) {
|
||||
error_log("MovieCovers: ❌ Film non trouvé pour '$title' (URL: $url)");
|
||||
return $empty;
|
||||
}
|
||||
|
||||
if (!$html) return $empty;
|
||||
|
||||
// Extraire le titre
|
||||
if (preg_match('/<TITLE>([^<]+)<\/TITLE>/i', $html, $m)) {
|
||||
if (preg_match('/<meta property="og:title" content="([^"]+)"/i', $html, $m)) {
|
||||
$empty['title'] = trim($m[1]);
|
||||
} elseif (preg_match('/<TITLE>([^<]+)<\/TITLE>/i', $html, $m)) {
|
||||
$empty['title'] = trim($m[1]);
|
||||
} elseif (preg_match('/<meta[^>]*property="og:title"[^>]*content="([^"]+)"/i', $html, $m)) {
|
||||
$empty['title'] = trim(html_entity_decode($m[1]));
|
||||
}
|
||||
|
||||
// Extraire l'affiche - plusieurs filets de sécurité, l'ordre des attributs
|
||||
// (src/alt/title) dans le <img> n'étant pas garanti
|
||||
if (preg_match('/<img[^>]*src="(https:\/\/moviecovers\.com\/DATA\/thumbs\/[^"]+)"[^>]*title="Recto/i', $html, $m)) {
|
||||
$empty['poster'] = $m[1];
|
||||
} elseif (preg_match('/title="Recto[^"]*"[^>]*src="(https:\/\/moviecovers\.com\/DATA\/thumbs\/[^"]+)"/i', $html, $m)) {
|
||||
// Même image mais avec title AVANT src dans la balise
|
||||
$empty['poster'] = $m[1];
|
||||
} elseif (preg_match('/<meta[^>]*property="og:image"[^>]*content="([^"]+)"/i', $html, $m)) {
|
||||
$empty['poster'] = $m[1];
|
||||
} elseif (preg_match('/<meta[^>]*(?:property|name)="twitter:image"[^>]*content="([^"]+)"/i', $html, $m)) {
|
||||
$empty['poster'] = $m[1];
|
||||
// Extraire l'IDMC pour construire l'URL de l'image HD (comme dans votre script Python)
|
||||
$idmc = '';
|
||||
if (preg_match('/IDMC.*?<PRE>([^<]+)<\/PRE>/is', $html, $m)) {
|
||||
$idmc = trim($m[1]);
|
||||
} elseif (preg_match('/<meta property="og:image" content="[^"]*\/getjpg\.html\/([^"\']+)\.jpg"/i', $html, $m)) {
|
||||
$idmc = urldecode($m[1]);
|
||||
}
|
||||
|
||||
// Essayer de récupérer l'affiche HD via les URLs du script Python
|
||||
if ($idmc) {
|
||||
$idmc_encoded = urlencode($idmc);
|
||||
$hd_urls = [
|
||||
"https://moviecovers.com/DATA/zipcache/{$idmc_encoded}.jpg",
|
||||
"https://moviecovers.com/getjpg.html/{$idmc_encoded}.jpg"
|
||||
];
|
||||
foreach ($hd_urls as $hd_url) {
|
||||
$img_data = httpGet($hd_url, 5);
|
||||
if ($img_data && strlen($img_data) > 5000) { // Vérifie que c'est une vraie image (>5Ko)
|
||||
$empty['poster'] = $hd_url;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback sur le thumbnail si pas d'image HD trouvée
|
||||
if (empty($empty['poster'])) {
|
||||
// CORRECTION : La regex gère le cas où title= est avant src=
|
||||
if (preg_match('/<img[^>]*title="Recto[^"]*"[^>]*src="([^"]+)"/i', $html, $m)) {
|
||||
$empty['poster'] = $m[1];
|
||||
} elseif (preg_match('/<img[^>]*src="([^"]+)"[^>]*title="Recto/i', $html, $m)) {
|
||||
$empty['poster'] = $m[1];
|
||||
} elseif (preg_match('/<meta[^>]*property="og:image"[^>]*content="([^"]+)"/i', $html, $m)) {
|
||||
$empty['poster'] = $m[1];
|
||||
}
|
||||
}
|
||||
|
||||
// Extraire le réalisateur
|
||||
@@ -712,15 +666,6 @@ function fetchFromMovieCovers($title, $year = '') {
|
||||
$empty['description'] = html_entity_decode($m[1]);
|
||||
}
|
||||
|
||||
// Format haute qualité de l'affiche
|
||||
if ($empty['poster']) {
|
||||
$empty['poster'] = str_replace('/thumbs/', '/films-l/', $empty['poster']);
|
||||
} else {
|
||||
error_log("MovieCovers: ⚠️ Jaquette non trouvée pour '$title' (URL: $url) — structure HTML probablement changée");
|
||||
}
|
||||
|
||||
error_log("MovieCovers: " . (!empty($empty['title']) ? "✅ Données récupérées pour '$title' → " . $empty['title'] : "⚠️ Page trouvée mais titre non extrait pour '$title'"));
|
||||
|
||||
return $empty;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user