Files
mon-petit-cinema/api.php
T
2026-06-26 14:03:45 +02:00

622 lines
32 KiB
PHP

<?php
ini_set('log_errors', 1);
ini_set('error_log', __DIR__ . '/php_errors.log');
error_reporting(E_ALL);
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization");
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
define('ENCRYPTION_KEY', 'MaCleSecreteSuperRobuste123!');
try {
$pdo = new PDO("mysql:host=localhost;dbname=mon_cinema;charset=utf8mb4", "root", "", [
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 ──
function makeStableId($type, $title, $year) {
return (abs(crc32(strtolower(trim($type ?? '')) . '|' . strtolower(trim($title ?? '')) . '|' . trim($year ?? ''))) % 2000000000) + 100000000;
}
function checkAuth($pdo) {
if ($pdo->query("SELECT COUNT(*) FROM users")->fetchColumn() == 0) return true;
$token = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
if (empty($token) && function_exists('apache_request_headers')) {
$headers = apache_request_headers();
$token = $headers['Authorization'] ?? $headers['authorization'] ?? '';
}
if ($token !== md5(ENCRYPTION_KEY . 'session')) { http_response_code(403); echo json_encode(["error" => "Accès interdit."]); exit; }
}
function encryptData($data) {
$iv = openssl_random_pseudo_bytes(16);
$key = hash('sha256', ENCRYPTION_KEY, true);
return base64_encode(openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv) . '::' . $iv);
}
function decryptData($str) {
$decoded = base64_decode($str);
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));
}
function getTmdbApiKey($pdo) {
$stmt = $pdo->prepare("SELECT key_value FROM config WHERE key_name = 'tmdb_api_key'");
$stmt->execute();
$row = $stmt->fetch();
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 = 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,
CURLOPT_TIMEOUT => $timeout,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_USERAGENT => $ua,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => is_array($postData) ? http_build_query($postData) : $postData,
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'
],
]);
$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 cleanTitle($title) {
$clean = preg_replace('/\s*[\[\(].*?[\]\)]\s*/', '', $title);
$clean = preg_replace('/\s*-\s*(Édition|Edition|Collector|Simple|Spéciale|Digibook|Ultimate|Intégrale|Combo|SteelBook|Boîtier).*$/i', '', $clean);
$clean = preg_replace('/(blu-ray|bluray|dvd|4k|ultra hd|combo|vhs|bdrip).*$/i', '', $clean);
return trim(preg_replace('/\s{2,}/', ' ', $clean));
}
function detectFormat($title, $desc = '') {
$t = strtoupper($title . ' ' . $desc);
if (strpos($t, '4K') !== false || strpos($t, 'UHD') !== false) return '4K Ultra HD';
if (strpos($t, 'BLU-RAY') !== false || strpos($t, 'BLURAY') !== false) return 'Blu-ray';
if (strpos($t, 'DVD') !== false) return 'DVD';
if (strpos($t, 'VHS') !== false) return 'VHS';
if (strpos($t, 'COFFRET') !== false || strpos($t, 'TRILOGIE') !== false) return 'Coffret';
return 'Blu-ray';
}
// ── FONCTION POUR RÉCUPÉRER LES IMAGES DEPUIS CINEMAPASSION.COM ──
function fetchCinemaPassion($title, $year = '', $ean = '', $pdo = null) {
$defaultPoster = 'assets/img/default_physical_media.jpg';
$cleanTitle = cleanTitle($title);
if (empty($cleanTitle)) {
return ['poster' => $defaultPoster, 'title' => '', 'format' => 'Blu-ray'];
}
// ÉTAPE 1 : Recherche POST sur /moteur2.php
$searchRes = httpPost('https://www.cinemapassion.com/moteur2.php', ['recherche' => $cleanTitle]);
if (!$searchRes) {
error_log("CinemaPassion: Recherche échouée pour '{$cleanTitle}'");
return ['poster' => $defaultPoster, 'title' => $cleanTitle, 'format' => 'Blu-ray'];
}
// ÉTAPE 2 : Trouver le lien qui correspond EXACTEMENT au titre
// Pattern : <a href='../film/Saw-3814.php'>Saw</a>
$filmUrl = null;
$filmName = null;
$filmId = null;
// Chercher tous les liens vers des films
if (preg_match_all('/<a\s+href=["\']?(?:\.\.\/)?film\/([^"\'\s]+)-(\d+)\.php["\']?[^>]*>([^<]+)<\/a>/i', $searchRes, $matches, PREG_SET_ORDER)) {
foreach ($matches as $match) {
$linkTitle = trim($match[3]);
$linkName = $match[1];
$linkId = $match[2];
// Vérifier si le titre du lien correspond au titre recherché
if (strcasecmp($linkTitle, $cleanTitle) === 0 ||
stripos($linkTitle, $cleanTitle) !== false ||
stripos($cleanTitle, $linkTitle) !== false) {
$filmUrl = "https://www.cinemapassion.com/film/{$linkName}-{$linkId}.php";
$filmName = $linkName;
$filmId = $linkId;
break;
}
}
// Si pas de correspondance exacte, prendre le premier résultat
if (!$filmUrl && !empty($matches)) {
$filmName = $matches[0][1];
$filmId = $matches[0][2];
$filmUrl = "https://www.cinemapassion.com/film/{$filmName}-{$filmId}.php";
}
}
if (!$filmUrl) {
error_log("CinemaPassion: Film non trouvé pour '{$cleanTitle}'");
return ['poster' => $defaultPoster, 'title' => $cleanTitle, 'format' => 'Blu-ray'];
}
// ÉTAPE 3 : Aller sur la page du film
$filmPageRes = httpGet($filmUrl, 10);
if (!$filmPageRes) {
error_log("CinemaPassion: Page film inaccessible : {$filmUrl}");
return ['poster' => $defaultPoster, 'title' => $cleanTitle, 'format' => 'Blu-ray'];
}
// ÉTAPE 4 : Chercher le lien vers la jaquette DVD ou Blu-ray
// Pattern : <a href='../jaquette-dvd-Saw-3814.php'> ou <a href='../jaquette-blu-ray-Saw-3814.php'>
$jaquetteUrl = null;
if (preg_match('/href=["\']?(?:\.\.\/)?(jaquette-(?:dvd|blu-ray)-[^"\'\s]+\.php)["\']?/i', $filmPageRes, $matches)) {
$jaquettePath = $matches[1];
$jaquetteUrl = "https://www.cinemapassion.com/" . str_replace('../', '', $jaquettePath);
}
// ÉTAPE 5 : Si page jaquette trouvée, aller dessus et extraire l'image covers_temp
if ($jaquetteUrl) {
$jaquettePageRes = httpGet($jaquetteUrl, 10);
if ($jaquettePageRes) {
// 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', $jaquettePageRes, $imgMatches)) {
$posterUrl = str_replace('http://', 'https://', $imgMatches[1]);
error_log("CinemaPassion OK (jaquette): '{$cleanTitle}' → {$posterUrl}");
return ['poster' => $posterUrl, 'title' => $cleanTitle, 'format' => 'Blu-ray'];
}
}
}
// ÉTAPE 6 : Fallback - Chercher l'image covers_temp directement sur la page du film
if (preg_match('/src=["\']?(https?:\/\/(?:www\.)?cinemapassion\.com\/covers_temp\/covers\d*\/[^"\'\s>]+\.jpg)["\']?/i', $filmPageRes, $imgMatches)) {
$posterUrl = str_replace('http://', 'https://', $imgMatches[1]);
error_log("CinemaPassion OK (covers_temp direct): '{$cleanTitle}' → {$posterUrl}");
return ['poster' => $posterUrl, 'title' => $cleanTitle, 'format' => 'Blu-ray'];
}
// ÉTAPE 7 : Fallback - Utiliser l'affiche trouvée sur la page du film
if (preg_match('/src=["\']?(https?:\/\/(?:www\.)?cinemapassion\.com\/lesaffiches\/[^"\'\s>]+\.jpg)["\']?/i', $filmPageRes, $imgMatches)) {
$posterUrl = str_replace('http://', 'https://', $imgMatches[1]);
error_log("CinemaPassion OK (affiche fallback): '{$cleanTitle}' → {$posterUrl}");
return ['poster' => $posterUrl, 'title' => $cleanTitle, 'format' => 'Blu-ray'];
}
error_log("CinemaPassion KO: Image NON trouvée pour '{$cleanTitle}'");
return ['poster' => $defaultPoster, 'title' => $cleanTitle, 'format' => 'Blu-ray'];
}
// ── 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'])) {
$frenchTitle = $translation['data']['title'];
break;
}
}
}
$director = '';
if (!empty($details['credits']['crew'])) {
$directorsList = [];
foreach ($details['credits']['crew'] as $crew) {
if ($crew['job'] === 'Director') $directorsList[] = $crew['name'];
}
$director = implode(', ', $directorsList);
}
$cast = [];
if (!empty($details['credits']['cast'])) {
$topCast = array_slice($details['credits']['cast'], 0, 4);
foreach ($topCast as $actor) $cast[] = $actor['name'];
}
$streaming = '';
$frProviders = $details['watch/providers']['results']['FR'] ?? [];
$platforms = [];
if (!empty($frProviders['flatrate'])) { foreach ($frProviders['flatrate'] as $p) $platforms[] = $p['provider_name']; }
if (empty($platforms)) {
if (!empty($frProviders['rent'])) { foreach ($frProviders['rent'] as $p) $platforms[] = $p['provider_name'] . ' (loc.)'; }
if (!empty($frProviders['buy'])) { foreach ($frProviders['buy'] as $p) $platforms[] = $p['provider_name'] . ' (achat)'; }
}
if (!empty($platforms)) $streaming = implode(', ', array_unique($platforms));
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' => $details['overview'] ?? '',
'cast' => $cast
];
}
// ── ROUTEUR PRINCIPAL ──
$action = $_GET['action'] ?? '';
$data = json_decode(file_get_contents('php://input'), true) ?? [];
switch ($action) {
case 'check_security_status':
echo json_encode(["is_blank" => ($pdo->query("SELECT COUNT(*) FROM users")->fetchColumn() == 0)]);
break;
case 'login':
if ($pdo->query("SELECT COUNT(*) FROM users")->fetchColumn() == 0) {
echo json_encode(["success" => true, "token" => md5(ENCRYPTION_KEY . 'session'), "blank" => true]);
} else {
$stmt = $pdo->prepare("SELECT password_hash FROM users WHERE username = 'admin'");
$stmt->execute(); $user = $stmt->fetch();
if ($user && password_verify($data['password'] ?? '', $user['password_hash'])) {
echo json_encode(["success" => true, "token" => md5(ENCRYPTION_KEY . 'session'), "blank" => false]);
} else { http_response_code(401); echo json_encode(["error" => "Mot de passe incorrect."]); }
}
break;
case 'setup_admin': case 'update_password':
checkAuth($pdo);
$pwd = $data['password'] ?? $data['new_password'] ?? '';
$stmt = $pdo->prepare("REPLACE INTO users (id, username, password_hash) VALUES (1, 'admin', :pass)");
$stmt->execute([':pass' => password_hash($pwd, PASSWORD_BCRYPT)]);
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 'save_config':
checkAuth($pdo);
$keyName = $data['key_name'] ?? '';
$keyValue = $data['key_value'] ?? '';
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;
case 'get_films':
$sql = "
SELECT id, title, year, director, poster, rating, review, NULL AS description, streaming, 'critique' AS type
FROM critiques
UNION ALL
SELECT id, title, year, director, poster, NULL AS rating, NULL AS review, description, NULL AS streaming, 'videotheque' AS type
FROM videotheque
ORDER BY id DESC
";
$result = $pdo->query($sql)->fetchAll();
foreach ($result as $row) {
if ($row['rating'] !== null) {
$ratingVal = (float)$row['rating'];
$row['rating'] = ($ratingVal == floor($ratingVal)) ? (int)$ratingVal : $ratingVal;
}
}
unset($row);
echo json_encode($result);
break;
case 'save_film':
checkAuth($pdo);
$type = $data['type'] ?? 'critique';
$id = !empty($data['id']) ? $data['id'] : makeStableId($type, $data['title'] ?? '', $data['year'] ?? '0000');
if ($type === 'critique' && (empty($data['director']) || empty($data['poster']))) {
$tmdbData = fetchTMDBFull($data['title'] ?? '', $data['year'] ?? '', getTmdbApiKey($pdo), $pdo);
if ($tmdbData) {
if (empty($data['director'])) $data['director'] = $tmdbData['director'];
if (empty($data['poster'])) $data['poster'] = $tmdbData['poster'];
}
}
if ($type === 'critique') {
$streaming = $data['streaming'] ?? '';
if (empty($streaming)) $streaming = 'Support physique / Cinéma';
$sql = "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), poster=VALUES(poster), rating=VALUES(rating), review=VALUES(review), streaming=VALUES(streaming)";
$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'])) {
$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'] ?? '']);
}
echo json_encode(["success" => true]);
break;
case 'delete_film':
checkAuth($pdo);
$type = $_GET['type'] ?? 'critique'; $table = ($type === 'videotheque') ? 'videotheque' : 'critiques';
$id = $_GET['id'] ?? null;
if (!$id) { http_response_code(400); echo json_encode(["error" => "ID manquant."]); break; }
$stmt = $pdo->prepare("DELETE FROM $table WHERE id = ?"); $stmt->execute([$id]);
echo json_encode(["success" => true]);
break;
case 'bulk_delete':
checkAuth($pdo);
$ids = $data['ids'] ?? []; $type = $data['type'] ?? 'critique'; $table = ($type === 'videotheque') ? 'videotheque' : 'critiques';
if (!empty($ids)) { $placeholders = implode(',', array_fill(0, count($ids), '?')); $stmt = $pdo->prepare("DELETE FROM $table WHERE id IN ($placeholders)"); $stmt->execute($ids); echo json_encode(["success" => true]); }
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;
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),
poster=VALUES(poster), rating=VALUES(rating), review=VALUES(review), streaming=VALUES(streaming)");
$tmdbApiKey = getTmdbApiKey($pdo);
foreach ($items as $rowData) {
$title = $rowData['Title'] ?? $rowData['title'] ?? '';
if (empty($title)) continue;
$year = $rowData['Year'] ?? $rowData['year'] ?? '';
$id = makeStableId('critique', $title, $year);
$ratingRaw = $rowData['Rating'] ?? $rowData['rating'] ?? '';
$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) {
$director = $tmdbData['director'];
$poster = $tmdbData['poster'];
$streaming = $tmdbData['streaming'];
if (empty($year)) $year = $tmdbData['year'];
if (!empty($tmdbData['title'])) $title = $tmdbData['title'];
}
}
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]);
} 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]
];
$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",
"https://www.cinemapassion.com/film/{$filmName}-{$filmId}.php",
];
foreach ($pagesToTry as $i => $pageUrl) {
$pageRes = httpGet($pageUrl, 10);
$pageDebug = [
'url' => $pageUrl,
'success' => !empty($pageRes),
'length' => $pageRes ? strlen($pageRes) : 0
];
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'] = 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 pour debug
$pageDebug['html_snippet'] = substr($pageRes, 0, 1000);
}
}
$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)
];
}
}
if (!isset($debugInfo['final_result'])) {
$debugInfo['final_result'] = [
'success' => false,
'poster' => 'assets/img/default_physical_media.jpg'
];
}
echo json_encode($debugInfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
exit;
break;
}
?>