| | <!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> |