diff --git a/api.php b/api.php index 1985d81..0de4816 100644 --- a/api.php +++ b/api.php @@ -16,15 +16,12 @@ try { PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ]); - $pdo->exec("CREATE TABLE IF NOT EXISTS users (id INT PRIMARY KEY, username VARCHAR(50) NOT NULL, password_hash VARCHAR(255) NOT NULL)"); $pdo->exec("CREATE TABLE IF NOT EXISTS config (key_name VARCHAR(50) PRIMARY KEY, key_value TEXT NOT NULL)"); $pdo->exec("CREATE TABLE IF NOT EXISTS critiques (id BIGINT PRIMARY KEY, title VARCHAR(255) NOT NULL, year VARCHAR(10), director VARCHAR(255), poster TEXT, rating DECIMAL(3,1) DEFAULT 3.0, review TEXT, streaming VARCHAR(255))"); try { $pdo->exec("ALTER TABLE critiques MODIFY COLUMN rating DECIMAL(3,1) DEFAULT 3.0"); } catch (\Exception $e) {} - $pdo->exec("CREATE TABLE IF NOT EXISTS videotheque (id BIGINT PRIMARY KEY, title VARCHAR(255) NOT NULL, year VARCHAR(10), director VARCHAR(255), poster TEXT, format VARCHAR(50), length VARCHAR(50), publisher VARCHAR(255), ean_isbn13 VARCHAR(50), number_of_discs INT DEFAULT 1, aspect_ratio VARCHAR(50), description TEXT, actors TEXT)"); try { $pdo->exec("ALTER TABLE videotheque ADD COLUMN actors TEXT AFTER description"); } catch (\Exception $e) {} - } catch (\PDOException $e) { echo json_encode(["error" => "Erreur BDD : " . $e->getMessage()]); exit; } // ── FONCTIONS UTILITAIRES ── @@ -50,7 +47,7 @@ function encryptData($data) { function decryptData($str) { $decoded = base64_decode($str); - if (strpos($decoded, '::') === false) return null; + if ($decoded === false || strpos($decoded, '::') === false) return null; list($enc, $iv) = explode('::', $decoded, 2); return openssl_decrypt($enc, 'AES-256-CBC', hash('sha256', ENCRYPTION_KEY, true), OPENSSL_RAW_DATA, substr($iv, 0, 16)); } @@ -69,9 +66,36 @@ function getFanartApiKey($pdo) { return $row ? decryptData($row['key_value']) : null; } -function httpGet($url, $timeout = 10, $ua = null) { +function httpGet($url, $timeout = 5, $ua = null) { if (!$ua) $ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36'; - + if (!function_exists('curl_init')) { + $ctx = stream_context_create(['http' => ['timeout' => $timeout, 'user_agent' => $ua]]); + $res = @file_get_contents($url, false, $ctx); + return $res ?: null; + } + $ch = curl_init($url); + curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_TIMEOUT => $timeout, + CURLOPT_CONNECTTIMEOUT => 3, + CURLOPT_SSL_VERIFYPEER => false, + CURLOPT_USERAGENT => $ua, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_REFERER => 'https://www.cinemapassion.com/', + CURLOPT_HTTPHEADER => [ + 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', + 'Accept-Language: fr-FR,fr;q=0.8', + ], + ]); + $res = curl_exec($ch); + $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + return ($code === 200 && is_string($res) && strlen($res) > 0) ? $res : null; +} + +function httpPost($url, $postData, $timeout = 10) { + $ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36'; + if (!function_exists('curl_init')) return null; $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, @@ -80,20 +104,20 @@ function httpGet($url, $timeout = 10, $ua = null) { CURLOPT_SSL_VERIFYPEER => false, CURLOPT_USERAGENT => $ua, CURLOPT_FOLLOWLOCATION => true, - CURLOPT_REFERER => 'https://www.cinemapassion.com/', // Crucial pour éviter le blocage + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => is_array($postData) ? http_build_query($postData) : $postData, + CURLOPT_REFERER => 'https://www.cinemapassion.com/', CURLOPT_HTTPHEADER => [ - 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8', - 'Accept-Language: fr-FR,fr;q=0.8,en-US;q=0.5,en;q=0.3', - 'Connection: keep-alive', - 'Upgrade-Insecure-Requests: 1' + 'Content-Type: application/x-www-form-urlencoded', + 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', + 'Accept-Language: fr-FR,fr;q=0.8', + 'Origin: https://www.cinemapassion.com' ], ]); $res = curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); - - // Si le code est 403, le site vous a banni, essayez de ralentir les requêtes - return ($code === 200) ? $res : null; + return ($code === 200 && is_string($res) && strlen($res) > 0) ? $res : null; } function cleanTitle($title) { @@ -113,12 +137,7 @@ function detectFormat($title, $desc = '') { return 'Blu-ray'; } -function extractYear($dateStr) { - if (preg_match('/(\d{4})/', $dateStr, $m)) return $m[1]; - return ''; -} - -// ── FONCTION POUR RÉCUPÉRER LES IMAGES DEPUIS CINEMAPASSION.COM ── +// ── FONCTION PRINCIPALE : CINEMAPASSION.COM ── function fetchCinemaPassion($title, $year = '', $ean = '', $pdo = null) { $defaultPoster = 'assets/img/default_physical_media.jpg'; $cleanTitle = cleanTitle($title); @@ -127,151 +146,78 @@ function fetchCinemaPassion($title, $year = '', $ean = '', $pdo = null) { return ['poster' => $defaultPoster, 'title' => '', 'format' => 'Blu-ray']; } - $userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36'; + // ÉTAPE 1 : Recherche POST sur /moteur2.php + $searchRes = httpPost('https://www.cinemapassion.com/moteur2.php', ['recherche' => $cleanTitle]); - // ── ÉTAPE 1 : Recherche via POST sur /moteur2.php ── - $searchUrl = "https://www.cinemapassion.com/moteur2.php"; - - $ch = curl_init($searchUrl); - curl_setopt_array($ch, [ - CURLOPT_RETURNTRANSFER => true, - CURLOPT_TIMEOUT => 15, - CURLOPT_CONNECTTIMEOUT => 5, - CURLOPT_SSL_VERIFYPEER => false, - CURLOPT_USERAGENT => $userAgent, - CURLOPT_FOLLOWLOCATION => true, - CURLOPT_POST => true, - CURLOPT_POSTFIELDS => http_build_query(['recherche' => $cleanTitle]), - CURLOPT_REFERER => 'https://www.cinemapassion.com/', - CURLOPT_HTTPHEADER => [ - 'Content-Type: application/x-www-form-urlencoded', - 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', - 'Accept-Language: fr-FR,fr;q=0.8', - 'Origin: https://www.cinemapassion.com' - ], - ]); - $searchRes = curl_exec($ch); - $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); - curl_close($ch); - - // ✅ CORRECTION : Vérifier que $searchRes n'est pas null ou false - $html = ($code === 200 && $searchRes && is_string($searchRes)) ? $searchRes : null; - - if ($html) { - // ── ÉTAPE 2 : Extraire le lien vers la page du film ── - if (preg_match('/href=["\']([^"\']*film\/[^"\'\/]+-\d+\.php)["\']/i', $html, $matches)) { - $filmPath = $matches[1]; + if ($searchRes) { + // ÉTAPE 2 : Extraire le lien vers la page du film + // Pattern : href='../film/Saw-3814.php' ou href='film/Saw-3814.php' + if (preg_match('/href=["\']?(?:\.\.\/)?film\/([^"\'\s]+)-(\d+)\.php["\']?/i', $searchRes, $matches)) { + $filmName = $matches[1]; + $filmId = $matches[2]; - $filmPath = str_replace('../', '', $filmPath); - if (strpos($filmPath, '/') !== 0) { - $filmUrl = 'https://www.cinemapassion.com/' . $filmPath; - } else { - $filmUrl = 'https://www.cinemapassion.com' . $filmPath; - } + // ÉTAPE 3 : Essayer plusieurs pages pour trouver l'image + $pagesToTry = [ + "https://www.cinemapassion.com/jaquette-dvd-{$filmName}-{$filmId}.php", + "https://www.cinemapassion.com/jaquette-blu-ray-{$filmName}-{$filmId}.php", + "https://www.cinemapassion.com/film/{$filmName}-{$filmId}.php", + "https://www.cinemapassion.com/sticker-dvd-{$filmName}-{$filmId}.php", + ]; - if (preg_match('/film\/([^\/]+)-(\d+)\.php/i', $filmUrl, $filmMatches)) { - $filmName = $filmMatches[1]; - $filmId = $filmMatches[2]; + foreach ($pagesToTry as $pageUrl) { + $pageRes = httpGet($pageUrl, 10); - // ── ÉTAPE 3 : Essayer plusieurs pages pour trouver l'image ── - $pagesToTry = [ - "https://www.cinemapassion.com/jaquette-dvd-{$filmName}-{$filmId}.php", - "https://www.cinemapassion.com/jaquette-blu-ray-{$filmName}-{$filmId}.php", - $filmUrl, - "https://www.cinemapassion.com/sticker-dvd-{$filmName}-{$filmId}.php", - ]; - - foreach ($pagesToTry as $pageUrl) { - $pageRes = httpGet($pageUrl, 10, $userAgent); + if ($pageRes) { + // Pattern : src='http://www.cinemapassion.com/covers_temp/covers3/Saw-13005811062007.jpg' + if (preg_match('/src=["\']?(https?:\/\/(?:www\.)?cinemapassion\.com\/covers_temp\/covers\d*\/[^"\'\s>]+\.jpg)["\']?/i', $pageRes, $imgMatches)) { + $posterUrl = $imgMatches[1]; + $posterUrl = str_replace('http://', 'https://', $posterUrl); + error_log("CinemaPassion OK: '{$cleanTitle}' → {$posterUrl}"); + return ['poster' => $posterUrl, 'title' => $cleanTitle, 'format' => 'Blu-ray']; + } - // ✅ CORRECTION : Vérifier que $pageRes est une string valide - if ($pageRes && is_string($pageRes) && strlen($pageRes) > 0) { - // Pattern pour l'image - if (preg_match('/src=["\']?(https?:\/\/[^"\'\s>]*cinemapassion\.com[^"\'\s>]*covers[^"\'\s>]*\.jpg)["\']?/i', $pageRes, $imgMatches)) { - $posterUrl = $imgMatches[1]; - $posterUrl = str_replace('http://', 'https://', $posterUrl); - - error_log("CinemaPassion: Image trouvée pour '{$cleanTitle}' → {$posterUrl}"); - - return [ - 'poster' => $posterUrl, - 'title' => $cleanTitle, - 'format' => 'Blu-ray' - ]; - } + // Fallback : image dans lesaffiches/ + if (preg_match('/src=["\']?(https?:\/\/(?:www\.)?cinemapassion\.com\/lesaffiches\/[^"\'\s>]+\.jpg)["\']?/i', $pageRes, $imgMatches)) { + $posterUrl = $imgMatches[1]; + $posterUrl = str_replace('http://', 'https://', $posterUrl); + error_log("CinemaPassion OK (affiche): '{$cleanTitle}' → {$posterUrl}"); + return ['poster' => $posterUrl, 'title' => $cleanTitle, 'format' => 'Blu-ray']; } } } } - // ── FALLBACK : Chercher directement une image dans les résultats ── - if (preg_match('/src=["\']?(https?:\/\/[^"\'\s>]*cinemapassion\.com[^"\'\s>]*covers[^"\'\s>]*\.jpg)["\']?/i', $html, $imgMatches)) { + // Fallback : chercher directement une image covers_temp dans les résultats + if (preg_match('/src=["\']?(https?:\/\/(?:www\.)?cinemapassion\.com\/covers_temp\/covers\d*\/[^"\'\s>]+\.jpg)["\']?/i', $searchRes, $imgMatches)) { $posterUrl = str_replace('http://', 'https://', $imgMatches[1]); - error_log("CinemaPassion: Image trouvée (fallback) pour '{$cleanTitle}' → {$posterUrl}"); - return [ - 'poster' => $posterUrl, - 'title' => $cleanTitle, - 'format' => 'Blu-ray' - ]; + error_log("CinemaPassion OK (direct): '{$cleanTitle}' → {$posterUrl}"); + return ['poster' => $posterUrl, 'title' => $cleanTitle, 'format' => 'Blu-ray']; } } - error_log("CinemaPassion: Image NON trouvée pour '{$cleanTitle}'"); + error_log("CinemaPassion KO: Image NON trouvée pour '{$cleanTitle}'"); return ['poster' => $defaultPoster, 'title' => $cleanTitle, 'format' => 'Blu-ray']; } -// ── ROUTEUR PRINCIPAL ── - -// Fonction pour vérifier si une URL existe -function urlExists($url, $timeout = 3) { - if (!function_exists('curl_init')) { - $ctx = stream_context_create(['http' => ['timeout' => $timeout, 'method' => 'HEAD']]); - $result = @get_headers($url, 0, $ctx); - return ($result && strpos($result[0], '200') !== false); - } - - $ch = curl_init($url); - curl_setopt_array($ch, [ - CURLOPT_RETURNTRANSFER => true, - CURLOPT_NOBODY => true, - CURLOPT_TIMEOUT => $timeout, - CURLOPT_CONNECTTIMEOUT => 2, - CURLOPT_SSL_VERIFYPEER => false, - CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', - CURLOPT_FOLLOWLOCATION => true, - ]); - curl_exec($ch); - $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); - curl_close($ch); - - return ($code >= 200 && $code < 400); -} - // ── API TMDB (uniquement pour les critiques) ── function fetchTMDBFull($title, $year, $apiKey, $pdo) { if (empty($apiKey) || empty($title)) return null; $cleanTitle = cleanTitle($title); - $searchUrl = "https://api.themoviedb.org/3/search/movie?api_key={$apiKey}&query=" . urlencode($cleanTitle) . "&year={$year}&language=fr-FR"; $searchRes = httpGet($searchUrl, 5); $searchData = $searchRes ? json_decode($searchRes, true) : []; - if (empty($searchData['results'])) { $searchUrl = "https://api.themoviedb.org/3/search/movie?api_key={$apiKey}&query=" . urlencode($cleanTitle) . "&language=fr-FR"; $searchRes = httpGet($searchUrl, 5); $searchData = $searchRes ? json_decode($searchRes, true) : []; } - if (empty($searchData['results'])) return null; $movieId = $searchData['results'][0]['id']; - $detailsUrl = "https://api.themoviedb.org/3/movie/{$movieId}?api_key={$apiKey}&append_to_response=credits,watch/providers,translations&language=fr-FR"; $detailsRes = httpGet($detailsUrl, 5); if (!$detailsRes) return null; $details = json_decode($detailsRes, true); - $frenchTitle = $details['title'] ?? ''; - if (!empty($details['translations']['translations'])) { foreach ($details['translations']['translations'] as $translation) { if ($translation['iso_3166_1'] === 'FR' && !empty($translation['data']['title'])) { @@ -280,7 +226,6 @@ function fetchTMDBFull($title, $year, $apiKey, $pdo) { } } } - $director = ''; if (!empty($details['credits']['crew'])) { $directorsList = []; @@ -289,15 +234,11 @@ function fetchTMDBFull($title, $year, $apiKey, $pdo) { } $director = implode(', ', $directorsList); } - $cast = []; if (!empty($details['credits']['cast'])) { $topCast = array_slice($details['credits']['cast'], 0, 4); foreach ($topCast as $actor) $cast[] = $actor['name']; } - - $overview = $details['overview'] ?? ''; - $streaming = ''; $frProviders = $details['watch/providers']['results']['FR'] ?? []; $platforms = []; @@ -307,19 +248,16 @@ function fetchTMDBFull($title, $year, $apiKey, $pdo) { if (!empty($frProviders['buy'])) { foreach ($frProviders['buy'] as $p) $platforms[] = $p['provider_name'] . ' (achat)'; } } if (!empty($platforms)) $streaming = implode(', ', array_unique($platforms)); - - $result = [ + return [ 'title' => $frenchTitle, 'year' => !empty($details['release_date']) ? substr($details['release_date'], 0, 4) : '', 'director' => $director, 'poster' => !empty($details['poster_path']) ? "https://image.tmdb.org/t/p/w500" . $details['poster_path'] : '', 'length' => !empty($details['runtime']) ? $details['runtime'] . ' min' : '', 'streaming' => $streaming, - 'overview' => $overview, + 'overview' => $details['overview'] ?? '', 'cast' => $cast ]; - - return $result; } // ── ROUTEUR PRINCIPAL ── @@ -351,20 +289,20 @@ switch ($action) { echo json_encode(["success" => true]); break; -case 'get_config_keys': - checkAuth($pdo); - $stmt = $pdo->prepare("SELECT key_name, key_value FROM config WHERE key_name IN ('tmdb_api_key', 'fanart_api_key')"); - $stmt->execute(); - $rows = $stmt->fetchAll(); - $config = []; - foreach ($rows as $row) { - $config[$row['key_name']] = $row['key_value'] ? '••••••••' : ''; - } - 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 'get_config_keys': + checkAuth($pdo); + $stmt = $pdo->prepare("SELECT key_name, key_value FROM config WHERE key_name IN ('tmdb_api_key', 'fanart_api_key')"); + $stmt->execute(); + $rows = $stmt->fetchAll(); + $config = []; + foreach ($rows as $row) { + $config[$row['key_name']] = $row['key_value'] ? '••••••••' : ''; + } + 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'] ?? ''; @@ -389,7 +327,6 @@ case 'get_config_keys': ORDER BY id DESC "; $result = $pdo->query($sql)->fetchAll(); - foreach ($result as $row) { if ($row['rating'] !== null) { $ratingVal = (float)$row['rating']; @@ -397,67 +334,9 @@ case 'get_config_keys': } } unset($row); - echo json_encode($result); break; - case 'search_ean_full': - $ean = $_GET['ean'] ?? ''; - $type = $_GET['type'] ?? 'videotheque'; - if (!$ean) { echo json_encode(['error' => 'EAN manquant']); exit; } - $result = [ - 'ean' => $ean, 'title' => '', 'director' => '', 'year' => '', - 'poster' => '', 'publisher' => '', 'format' => '', - 'length' => '', 'number_of_discs' => 1, 'aspect_ratio' => '', 'actors' => '' - ]; - - $tmdbKey = getTmdbApiKey($pdo); - $titleForSearch = ''; - - if ($tmdbKey) { - $searchUrl = "https://api.themoviedb.org/3/find/{$ean}?api_key={$tmdbKey}&external_source=imdb_id"; - $searchRes = httpGet($searchUrl, 5); - $searchData = $searchRes ? json_decode($searchRes, true) : []; - - if (!empty($searchData['movie_results'][0])) { - $titleForSearch = $searchData['movie_results'][0]['title']; - $result['title'] = $titleForSearch; - if (!empty($searchData['movie_results'][0]['release_date'])) { - $result['year'] = substr($searchData['movie_results'][0]['release_date'], 0, 4); - } - } - } - - if (empty($titleForSearch)) { - echo json_encode(['success' => true, 'data' => $result, 'warning' => 'Titre non trouvé']); - exit; - } - - if ($type === 'videotheque') { - $format = $result['format'] ?: 'Blu-ray'; - $fanartData = fetchFanartTv($titleForSearch, $result['year'], $format, $pdo); - if (!empty($fanartData)) { - if (!empty($fanartData['poster'])) $result['poster'] = $fanartData['poster']; - if (!empty($fanartData['title'])) $result['title'] = $fanartData['title']; - $result['format'] = $format; - } - } else { - if ($tmdbKey) { - $tmdbData = fetchTMDBFull($titleForSearch, $result['year'], $tmdbKey, $pdo); - if ($tmdbData) { - if (!empty($tmdbData['title'])) $result['title'] = $tmdbData['title']; - if (!empty($tmdbData['year'])) $result['year'] = $tmdbData['year']; - if (!empty($tmdbData['director'])) $result['director'] = $tmdbData['director']; - if (!empty($tmdbData['poster'])) $result['poster'] = $tmdbData['poster']; - if (!empty($tmdbData['length'])) $result['length'] = $tmdbData['length']; - if (!empty($tmdbData['cast'])) $result['actors'] = implode(', ', $tmdbData['cast']); - } - } - } - - echo json_encode(['success' => true, 'data' => $result]); - break; - case 'save_film': checkAuth($pdo); $type = $data['type'] ?? 'critique'; @@ -468,7 +347,6 @@ case 'get_config_keys': if ($tmdbData) { if (empty($data['director'])) $data['director'] = $tmdbData['director']; if (empty($data['poster'])) $data['poster'] = $tmdbData['poster']; - if (empty($data['length']) && !empty($tmdbData['length'])) $data['length'] = $tmdbData['length']; } } @@ -479,14 +357,12 @@ case 'get_config_keys': $stmt = $pdo->prepare($sql); $stmt->execute([$id, $data['title'] ?? '', $data['year'] ?? '', $data['director'] ?? '', $data['poster'] ?? '', $data['rating'] ?? 3.0, $data['review'] ?? '', $streaming]); } else { - if (empty($data['poster']) && !empty($data['title'])) { - $format = $data['format'] ?: 'Blu-ray'; - $fanartData = fetchFanartTv($data['title'], $data['year'] ?? '', $format, $pdo); - if (!empty($fanartData['poster'])) { - $data['poster'] = $fanartData['poster']; + if (empty($data['poster']) && !empty($data['title'])) { + $cpData = fetchCinemaPassion($data['title'], $data['year'] ?? '', $data['ean_isbn13'] ?? '', $pdo); + if (!empty($cpData['poster']) && $cpData['poster'] !== 'assets/img/default_physical_media.jpg') { + $data['poster'] = $cpData['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); $stmt->execute([$id, $data['title'] ?? '', $data['year'] ?? '', $data['director'] ?? '', $data['poster'] ?? '', $data['format'] ?? '', $data['length'] ?? '', $data['publisher'] ?? '', $data['ean_isbn13'] ?? '', $data['number_of_discs'] ?? 1, $data['aspect_ratio'] ?? '', $data['description'] ?? '', $data['actors'] ?? '']); @@ -510,65 +386,61 @@ case 'get_config_keys': else { http_response_code(400); echo json_encode(["success" => false, "error" => "Aucun élément sélectionné."]); } break; - case 'import_batch': - checkAuth($pdo); - $data = json_decode(file_get_contents("php://input"), true); - $type = $data['type'] ?? 'critique'; - $items = $data['items'] ?? []; - - $pdo->beginTransaction(); - $imported = 0; - - if ($type === 'videotheque') { - $stmtVideo = $pdo->prepare("INSERT INTO videotheque (id, title, year, format, poster, ean_isbn13, description, length, number_of_discs, aspect_ratio, actors, publisher, director) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - ON DUPLICATE KEY UPDATE - ean_isbn13 = VALUES(ean_isbn13), - poster = VALUES(poster), - description = VALUES(description), - format = VALUES(format), - length = VALUES(length), - number_of_discs = VALUES(number_of_discs), - aspect_ratio = VALUES(aspect_ratio), - actors = VALUES(actors), - publisher = VALUES(publisher)"); + case 'import_batch': + checkAuth($pdo); + $data = json_decode(file_get_contents("php://input"), true); + $type = $data['type'] ?? 'critique'; + $items = $data['items'] ?? []; - foreach ($items as $item) { - $title = $item['title'] ?? ''; - if (empty($title)) continue; - - $year = $item['year'] ?? ''; - $ean = $item['ean'] ?? ''; - $desc = $item['description'] ?? ''; - $length = $item['length'] ?? ''; - $discs = $item['number_of_discs'] ?? 1; - $aspect = $item['aspect_ratio'] ?? ''; - $actors = $item['actors'] ?? ''; - $publisher = $item['publisher'] ?? ''; - $director = $item['director'] ?? ''; - - $id = makeStableId('videotheque', $title, $year); - - // Utiliser cinemapassion.com pour récupérer l'image - $cinemaPassionData = fetchCinemaPassion($title, $year, $ean, $pdo); - $poster = $cinemaPassionData['poster']; - - // Déterminer le format - $format = 'Blu-ray'; - if (stripos($title, '4K') !== false || stripos($title, 'UHD') !== false) { - $format = '4K Ultra HD'; - } elseif (stripos($desc, 'DVD') !== false) { - $format = 'DVD'; - } - - $stmtVideo->execute([ - $id, $title, $year, $format, $poster, $ean, $desc, - $length, $discs, $aspect, $actors, $publisher, $director - ]); - $imported++; - } -} else { - // CORRECTION : Initialisation des variables manquantes + $pdo->beginTransaction(); + $imported = 0; + + try { + if ($type === 'videotheque') { + $stmtVideo = $pdo->prepare("INSERT INTO videotheque (id, title, year, format, poster, ean_isbn13, description, length, number_of_discs, aspect_ratio, actors, publisher, director) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ON DUPLICATE KEY UPDATE + ean_isbn13 = VALUES(ean_isbn13), + poster = VALUES(poster), + description = VALUES(description), + format = VALUES(format), + length = VALUES(length), + number_of_discs = VALUES(number_of_discs), + aspect_ratio = VALUES(aspect_ratio), + actors = VALUES(actors), + publisher = VALUES(publisher), + director = VALUES(director)"); + + foreach ($items as $item) { + $title = $item['title'] ?? ''; + if (empty($title)) continue; + + $year = $item['year'] ?? ''; + $ean = $item['ean'] ?? ''; + $desc = $item['description'] ?? ''; + $length = $item['length'] ?? ''; + $discs = $item['number_of_discs'] ?? 1; + $aspect = $item['aspect_ratio'] ?? ''; + $actors = $item['actors'] ?? ''; + $publisher = $item['publisher'] ?? ''; + $director = $item['director'] ?? ''; + + $id = makeStableId('videotheque', $title, $year); + + // ✅ UTILISER CINEMAPASSION.COM + $cpData = fetchCinemaPassion($title, $year, $ean, $pdo); + $poster = $cpData['poster']; + + $format = detectFormat($title, $desc); + + $stmtVideo->execute([ + $id, $title, $year, $format, $poster, $ean, $desc, + $length, $discs, $aspect, $actors, $publisher, $director + ]); + $imported++; + } + } else { + // ✅ CORRECTION CRITIQUE : Initialisation des variables pour les critiques $stmtCritiques = $pdo->prepare("INSERT INTO critiques (id, title, year, director, poster, rating, review, streaming) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE title=VALUES(title), year=VALUES(year), director=VALUES(director), @@ -586,7 +458,7 @@ case 'get_config_keys': $rating = ($ratingRaw !== '' && $ratingRaw !== null) ? (float)$ratingRaw : null; $review = $rowData['Review'] ?? $rowData['review'] ?? ''; $director = ''; $poster = ''; $streaming = ''; - + if ($tmdbApiKey && !empty($title)) { $tmdbData = fetchTMDBFull($title, $year, $tmdbApiKey, $pdo); if ($tmdbData) { @@ -598,173 +470,112 @@ case 'get_config_keys': } } if (empty($streaming)) $streaming = 'Support physique / Cinéma'; - + $stmtCritiques->execute([$id, $title, $year, $director, $poster, $rating, $review, $streaming]); $imported++; } } $pdo->commit(); echo json_encode(["success" => true, "imported" => $imported]); - break; - -// ── ENDPOINT DE DEBUG DÉTAILLÉ ── -case 'debug_cinemapassion_detailed': - $title = $_GET['title'] ?? 'Saw'; - $year = $_GET['year'] ?? ''; - $ean = $_GET['ean'] ?? ''; - - $debugInfo = [ - 'title' => $title, - 'year' => $year, - 'ean' => $ean, - 'cleanTitle' => cleanTitle($title), - 'steps' => [] - ]; - - $userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36'; - - // ÉTAPE 1 : Test de la recherche POST - $searchUrl = "https://www.cinemapassion.com/moteur2.php"; - $ch = curl_init($searchUrl); - curl_setopt_array($ch, [ - CURLOPT_RETURNTRANSFER => true, - CURLOPT_TIMEOUT => 15, - CURLOPT_CONNECTTIMEOUT => 5, - CURLOPT_SSL_VERIFYPEER => false, - CURLOPT_USERAGENT => $userAgent, - CURLOPT_FOLLOWLOCATION => true, - CURLOPT_POST => true, - CURLOPT_POSTFIELDS => http_build_query(['recherche' => cleanTitle($title)]), - CURLOPT_REFERER => 'https://www.cinemapassion.com/', - CURLOPT_HTTPHEADER => [ - 'Content-Type: application/x-www-form-urlencoded', - 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', - 'Accept-Language: fr-FR,fr;q=0.8', - 'Origin: https://www.cinemapassion.com' - ], - ]); - $searchRes = curl_exec($ch); - $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); - curl_close($ch); - - // ✅ CORRECTION : Vérifier que $searchRes est une string - $searchResStr = ($searchRes && is_string($searchRes)) ? $searchRes : ''; - - $debugInfo['steps']['search'] = [ - 'url' => $searchUrl, - 'http_code' => $code, - 'response_length' => strlen($searchResStr), - 'success' => ($code === 200 && strlen($searchResStr) > 0) - ]; - - if ($code === 200 && strlen($searchResStr) > 0) { - // ÉTAPE 2 : Extraction du lien film - if (preg_match('/href=["\']([^"\']*film\/[^"\'\/]+-\d+\.php)["\']/i', $searchResStr, $matches)) { - $filmPath = $matches[1]; - $filmPath = str_replace('../', '', $filmPath); - $filmUrl = 'https://www.cinemapassion.com/' . $filmPath; - - $debugInfo['steps']['film_link'] = [ - 'found' => true, - 'filmPath' => $filmPath, - 'filmUrl' => $filmUrl - ]; - - // ÉTAPE 3 : Extraction du nom et ID - if (preg_match('/film\/([^\/]+)-(\d+)\.php/i', $filmUrl, $filmMatches)) { - $filmName = $filmMatches[1]; - $filmId = $filmMatches[2]; - - $debugInfo['steps']['film_details'] = [ - 'filmName' => $filmName, - 'filmId' => $filmId + } catch (Exception $e) { + $pdo->rollBack(); + error_log("import_batch error: " . $e->getMessage()); + http_response_code(500); + echo json_encode(["success" => false, "error" => $e->getMessage()]); + } + break; + + // ── ENDPOINT DE DEBUG DÉTAILLÉ ── + case 'debug_cinemapassion': + $title = $_GET['title'] ?? 'Saw'; + $year = $_GET['year'] ?? ''; + $ean = $_GET['ean'] ?? ''; + + $debugInfo = [ + 'title' => $title, + 'year' => $year, + 'cleanTitle' => cleanTitle($title), + 'steps' => [] + ]; + + // Test 1 : POST sur moteur2.php + $searchRes = httpPost('https://www.cinemapassion.com/moteur2.php', ['recherche' => cleanTitle($title)]); + $debugInfo['steps']['search_post'] = [ + 'success' => !empty($searchRes), + 'length' => $searchRes ? strlen($searchRes) : 0 + ]; + + if ($searchRes) { + // Test 2 : Extraction du lien film + if (preg_match('/href=["\']?(?:\.\.\/)?film\/([^"\'\s]+)-(\d+)\.php["\']?/i', $searchRes, $matches)) { + $debugInfo['steps']['film_found'] = [ + 'success' => true, + 'filmName' => $matches[1], + 'filmId' => $matches[2] ]; - // ÉTAPE 4 : Test des pages de jaquettes + $filmName = $matches[1]; + $filmId = $matches[2]; + + // Test 3 : Pages de jaquettes $pagesToTry = [ "https://www.cinemapassion.com/jaquette-dvd-{$filmName}-{$filmId}.php", "https://www.cinemapassion.com/jaquette-blu-ray-{$filmName}-{$filmId}.php", - $filmUrl, - "https://www.cinemapassion.com/sticker-dvd-{$filmName}-{$filmId}.php", + "https://www.cinemapassion.com/film/{$filmName}-{$filmId}.php", ]; - foreach ($pagesToTry as $index => $pageUrl) { - $pageRes = httpGet($pageUrl, 10, $userAgent); - - // ✅ CORRECTION : Vérifier que $pageRes est une string - $pageResStr = ($pageRes && is_string($pageRes)) ? $pageRes : ''; - + foreach ($pagesToTry as $i => $pageUrl) { + $pageRes = httpGet($pageUrl, 10); $pageDebug = [ 'url' => $pageUrl, - 'success' => (strlen($pageResStr) > 0), - 'response_length' => strlen($pageResStr) + 'success' => !empty($pageRes), + 'length' => $pageRes ? strlen($pageRes) : 0 ]; - if (strlen($pageResStr) > 0) { - // Test du pattern d'image - if (preg_match('/src=["\']?(https?:\/\/[^"\'\s>]*cinemapassion\.com[^"\'\s>]*covers[^"\'\s>]*\.jpg)["\']?/i', $pageResStr, $imgMatches)) { - $posterUrl = str_replace('http://', 'https://', $imgMatches[1]); + if ($pageRes) { + if (preg_match('/src=["\']?(https?:\/\/(?:www\.)?cinemapassion\.com\/covers_temp\/covers\d*\/[^"\'\s>]+\.jpg)["\']?/i', $pageRes, $imgMatches)) { $pageDebug['image_found'] = true; - $pageDebug['image_url'] = $posterUrl; - - $debugInfo['steps']['pages_tested'][$index] = $pageDebug; - $debugInfo['final_result'] = [ - 'success' => true, - 'poster' => $posterUrl, - 'title' => cleanTitle($title), - 'format' => 'Blu-ray' - ]; - - echo json_encode($debugInfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); - exit; + $pageDebug['image_url'] = str_replace('http://', 'https://', $imgMatches[1]); + } elseif (preg_match('/src=["\']?(https?:\/\/(?:www\.)?cinemapassion\.com\/lesaffiches\/[^"\'\s>]+\.jpg)["\']?/i', $pageRes, $imgMatches)) { + $pageDebug['affiche_found'] = true; + $pageDebug['image_url'] = str_replace('http://', 'https://', $imgMatches[1]); } else { $pageDebug['image_found'] = false; - // Extraire un extrait du HTML pour debug - $pageDebug['html_snippet'] = substr($pageResStr, 0, 500); + // Extraire un extrait pour debug + $pageDebug['html_snippet'] = substr($pageRes, 0, 1000); } } - $debugInfo['steps']['pages_tested'][$index] = $pageDebug; + $debugInfo['steps']['pages'][$i] = $pageDebug; + + if (!empty($pageDebug['image_found']) || !empty($pageDebug['affiche_found'])) { + $debugInfo['final_result'] = [ + 'success' => true, + 'poster' => $pageDebug['image_url'], + 'title' => cleanTitle($title), + 'format' => 'Blu-ray' + ]; + echo json_encode($debugInfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); + exit; + } } + } else { + $debugInfo['steps']['film_found'] = [ + 'success' => false, + 'html_snippet' => substr($searchRes, 0, 2000) + ]; } - } else { - $debugInfo['steps']['film_link'] = [ - 'found' => false, - 'html_snippet' => substr($searchResStr, 0, 1000) + } + + if (!isset($debugInfo['final_result'])) { + $debugInfo['final_result'] = [ + 'success' => false, + 'poster' => 'assets/img/default_physical_media.jpg' ]; } - // Test du fallback - if (preg_match('/src=["\']?(https?:\/\/[^"\'\s>]*cinemapassion\.com[^"\'\s>]*covers[^"\'\s>]*\.jpg)["\']?/i', $searchResStr, $imgMatches)) { - $posterUrl = str_replace('http://', 'https://', $imgMatches[1]); - $debugInfo['steps']['fallback'] = [ - 'success' => true, - 'image_url' => $posterUrl - ]; - $debugInfo['final_result'] = [ - 'success' => true, - 'poster' => $posterUrl, - 'title' => cleanTitle($title), - 'format' => 'Blu-ray' - ]; - } else { - $debugInfo['steps']['fallback'] = [ - 'success' => false - ]; - } - } - - if (!isset($debugInfo['final_result'])) { - $debugInfo['final_result'] = [ - 'success' => false, - 'poster' => 'assets/img/default_physical_media.jpg', - 'title' => cleanTitle($title), - 'format' => 'Blu-ray' - ]; - } - - echo json_encode($debugInfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); - exit; - break; + echo json_encode($debugInfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); + exit; + break; } ?> \ No newline at end of file