]*class=[\'"](?:affiche|poster|movie-poster)[^"]*"[^>]*>.*?
![]()
]*src=[\'"]([^\'"]+)[\'"][^>]*>/is', $filmRes, $imgMatches)) {
$posterUrl = $imgMatches[1];
}
// Méthode 3 : Chercher toute image de film
elseif (preg_match('/
![]()
]*src=[\'"](https?:\/\/www\.cinemapassion\.com\/[^\'"]*\/?(?:affiches|posters|images|films)[^\'"]*\.(?:jpg|jpeg|png|webp))[^>]*>/i', $filmRes, $imgMatches)) {
$posterUrl = $imgMatches[1];
}
if (!empty($posterUrl)) {
// S'assurer que l'URL est absolue
if (strpos($posterUrl, 'http') !== 0) {
$posterUrl = 'https://www.cinemapassion.com' . (strpos($posterUrl, '/') === 0 ? '' : '/') . $posterUrl;
}
return [
'poster' => $posterUrl,
'title' => $cleanTitle,
'format' => 'Blu-ray'
];
}
}
}
// ÉTAPE 2 : Recherche alternative par EAN si disponible
if (!empty($ean)) {
$cleanEan = preg_replace('/[^0-9]/', '', $ean);
$searchUrl = "https://www.cinemapassion.com/recherche.php?recherche=" . urlencode($cleanEan);
$searchRes = httpGet($searchUrl, 10, $userAgent);
if ($searchRes && preg_match('/
]*>/i', $searchRes, $matches)) {
$filmUrl = $matches[1];
if (strpos($filmUrl, 'http') !== 0) {
$filmUrl = 'https://www.cinemapassion.com' . (strpos($filmUrl, '/') === 0 ? '' : '/') . $filmUrl;
}
$filmRes = httpGet($filmUrl, 10, $userAgent);
if ($filmRes && preg_match('/
]*src=[\'"](https?:\/\/www\.cinemapassion\.com\/[^\'"]*\/?(?:affiches|posters|images|films)[^\'"]*\.(?:jpg|jpeg|png|webp))[^>]*>/i', $filmRes, $imgMatches)) {
$posterUrl = $imgMatches[1];
if (strpos($posterUrl, 'http') !== 0) {
$posterUrl = 'https://www.cinemapassion.com' . (strpos($posterUrl, '/') === 0 ? '' : '/') . $posterUrl;
}
return [
'poster' => $posterUrl,
'title' => $cleanTitle,
'format' => 'Blu-ray'
];
}
}
}
}
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'])) {
$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'];
}
$overview = $details['overview'] ?? '';
$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));
$result = [
'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,
'cast' => $cast
];
return $result;
}
// ── 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 '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';
$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 (empty($data['length']) && !empty($tmdbData['length'])) $data['length'] = $tmdbData['length'];
}
}
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'])) {
$format = $data['format'] ?: 'Blu-ray';
$fanartData = fetchFanartTv($data['title'], $data['year'] ?? '', $format, $pdo);
if (!empty($fanartData['poster'])) {
$data['poster'] = $fanartData['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;
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)");
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 {
$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]);
break;
case 'debug_cinemapassion':
$title = $_GET['title'] ?? '';
$year = $_GET['year'] ?? '';
$ean = $_GET['ean'] ?? '';
$result = fetchCinemaPassion($title, $year, $ean, $pdo);
echo json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
exit;
break;
}
?>