Actualiser api.php
This commit is contained in:
@@ -93,23 +93,57 @@ function httpGet($url, $timeout = 3, $ua = null) {
|
|||||||
return $res ?: null;
|
return $res ?: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vérifie si une URL existe (HEAD request)
|
// OPTIMISATION MAJEURE : Vérification des URLs en parallèle
|
||||||
function urlExists($url, $timeout = 3) {
|
function checkUrlsParallel($urls, $timeout = 3) {
|
||||||
if (!function_exists('curl_init')) return false;
|
if (empty($urls)) return false;
|
||||||
|
if (!function_exists('curl_multi_init')) return false;
|
||||||
|
|
||||||
|
$multiHandle = curl_multi_init();
|
||||||
|
$curlHandles = [];
|
||||||
|
|
||||||
|
foreach ($urls as $url) {
|
||||||
$ch = curl_init($url);
|
$ch = curl_init($url);
|
||||||
curl_setopt_array($ch, [
|
curl_setopt_array($ch, [
|
||||||
CURLOPT_RETURNTRANSFER => true,
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
CURLOPT_NOBODY => true,
|
CURLOPT_NOBODY => true, // On télécharge juste l'entête, pas l'image
|
||||||
CURLOPT_TIMEOUT => $timeout,
|
CURLOPT_TIMEOUT => $timeout,
|
||||||
CURLOPT_CONNECTTIMEOUT => 2,
|
CURLOPT_CONNECTTIMEOUT => 2,
|
||||||
CURLOPT_SSL_VERIFYPEER => false,
|
CURLOPT_SSL_VERIFYPEER => false,
|
||||||
CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
||||||
CURLOPT_FOLLOWLOCATION => true,
|
CURLOPT_FOLLOWLOCATION => true,
|
||||||
]);
|
]);
|
||||||
curl_exec($ch);
|
curl_multi_add_handle($multiHandle, $ch);
|
||||||
|
$curlHandles[] = $ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
$active = null;
|
||||||
|
$validUrl = false;
|
||||||
|
|
||||||
|
do {
|
||||||
|
$status = curl_multi_exec($multiHandle, $active);
|
||||||
|
if ($active) curl_multi_select($multiHandle, 0.1);
|
||||||
|
|
||||||
|
while ($info = curl_multi_info_read($multiHandle)) {
|
||||||
|
$ch = $info['handle'];
|
||||||
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
|
||||||
|
// Si on trouve UNE url valide, on arrête tout immédiatement
|
||||||
|
if ($code >= 200 && $code < 400) {
|
||||||
|
$validUrl = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
|
||||||
|
break 2;
|
||||||
|
}
|
||||||
|
curl_multi_remove_handle($multiHandle, $ch);
|
||||||
|
}
|
||||||
|
} while ($active && $status == CURLM_OK);
|
||||||
|
|
||||||
|
// Nettoyage de la mémoire
|
||||||
|
foreach ($curlHandles as $ch) {
|
||||||
|
curl_multi_remove_handle($multiHandle, $ch);
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
return ($code >= 200 && $code < 400);
|
}
|
||||||
|
curl_multi_close($multiHandle);
|
||||||
|
|
||||||
|
return $validUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanTitle($title) {
|
function cleanTitle($title) {
|
||||||
@@ -134,16 +168,13 @@ function extractYear($dateStr) {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── COVERCENTURY.COM ──
|
// ── COVERCENTURY.COM (Version Parallélisée) ──
|
||||||
// Structure : https://www.covercentury.com/covers/{format}/{première_lettre}/{Nom_Normalisé}{numéro}.jpg
|
|
||||||
// Exemple : https://www.covercentury.com/covers/dvd/t/The_Matrix_Reloaded1.jpg
|
|
||||||
function fetchCoverCentury($title, $year = '', $format = 'bluray') {
|
function fetchCoverCentury($title, $year = '', $format = 'bluray') {
|
||||||
if (empty($title)) return null;
|
if (empty($title)) return null;
|
||||||
|
|
||||||
$cleanTitle = cleanTitle($title);
|
$cleanTitle = cleanTitle($title);
|
||||||
if (empty($cleanTitle)) return null;
|
if (empty($cleanTitle)) return null;
|
||||||
|
|
||||||
// Mapping des formats pour CoverCentury
|
|
||||||
$formatMap = [
|
$formatMap = [
|
||||||
'4k ultra hd' => '4kultrahd',
|
'4k ultra hd' => '4kultrahd',
|
||||||
'4k' => '4kultrahd',
|
'4k' => '4kultrahd',
|
||||||
@@ -153,79 +184,66 @@ function fetchCoverCentury($title, $year = '', $format = 'bluray') {
|
|||||||
];
|
];
|
||||||
$ccFormat = $formatMap[strtolower($format)] ?? 'bluray';
|
$ccFormat = $formatMap[strtolower($format)] ?? 'bluray';
|
||||||
|
|
||||||
// Normaliser le titre pour CoverCentury
|
|
||||||
// Ex: "The Matrix" → "The_Matrix"
|
|
||||||
// CoverCentury utilise souvent le titre anglais, on va essayer plusieurs variantes
|
|
||||||
$titleVariants = [];
|
$titleVariants = [];
|
||||||
|
|
||||||
// Variante 1 : titre original nettoyé
|
$normalized = trim(preg_replace('/\s+/', '_', preg_replace('/[^a-zA-Z0-9\s]/', '', $cleanTitle)));
|
||||||
$normalized = $cleanTitle;
|
|
||||||
$normalized = preg_replace('/[^a-zA-Z0-9\s]/', '', $normalized);
|
|
||||||
$normalized = trim($normalized);
|
|
||||||
$normalized = preg_replace('/\s+/', '_', $normalized);
|
|
||||||
if (!empty($normalized)) $titleVariants[] = $normalized;
|
if (!empty($normalized)) $titleVariants[] = $normalized;
|
||||||
|
|
||||||
// Variante 2 : sans article au début (The, Le, La, Les)
|
$withoutArticle = trim(preg_replace('/\s+/', '_', preg_replace('/[^a-zA-Z0-9\s]/', '', preg_replace('/^(The|Le|La|Les|Un|Une|A)\s+/i', '', $cleanTitle))));
|
||||||
$withoutArticle = preg_replace('/^(The|Le|La|Les|Un|Une|A)\s+/i', '', $cleanTitle);
|
|
||||||
$withoutArticle = preg_replace('/[^a-zA-Z0-9\s]/', '', $withoutArticle);
|
|
||||||
$withoutArticle = trim($withoutArticle);
|
|
||||||
$withoutArticle = preg_replace('/\s+/', '_', $withoutArticle);
|
|
||||||
if (!empty($withoutArticle) && $withoutArticle !== $normalized) {
|
if (!empty($withoutArticle) && $withoutArticle !== $normalized) {
|
||||||
$titleVariants[] = $withoutArticle;
|
$titleVariants[] = $withoutArticle;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Variante 3 : ajouter l'article "The_" si absent
|
|
||||||
if (!preg_match('/^The_/i', $normalized)) {
|
if (!preg_match('/^The_/i', $normalized)) {
|
||||||
$withThe = 'The_' . $normalized;
|
$titleVariants[] = 'The_' . $normalized;
|
||||||
if (!in_array($withThe, $titleVariants)) {
|
|
||||||
$titleVariants[] = $withThe;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construire toutes les URLs candidates
|
// Groupement 1 : Le format exact (Testé en parallèle)
|
||||||
$candidates = [];
|
$primaryCandidates = [];
|
||||||
foreach ($titleVariants as $variant) {
|
foreach ($titleVariants as $variant) {
|
||||||
if (empty($variant)) continue;
|
if (empty($variant)) continue;
|
||||||
$firstLetter = strtolower(substr($variant, 0, 1));
|
$firstLetter = strtolower(substr($variant, 0, 1));
|
||||||
|
$primaryCandidates[] = "https://www.covercentury.com/covers/{$ccFormat}/{$firstLetter}/{$variant}.jpg";
|
||||||
// Essayer avec différents suffixes numériques (1, 2, 3, etc.)
|
|
||||||
for ($i = 1; $i <= 5; $i++) {
|
for ($i = 1; $i <= 5; $i++) {
|
||||||
$candidates[] = "https://www.covercentury.com/covers/{$ccFormat}/{$firstLetter}/{$variant}{$i}.jpg";
|
$primaryCandidates[] = "https://www.covercentury.com/covers/{$ccFormat}/{$firstLetter}/{$variant}{$i}.jpg";
|
||||||
}
|
}
|
||||||
// Et sans numéro
|
|
||||||
$candidates[] = "https://www.covercentury.com/covers/{$ccFormat}/{$firstLetter}/{$variant}.jpg";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tester chaque URL
|
// On teste toutes les URLs du format désiré d'un seul coup (ultra rapide)
|
||||||
foreach ($candidates as $url) {
|
$validUrl = checkUrlsParallel($primaryCandidates, 2);
|
||||||
if (urlExists($url, 2)) {
|
|
||||||
|
if ($validUrl) {
|
||||||
return [
|
return [
|
||||||
'poster' => $url,
|
'poster' => $validUrl,
|
||||||
'title' => $cleanTitle,
|
'title' => $cleanTitle,
|
||||||
'format' => $format,
|
'format' => $format,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Si aucun format ne marche, essayer les autres formats
|
// Groupement 2 : Si échec, on cherche sur les autres formats en parallèle
|
||||||
|
$fallbackCandidates = [];
|
||||||
$otherFormats = ['dvd', 'bluray', '4kultrahd'];
|
$otherFormats = ['dvd', 'bluray', '4kultrahd'];
|
||||||
foreach ($otherFormats as $altFormat) {
|
foreach ($otherFormats as $altFormat) {
|
||||||
if ($altFormat === $ccFormat) continue;
|
if ($altFormat === $ccFormat) continue;
|
||||||
foreach ($titleVariants as $variant) {
|
foreach ($titleVariants as $variant) {
|
||||||
if (empty($variant)) continue;
|
if (empty($variant)) continue;
|
||||||
$firstLetter = strtolower(substr($variant, 0, 1));
|
$firstLetter = strtolower(substr($variant, 0, 1));
|
||||||
|
$fallbackCandidates[] = "https://www.covercentury.com/covers/{$altFormat}/{$firstLetter}/{$variant}.jpg";
|
||||||
for ($i = 1; $i <= 3; $i++) {
|
for ($i = 1; $i <= 3; $i++) {
|
||||||
$url = "https://www.covercentury.com/covers/{$altFormat}/{$firstLetter}/{$variant}{$i}.jpg";
|
$fallbackCandidates[] = "https://www.covercentury.com/covers/{$altFormat}/{$firstLetter}/{$variant}{$i}.jpg";
|
||||||
if (urlExists($url, 2)) {
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$validUrl = checkUrlsParallel($fallbackCandidates, 2);
|
||||||
|
|
||||||
|
if ($validUrl) {
|
||||||
return [
|
return [
|
||||||
'poster' => $url,
|
'poster' => $validUrl,
|
||||||
'title' => $cleanTitle,
|
'title' => $cleanTitle,
|
||||||
'format' => $format,
|
'format' => $format,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
error_log("CoverCentury: Aucune jaquette trouvée pour '$title'");
|
error_log("CoverCentury: Aucune jaquette trouvée pour '$title'");
|
||||||
return null;
|
return null;
|
||||||
@@ -366,12 +384,14 @@ switch ($action) {
|
|||||||
";
|
";
|
||||||
$result = $pdo->query($sql)->fetchAll();
|
$result = $pdo->query($sql)->fetchAll();
|
||||||
|
|
||||||
foreach ($result as $row) {
|
// CORRECTION BUG: L'esperluette "&" est indispensable pour modifier la variable dans le tableau
|
||||||
|
foreach ($result as &$row) {
|
||||||
if ($row['rating'] !== null) {
|
if ($row['rating'] !== null) {
|
||||||
$ratingVal = (float)$row['rating'];
|
$ratingVal = (float)$row['rating'];
|
||||||
$row['rating'] = ($ratingVal == floor($ratingVal)) ? (int)$ratingVal : $ratingVal;
|
$row['rating'] = ($ratingVal == floor($ratingVal)) ? (int)$ratingVal : $ratingVal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
unset($row);
|
||||||
|
|
||||||
echo json_encode($result);
|
echo json_encode($result);
|
||||||
break;
|
break;
|
||||||
@@ -409,7 +429,6 @@ switch ($action) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($type === 'videotheque') {
|
if ($type === 'videotheque') {
|
||||||
// CoverCentury pour vidéothèque
|
|
||||||
$format = $result['format'] ?: 'Blu-ray';
|
$format = $result['format'] ?: 'Blu-ray';
|
||||||
$ccData = fetchCoverCentury($titleForSearch, $result['year'], $format);
|
$ccData = fetchCoverCentury($titleForSearch, $result['year'], $format);
|
||||||
if (!empty($ccData)) {
|
if (!empty($ccData)) {
|
||||||
@@ -455,7 +474,6 @@ 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 : CoverCentury 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';
|
||||||
$ccData = fetchCoverCentury($data['title'], $data['year'] ?? '', $format);
|
$ccData = fetchCoverCentury($data['title'], $data['year'] ?? '', $format);
|
||||||
@@ -498,6 +516,34 @@ switch ($action) {
|
|||||||
|
|
||||||
$pdo->beginTransaction();
|
$pdo->beginTransaction();
|
||||||
try {
|
try {
|
||||||
|
// OPTIMISATION MAJEURE : On prépare les requêtes SQL UNE SEULE FOIS en dehors de la boucle
|
||||||
|
$sqlVideotheque = "INSERT INTO videotheque (id, title, year, director, poster, format, length, publisher, ean_isbn13, number_of_discs, aspect_ratio, description, actors)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
ON DUPLICATE KEY UPDATE
|
||||||
|
title=VALUES(title), year=VALUES(year),
|
||||||
|
director=IF(VALUES(director)!='',VALUES(director),director),
|
||||||
|
poster=IF(VALUES(poster)!='',VALUES(poster),poster),
|
||||||
|
format=IF(VALUES(format)!='',VALUES(format),format),
|
||||||
|
length=IF(VALUES(length)!='',VALUES(length),length),
|
||||||
|
publisher=IF(VALUES(publisher)!='',VALUES(publisher),publisher),
|
||||||
|
ean_isbn13=IF(VALUES(ean_isbn13)!='',VALUES(ean_isbn13),ean_isbn13),
|
||||||
|
number_of_discs=IF(VALUES(number_of_discs)!=1,VALUES(number_of_discs),number_of_discs),
|
||||||
|
aspect_ratio=IF(VALUES(aspect_ratio)!='',VALUES(aspect_ratio),aspect_ratio),
|
||||||
|
description=IF(VALUES(description)!='',VALUES(description),description),
|
||||||
|
actors=IF(VALUES(actors)!='',VALUES(actors),actors)";
|
||||||
|
$stmtVideotheque = $pdo->prepare($sqlVideotheque);
|
||||||
|
|
||||||
|
$sqlCritiques = "INSERT INTO critiques (id, title, year, director, poster, rating, review, streaming)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
ON DUPLICATE KEY UPDATE
|
||||||
|
title=VALUES(title), year=VALUES(year),
|
||||||
|
rating=VALUES(rating),
|
||||||
|
review=IF(VALUES(review)!='',VALUES(review),review),
|
||||||
|
director=IF(VALUES(director)!='',VALUES(director),director),
|
||||||
|
poster=IF(VALUES(poster)!='',VALUES(poster),poster),
|
||||||
|
streaming=IF(VALUES(streaming)!='',VALUES(streaming),streaming)";
|
||||||
|
$stmtCritiques = $pdo->prepare($sqlCritiques);
|
||||||
|
|
||||||
foreach ($items as $rowData) {
|
foreach ($items as $rowData) {
|
||||||
$title = $rowData['title'] ?? $rowData['Name'] ?? $rowData['Title'] ?? 'Sans titre';
|
$title = $rowData['title'] ?? $rowData['Name'] ?? $rowData['Title'] ?? 'Sans titre';
|
||||||
$publishDate = $rowData['publish_date'] ?? $rowData['Year'] ?? $rowData['year'] ?? $rowData['Date'] ?? '';
|
$publishDate = $rowData['publish_date'] ?? $rowData['Year'] ?? $rowData['year'] ?? $rowData['Date'] ?? '';
|
||||||
@@ -536,7 +582,6 @@ switch ($action) {
|
|||||||
$poster = $rowData['poster'] ?? '';
|
$poster = $rowData['poster'] ?? '';
|
||||||
$director = '';
|
$director = '';
|
||||||
|
|
||||||
// Récupération jaquette via CoverCentury
|
|
||||||
$cleanTitleForCC = cleanTitle($title);
|
$cleanTitleForCC = cleanTitle($title);
|
||||||
if (!empty($cleanTitleForCC)) {
|
if (!empty($cleanTitleForCC)) {
|
||||||
$ccData = fetchCoverCentury($cleanTitleForCC, $year, $format);
|
$ccData = fetchCoverCentury($cleanTitleForCC, $year, $format);
|
||||||
@@ -550,22 +595,8 @@ switch ($action) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql = "INSERT INTO videotheque (id, title, year, director, poster, format, length, publisher, ean_isbn13, number_of_discs, aspect_ratio, description, actors)
|
// Exécution avec la requête préparée hors de la boucle
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
$stmtVideotheque->execute([$id, $title, $year, $director, $poster, $format, $length, $publisher, $ean, $discs, $aspect, $description, $actors]);
|
||||||
ON DUPLICATE KEY UPDATE
|
|
||||||
title=VALUES(title), year=VALUES(year),
|
|
||||||
director=IF(VALUES(director)!='',VALUES(director),director),
|
|
||||||
poster=IF(VALUES(poster)!='',VALUES(poster),poster),
|
|
||||||
format=IF(VALUES(format)!='',VALUES(format),format),
|
|
||||||
length=IF(VALUES(length)!='',VALUES(length),length),
|
|
||||||
publisher=IF(VALUES(publisher)!='',VALUES(publisher),publisher),
|
|
||||||
ean_isbn13=IF(VALUES(ean_isbn13)!='',VALUES(ean_isbn13),ean_isbn13),
|
|
||||||
number_of_discs=IF(VALUES(number_of_discs)!=1,VALUES(number_of_discs),number_of_discs),
|
|
||||||
aspect_ratio=IF(VALUES(aspect_ratio)!='',VALUES(aspect_ratio),aspect_ratio),
|
|
||||||
description=IF(VALUES(description)!='',VALUES(description),description),
|
|
||||||
actors=IF(VALUES(actors)!='',VALUES(actors),actors)";
|
|
||||||
$stmt = $pdo->prepare($sql);
|
|
||||||
$stmt->execute([$id, $title, $year, $director, $poster, $format, $length, $publisher, $ean, $discs, $aspect, $description, $actors]);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$ratingRaw = $rowData['Rating'] ?? $rowData['rating'] ?? '';
|
$ratingRaw = $rowData['Rating'] ?? $rowData['rating'] ?? '';
|
||||||
@@ -585,17 +616,8 @@ switch ($action) {
|
|||||||
}
|
}
|
||||||
if (empty($streaming)) $streaming = 'Support physique / Cinéma';
|
if (empty($streaming)) $streaming = 'Support physique / Cinéma';
|
||||||
|
|
||||||
$sql = "INSERT INTO critiques (id, title, year, director, poster, rating, review, streaming)
|
// Exécution avec la requête préparée hors de la boucle
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
$stmtCritiques->execute([$id, $title, $year, $director, $poster, $rating, $review, $streaming]);
|
||||||
ON DUPLICATE KEY UPDATE
|
|
||||||
title=VALUES(title), year=VALUES(year),
|
|
||||||
rating=VALUES(rating),
|
|
||||||
review=IF(VALUES(review)!='',VALUES(review),review),
|
|
||||||
director=IF(VALUES(director)!='',VALUES(director),director),
|
|
||||||
poster=IF(VALUES(poster)!='',VALUES(poster),poster),
|
|
||||||
streaming=IF(VALUES(streaming)!='',VALUES(streaming),streaming)";
|
|
||||||
$stmt = $pdo->prepare($sql);
|
|
||||||
$stmt->execute([$id, $title, $year, $director, $poster, $rating, $review, $streaming]);
|
|
||||||
}
|
}
|
||||||
$imported++;
|
$imported++;
|
||||||
}
|
}
|
||||||
@@ -621,7 +643,6 @@ switch ($action) {
|
|||||||
|
|
||||||
$result = ['title' => $title, 'year' => $year, 'format' => $format];
|
$result = ['title' => $title, 'year' => $year, 'format' => $format];
|
||||||
|
|
||||||
// Afficher les variantes testées
|
|
||||||
$cleanTitle = cleanTitle($title);
|
$cleanTitle = cleanTitle($title);
|
||||||
$normalized = preg_replace('/[^a-zA-Z0-9\s]/', '', $cleanTitle);
|
$normalized = preg_replace('/[^a-zA-Z0-9\s]/', '', $cleanTitle);
|
||||||
$normalized = trim(preg_replace('/\s+/', '_', $normalized));
|
$normalized = trim(preg_replace('/\s+/', '_', $normalized));
|
||||||
|
|||||||
Reference in New Issue
Block a user