From 3dd61b4fb05e94fb23645662b7728595661408c3 Mon Sep 17 00:00:00 2001 From: Cedric Date: Thu, 25 Jun 2026 16:14:29 +0200 Subject: [PATCH] Actualiser api.php --- api.php | 220 ++++++++++++++++++++++++-------------------------------- 1 file changed, 95 insertions(+), 125 deletions(-) diff --git a/api.php b/api.php index e4f097a..f8352e2 100644 --- a/api.php +++ b/api.php @@ -62,6 +62,13 @@ function getTmdbApiKey($pdo) { return $row ? decryptData($row['key_value']) : null; } +function getFanartApiKey($pdo) { + $stmt = $pdo->prepare("SELECT key_value FROM config WHERE key_name = 'fanart_api_key'"); + $stmt->execute(); + $row = $stmt->fetch(); + return $row ? decryptData($row['key_value']) : null; +} + function httpGet($url, $timeout = 3, $ua = null) { if (!$ua) $ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'; @@ -113,142 +120,95 @@ function extractYear($dateStr) { return ''; } -// ── DVDCover.com via API REST WordPress ── -function fetchDVDCover($title, $year = '', $format = 'bluray') { +function fetchFanartTv($title, $year = '', $format = 'bluray', $pdo = null) { if (empty($title)) return null; $cleanTitle = cleanTitle($title); if (empty($cleanTitle)) return null; - // API REST WordPress de DVDcover - $searchUrl = "https://www.dvdcover.com/wp-json/wp/v2/posts?search=" . urlencode($cleanTitle) . "&_embed&per_page=10"; + // Récupérer la clé API + $apiKey = getFanartApiKey($pdo); + if (empty($apiKey)) { + // Fallback sur la clé en dur si non configurée + $apiKey = '70f9747dafe9b27f9b14ef80ee0cacc9'; + } - $json = httpGet($searchUrl, 10); - if (!$json) { - error_log("DVDCover API: Échec requête pour '$title'"); + // Étape 1 : Chercher le film sur TMDB pour obtenir son ID + $tmdbKey = getTmdbApiKey($pdo); + if (!$tmdbKey) { + error_log("Fanart.tv: Clé TMDB requise pour obtenir l'ID du film"); return null; } - $posts = json_decode($json, true); - if (!is_array($posts) || empty($posts)) { - error_log("DVDCover API: Aucun résultat pour '$title'"); + $searchUrl = "https://api.themoviedb.org/3/search/movie?api_key={$tmdbKey}&query=" . urlencode($cleanTitle); + if (!empty($year)) { + $searchUrl .= "&year={$year}"; + } + + $searchRes = httpGet($searchUrl, 5); + $searchData = $searchRes ? json_decode($searchRes, true) : []; + + if (empty($searchData['results'])) { + error_log("Fanart.tv: Film non trouvé sur TMDB pour '$title'"); return null; } - $cleanTitleLower = strtolower($cleanTitle); - $bestPost = null; - $bestScore = 0; + $tmdbId = $searchData['results'][0]['id']; - foreach ($posts as $post) { - $postTitle = $post['title']['rendered'] ?? ''; - $postTitleLower = strtolower($postTitle); - - $score = 0; - if (strpos($postTitleLower, $cleanTitleLower) !== false) { - $score += 50; - } - if (!empty($year) && strpos($postTitle, $year) !== false) { - $score += 30; - } - $formatLower = strtolower($format); - if (stripos($postTitle, $format) !== false || - stripos($postTitle, str_replace('-', ' ', $format)) !== false) { - $score += 20; - } - if (stripos($postTitle, 'cover') !== false) { - $score += 10; - } - - if ($score > $bestScore) { - $bestScore = $score; - $bestPost = $post; - } - if ($score >= 100) break; + // Étape 2 : Récupérer les artworks depuis fanart.tv + $fanartUrl = "https://webservice.fanart.tv/v3/movies/{$tmdbId}?api_key={$apiKey}"; + $fanartRes = httpGet($fanartUrl, 5); + $fanartData = $fanartRes ? json_decode($fanartRes, true) : []; + + if (isset($fanartData['error'])) { + error_log("Fanart.tv: Erreur API - " . $fanartData['error']); + return null; } - if (!$bestPost && !empty($posts)) { - $bestPost = $posts[0]; - } - - if (!$bestPost) return null; - - // Extraire l'image du post $poster = ''; - // Méthode 1 : Image mise en avant (_embedded.wp:featuredmedia) - if (isset($bestPost['_embedded']['wp:featuredmedia'][0])) { - $featured = $bestPost['_embedded']['wp:featuredmedia'][0]; - if (!empty($featured['media_details']['sizes'])) { - $sizes = $featured['media_details']['sizes']; - $preferredSizes = ['full', 'large', 'medium', 'thumbnail']; - foreach ($preferredSizes as $size) { - if (isset($sizes[$size]['source_url'])) { - $poster = $sizes[$size]['source_url']; - break; - } + // Priorité aux movieposter (jaquettes complètes) + if (!empty($fanartData['movieposter'])) { + // Filtrer par langue (fr d'abord, puis en, puis tout) + $posters = $fanartData['movieposter']; + $preferredLangs = ['fr', 'en', '']; + + foreach ($preferredLangs as $lang) { + $filtered = array_filter($posters, function($p) use ($lang) { + return ($lang === '' || ($p['lang'] ?? '') === $lang); + }); + + if (!empty($filtered)) { + // Trier par likes (le plus populaire en premier) + usort($filtered, function($a, $b) { + return ($b['likes'] ?? 0) - ($a['likes'] ?? 0); + }); + $poster = $filtered[0]['url']; + break; } } - if (empty($poster) && !empty($featured['source_url'])) { - $poster = $featured['source_url']; - } } - // Méthode 2 : Images dans le contenu du post - if (empty($poster) && !empty($bestPost['content']['rendered'])) { - $content = $bestPost['content']['rendered']; - if (preg_match_all('/]+src=["\']([^"\']+)["\'][^>]*>/i', $content, $matches)) { - foreach ($matches[1] as $img) { - 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; - } - } - } + // Fallback sur hdmovielogo si pas de movieposter + if (empty($poster) && !empty($fanartData['hdmovielogo'])) { + $logos = $fanartData['hdmovielogo']; + $poster = $logos[0]['url']; + } + + // Fallback sur moviebackground + if (empty($poster) && !empty($fanartData['moviebackground'])) { + $backgrounds = $fanartData['moviebackground']; + $poster = $backgrounds[0]['url']; } if (empty($poster)) { - error_log("DVDCover API: Pas d'image trouvée pour le post ID " . ($bestPost['id'] ?? '?')); + error_log("Fanart.tv: Aucune jaquette trouvée pour TMDB ID {$tmdbId}"); return null; } - // S'assurer que l'URL est absolue - if (strpos($poster, 'http') !== 0) { - $poster = 'https://www.dvdcover.com' . (strpos($poster, '/') === 0 ? '' : '/') . ltrim($poster, '/'); - } - - // Supprimer les suffixes de taille WordPress - $poster = preg_replace('/-\d+x\d+(\.\w+)$/', '$1', $poster); - - // VÉRIFICATION : Tester si l'image est accessible - // Essayer différentes variantes d'URL - $urlVariants = [ - $poster, - str_replace('dvdcover.com', 'www.dvdcover.com', $poster), - str_replace('https://www.dvdcover.com', 'https://dvdcover.com', $poster), - ]; - - foreach ($urlVariants as $testUrl) { - if (urlExists($testUrl, 3)) { - error_log("DVDCover API: Image valide trouvée - $testUrl"); - return [ - 'poster' => $testUrl, - 'title' => $bestPost['title']['rendered'] ?? $cleanTitle, - 'format' => $format, - ]; - } - } - - // Si aucune URL ne fonctionne, retourner quand même la première (peut-être un problème temporaire) - error_log("DVDCover API: Aucune URL d'image valide trouvée, retour de la première URL"); return [ 'poster' => $poster, - 'title' => $bestPost['title']['rendered'] ?? $cleanTitle, + 'title' => $cleanTitle, 'format' => $format, ]; } @@ -384,23 +344,35 @@ switch ($action) { case 'get_config_keys': checkAuth($pdo); - $stmt = $pdo->prepare("SELECT key_value FROM config WHERE key_name = 'tmdb_api_key'"); - $stmt->execute(); $row = $stmt->fetch(); - echo json_encode(['tmdb_api_key' => $row ? '••••••••' : '']); + $stmt = $pdo->prepare("SELECT key_value FROM config WHERE key_name IN ('tmdb_api_key', 'fanart_api_key')"); + $stmt->execute(); + $rows = $stmt->fetchAll(); + $config = []; + foreach ($rows as $row) { + if ($row['key_name'] === 'tmdb_api_key') { + $config['tmdb_api_key'] = $row['key_value'] ? '••••••••' : ''; + } elseif ($row['key_name'] === 'fanart_api_key') { + $config['fanart_api_key'] = $row['key_value'] ? '••••••••' : ''; + } + } + // Valeurs par défaut si non configurées + if (!isset($config['tmdb_api_key'])) $config['tmdb_api_key'] = ''; + if (!isset($config['fanart_api_key'])) $config['fanart_api_key'] = ''; + echo json_encode($config); break; - + case 'save_config': checkAuth($pdo); $keyName = $data['key_name'] ?? ''; $keyValue = $data['key_value'] ?? ''; - if ($keyName === 'tmdb_api_key' && !empty($keyValue)) { + if (in_array($keyName, ['tmdb_api_key', 'fanart_api_key']) && !empty($keyValue)) { $stmt = $pdo->prepare("REPLACE INTO config (key_name, key_value) VALUES (?, ?)"); $stmt->execute([$keyName, encryptData($keyValue)]); echo json_encode(["success" => true]); } else { http_response_code(400); echo json_encode(["error" => "Données invalides."]); } - break; + break; case 'get_films': $sql = " @@ -413,7 +385,7 @@ switch ($action) { "; $result = $pdo->query($sql)->fetchAll(); - foreach ($result as &$row) { + foreach ($result as $row) { if ($row['rating'] !== null) { $ratingVal = (float)$row['rating']; $row['rating'] = ($ratingVal == floor($ratingVal)) ? (int)$ratingVal : $ratingVal; @@ -456,10 +428,9 @@ switch ($action) { exit; } - if ($type === 'videotheque') { - // DVDCover API pour vidéothèque + if ($type === 'videotheque') { $format = $result['format'] ?: 'Blu-ray'; - $dcData = fetchDVDCover($titleForSearch, $result['year'], $format); + $dcData = fetchFanartTv($titleForSearch, $result['year'], $format, $pdo); if (!empty($dcData)) { if (!empty($dcData['poster'])) $result['poster'] = $dcData['poster']; if (!empty($dcData['title'])) $result['title'] = $dcData['title']; @@ -503,14 +474,13 @@ switch ($action) { $stmt = $pdo->prepare($sql); $stmt->execute([$id, $data['title'] ?? '', $data['year'] ?? '', $data['director'] ?? '', $data['poster'] ?? '', $data['rating'] ?? 3.0, $data['review'] ?? '', $streaming]); } else { - // Vidéothèque : DVDCover API pour la jaquette - if (empty($data['poster']) && !empty($data['title'])) { - $format = $data['format'] ?: 'Blu-ray'; - $dcData = fetchDVDCover($data['title'], $data['year'] ?? '', $format); - if (!empty($dcData['poster'])) { - $data['poster'] = $dcData['poster']; - } + if (empty($data['poster']) && !empty($data['title'])) { + $format = $data['format'] ?: 'Blu-ray'; + $dcData = fetchFanartTv($data['title'], $data['year'] ?? '', $format, $pdo); + if (!empty($dcData['poster'])) { + $data['poster'] = $dcData['poster']; } + } $sql = "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)"; $stmt = $pdo->prepare($sql); @@ -614,7 +584,7 @@ switch ($action) { // Récupération jaquette via DVDCover API $cleanTitleForDC = cleanTitle($title); if (!empty($cleanTitleForDC)) { - $dcData = fetchDVDCover($cleanTitleForDC, $year, $format); + $dcData = fetchFanartTv($cleanTitleForDC, $year, $format, $pdo); if (!empty($dcData)) { if (!empty($dcData['poster'])) { $poster = $dcData['poster'];