Spaces:
Running
Running
| <html lang="fr"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>MegaFlix Turbo - Streaming Automatique</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"> | |
| <!-- Plyr.js pour le lecteur vidéo --> | |
| <link href="https://cdn.jsdelivr.net/npm/plyr@3.7.8/dist/plyr.css" rel="stylesheet"> | |
| <script src="https://cdn.jsdelivr.net/npm/plyr@3.7.8/dist/plyr.min.js"></script> | |
| <!-- HLS.js pour la lecture des streams HLS --> | |
| <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script> | |
| <style> | |
| @import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700;900&display=swap'); | |
| body { | |
| font-family: 'Montserrat', sans-serif; | |
| background-color: #0f0f0f; | |
| color: #fff; | |
| overflow-x: hidden; | |
| } | |
| .player-container { | |
| --plyr-color-main: #e50914; | |
| --plyr-video-controls-background: rgba(0,0,0,0.7); | |
| --plyr-video-control-color: #fff; | |
| --plyr-menu-color: #fff; | |
| --plyr-menu-background: rgba(20,20,20,0.95); | |
| --plyr-tooltip-background: #141414; | |
| --plyr-tooltip-color: #fff; | |
| } | |
| .film-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); | |
| gap: 20px; | |
| } | |
| .film-card { | |
| transition: all 0.2s ease; | |
| animation: fadeIn 0.3s ease forwards; | |
| cursor: pointer; | |
| } | |
| .film-card:hover { | |
| transform: scale(1.05) translateY(-5px); | |
| z-index: 2; | |
| box-shadow: 0 10px 25px rgba(229, 9, 20, 0.3); | |
| } | |
| .film-card:hover .play-icon { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(20px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| .loading-bar { | |
| height: 4px; | |
| background: linear-gradient(90deg, #e50914, #f01828, #e50914); | |
| background-size: 200% 100%; | |
| animation: loadingBar 1.5s linear infinite; | |
| } | |
| @keyframes loadingBar { | |
| 0% { background-position: 100% 0; } | |
| 100% { background-position: -100% 0; } | |
| } | |
| .robot-mode { | |
| position: fixed; | |
| bottom: 20px; | |
| right: 20px; | |
| background: #e50914; | |
| color: white; | |
| padding: 10px 15px; | |
| border-radius: 50px; | |
| font-weight: bold; | |
| box-shadow: 0 0 20px rgba(229, 9, 20, 0.7); | |
| z-index: 1000; | |
| display: flex; | |
| align-items: center; | |
| } | |
| .robot-mode i { | |
| margin-right: 8px; | |
| animation: pulse 1s infinite alternate; | |
| } | |
| @keyframes pulse { | |
| from { transform: scale(1); } | |
| to { transform: scale(1.2); } | |
| } | |
| .counter { | |
| position: fixed; | |
| top: 80px; | |
| right: 20px; | |
| background: rgba(20,20,20,0.9); | |
| padding: 10px 15px; | |
| border-radius: 5px; | |
| font-family: monospace; | |
| font-size: 1.2rem; | |
| color: #0f0; | |
| border: 1px solid #0f0; | |
| z-index: 1000; | |
| } | |
| .api-status { | |
| position: fixed; | |
| top: 120px; | |
| right: 20px; | |
| background: rgba(20,20,20,0.9); | |
| padding: 10px 15px; | |
| border-radius: 5px; | |
| font-family: monospace; | |
| font-size: 1rem; | |
| color: #0f0; | |
| border: 1px solid #0f0; | |
| z-index: 1000; | |
| } | |
| /* Player overlay */ | |
| .player-overlay { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background: rgba(0,0,0,0.9); | |
| z-index: 9999; | |
| display: none; | |
| flex-direction: column; | |
| justify-content: center; | |
| align-items: center; | |
| padding: 20px; | |
| } | |
| .player-wrapper { | |
| width: 90%; | |
| max-width: 1200px; | |
| position: relative; | |
| } | |
| .close-player { | |
| position: absolute; | |
| top: -40px; | |
| right: 0; | |
| background: #e50914; | |
| color: white; | |
| border: none; | |
| width: 30px; | |
| height: 30px; | |
| border-radius: 50%; | |
| font-size: 16px; | |
| cursor: pointer; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| z-index: 100; | |
| } | |
| .player-controls { | |
| display: flex; | |
| justify-content: center; | |
| margin-top: 20px; | |
| gap: 10px; | |
| } | |
| .player-btn { | |
| background: #e50914; | |
| color: white; | |
| border: none; | |
| padding: 10px 20px; | |
| border-radius: 5px; | |
| cursor: pointer; | |
| font-weight: bold; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| transition: all 0.2s; | |
| } | |
| .player-btn:hover { | |
| background: #f01828; | |
| transform: translateY(-2px); | |
| } | |
| .player-btn i { | |
| font-size: 16px; | |
| } | |
| .quality-selector { | |
| background: #333; | |
| color: white; | |
| border: none; | |
| padding: 10px; | |
| border-radius: 5px; | |
| cursor: pointer; | |
| } | |
| .film-info { | |
| width: 90%; | |
| max-width: 1200px; | |
| margin-top: 20px; | |
| padding: 20px; | |
| background: rgba(20,20,20,0.8); | |
| border-radius: 10px; | |
| } | |
| .film-title { | |
| font-size: 24px; | |
| font-weight: bold; | |
| margin-bottom: 10px; | |
| } | |
| .film-meta { | |
| display: flex; | |
| gap: 15px; | |
| margin-bottom: 15px; | |
| color: #aaa; | |
| font-size: 14px; | |
| } | |
| .film-overview { | |
| line-height: 1.6; | |
| color: #ddd; | |
| } | |
| .server-btn { | |
| background: #333; | |
| color: white; | |
| border: none; | |
| padding: 8px 15px; | |
| border-radius: 5px; | |
| cursor: pointer; | |
| font-size: 14px; | |
| transition: all 0.2s; | |
| } | |
| .server-btn:hover { | |
| background: #444; | |
| } | |
| .server-btn.active { | |
| background: #e50914; | |
| font-weight: bold; | |
| } | |
| .server-container { | |
| display: flex; | |
| gap: 10px; | |
| margin-bottom: 15px; | |
| flex-wrap: wrap; | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-900 text-white"> | |
| <!-- Barre de chargement robotisé --> | |
| <div class="loading-bar"></div> | |
| <!-- Compteur de films --> | |
| <div class="counter" id="film-counter">Chargement: 0/∞</div> | |
| <!-- Statut API --> | |
| <div class="api-status" id="api-status"> | |
| <i class="fas fa-circle-notch fa-spin mr-2"></i> | |
| Connexion API en cours... | |
| </div> | |
| <!-- Mode robot --> | |
| <div class="robot-mode"> | |
| <i class="fas fa-robot"></i> | |
| MODE ROBOT ACTIVÉ | |
| </div> | |
| <!-- Barre de navigation --> | |
| <nav class="bg-black bg-opacity-90 fixed w-full z-50 border-b border-gray-800"> | |
| <div class="container mx-auto px-4 py-3 flex justify-between items-center"> | |
| <div class="flex items-center space-x-4"> | |
| <a href="#" class="text-red-600 font-bold text-2xl">MegaFlix TURBO</a> | |
| <div class="text-xs bg-green-500 text-black px-2 py-1 rounded-full font-bold">ROBOT MODE</div> | |
| </div> | |
| <div class="flex items-center space-x-4"> | |
| <div class="text-sm text-gray-300"> | |
| <i class="fas fa-bolt mr-1 text-yellow-400"></i> | |
| <span id="load-speed">Chargement: ∞ films/sec</span> | |
| </div> | |
| <div class="text-sm text-gray-300 hidden md:block"> | |
| <i class="fas fa-key mr-1 text-blue-400"></i> | |
| <span>API: TMDB v3</span> | |
| </div> | |
| </div> | |
| </div> | |
| </nav> | |
| <!-- Contenu principal --> | |
| <main class="pt-16 pb-8"> | |
| <!-- Catalogue de films --> | |
| <section class="container mx-auto px-4 py-8"> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h2 class="text-2xl font-bold"> | |
| <i class="fas fa-server mr-2 text-red-500"></i> | |
| BIBLIOTHÈQUE ULTRA-RAPIDE | |
| </h2> | |
| <div class="text-sm text-gray-400"> | |
| <span id="total-films">Chargement des données...</span> | |
| </div> | |
| </div> | |
| <!-- Liste des films --> | |
| <div id="films-container" class="film-grid"> | |
| <!-- Les films seront chargés ici dynamiquement --> | |
| </div> | |
| <!-- Chargement supplémentaire --> | |
| <div id="loading-more" class="text-center py-8 hidden"> | |
| <div class="inline-block animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-red-500 mr-2"></div> | |
| <span>Chargement turbo en cours...</span> | |
| </div> | |
| </section> | |
| </main> | |
| <!-- Lecteur vidéo overlay --> | |
| <div class="player-overlay" id="player-overlay"> | |
| <div class="player-wrapper"> | |
| <button class="close-player" id="close-player"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| <div class="player-container"> | |
| <video id="player" playsinline controls></video> | |
| </div> | |
| <div class="server-container" id="server-container"> | |
| <!-- Les boutons de serveur seront ajoutés ici --> | |
| </div> | |
| <div class="player-controls"> | |
| <button class="player-btn" id="play-btn"> | |
| <i class="fas fa-play"></i> Lecture | |
| </button> | |
| <button class="player-btn" id="pause-btn"> | |
| <i class="fas fa-pause"></i> Pause | |
| </button> | |
| <button class="player-btn" id="fullscreen-btn"> | |
| <i class="fas fa-expand"></i> Plein écran | |
| </button> | |
| <select class="quality-selector" id="quality-selector"> | |
| <option value="auto">Auto</option> | |
| <option value="1080">1080p</option> | |
| <option value="720">720p</option> | |
| <option value="480">480p</option> | |
| </select> | |
| </div> | |
| <div class="film-info" id="film-info"> | |
| <div class="film-title" id="film-title">Titre du film</div> | |
| <div class="film-meta" id="film-meta"> | |
| <span id="film-year">2023</span> | |
| <span id="film-rating"><i class="fas fa-star text-yellow-400"></i> 8.5</span> | |
| <span id="film-duration">2h 15m</span> | |
| </div> | |
| <div class="film-overview" id="film-overview"> | |
| Synopsis du film chargé ici... | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Script principal --> | |
| <script> | |
| // Configuration API TMDB | |
| const API_KEY = 'fb437b10727a5a4eb8d9134e29c82ae0'; | |
| const ACCESS_TOKEN = 'eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJmYjQzN2IxMDcyN2E1YTRlYjhkOTEzNGUyOWM4MmFlMCIsInN1YiI6IjY0MmM3ZmQ2OGI5NTllMDBmNDRkNzNhMCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.Nhl261Ha3z0Ujg5vM1PpFoZBiTGjlXQ1g9VFPh6dVvs'; | |
| const API_URL = 'https://api.themoviedb.org/3'; | |
| const IMAGE_URL = 'https://image.tmdb.org/t/p/w500'; | |
| // API pour les liens de streaming (simulée) | |
| const STREAM_API_URL = 'https://api.streamapi.com/v1/movies'; | |
| // Configuration turbo | |
| const LOAD_SPEED = 20; // films chargés par batch | |
| const LOAD_INTERVAL = 500; // ms entre chaque batch | |
| // Variables globales | |
| let loadedFilms = 0; | |
| let isLoading = false; | |
| let loadInterval; | |
| let lastLoadTime = Date.now(); | |
| let filmsPerSecond = 0; | |
| let totalFilms = 0; | |
| let currentPage = 1; | |
| let player; | |
| let currentFilm = null; | |
| let currentStreamUrl = ''; | |
| let availableServers = []; | |
| // Éléments du DOM | |
| const filmsContainer = document.getElementById('films-container'); | |
| const filmCounter = document.getElementById('film-counter'); | |
| const totalFilmsElement = document.getElementById('total-films'); | |
| const loadSpeedElement = document.getElementById('load-speed'); | |
| const apiStatusElement = document.getElementById('api-status'); | |
| const loadingMoreElement = document.getElementById('loading-more'); | |
| const playerOverlay = document.getElementById('player-overlay'); | |
| const closePlayerBtn = document.getElementById('close-player'); | |
| const playBtn = document.getElementById('play-btn'); | |
| const pauseBtn = document.getElementById('pause-btn'); | |
| const fullscreenBtn = document.getElementById('fullscreen-btn'); | |
| const qualitySelector = document.getElementById('quality-selector'); | |
| const filmTitle = document.getElementById('film-title'); | |
| const filmYear = document.getElementById('film-year'); | |
| const filmRating = document.getElementById('film-rating'); | |
| const filmDuration = document.getElementById('film-duration'); | |
| const filmOverview = document.getElementById('film-overview'); | |
| const serverContainer = document.getElementById('server-container'); | |
| // Initialisation | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Vérifier la connexion API | |
| checkAPI(); | |
| // Démarrer le chargement automatique | |
| startAutoLoading(); | |
| // Configurer le suivi de la vitesse de chargement | |
| setInterval(calculateLoadSpeed, 1000); | |
| // Chargement infini au scroll | |
| window.addEventListener('scroll', turboScrollHandler); | |
| // Initialiser le lecteur vidéo | |
| initPlayer(); | |
| // Écouteurs d'événements pour le lecteur | |
| closePlayerBtn.addEventListener('click', closePlayer); | |
| playBtn.addEventListener('click', playVideo); | |
| pauseBtn.addEventListener('click', pauseVideo); | |
| fullscreenBtn.addEventListener('click', toggleFullscreen); | |
| qualitySelector.addEventListener('change', changeQuality); | |
| }); | |
| // Initialiser le lecteur vidéo | |
| function initPlayer() { | |
| player = new Plyr('#player', { | |
| controls: ['play-large', 'play', 'progress', 'current-time', 'mute', 'volume', 'captions', 'settings', 'pip', 'airplay', 'fullscreen'], | |
| settings: ['quality', 'speed'], | |
| keyboard: { focused: true, global: true } | |
| }); | |
| // Détection HLS | |
| if (Hls.isSupported()) { | |
| const hls = new Hls(); | |
| hls.on(Hls.Events.MANIFEST_PARSED, function(event, data) { | |
| const availableQualities = hls.levels.map(level => level.height); | |
| // Mettre à jour le sélecteur de qualité | |
| updateQualitySelector(availableQualities); | |
| }); | |
| window.hls = hls; | |
| } | |
| } | |
| // Mettre à jour le sélecteur de qualité | |
| function updateQualitySelector(qualities) { | |
| qualitySelector.innerHTML = ''; | |
| // Ajouter l'option auto | |
| const autoOption = document.createElement('option'); | |
| autoOption.value = 'auto'; | |
| autoOption.textContent = 'Auto'; | |
| qualitySelector.appendChild(autoOption); | |
| // Ajouter les qualités disponibles | |
| qualities.forEach(quality => { | |
| const option = document.createElement('option'); | |
| option.value = quality; | |
| option.textContent = `${quality}p`; | |
| qualitySelector.appendChild(option); | |
| }); | |
| } | |
| // Jouer la vidéo | |
| function playVideo() { | |
| player.play(); | |
| } | |
| // Mettre en pause la vidéo | |
| function pauseVideo() { | |
| player.pause(); | |
| } | |
| // Basculer en plein écran | |
| function toggleFullscreen() { | |
| player.fullscreen.toggle(); | |
| } | |
| // Changer la qualité | |
| function changeQuality() { | |
| const quality = qualitySelector.value; | |
| if (window.hls) { | |
| if (quality === 'auto') { | |
| window.hls.currentLevel = -1; // auto | |
| } else { | |
| const level = window.hls.levels.findIndex(l => l.height === parseInt(quality)); | |
| if (level >= 0) { | |
| window.hls.currentLevel = level; | |
| } | |
| } | |
| } | |
| } | |
| // Fermer le lecteur | |
| function closePlayer() { | |
| playerOverlay.style.display = 'none'; | |
| player.pause(); | |
| document.body.style.overflow = 'auto'; | |
| } | |
| // Ouvrir le lecteur avec un film | |
| async function openPlayer(film) { | |
| currentFilm = film; | |
| // Mettre à jour les infos du film | |
| filmTitle.textContent = film.title; | |
| filmYear.textContent = film.release_date ? new Date(film.release_date).getFullYear() : 'N/A'; | |
| filmRating.innerHTML = `<i class="fas fa-star text-yellow-400"></i> ${film.vote_average ? film.vote_average.toFixed(1) : 'N/A'}`; | |
| filmDuration.textContent = '2h 15m'; // Durée simulée | |
| filmOverview.textContent = film.overview || 'Aucun synopsis disponible.'; | |
| // Afficher l'overlay | |
| playerOverlay.style.display = 'flex'; | |
| document.body.style.overflow = 'hidden'; | |
| // Charger les liens de streaming | |
| await loadStreamingLinks(film); | |
| } | |
| // Charger les liens de streaming pour un film | |
| async function loadStreamingLinks(film) { | |
| // Simuler une requête API pour obtenir les liens de streaming | |
| // En réalité, vous utiliseriez une vraie API comme Allocine, JustWatch, etc. | |
| // Afficher un message de chargement | |
| serverContainer.innerHTML = '<div class="text-gray-400">Chargement des serveurs...</div>'; | |
| try { | |
| // Simuler un délai de chargement | |
| await new Promise(resolve => setTimeout(resolve, 800)); | |
| // Générer des serveurs simulés avec des liens de streaming | |
| availableServers = [ | |
| { name: 'Serveur Turbo 1', url: generateStreamUrl(film.id, 1), type: 'hls' }, | |
| { name: 'Serveur Turbo 2', url: generateStreamUrl(film.id, 2), type: 'mp4' }, | |
| { name: 'Serveur Premium', url: generateStreamUrl(film.id, 3), type: 'hls' }, | |
| { name: 'Serveur Rapide', url: generateStreamUrl(film.id, 4), type: 'mp4' } | |
| ]; | |
| // Afficher les boutons de serveur | |
| updateServerButtons(); | |
| // Sélectionner le premier serveur par défaut | |
| if (availableServers.length > 0) { | |
| changeServer(availableServers[0]); | |
| } | |
| } catch (error) { | |
| console.error('Erreur lors du chargement des liens:', error); | |
| serverContainer.innerHTML = '<div class="text-red-500">Erreur de chargement des serveurs</div>'; | |
| } | |
| } | |
| // Générer une URL de streaming simulée | |
| function generateStreamUrl(movieId, serverId) { | |
| // En réalité, vous utiliseriez une vraie API pour obtenir ces URLs | |
| const baseUrls = [ | |
| `https://vidsrc.to/embed/movie/${movieId}`, | |
| `https://2embed.org/embed/${movieId}`, | |
| `https://www.2embed.cc/embed/${movieId}`, | |
| `https://multiembed.mov/?video_id=${movieId}&tmdb=1` | |
| ]; | |
| return baseUrls[serverId % baseUrls.length]; | |
| } | |
| // Mettre à jour les boutons de serveur | |
| function updateServerButtons() { | |
| serverContainer.innerHTML = ''; | |
| availableServers.forEach((server, index) => { | |
| const btn = document.createElement('button'); | |
| btn.className = 'server-btn'; | |
| btn.textContent = server.name; | |
| btn.onclick = () => changeServer(server); | |
| if (index === 0) { | |
| btn.classList.add('active'); | |
| } | |
| serverContainer.appendChild(btn); | |
| }); | |
| } | |
| // Changer de serveur | |
| function changeServer(server) { | |
| // Mettre à jour le bouton actif | |
| document.querySelectorAll('.server-btn').forEach(btn => { | |
| btn.classList.remove('active'); | |
| if (btn.textContent === server.name) { | |
| btn.classList.add('active'); | |
| } | |
| }); | |
| // Charger la vidéo depuis le nouveau serveur | |
| loadVideoFromServer(server.url, server.type); | |
| } | |
| // Charger la vidéo depuis un serveur | |
| function loadVideoFromServer(url, type) { | |
| currentStreamUrl = url; | |
| // Réinitialiser le lecteur | |
| if (player) { | |
| player.stop(); | |
| } | |
| // Configurer la source vidéo en fonction du type | |
| if (type === 'hls' && Hls.isSupported()) { | |
| // Pour les streams HLS | |
| if (window.hls) { | |
| window.hls.destroy(); | |
| } | |
| window.hls = new Hls(); | |
| window.hls.loadSource(url); | |
| window.hls.attachMedia(document.getElementById('player')); | |
| window.hls.on(Hls.Events.MANIFEST_PARSED, function() { | |
| player.play(); | |
| }); | |
| } else { | |
| // Pour les MP4 standard | |
| player.source = { | |
| type: 'video', | |
| sources: [{ | |
| src: url, | |
| type: type === 'hls' ? 'application/x-mpegURL' : 'video/mp4' | |
| }] | |
| }; | |
| player.play(); | |
| } | |
| } | |
| // Vérifier la connexion API | |
| async function checkAPI() { | |
| try { | |
| const response = await fetch(`${API_URL}/configuration?api_key=${API_KEY}`, { | |
| headers: { | |
| 'Authorization': `Bearer ${ACCESS_TOKEN}`, | |
| 'Content-Type': 'application/json;charset=utf-8' | |
| } | |
| }); | |
| if (response.ok) { | |
| const data = await response.json(); | |
| apiStatusElement.innerHTML = `<i class="fas fa-check-circle text-green-500 mr-2"></i> API connectée (${data.images.secure_base_url})`; | |
| // Récupérer le nombre total de films | |
| fetchTotalMovies(); | |
| } else { | |
| apiStatusElement.innerHTML = `<i class="fas fa-times-circle text-red-500 mr-2"></i> Erreur API: ${response.status}`; | |
| } | |
| } catch (error) { | |
| apiStatusElement.innerHTML = `<i class="fas fa-times-circle text-red-500 mr-2"></i> Erreur: ${error.message}`; | |
| } | |
| } | |
| // Récupérer le nombre total de films | |
| async function fetchTotalMovies() { | |
| try { | |
| const response = await fetch(`${API_URL}/discover/movie?api_key=${API_KEY}&page=1`, { | |
| headers: { | |
| 'Authorization': `Bearer ${ACCESS_TOKEN}`, | |
| 'Content-Type': 'application/json;charset=utf-8' | |
| } | |
| }); | |
| if (response.ok) { | |
| const data = await response.json(); | |
| totalFilms = data.total_results; | |
| totalFilmsElement.textContent = `${totalFilms.toLocaleString()} films disponibles`; | |
| // Animer le compteur | |
| animateCounter(totalFilmsElement, totalFilms); | |
| } | |
| } catch (error) { | |
| console.error('Erreur:', error); | |
| totalFilmsElement.textContent = "Données indisponibles"; | |
| } | |
| } | |
| // Animer un compteur | |
| function animateCounter(element, target) { | |
| let current = 0; | |
| const increment = target / 50; | |
| const interval = setInterval(() => { | |
| current += increment; | |
| if (current >= target) { | |
| current = target; | |
| clearInterval(interval); | |
| } | |
| element.textContent = Math.floor(current).toLocaleString() + ' films disponibles'; | |
| }, 20); | |
| } | |
| // Démarrer le chargement automatique | |
| function startAutoLoading() { | |
| loadInterval = setInterval(() => { | |
| if (!isLoading) { | |
| loadFilmsBatch(); | |
| } | |
| }, LOAD_INTERVAL); | |
| } | |
| // Charger un batch de films depuis l'API TMDB | |
| async function loadFilmsBatch() { | |
| if (isLoading) return; | |
| isLoading = true; | |
| loadingMoreElement.classList.remove('hidden'); | |
| try { | |
| const response = await fetch(`${API_URL}/discover/movie?api_key=${API_KEY}&page=${currentPage}&sort_by=popularity.desc`, { | |
| headers: { | |
| 'Authorization': `Bearer ${ACCESS_TOKEN}`, | |
| 'Content-Type': 'application/json;charset=utf-8' | |
| } | |
| }); | |
| if (response.ok) { | |
| const data = await response.json(); | |
| const fragment = document.createDocumentFragment(); | |
| // Limiter à LOAD_SPEED films par batch | |
| const filmsToLoad = data.results.slice(0, LOAD_SPEED); | |
| filmsToLoad.forEach(film => { | |
| const filmCard = createFilmCard(film); | |
| fragment.appendChild(filmCard); | |
| loadedFilms++; | |
| }); | |
| filmsContainer.appendChild(fragment); | |
| filmCounter.textContent = `Chargement: ${loadedFilms.toLocaleString()}/${totalFilms.toLocaleString()}`; | |
| // Mettre à jour le compteur de vitesse | |
| filmsPerSecond += filmsToLoad.length; | |
| // Passer à la page suivante | |
| currentPage++; | |
| // Si on a atteint la fin des résultats, recommencer à la page 1 | |
| if (currentPage > data.total_pages) { | |
| currentPage = 1; | |
| } | |
| } | |
| } catch (error) { | |
| console.error('Erreur:', error); | |
| } finally { | |
| isLoading = false; | |
| loadingMoreElement.classList.add('hidden'); | |
| lastLoadTime = Date.now(); | |
| } | |
| } | |
| // Calculer la vitesse de chargement | |
| function calculateLoadSpeed() { | |
| const speed = filmsPerSecond; | |
| filmsPerSecond = 0; | |
| let speedText; | |
| if (speed > 1000) { | |
| speedText = `${(speed/1000).toFixed(1)}k films/sec`; | |
| } else { | |
| speedText = `${speed} films/sec`; | |
| } | |
| loadSpeedElement.textContent = `Vitesse: ${speedText}`; | |
| } | |
| // Gérer le scroll en mode turbo | |
| function turboScrollHandler() { | |
| if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 500) { | |
| // Charger immédiatement un nouveau batch | |
| if (!isLoading && Date.now() - lastLoadTime > LOAD_INTERVAL) { | |
| loadFilmsBatch(); | |
| } | |
| } | |
| } | |
| // Créer une carte de film | |
| function createFilmCard(film) { | |
| const card = document.createElement('div'); | |
| card.className = `film-card group`; | |
| // Image du film | |
| const imgUrl = film.poster_path | |
| ? `${IMAGE_URL}${film.poster_path}` | |
| : 'https://via.placeholder.com/500x750?text=Aucune+image'; | |
| // Date de sortie formatée | |
| const releaseDate = film.release_date | |
| ? new Date(film.release_date).getFullYear() | |
| : 'N/A'; | |
| // Note arrondie | |
| const voteAverage = film.vote_average | |
| ? film.vote_average.toFixed(1) | |
| : 'N/A'; | |
| card.innerHTML = ` | |
| <div class="relative overflow-hidden rounded-lg shadow-lg h-full bg-gray-800"> | |
| <img src="${imgUrl}" alt="${film.title}" | |
| class="w-full h-full object-cover transition-transform duration-300 group-hover:scale-110"> | |
| <div class="absolute inset-0 bg-black bg-opacity-40 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity"> | |
| <div class="play-icon transform translate-y-4 opacity-0 group-hover:opacity-100 group-hover:translate-y-0 transition-all duration-300"> | |
| <i class="fas fa-play-circle text-5xl text-red-600"></i> | |
| </div> | |
| </div> | |
| <div class="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black to-transparent p-4"> | |
| <h3 class="font-bold truncate">${film.title}</h3> | |
| <div class="flex justify-between text-xs text-gray-300 mt-1"> | |
| <span>${releaseDate} • ${film.original_language.toUpperCase()}</span> | |
| <span class="flex items-center"> | |
| <i class="fas fa-star text-yellow-400 mr-1"></i> ${voteAverage} | |
| </span> | |
| </div> | |
| </div> | |
| <div class="absolute top-2 right-2 bg-green-500 text-black text-xs px-2 py-1 rounded font-bold"> | |
| #${film.id.toString().padStart(8, '0')} | |
| </div> | |
| </div> | |
| `; | |
| // Ajouter l'événement de clic pour ouvrir le lecteur | |
| card.addEventListener('click', () => openPlayer(film)); | |
| return card; | |
| } | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=docto41/stream-cine" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |