|
<!DOCTYPE html> |
|
<html lang="fr"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>CinéVerse - Films populaires</title> |
|
<script src="https://cdn.tailwindcss.com"></script> |
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
|
<style> |
|
.movie-card { |
|
transition: transform 0.3s ease, box-shadow 0.3s ease; |
|
} |
|
.movie-card:hover { |
|
transform: scale(1.05); |
|
box-shadow: 0 10px 25px rgba(220, 38, 38, 0.3); |
|
} |
|
.scroll-container { |
|
height: calc(100vh - 200px); |
|
overflow-y: auto; |
|
} |
|
.scroll-container::-webkit-scrollbar { |
|
width: 8px; |
|
} |
|
.scroll-container::-webkit-scrollbar-track { |
|
background: #1a202c; |
|
} |
|
.scroll-container::-webkit-scrollbar-thumb { |
|
background: #e53e3e; |
|
border-radius: 4px; |
|
} |
|
.loading-spinner { |
|
animation: spin 1s linear infinite; |
|
} |
|
@keyframes spin { |
|
0% { transform: rotate(0deg); } |
|
100% { transform: rotate(360deg); } |
|
} |
|
.streaming-option { |
|
transition: all 0.3s ease; |
|
} |
|
.streaming-option:hover { |
|
transform: translateY(-5px); |
|
box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1); |
|
} |
|
</style> |
|
</head> |
|
<body class="bg-gray-900 text-white"> |
|
<header class="bg-black py-6 shadow-lg sticky top-0 z-50"> |
|
<div class="container mx-auto px-4"> |
|
<div class="flex flex-col md:flex-row justify-between items-center space-y-4 md:space-y-0"> |
|
<div class="flex items-center space-x-2"> |
|
<i class="fas fa-film text-3xl text-red-500"></i> |
|
<h1 class="text-2xl font-bold">CinéVerse</h1> |
|
</div> |
|
<div class="relative w-full md:w-1/3"> |
|
<input type="text" id="searchInput" placeholder="Rechercher un film..." class="w-full bg-gray-800 rounded-full py-2 px-4 text-white focus:outline-none focus:ring-2 focus:ring-red-500"> |
|
<button id="searchButton" class="absolute right-3 top-2 text-gray-400 hover:text-white"> |
|
<i class="fas fa-search"></i> |
|
</button> |
|
</div> |
|
<div class="flex space-x-4"> |
|
<button class="bg-red-600 hover:bg-red-700 px-4 py-2 rounded-md font-medium"> |
|
<i class="fas fa-user mr-2"></i>Connexion |
|
</button> |
|
</div> |
|
</div> |
|
</div> |
|
</header> |
|
|
|
<main class="container mx-auto px-4 py-8"> |
|
<div class="flex flex-col md:flex-row justify-between items-start md:items-center mb-8 space-y-4 md:space-y-0"> |
|
<h2 class="text-2xl font-bold" id="sectionTitle">Films populaires</h2> |
|
<div class="flex flex-wrap gap-2"> |
|
<button class="genre-btn bg-red-600 hover:bg-red-700 px-4 py-2 rounded-md" data-id="28">Action</button> |
|
<button class="genre-btn bg-red-600 hover:bg-red-700 px-4 py-2 rounded-md" data-id="35">Comédie</button> |
|
<button class="genre-btn bg-red-600 hover:bg-red-700 px-4 py-2 rounded-md" data-id="18">Drame</button> |
|
<button class="genre-btn bg-red-600 hover:bg-red-700 px-4 py-2 rounded-md" data-id="27">Horreur</button> |
|
<button class="genre-btn bg-red-600 hover:bg-red-700 px-4 py-2 rounded-md" data-id="10749">Romance</button> |
|
</div> |
|
</div> |
|
|
|
<div id="loading" class="flex justify-center items-center py-20"> |
|
<i class="fas fa-spinner loading-spinner text-4xl text-red-500"></i> |
|
</div> |
|
|
|
<div class="scroll-container hidden" id="moviesContainer"> |
|
<div id="moviesGrid" class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-6"> |
|
|
|
</div> |
|
<div class="flex justify-center mt-8 mb-4"> |
|
<button id="loadMore" class="bg-red-600 hover:bg-red-700 px-6 py-3 rounded-md font-medium hidden"> |
|
Charger plus de films |
|
</button> |
|
</div> |
|
</div> |
|
</main> |
|
|
|
|
|
<div id="movieDetailsTemplate" class="hidden fixed inset-0 bg-black bg-opacity-90 z-50 overflow-y-auto"> |
|
<div class="container mx-auto px-4 py-12"> |
|
<button onclick="closeMovieDetails()" class="absolute top-4 right-4 text-3xl text-white hover:text-red-500"> |
|
<i class="fas fa-times"></i> |
|
</button> |
|
|
|
<div class="flex flex-col lg:flex-row gap-8"> |
|
<div class="lg:w-1/3"> |
|
<img id="detailPoster" src="" alt="Affiche du film" class="w-full rounded-lg shadow-xl"> |
|
</div> |
|
|
|
<div class="lg:w-2/3"> |
|
<h1 id="detailTitle" class="text-3xl font-bold mb-2"></h1> |
|
<div class="flex items-center space-x-4 mb-4"> |
|
<span id="detailYear" class="text-gray-400"></span> |
|
<span id="detailRuntime" class="text-gray-400"></span> |
|
<span id="detailRating" class="flex items-center text-yellow-400"> |
|
<i class="fas fa-star mr-1"></i> |
|
<span></span> |
|
</span> |
|
</div> |
|
|
|
<p id="detailOverview" class="text-lg mb-6"></p> |
|
|
|
<div class="mb-8"> |
|
<h2 class="text-xl font-semibold mb-4">Où regarder</h2> |
|
<div id="streamingOptions" class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-4"> |
|
|
|
</div> |
|
<p class="text-gray-400 mt-4 text-sm">* Les liens pointent vers des plateformes légales de streaming</p> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<footer class="bg-black py-8 mt-12"> |
|
<div class="container mx-auto px-4"> |
|
<div class="grid grid-cols-1 md:grid-cols-4 gap-8"> |
|
<div> |
|
<h3 class="text-xl font-bold mb-4">CinéVerse</h3> |
|
<p class="text-gray-400">Votre destination pour découvrir les meilleurs films et où les regarder légalement.</p> |
|
</div> |
|
<div> |
|
<h4 class="text-lg font-semibold mb-4">Liens utiles</h4> |
|
<ul class="space-y-2 text-gray-400"> |
|
<li><a href="#" class="hover:text-red-500">À propos</a></li> |
|
<li><a href="#" class="hover:text-red-500">Contact</a></li> |
|
<li><a href="#" class="hover:text-red-500">Politique de confidentialité</a></li> |
|
</ul> |
|
</div> |
|
<div> |
|
<h4 class="text-lg font-semibold mb-4">Plateformes</h4> |
|
<ul class="space-y-2 text-gray-400"> |
|
<li><a href="https://www.netflix.com" target="_blank" class="hover:text-red-500">Netflix</a></li> |
|
<li><a href="https://www.primevideo.com" target="_blank" class="hover:text-red-500">Amazon Prime</a></li> |
|
<li><a href="https://www.disneyplus.com" target="_blank" class="hover:text-red-500">Disney+</a></li> |
|
</ul> |
|
</div> |
|
<div> |
|
<h4 class="text-lg font-semibold mb-4">Réseaux sociaux</h4> |
|
<div class="flex space-x-4"> |
|
<a href="#" class="text-gray-400 hover:text-red-500 text-xl"><i class="fab fa-facebook"></i></a> |
|
<a href="#" class="text-gray-400 hover:text-red-500 text-xl"><i class="fab fa-twitter"></i></a> |
|
<a href="#" class="text-gray-400 hover:text-red-500 text-xl"><i class="fab fa-instagram"></i></a> |
|
</div> |
|
</div> |
|
</div> |
|
<div class="border-t border-gray-800 mt-8 pt-6 text-center text-gray-400"> |
|
<p>Ce site utilise l'API TMDB mais n'est pas affilié à TMDB.</p> |
|
<p class="mt-2">Les films présentés sont protégés par des droits d'auteur.</p> |
|
</div> |
|
</div> |
|
</footer> |
|
|
|
<script> |
|
|
|
const API_KEY = '3fd2be6f0c70a2a598f084ddfb75487c'; |
|
const BASE_URL = 'https://api.themoviedb.org/3'; |
|
const IMAGE_BASE_URL = 'https://image.tmdb.org/t/p/w500'; |
|
const FRENCH_LANGUAGE = 'fr-FR'; |
|
|
|
let currentPage = 1; |
|
let currentGenre = ''; |
|
let currentSearch = ''; |
|
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
|
const moviesGrid = document.getElementById('moviesGrid'); |
|
const loadingElement = document.getElementById('loading'); |
|
const moviesContainer = document.getElementById('moviesContainer'); |
|
const loadMoreButton = document.getElementById('loadMore'); |
|
const searchInput = document.getElementById('searchInput'); |
|
const searchButton = document.getElementById('searchButton'); |
|
const sectionTitle = document.getElementById('sectionTitle'); |
|
const genreButtons = document.querySelectorAll('.genre-btn'); |
|
|
|
|
|
fetchPopularMovies(); |
|
|
|
|
|
loadMoreButton.addEventListener('click', loadMoreMovies); |
|
searchButton.addEventListener('click', searchMovies); |
|
searchInput.addEventListener('keypress', function(e) { |
|
if (e.key === 'Enter') searchMovies(); |
|
}); |
|
|
|
|
|
genreButtons.forEach(button => { |
|
button.addEventListener('click', function() { |
|
currentGenre = this.dataset.id; |
|
currentSearch = ''; |
|
currentPage = 1; |
|
sectionTitle.textContent = this.textContent; |
|
fetchMoviesByGenre(currentGenre); |
|
}); |
|
}); |
|
|
|
|
|
async function fetchPopularMovies() { |
|
try { |
|
const response = await fetch(`${BASE_URL}/movie/popular?api_key=${API_KEY}&language=${FRENCH_LANGUAGE}&page=${currentPage}`); |
|
const data = await response.json(); |
|
displayMovies(data.results); |
|
} catch (error) { |
|
console.error('Erreur:', error); |
|
loadingElement.innerHTML = '<p class="text-red-500">Erreur lors du chargement des films. Veuillez réessayer.</p>'; |
|
} |
|
} |
|
|
|
|
|
async function fetchMoviesByGenre(genreId) { |
|
try { |
|
loadingElement.classList.remove('hidden'); |
|
moviesContainer.classList.add('hidden'); |
|
loadMoreButton.classList.add('hidden'); |
|
moviesGrid.innerHTML = ''; |
|
|
|
const response = await fetch(`${BASE_URL}/discover/movie?api_key=${API_KEY}&language=${FRENCH_LANGUAGE}&sort_by=popularity.desc&page=${currentPage}&with_genres=${genreId}`); |
|
const data = await response.json(); |
|
displayMovies(data.results); |
|
} catch (error) { |
|
console.error('Erreur:', error); |
|
loadingElement.innerHTML = '<p class="text-red-500">Erreur lors du chargement des films. Veuillez réessayer.</p>'; |
|
} |
|
} |
|
|
|
|
|
async function searchMovies() { |
|
const query = searchInput.value.trim(); |
|
if (query === '') return; |
|
|
|
currentSearch = query; |
|
currentGenre = ''; |
|
currentPage = 1; |
|
sectionTitle.textContent = `Résultats pour "${query}"`; |
|
|
|
try { |
|
loadingElement.classList.remove('hidden'); |
|
moviesContainer.classList.add('hidden'); |
|
loadMoreButton.classList.add('hidden'); |
|
moviesGrid.innerHTML = ''; |
|
|
|
const response = await fetch(`${BASE_URL}/search/movie?api_key=${API_KEY}&language=${FRENCH_LANGUAGE}&query=${encodeURIComponent(query)}&page=${currentPage}`); |
|
const data = await response.json(); |
|
displayMovies(data.results); |
|
} catch (error) { |
|
console.error('Erreur:', error); |
|
loadingElement.innerHTML = '<p class="text-red-500">Erreur lors de la recherche. Veuillez réessayer.</p>'; |
|
} |
|
} |
|
|
|
|
|
async function loadMoreMovies() { |
|
currentPage++; |
|
try { |
|
loadMoreButton.disabled = true; |
|
loadMoreButton.innerHTML = '<i class="fas fa-spinner loading-spinner mr-2"></i> Chargement...'; |
|
|
|
let response; |
|
if (currentSearch) { |
|
response = await fetch(`${BASE_URL}/search/movie?api_key=${API_KEY}&language=${FRENCH_LANGUAGE}&query=${encodeURIComponent(currentSearch)}&page=${currentPage}`); |
|
} else if (currentGenre) { |
|
response = await fetch(`${BASE_URL}/discover/movie?api_key=${API_KEY}&language=${FRENCH_LANGUAGE}&sort_by=popularity.desc&page=${currentPage}&with_genres=${currentGenre}`); |
|
} else { |
|
response = await fetch(`${BASE_URL}/movie/popular?api_key=${API_KEY}&language=${FRENCH_LANGUAGE}&page=${currentPage}`); |
|
} |
|
|
|
const data = await response.json(); |
|
appendMovies(data.results); |
|
|
|
loadMoreButton.disabled = false; |
|
loadMoreButton.innerHTML = 'Charger plus de films'; |
|
} catch (error) { |
|
console.error('Erreur:', error); |
|
loadMoreButton.innerHTML = 'Erreur - Réessayer'; |
|
} |
|
} |
|
|
|
|
|
function displayMovies(movies) { |
|
if (movies.length === 0) { |
|
loadingElement.innerHTML = '<p class="text-red-500">Aucun film trouvé.</p>'; |
|
return; |
|
} |
|
|
|
moviesGrid.innerHTML = ''; |
|
appendMovies(movies); |
|
|
|
loadingElement.classList.add('hidden'); |
|
moviesContainer.classList.remove('hidden'); |
|
|
|
if (movies.length >= 20) { |
|
loadMoreButton.classList.remove('hidden'); |
|
} else { |
|
loadMoreButton.classList.add('hidden'); |
|
} |
|
} |
|
|
|
|
|
function appendMovies(movies) { |
|
movies.forEach(movie => { |
|
const movieCard = document.createElement('div'); |
|
movieCard.className = 'movie-card bg-gray-800 rounded-lg overflow-hidden cursor-pointer'; |
|
|
|
|
|
const posterPath = movie.poster_path ? |
|
`${IMAGE_BASE_URL}${movie.poster_path}` : |
|
'https://via.placeholder.com/500x750?text=Affiche+non+disponible'; |
|
|
|
|
|
const releaseDate = movie.release_date ? |
|
new Date(movie.release_date).getFullYear() : |
|
'Date inconnue'; |
|
|
|
|
|
movieCard.innerHTML = ` |
|
<div onclick="showMovieDetails(${movie.id})"> |
|
<img src="${posterPath}" alt="${movie.title}" class="w-full h-64 sm:h-80 object-cover"> |
|
<div class="p-4"> |
|
<h3 class="font-bold truncate">${movie.title}</h3> |
|
<div class="flex justify-between items-center mt-2 text-sm text-gray-400"> |
|
<span>${releaseDate}</span> |
|
<span class="flex items-center"> |
|
<i class="fas fa-star text-yellow-400 mr-1"></i> |
|
${movie.vote_average ? movie.vote_average.toFixed(1) : 'N/A'} |
|
</span> |
|
</div> |
|
</div> |
|
</div> |
|
`; |
|
moviesGrid.appendChild(movieCard); |
|
}); |
|
} |
|
}); |
|
|
|
|
|
async function showMovieDetails(movieId) { |
|
try { |
|
|
|
const detailsTemplate = document.getElementById('movieDetailsTemplate'); |
|
detailsTemplate.classList.remove('hidden'); |
|
detailsTemplate.innerHTML = ` |
|
<div class="flex justify-center items-center h-full"> |
|
<i class="fas fa-spinner loading-spinner text-4xl text-red-500"></i> |
|
</div> |
|
`; |
|
|
|
|
|
const movieResponse = await fetch(`https://api.themoviedb.org/3/movie/${movieId}?api_key=3fd2be6f0c70a2a598f084ddfb75487c&language=fr-FR`); |
|
const movieData = await movieResponse.json(); |
|
|
|
|
|
|
|
const streamingOptions = [ |
|
{ provider_name: "Netflix", logo_path: "/9A1JSVmSxsyaBK4SUFsYVqbAYfW.jpg", link: `https://www.netflix.com/search?q=${encodeURIComponent(movieData.title)}` }, |
|
{ provider_name: "Amazon Prime", logo_path: "/5NyLm42TmCqCMOZFvH4fcoSNKEW.jpg", link: `https://www.primevideo.com/search/ref=atv_nb_sr?phrase=${encodeURIComponent(movieData.title)}` }, |
|
{ provider_name: "Disney+", logo_path: "/drg0fW8CQ5icOq2PZ3mzAfpXvDF.jpg", link: `https://www.disneyplus.com/fr-fr/search?q=${encodeURIComponent(movieData.title)}` }, |
|
{ provider_name: "Canal+", logo_path: "/sVBEF7q7LqjHAWSnKwDbzmr2EMY.jpg", link: `https://www.canalplus.com/recherche/?q=${encodeURIComponent(movieData.title)}` } |
|
]; |
|
|
|
|
|
detailsTemplate.innerHTML = ` |
|
<div class="container mx-auto px-4 py-12"> |
|
<button onclick="closeMovieDetails()" class="absolute top-4 right-4 text-3xl text-white hover:text-red-500"> |
|
<i class="fas fa-times"></i> |
|
</button> |
|
|
|
<div class="flex flex-col lg:flex-row gap-8"> |
|
<div class="lg:w-1/3"> |
|
<img id="detailPoster" src="${movieData.poster_path ? 'https://image.tmdb.org/t/p/w500' + movieData.poster_path : 'https://via.placeholder.com/500x750?text=Affiche+non+disponible'}" alt="${movieData.title}" class="w-full rounded-lg shadow-xl"> |
|
</div> |
|
|
|
<div class="lg:w-2/3"> |
|
<h1 id="detailTitle" class="text-3xl font-bold mb-2">${movieData.title}</h1> |
|
<div class="flex items-center space-x-4 mb-4"> |
|
<span id="detailYear" class="text-gray-400"> |
|
</html> |