Spaces:
Running
Running
| <html lang="fr"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>StreamHub Pro - Plateforme de Streaming Automatisée</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> | |
| @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;600;700;800;900&family=Roboto:wght@300;400;500;700&display=swap'); | |
| :root { | |
| --primary: #00f0ff; | |
| --secondary: #ff00f0; | |
| --dark: #0a0a1a; | |
| --light: #f0f0ff; | |
| } | |
| body { | |
| font-family: 'Roboto', sans-serif; | |
| background-color: var(--dark); | |
| color: var(--light); | |
| overflow-x: hidden; | |
| } | |
| .font-orbitron { | |
| font-family: 'Orbitron', sans-serif; | |
| } | |
| .glow-text { | |
| text-shadow: 0 0 10px var(--primary), 0 0 20px var(--primary); | |
| } | |
| .glow-box { | |
| box-shadow: 0 0 15px var(--primary), 0 0 30px rgba(0, 240, 255, 0.3); | |
| } | |
| .pulse { | |
| animation: pulse 2s infinite; | |
| } | |
| @keyframes pulse { | |
| 0% { opacity: 1; } | |
| 50% { opacity: 0.7; } | |
| 100% { opacity: 1; } | |
| } | |
| .holographic { | |
| background: linear-gradient(135deg, rgba(0, 240, 255, 0.1), rgba(255, 0, 240, 0.1)); | |
| backdrop-filter: blur(10px); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| } | |
| .neon-border { | |
| position: relative; | |
| } | |
| .neon-border::before { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| border: 2px solid transparent; | |
| border-radius: inherit; | |
| background: linear-gradient(135deg, var(--primary), var(--secondary)) border-box; | |
| -webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0); | |
| -webkit-mask-composite: destination-out; | |
| mask-composite: exclude; | |
| pointer-events: none; | |
| } | |
| .scanline { | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .scanline::after { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| height: 2px; | |
| background: rgba(0, 240, 255, 0.3); | |
| animation: scan 8s linear infinite; | |
| } | |
| @keyframes scan { | |
| 0% { top: -2px; } | |
| 100% { top: 100%; } | |
| } | |
| .matrix-fall { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><rect width="1" height="1" fill="rgba(0,240,255,0.1)"/></svg>'); | |
| opacity: 0.05; | |
| pointer-events: none; | |
| } | |
| .movie-card { | |
| transition: all 0.3s ease; | |
| transform-style: preserve-3d; | |
| } | |
| .movie-card:hover { | |
| transform: translateY(-10px) scale(1.03) rotateX(5deg); | |
| z-index: 10; | |
| } | |
| .player-container { | |
| aspect-ratio: 16/9; | |
| background: linear-gradient(135deg, #0a0a1a, #0a0a2a); | |
| } | |
| .quality-badge { | |
| position: absolute; | |
| top: 10px; | |
| right: 10px; | |
| font-size: 12px; | |
| padding: 2px 6px; | |
| border-radius: 4px; | |
| font-weight: bold; | |
| } | |
| .PM4 { background: linear-gradient(135deg, #ff0000, #ff6600); } | |
| .EMB { background: linear-gradient(135deg, #00ff00, #00cc00); } | |
| .HD { background: linear-gradient(135deg, #0066ff, #0033cc); } | |
| .UHD { background: linear-gradient(135deg, #cc00ff, #9900cc); } | |
| .loading-dots::after { | |
| content: '.'; | |
| animation: dots 1.5s steps(5, end) infinite; | |
| } | |
| @keyframes dots { | |
| 0%, 20% { content: '.'; } | |
| 40% { content: '..'; } | |
| 60% { content: '...'; } | |
| 80%, 100% { content: ''; } | |
| } | |
| .grid-stack { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); | |
| gap: 20px; | |
| } | |
| @media (max-width: 768px) { | |
| .grid-stack { | |
| grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); | |
| gap: 15px; | |
| } | |
| } | |
| .floating-nav { | |
| animation: float 6s ease-in-out infinite; | |
| } | |
| @keyframes float { | |
| 0% { transform: translateY(0px); } | |
| 50% { transform: translateY(-10px); } | |
| 100% { transform: translateY(0px); } | |
| } | |
| /* Animation de chargement */ | |
| @keyframes spin { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| .loader { | |
| border: 4px solid rgba(0, 240, 255, 0.3); | |
| border-radius: 50%; | |
| border-top: 4px solid var(--primary); | |
| width: 40px; | |
| height: 40px; | |
| animation: spin 1s linear infinite; | |
| } | |
| /* Auto-play animation */ | |
| .autoplay-indicator { | |
| position: absolute; | |
| bottom: 20px; | |
| left: 20px; | |
| background: rgba(0, 0, 0, 0.7); | |
| padding: 5px 10px; | |
| border-radius: 20px; | |
| display: flex; | |
| align-items: center; | |
| z-index: 10; | |
| } | |
| .autoplay-indicator i { | |
| margin-right: 5px; | |
| color: var(--primary); | |
| } | |
| /* Server status indicators */ | |
| .server-status { | |
| display: inline-block; | |
| width: 10px; | |
| height: 10px; | |
| border-radius: 50%; | |
| margin-right: 5px; | |
| } | |
| .server-online { | |
| background-color: #00ff00; | |
| box-shadow: 0 0 10px #00ff00; | |
| } | |
| .server-offline { | |
| background-color: #ff0000; | |
| } | |
| .server-busy { | |
| background-color: #ffff00; | |
| box-shadow: 0 0 10px #ffff00; | |
| } | |
| /* Server selection panel */ | |
| .server-panel { | |
| max-height: 300px; | |
| overflow-y: auto; | |
| scrollbar-width: thin; | |
| scrollbar-color: var(--primary) var(--dark); | |
| } | |
| .server-panel::-webkit-scrollbar { | |
| width: 6px; | |
| } | |
| .server-panel::-webkit-scrollbar-track { | |
| background: var(--dark); | |
| } | |
| .server-panel::-webkit-scrollbar-thumb { | |
| background-color: var(--primary); | |
| border-radius: 6px; | |
| } | |
| /* Server card */ | |
| .server-card { | |
| transition: all 0.2s ease; | |
| } | |
| .server-card:hover { | |
| transform: translateX(5px); | |
| } | |
| .server-card.selected { | |
| border-left: 3px solid var(--primary); | |
| background: rgba(0, 240, 255, 0.1); | |
| } | |
| </style> | |
| <!-- Video.js pour le lecteur vidéo --> | |
| <link href="https://vjs.zencdn.net/8.10.0/video-js.css" rel="stylesheet" /> | |
| <!-- YouTube API --> | |
| <script src="https://www.youtube.com/iframe_api"></script> | |
| </head> | |
| <body class="relative"> | |
| <!-- Effet Matrix en arrière-plan --> | |
| <div class="matrix-fall"></div> | |
| <!-- Barre de chargement initiale --> | |
| <div id="init-loader" class="fixed inset-0 z-50 flex flex-col items-center justify-center bg-black bg-opacity-90 transition-opacity duration-1000"> | |
| <div class="text-4xl md:text-6xl font-orbitron mb-8 glow-text"> | |
| <span class="text-primary">STREAM</span><span class="text-secondary">HUB</span> <span class="text-primary">PRO</span> | |
| </div> | |
| <div class="w-3/4 md:w-1/2 h-2 bg-gray-800 rounded-full overflow-hidden"> | |
| <div id="progress-bar" class="h-full bg-gradient-to-r from-secondary to-primary" style="width: 0%"></div> | |
| </div> | |
| <div class="mt-4 text-lg font-orbitron"> | |
| Initialisation des serveurs robotisés <span class="loading-dots"></span> | |
| </div> | |
| <div class="mt-2 text-sm opacity-70"> | |
| <span id="server-count">0</span>/12 serveurs connectés | |
| </div> | |
| </div> | |
| <!-- Interface principale --> | |
| <div id="main-interface" class="hidden min-h-screen"> | |
| <!-- En-tête holographique --> | |
| <header class="holographic sticky top-0 z-40"> | |
| <div class="container mx-auto px-4 py-3 flex items-center justify-between"> | |
| <div class="flex items-center space-x-4"> | |
| <div class="text-2xl md:text-3xl font-orbitron glow-text"> | |
| <span class="text-primary">STREAM</span><span class="text-secondary">HUB</span> <span class="text-primary">PRO</span> | |
| </div> | |
| <div class="hidden md:block text-sm bg-black bg-opacity-50 px-3 py-1 rounded-full"> | |
| <span class="text-primary" id="total-movies">0</span> contenus disponibles | |
| </div> | |
| </div> | |
| <div class="flex items-center space-x-4"> | |
| <div class="relative group"> | |
| <button class="px-4 py-2 bg-black bg-opacity-50 rounded-full flex items-center space-x-2 hover:bg-opacity-70 transition"> | |
| <i class="fas fa-server text-primary"></i> | |
| <span>Serveurs</span> | |
| </button> | |
| <div class="absolute right-0 mt-2 w-64 bg-black bg-opacity-90 rounded-lg shadow-lg hidden group-hover:block z-50"> | |
| <div class="p-3 font-orbitron text-sm border-b border-gray-700"> | |
| Statut des serveurs | |
| </div> | |
| <div id="server-status-list" class="max-h-60 overflow-y-auto"> | |
| <!-- Les serveurs seront ajoutés dynamiquement ici --> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="relative group"> | |
| <button class="px-4 py-2 bg-black bg-opacity-50 rounded-full flex items-center space-x-2 hover:bg-opacity-70 transition"> | |
| <i class="fas fa-user text-primary"></i> | |
| <span>Profil</span> | |
| </button> | |
| <div class="absolute right-0 mt-2 w-48 bg-black bg-opacity-90 rounded-lg shadow-lg hidden group-hover:block z-50"> | |
| <div class="py-1"> | |
| <a href="#" class="block px-4 py-2 hover:bg-primary hover:bg-opacity-20">Mon compte</a> | |
| <a href="#" class="block px-4 py-2 hover:bg-primary hover:bg-opacity-20">Paramètres</a> | |
| <a href="#" class="block px-4 py-2 hover:bg-primary hover:bg-opacity-20">Déconnexion</a> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="relative"> | |
| <button id="search-toggle" class="w-10 h-10 flex items-center justify-center rounded-full bg-black bg-opacity-50 hover:bg-opacity-70 transition"> | |
| <i class="fas fa-search text-primary"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Barre de recherche avancée --> | |
| <div id="search-bar" class="hidden container mx-auto px-4 pb-4"> | |
| <div class="relative"> | |
| <input id="search-input" type="text" placeholder="Rechercher des films, séries..." | |
| class="w-full bg-black bg-opacity-50 border border-primary border-opacity-30 rounded-full px-6 py-3 text-white focus:outline-none focus:ring-2 focus:ring-primary focus:ring-opacity-50"> | |
| <button id="search-button" class="absolute right-3 top-3 bg-primary text-black rounded-full w-8 h-8 flex items-center justify-center"> | |
| <i class="fas fa-arrow-right"></i> | |
| </button> | |
| </div> | |
| <div class="flex flex-wrap gap-3 mt-3"> | |
| <select id="genre-filter" class="bg-black bg-opacity-50 border border-primary border-opacity-30 rounded-full px-4 py-2 text-white focus:outline-none text-sm"> | |
| <option value="">Tous les genres</option> | |
| </select> | |
| <select id="year-filter" class="bg-black bg-opacity-50 border border-primary border-opacity-30 rounded-full px-4 py-2 text-white focus:outline-none text-sm"> | |
| <option value="">Toutes les années</option> | |
| </select> | |
| <select id="quality-filter" class="bg-black bg-opacity-50 border border-primary border-opacity-30 rounded-full px-4 py-2 text-white focus:outline-none text-sm"> | |
| <option value="">Toutes les qualités</option> | |
| <option value="PM4">PM4</option> | |
| <option value="EMB">EMB</option> | |
| <option value="HD">HD</option> | |
| <option value="UHD">UHD</option> | |
| </select> | |
| <select id="language-filter" class="bg-black bg-opacity-50 border border-primary border-opacity-30 rounded-full px-4 py-2 text-white focus:outline-none text-sm"> | |
| <option value="">Toutes les langues</option> | |
| <option value="fr">Français</option> | |
| <option value="en">Anglais</option> | |
| <option value="vostfr">VOSTFR</option> | |
| </select> | |
| </div> | |
| </div> | |
| </header> | |
| <!-- Contenu principal --> | |
| <main class="container mx-auto px-4 py-6 relative"> | |
| <!-- Lecteur principal --> | |
| <div id="player-section" class="mb-8 glow-box rounded-xl overflow-hidden neon-border hidden"> | |
| <div class="player-container relative"> | |
| <div id="youtube-player"></div> | |
| <div id="autoplay-indicator" class="autoplay-indicator hidden"> | |
| <i class="fas fa-play"></i> | |
| <span>Lecture automatique dans <span id="countdown">5</span>s</span> | |
| </div> | |
| </div> | |
| <div class="bg-black bg-opacity-70 p-4 flex items-center justify-between"> | |
| <div class="flex items-center space-x-4"> | |
| <button id="play-button" class="w-10 h-10 rounded-full bg-primary bg-opacity-20 hover:bg-opacity-40 flex items-center justify-center"> | |
| <i class="fas fa-play text-primary"></i> | |
| </button> | |
| <div class="text-sm"> | |
| <div id="now-playing-title" class="font-orbitron">Aucun contenu sélectionné</div> | |
| <div id="now-playing-quality" class="opacity-70 text-xs">Prêt à diffuser</div> | |
| </div> | |
| </div> | |
| <div class="flex items-center space-x-3"> | |
| <button id="server-button" class="w-8 h-8 rounded-full bg-black bg-opacity-50 hover:bg-opacity-70 flex items-center justify-center"> | |
| <i class="fas fa-server text-primary"></i> | |
| </button> | |
| <button id="subtitles-button" class="w-8 h-8 rounded-full bg-black bg-opacity-50 hover:bg-opacity-70 flex items-center justify-center"> | |
| <i class="fas fa-closed-captioning text-primary"></i> | |
| </button> | |
| <button id="settings-button" class="w-8 h-8 rounded-full bg-black bg-opacity-50 hover:bg-opacity-70 flex items-center justify-center"> | |
| <i class="fas fa-cog text-primary"></i> | |
| </button> | |
| <button id="fullscreen-button" class="w-8 h-8 rounded-full bg-black bg-opacity-50 hover:bg-opacity-70 flex items-center justify-center"> | |
| <i class="fas fa-expand text-primary"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Navigation flottante --> | |
| <div class="floating-nav sticky top-20 z-30 mb-6 bg-black bg-opacity-70 rounded-full px-4 py-2 flex justify-center space-x-1 md:space-x-4"> | |
| <button data-category="popular" class="px-3 md:px-4 py-1 rounded-full bg-primary text-black font-medium text-sm">Tendance</button> | |
| <button data-category="now_playing" class="px-3 md:px-4 py-1 rounded-full hover:bg-white hover:bg-opacity-10 text-sm">Nouveautés</button> | |
| <button data-category="top_rated" class="px-3 md:px-4 py-1 rounded-full hover:bg-white hover:bg-opacity-10 text-sm">Populaire</button> | |
| <button data-category="upcoming" class="px-3 md:px-4 py-1 rounded-full hover:bg-white hover:bg-opacity-10 text-sm">Prochainement</button> | |
| <button id="random-movie" class="px-3 md:px-4 py-1 rounded-full hover:bg-white hover:bg-opacity-10 text-sm">Aléatoire</button> | |
| <button data-category="watchlist" class="px-3 md:px-4 py-1 rounded-full hover:bg-white hover:bg-opacity-10 text-sm">Ma liste</button> | |
| </div> | |
| <!-- Sections de films --> | |
| <div id="movies-container" class="space-y-10"> | |
| <!-- Les films seront chargés ici dynamiquement --> | |
| <div class="flex justify-center items-center py-20"> | |
| <div class="loader"></div> | |
| </div> | |
| </div> | |
| </main> | |
| <!-- Pied de page --> | |
| <footer class="bg-black bg-opacity-70 mt-20 py-8"> | |
| <div class="container mx-auto px-4"> | |
| <div class="grid grid-cols-1 md:grid-cols-4 gap-8"> | |
| <div> | |
| <h3 class="font-orbitron text-lg mb-4">StreamHub Pro</h3> | |
| <p class="text-sm opacity-70">Plateforme de streaming automatisée avec 12 serveurs robotisés pour une expérience optimale.</p> | |
| </div> | |
| <div> | |
| <h3 class="font-orbitron text-lg mb-4">Navigation</h3> | |
| <ul class="space-y-2"> | |
| <li><a href="#" class="text-sm hover:text-primary transition">Accueil</a></li> | |
| <li><a href="#" class="text-sm hover:text-primary transition">Nouveautés</a></li> | |
| <li><a href="#" class="text-sm hover:text-primary transition">Tendances</a></li> | |
| <li><a href="#" class="text-sm hover:text-primary transition">Ma liste</a></li> | |
| </ul> | |
| </div> | |
| <div> | |
| <h3 class="font-orbitron text-lg mb-4">Serveurs</h3> | |
| <ul class="space-y-2"> | |
| <li><a href="#" class="text-sm hover:text-primary transition">Statut des serveurs</a></li> | |
| <li><a href="#" class="text-sm hover:text-primary transition">Serveurs Français</a></li> | |
| <li><a href="#" class="text-sm hover:text-primary transition">Serveurs Internationaux</a></li> | |
| <li><a href="#" class="text-sm hover:text-primary transition">Serveurs Premium</a></li> | |
| </ul> | |
| </div> | |
| <div> | |
| <h3 class="font-orbitron text-lg mb-4">Contact</h3> | |
| <div class="flex space-x-4 mb-4"> | |
| <a href="#" class="w-8 h-8 rounded-full bg-primary bg-opacity-20 hover:bg-opacity-40 flex items-center justify-center"> | |
| <i class="fab fa-twitter"></i> | |
| </a> | |
| <a href="#" class="w-8 h-8 rounded-full bg-primary bg-opacity-20 hover:bg-opacity-40 flex items-center justify-center"> | |
| <i class="fab fa-facebook-f"></i> | |
| </a> | |
| <a href="#" class="w-8 h-8 rounded-full bg-primary bg-opacity-20 hover:bg-opacity-40 flex items-center justify-center"> | |
| <i class="fab fa-instagram"></i> | |
| </a> | |
| <a href="#" class="w-8 h-8 rounded-full bg-primary bg-opacity-20 hover:bg-opacity-40 flex items-center justify-center"> | |
| <i class="fab fa-discord"></i> | |
| </a> | |
| </div> | |
| <p class="text-xs opacity-50">© 2024 StreamHub Pro. Tous droits réservés.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </footer> | |
| </div> | |
| <!-- Panneau latéral pour les détails du film --> | |
| <div id="movie-details" class="fixed top-0 right-0 h-full w-full md:w-1/3 bg-black bg-opacity-90 backdrop-blur-lg transform translate-x-full transition-transform duration-300 z-50 overflow-y-auto"> | |
| <div class="p-6"> | |
| <button id="close-details" class="absolute top-4 right-4 w-10 h-10 rounded-full bg-primary bg-opacity-20 hover:bg-opacity-40 flex items-center justify-center"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| <div class="mt-8"> | |
| <div class="relative pb-[150%] rounded-lg overflow-hidden mb-6"> | |
| <img id="detail-poster" src="" alt="Film détaillé" class="absolute h-full w-full object-cover"> | |
| </div> | |
| <h2 id="detail-title" class="text-2xl md:text-3xl font-orbitron mb-2"></h2> | |
| <div class="flex items-center space-x-4 mb-4"> | |
| <span id="detail-year" class="text-sm opacity-80"></span> | |
| <span id="detail-rating" class="flex items-center text-sm"> | |
| <i class="fas fa-star text-yellow-400 mr-1"></i> | |
| </span> | |
| <span id="detail-quality" class="px-2 py-1 rounded-full text-xs font-bold"></span> | |
| </div> | |
| <div class="mb-6"> | |
| <h3 class="font-orbitron text-lg mb-2">Synopsis</h3> | |
| <p id="detail-synopsis" class="text-sm opacity-90"></p> | |
| </div> | |
| <div class="mb-6"> | |
| <h3 class="font-orbitron text-lg mb-2">Informations</h3> | |
| <div class="grid grid-cols-2 gap-4 text-sm"> | |
| <div> | |
| <p class="opacity-70">Réalisateur:</p> | |
| <p id="detail-director" class="opacity-90"></p> | |
| </div> | |
| <div> | |
| <p class="opacity-70">Acteurs:</p> | |
| <p id="detail-actors" class="opacity-90"></p> | |
| </div> | |
| <div> | |
| <p class="opacity-70">Genre:</p> | |
| <p id="detail-genre" class="opacity-90"></p> | |
| </div> | |
| <div> | |
| <p class="opacity-70">Durée:</p> | |
| <p id="detail-duration" class="opacity-90"></p> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="mb-6"> | |
| <h3 class="font-orbitron text-lg mb-2">Serveurs disponibles</h3> | |
| <div id="server-panel" class="server-panel bg-black bg-opacity-50 rounded-lg p-3"> | |
| <!-- Les serveurs seront ajoutés dynamiquement ici --> | |
| </div> | |
| </div> | |
| <button id="play-movie-btn" class="w-full py-3 bg-primary text-black rounded-lg font-orbitron flex items-center justify-center space-x-2 hover:bg-opacity-90 transition"> | |
| <i class="fas fa-play"></i> | |
| <span>Lire automatiquement</span> | |
| </button> | |
| <div class="mt-4 text-xs opacity-70"> | |
| <p>Les serveurs robotisés détectent automatiquement le meilleur flux disponible.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Panneau de sélection des serveurs --> | |
| <div id="server-selection" class="fixed inset-0 bg-black bg-opacity-90 z-50 hidden flex items-center justify-center"> | |
| <div class="bg-gray-900 rounded-xl w-full max-w-2xl max-h-[90vh] overflow-hidden neon-border"> | |
| <div class="p-4 border-b border-gray-800 flex justify-between items-center"> | |
| <h3 class="font-orbitron text-lg">Sélection du serveur</h3> | |
| <button id="close-server-selection" class="w-8 h-8 rounded-full bg-black bg-opacity-50 hover:bg-opacity-70 flex items-center justify-center"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <div class="p-4"> | |
| <div class="flex items-center mb-4"> | |
| <div class="relative flex-1"> | |
| <input type="text" id="server-search" placeholder="Rechercher un serveur..." class="w-full bg-black bg-opacity-50 border border-primary border-opacity-30 rounded-full px-4 py-2 text-white focus:outline-none text-sm"> | |
| <button class="absolute right-3 top-2"> | |
| <i class="fas fa-search text-primary text-sm"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="server-panel space-y-2"> | |
| <!-- Les serveurs seront ajoutés dynamiquement ici --> | |
| </div> | |
| </div> | |
| <div class="p-4 border-t border-gray-800 flex justify-end"> | |
| <button id="confirm-server" class="px-4 py-2 bg-primary text-black rounded-lg font-orbitron hover:bg-opacity-90 transition"> | |
| Confirmer la sélection | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Scripts --> | |
| <script src="https://vjs.zencdn.net/8.10.0/video.min.js"></script> | |
| <script> | |
| // Configuration de l'API TMDB | |
| const API_KEY = 'fb437b10727a5a4eb8d9134e29c82ae0'; | |
| const BASE_URL = 'https://api.themoviedb.org/3'; | |
| const IMAGE_BASE_URL = 'https://image.tmdb.org/t/p/w500'; | |
| const LANGUAGE = 'fr-FR'; | |
| // Serveurs robotisés | |
| const SERVERS = [ | |
| { id: 'fr1', name: 'Serveur Français #1', country: 'fr', status: 'online', type: 'premium', speed: 'high', languages: ['fr', 'vostfr'], quality: ['HD', 'UHD'] }, | |
| { id: 'fr2', name: 'Serveur Français #2', country: 'fr', status: 'online', type: 'standard', speed: 'medium', languages: ['fr'], quality: ['HD'] }, | |
| { id: 'fr3', name: 'Serveur Français #3', country: 'fr', status: 'online', type: 'premium', speed: 'high', languages: ['fr', 'vostfr'], quality: ['UHD'] }, | |
| { id: 'int1', name: 'Serveur International #1', country: 'us', status: 'online', type: 'premium', speed: 'high', languages: ['en', 'fr', 'vostfr'], quality: ['HD', 'UHD'] }, | |
| { id: 'int2', name: 'Serveur International #2', country: 'de', status: 'online', type: 'standard', speed: 'medium', languages: ['en', 'vostfr'], quality: ['HD'] }, | |
| { id: 'int3', name: 'Serveur International #3', country: 'uk', status: 'online', type: 'premium', speed: 'high', languages: ['en'], quality: ['UHD'] }, | |
| { id: 'auto1', name: 'Auto-Serveur #1', country: 'auto', status: 'online', type: 'auto', speed: 'high', languages: ['auto'], quality: ['auto'] }, | |
| { id: 'auto2', name: 'Auto-Serveur #2', country: 'auto', status: 'online', type: 'auto', speed: 'medium', languages: ['auto'], quality: ['auto'] }, | |
| { id: 'vostfr1', name: 'Serveur VOSTFR #1', country: 'fr', status: 'online', type: 'premium', speed: 'high', languages: ['vostfr'], quality: ['HD', 'UHD'] }, | |
| { id: 'vostfr2', name: 'Serveur VOSTFR #2', country: 'fr', status: 'online', type: 'standard', speed: 'medium', languages: ['vostfr'], quality: ['HD'] }, | |
| { id: 'fast1', name: 'Serveur Rapide #1', country: 'nl', status: 'online', type: 'premium', speed: 'very-high', languages: ['en', 'fr', 'vostfr'], quality: ['HD', 'UHD'] }, | |
| { id: 'fast2', name: 'Serveur Rapide #2', country: 'sg', status: 'online', type: 'premium', speed: 'very-high', languages: ['en', 'fr', 'vostfr'], quality: ['UHD'] } | |
| ]; | |
| // Variables globales | |
| let currentMovies = []; | |
| let genres = []; | |
| let currentCategory = 'popular'; | |
| let youtubePlayer; | |
| let currentMovieDetails = null; | |
| let autoplayTimeout; | |
| let currentSourceIndex = 0; | |
| let selectedServer = null; | |
| let connectedServers = 0; | |
| // Simulation du chargement initial | |
| document.addEventListener('DOMContentLoaded', function() { | |
| let progress = 0; | |
| const progressBar = document.getElementById('progress-bar'); | |
| const serverCount = document.getElementById('server-count'); | |
| const initLoader = document.getElementById('init-loader'); | |
| const mainInterface = document.getElementById('main-interface'); | |
| // Simuler la connexion aux serveurs | |
| const serverInterval = setInterval(() => { | |
| connectedServers = Math.min(12, Math.floor(progress / 8.33)); | |
| serverCount.textContent = connectedServers; | |
| if (connectedServers === 12) { | |
| clearInterval(serverInterval); | |
| } | |
| }, 100); | |
| const interval = setInterval(() => { | |
| progress += Math.random() * 5; | |
| if (progress > 100) progress = 100; | |
| progressBar.style.width = `${progress}%`; | |
| if (progress >= 100) { | |
| clearInterval(interval); | |
| setTimeout(() => { | |
| initLoader.classList.add('opacity-0'); | |
| setTimeout(() => { | |
| initLoader.classList.add('hidden'); | |
| mainInterface.classList.remove('hidden'); | |
| // Initialiser l'application après le chargement | |
| initApp(); | |
| }, 1000); | |
| }, 500); | |
| } | |
| }, 100); | |
| // Gestion de la barre de recherche | |
| const searchToggle = document.getElementById('search-toggle'); | |
| const searchBar = document.getElementById('search-bar'); | |
| searchToggle.addEventListener('click', function() { | |
| searchBar.classList.toggle('hidden'); | |
| }); | |
| // Gestion des détails du film | |
| const movieDetails = document.getElementById('movie-details'); | |
| const closeDetails = document.getElementById('close-details'); | |
| closeDetails.addEventListener('click', function() { | |
| movieDetails.classList.remove('translate-x-0'); | |
| movieDetails.classList.add('translate-x-full'); | |
| }); | |
| // Gestion de la sélection des serveurs | |
| const serverSelection = document.getElementById('server-selection'); | |
| const closeServerSelection = document.getElementById('close-server-selection'); | |
| closeServerSelection.addEventListener('click', function() { | |
| serverSelection.classList.add('hidden'); | |
| }); | |
| document.getElementById('server-button').addEventListener('click', function() { | |
| showServerSelection(); | |
| }); | |
| document.getElementById('confirm-server').addEventListener('click', function() { | |
| if (selectedServer) { | |
| // Mettre à jour l'interface avec le serveur sélectionné | |
| serverSelection.classList.add('hidden'); | |
| } | |
| }); | |
| // Initialiser YouTube Player | |
| onYouTubeIframeAPIReady(); | |
| }); | |
| // Fonction appelée par l'API YouTube | |
| function onYouTubeIframeAPIReady() { | |
| youtubePlayer = new YT.Player('youtube-player', { | |
| height: '100%', | |
| width: '100%', | |
| playerVars: { | |
| 'autoplay': 0, | |
| 'controls': 1, | |
| 'rel': 0, | |
| 'showinfo': 0, | |
| 'modestbranding': 1 | |
| }, | |
| events: { | |
| 'onReady': onPlayerReady, | |
| 'onStateChange': onPlayerStateChange | |
| } | |
| }); | |
| } | |
| function onPlayerReady(event) { | |
| console.log('YouTube Player prêt'); | |
| } | |
| function onPlayerStateChange(event) { | |
| // Gérer les changements d'état du lecteur YouTube | |
| } | |
| // Initialiser l'application | |
| async function initApp() { | |
| try { | |
| // Charger les genres de films | |
| await loadGenres(); | |
| // Charger les films populaires par défaut | |
| await loadMovies(currentCategory); | |
| // Initialiser les serveurs | |
| initServers(); | |
| // Configurer les écouteurs d'événements | |
| setupEventListeners(); | |
| } catch (error) { | |
| console.error('Erreur lors de l\'initialisation:', error); | |
| } | |
| } | |
| // Initialiser les serveurs | |
| function initServers() { | |
| const serverStatusList = document.getElementById('server-status-list'); | |
| SERVERS.forEach(server => { | |
| const serverItem = document.createElement('div'); | |
| serverItem.className = 'px-4 py-2 hover:bg-gray-800 flex items-center justify-between'; | |
| const serverInfo = document.createElement('div'); | |
| serverInfo.className = 'flex items-center'; | |
| const statusIndicator = document.createElement('span'); | |
| statusIndicator.className = `server-status server-${server.status}`; | |
| const serverName = document.createElement('span'); | |
| serverName.className = 'ml-2'; | |
| serverName.textContent = server.name; | |
| serverInfo.appendChild(statusIndicator); | |
| serverInfo.appendChild(serverName); | |
| const serverSpeed = document.createElement('span'); | |
| serverSpeed.className = 'text-xs opacity-70'; | |
| serverSpeed.textContent = server.speed === 'high' ? 'Rapide' : server.speed === 'very-high' ? 'Très rapide' : 'Moyen'; | |
| serverItem.appendChild(serverInfo); | |
| serverItem.appendChild(serverSpeed); | |
| serverStatusList.appendChild(serverItem); | |
| }); | |
| } | |
| // Afficher la sélection des serveurs | |
| function showServerSelection() { | |
| const serverSelection = document.getElementById('server-selection'); | |
| const serverPanel = serverSelection.querySelector('.server-panel'); | |
| serverPanel.innerHTML = ''; | |
| SERVERS.forEach(server => { | |
| const serverCard = document.createElement('div'); | |
| serverCard.className = `server-card p-3 rounded-lg cursor-pointer flex items-center justify-between ${selectedServer?.id === server.id ? 'selected' : ''}`; | |
| serverCard.dataset.id = server.id; | |
| const serverInfo = document.createElement('div'); | |
| serverInfo.className = 'flex items-center'; | |
| const flagIcon = document.createElement('i'); | |
| flagIcon.className = `fas fa-${server.country === 'fr' ? 'flag' : 'globe'} mr-2 text-${server.type === 'premium' ? 'primary' : 'white'}`; | |
| const serverName = document.createElement('span'); | |
| serverName.textContent = server.name; | |
| serverInfo.appendChild(flagIcon); | |
| serverInfo.appendChild(serverName); | |
| const serverDetails = document.createElement('div'); | |
| serverDetails.className = 'flex items-center space-x-2'; | |
| const qualityBadge = document.createElement('span'); | |
| qualityBadge.className = 'text-xs px-2 py-1 rounded-full bg-gray-800'; | |
| qualityBadge.textContent = server.quality.includes('UHD') ? 'UHD' : 'HD'; | |
| const langBadge = document.createElement('span'); | |
| langBadge.className = 'text-xs px-2 py-1 rounded-full bg-gray-800'; | |
| langBadge.textContent = server.languages.includes('fr') ? 'FR' : server.languages.includes('vostfr') ? 'VOSTFR' : 'EN'; | |
| serverDetails.appendChild(qualityBadge); | |
| serverDetails.appendChild(langBadge); | |
| serverCard.appendChild(serverInfo); | |
| serverCard.appendChild(serverDetails); | |
| serverCard.addEventListener('click', () => { | |
| document.querySelectorAll('.server-card').forEach(card => { | |
| card.classList.remove('selected'); | |
| }); | |
| serverCard.classList.add('selected'); | |
| selectedServer = server; | |
| }); | |
| serverPanel.appendChild(serverCard); | |
| }); | |
| serverSelection.classList.remove('hidden'); | |
| } | |
| // Charger les genres de films | |
| async function loadGenres() { | |
| try { | |
| const response = await fetch(`${BASE_URL}/genre/movie/list?api_key=${API_KEY}&language=${LANGUAGE}`); | |
| const data = await response.json(); | |
| genres = data.genres; | |
| // Remplir le filtre des genres | |
| const genreFilter = document.getElementById('genre-filter'); | |
| genres.forEach(genre => { | |
| const option = document.createElement('option'); | |
| option.value = genre.id; | |
| option.textContent = genre.name; | |
| genreFilter.appendChild(option); | |
| }); | |
| // Remplir le filtre des années (dernières 30 années) | |
| const yearFilter = document.getElementById('year-filter'); | |
| const currentYear = new Date().getFullYear(); | |
| for (let year = currentYear; year >= currentYear - 30; year--) { | |
| const option = document.createElement('option'); | |
| option.value = year; | |
| option.textContent = year; | |
| yearFilter.appendChild(option); | |
| } | |
| } catch (error) { | |
| console.error('Erreur lors du chargement des genres:', error); | |
| } | |
| } | |
| // Charger les films | |
| async function loadMovies(category, page = 1, query = '') { | |
| try { | |
| let url; | |
| if (query) { | |
| // Recherche de films | |
| url = `${BASE_URL}/search/movie?api_key=${API_KEY}&language=${LANGUAGE}&query=${encodeURIComponent(query)}&page=${page}`; | |
| } else { | |
| // Catégories normales | |
| url = `${BASE_URL}/movie/${category}?api_key=${API_KEY}&language=${LANGUAGE}&page=${page}`; | |
| } | |
| // Appliquer les filtres | |
| const genreFilter = document.getElementById('genre-filter').value; | |
| const yearFilter = document.getElementById('year-filter').value; | |
| if (genreFilter) { | |
| url += `&with_genres=${genreFilter}`; | |
| } | |
| if (yearFilter) { | |
| url += `&year=${yearFilter}`; | |
| } | |
| const response = await fetch(url); | |
| const data = await response.json(); | |
| currentMovies = data.results; | |
| // Mettre à jour le compteur de films | |
| document.getElementById('total-movies').textContent = data.total_results.toLocaleString('fr-FR'); | |
| // Afficher les films | |
| displayMovies(currentMovies); | |
| } catch (error) { | |
| console.error('Erreur lors du chargement des films:', error); | |
| } | |
| } | |
| // Afficher les films | |
| function displayMovies(movies) { | |
| const moviesContainer = document.getElementById('movies-container'); | |
| moviesContainer.innerHTML = ''; | |
| if (movies.length === 0) { | |
| moviesContainer.innerHTML = ` | |
| <div class="text-center py-20"> | |
| <i class="fas fa-film text-4xl text-primary mb-4"></i> | |
| <h3 class="text-xl font-orbitron mb-2">Aucun film trouvé</h3> | |
| <p class="opacity-80">Essayez de modifier vos critères de recherche</p> | |
| </div> | |
| `; | |
| return; | |
| } | |
| const section = document.createElement('section'); | |
| section.className = 'scanline relative'; | |
| const title = document.createElement('div'); | |
| title.className = 'flex items-center justify-between mb-4'; | |
| const h2 = document.createElement('h2'); | |
| h2.className = 'text-xl md:text-2xl font-orbitron flex items-center'; | |
| const spanDot = document.createElement('span'); | |
| spanDot.className = 'w-3 h-3 rounded-full bg-primary mr-2 pulse'; | |
| const spanText = document.createElement('span'); | |
| spanText.className = 'glow-text'; | |
| if (currentCategory === 'popular') spanText.textContent = 'Tendance cette semaine'; | |
| else if (currentCategory === 'now_playing') spanText.textContent = 'Nouveautés exclusives'; | |
| else if (currentCategory === 'top_rated') spanText.textContent = 'Les mieux notés'; | |
| else if (currentCategory === 'upcoming') spanText.textContent = 'Prochainement'; | |
| else spanText.textContent = 'Résultats de recherche'; | |
| h2.appendChild(spanDot); | |
| h2.appendChild(spanText); | |
| const seeMore = document.createElement('a'); | |
| seeMore.href = '#'; | |
| seeMore.className = 'text-sm hover:text-primary flex items-center'; | |
| seeMore.innerHTML = 'Voir plus <i class="fas fa-chevron-right ml-1 text-xs"></i>'; | |
| title.appendChild(h2); | |
| title.appendChild(seeMore); | |
| const grid = document.createElement('div'); | |
| grid.className = 'grid-stack'; | |
| // Ajouter chaque film à la grille | |
| movies.forEach(movie => { | |
| const movieCard = createMovieCard(movie); | |
| grid.appendChild(movieCard); | |
| }); | |
| section.appendChild(title); | |
| section.appendChild(grid); | |
| moviesContainer.appendChild(section); | |
| } | |
| // Créer une carte de film | |
| function createMovieCard(movie) { | |
| const card = document.createElement('div'); | |
| card.className = 'movie-card rounded-lg overflow-hidden relative group neon-border'; | |
| card.dataset.id = movie.id; | |
| const cardContent = document.createElement('div'); | |
| cardContent.className = 'relative pb-[150%] bg-gradient-to-br from-gray-900 to-gray-800'; | |
| const img = document.createElement('img'); | |
| img.src = movie.poster_path ? `${IMAGE_BASE_URL}${movie.poster_path}` : 'https://via.placeholder.com/500x750?text=Aucune+affiche'; | |
| img.alt = movie.title; | |
| img.className = 'absolute h-full w-full object-cover group-hover:opacity-70 transition-opacity'; | |
| // Qualité aléatoire pour la démo | |
| const qualities = ['PM4', 'EMB', 'HD', 'UHD']; | |
| const randomQuality = qualities[Math.floor(Math.random() * qualities.length)]; | |
| const qualityBadge = document.createElement('div'); | |
| qualityBadge.className = `quality-badge ${randomQuality}`; | |
| qualityBadge.textContent = randomQuality; | |
| const overlay = document.createElement('div'); | |
| overlay.className = 'absolute inset-0 bg-gradient-to-t from-black via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity'; | |
| const info = document.createElement('div'); | |
| info.className = 'absolute bottom-0 left-0 right-0 p-3 translate-y-2 opacity-0 group-hover:translate-y-0 group-hover:opacity-100 transition-all'; | |
| const title = document.createElement('h3'); | |
| title.className = 'font-medium text-sm truncate'; | |
| title.textContent = movie.title; | |
| const meta = document.createElement('div'); | |
| meta.className = 'flex justify-between items-center mt-1 text-xs opacity-80'; | |
| const year = document.createElement('span'); | |
| year.textContent = movie.release_date ? movie.release_date.split('-')[0] : 'N/A'; | |
| const rating = document.createElement('span'); | |
| rating.className = 'flex items-center'; | |
| rating.innerHTML = `<i class="fas fa-star text-yellow-400 mr-1"></i> ${movie.vote_average.toFixed(1)}`; | |
| meta.appendChild(year); | |
| meta.appendChild(rating); | |
| const playBtn = document.createElement('button'); | |
| playBtn.className = 'absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-12 h-12 bg-primary bg-opacity-90 rounded-full flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity'; | |
| playBtn.innerHTML = '<i class="fas fa-play text-black"></i>'; | |
| info.appendChild(title); | |
| info.appendChild(meta); | |
| cardContent.appendChild(img); | |
| cardContent.appendChild(qualityBadge); | |
| cardContent.appendChild(overlay); | |
| cardContent.appendChild(info); | |
| cardContent.appendChild(playBtn); | |
| card.appendChild(cardContent); | |
| // Ajouter les écouteurs d'événements | |
| card.addEventListener('click', () => showMovieDetails(movie.id)); | |
| playBtn.addEventListener('click', (e) => { | |
| e.stopPropagation(); | |
| playMovie(movie.id, randomQuality); | |
| }); | |
| return card; | |
| } | |
| // Afficher les détails d'un film | |
| async function showMovieDetails(movieId) { | |
| try { | |
| const response = await fetch(`${BASE_URL}/movie/${movieId}?api_key=${API_KEY}&language=${LANGUAGE}&append_to_response=credits`); | |
| const movie = await response.json(); | |
| currentMovieDetails = movie; | |
| // Mettre à jour les détails dans le panneau | |
| document.getElementById('detail-poster').src = movie.poster_path ? | |
| `${IMAGE_BASE_URL}${movie.poster_path}` : | |
| 'https://via.placeholder.com/500x750?text=Aucune+affiche'; | |
| document.getElementById('detail-title').textContent = movie.title; | |
| document.getElementById('detail-year').textContent = movie.release_date ? movie.release_date.split('-')[0] : 'N/A'; | |
| document.getElementById('detail-rating').innerHTML = `<i class="fas fa-star text-yellow-400 mr-1"></i> ${movie.vote_average.toFixed(1)}`; | |
| document.getElementById('detail-synopsis').textContent = movie.overview || 'Aucun synopsis disponible'; | |
| // Réalisateur | |
| const director = movie.credits.crew.find(person => person.job === 'Director'); | |
| document.getElementById('detail-director').textContent = director ? director.name : 'Inconnu'; | |
| // Acteurs principaux (5 premiers) | |
| const actors = movie.credits.cast.slice(0, 5).map(actor => actor.name).join(', '); | |
| document.getElementById('detail-actors').textContent = actors || 'Inconnu'; | |
| // Genres | |
| const movieGenres = movie.genres.map(genre => genre.name).join(', '); | |
| document.getElementById('detail-genre').textContent = movieGenres || 'Inconnu'; | |
| // Durée | |
| document.getElementById('detail-duration').textContent = movie.runtime ? `${Math.floor(movie.runtime / 60)}h ${movie.runtime % 60}min` : 'Inconnue'; | |
| // Options de serveurs | |
| const serverPanel = document.getElementById('server-panel'); | |
| serverPanel.innerHTML = ''; | |
| // Filtrer les serveurs appropriés pour ce film | |
| const availableServers = SERVERS.filter(server => { | |
| // Dans une vraie application, vous filtreriez selon les capacités réelles du serveur | |
| return true; | |
| }); | |
| // Trier les serveurs par pertinence | |
| availableServers.sort((a, b) => { | |
| // Prioriser les serveurs français | |
| if (a.country === 'fr' && b.country !== 'fr') return -1; | |
| if (b.country === 'fr' && a.country !== 'fr') return 1; | |
| // Prioriser les serveurs premium | |
| if (a.type === 'premium' && b.type !== 'premium') return -1; | |
| if (b.type === 'premium' && a.type !== 'premium') return 1; | |
| // Prioriser les serveurs rapides | |
| if (a.speed === 'very-high' && b.speed !== 'very-high') return -1; | |
| if (b.speed === 'very-high' && a.speed !== 'very-high') return 1; | |
| if (a.speed === 'high' && b.speed === 'medium') return -1; | |
| if (b.speed === 'high' && a.speed === 'medium') return 1; | |
| return 0; | |
| }); | |
| // Afficher les serveurs disponibles | |
| availableServers.forEach((server, index) => { | |
| const serverCard = document.createElement('div'); | |
| serverCard.className = `server-card p-3 rounded-lg cursor-pointer flex items-center justify-between ${index === 0 ? 'selected' : ''}`; | |
| serverCard.dataset.id = server.id; | |
| const serverInfo = document.createElement('div'); | |
| serverInfo.className = 'flex items-center'; | |
| const statusIndicator = document.createElement('span'); | |
| statusIndicator.className = `server-status server-${server.status} mr-2`; | |
| const serverName = document.createElement('span'); | |
| serverName.textContent = server.name; | |
| serverInfo.appendChild(statusIndicator); | |
| serverInfo.appendChild(serverName); | |
| const serverDetails = document.createElement('div'); | |
| serverDetails.className = 'flex items-center space-x-2'; | |
| const qualityBadge = document.createElement('span'); | |
| qualityBadge.className = 'text-xs px-2 py-1 rounded-full bg-gray-800'; | |
| qualityBadge.textContent = server.quality.includes('UHD') ? 'UHD' : 'HD'; | |
| const langBadge = document.createElement('span'); | |
| langBadge.className = 'text-xs px-2 py-1 rounded-full bg-gray-800'; | |
| langBadge.textContent = server.languages.includes('fr') ? 'FR' : server.languages.includes('vostfr') ? 'VOSTFR' : 'EN'; | |
| serverDetails.appendChild(qualityBadge); | |
| serverDetails.appendChild(langBadge); | |
| serverCard.appendChild(serverInfo); | |
| serverCard.appendChild(serverDetails); | |
| serverCard.addEventListener('click', () => { | |
| document.querySelectorAll('.server-card').forEach(card => { | |
| card.classList.remove('selected'); | |
| }); | |
| serverCard.classList.add('selected'); | |
| selectedServer = server; | |
| }); | |
| serverPanel.appendChild(serverCard); | |
| }); | |
| // Sélectionner le premier serveur par défaut | |
| if (availableServers.length > 0) { | |
| selectedServer = availableServers[0]; | |
| } | |
| // Afficher le panneau de détails | |
| const movieDetails = document.getElementById('movie-details'); | |
| movieDetails.classList.remove('translate-x-full'); | |
| movieDetails.classList.add('translate-x-0'); | |
| } catch (error) { | |
| console.error('Erreur lors du chargement des détails du film:', error); | |
| } | |
| } | |
| // Jouer un film | |
| async function playMovie(movieId, quality = 'HD') { | |
| try { | |
| // Afficher le lecteur | |
| const playerSection = document.getElementById('player-section'); | |
| playerSection.classList.remove('hidden'); | |
| // Mettre à jour les informations du film en cours de lecture | |
| const movie = currentMovies.find(m => m.id == movieId) || currentMovieDetails; | |
| document.getElementById('now-playing-title').textContent = movie.title; | |
| document.getElementById('now-playing-quality').textContent = `Lecture en ${quality} - ${movie.release_date ? movie.release_date.split('-')[0] : ''}`; | |
| // Simuler une URL de streaming basée sur le serveur sélectionné | |
| let videoId; | |
| if (selectedServer) { | |
| // Dans une vraie application, vous utiliseriez l'API du serveur sélectionné | |
| videoId = getYouTubeVideoId(movie.title, selectedServer); | |
| } else { | |
| // Utiliser un serveur par défaut si aucun n'est sélectionné | |
| videoId = getYouTubeVideoId(movie.title); | |
| } | |
| // Charger la vidéo YouTube | |
| youtubePlayer.loadVideoById({ | |
| videoId: videoId, | |
| suggestedQuality: quality === 'UHD' ? 'highres' : 'hd720' | |
| }); | |
| // Faire défiler jusqu'au lecteur | |
| playerSection.scrollIntoView({ behavior: 'smooth' }); | |
| // Masquer les détails du film s'ils sont ouverts | |
| document.getElementById('movie-details').classList.add('translate-x-full'); | |
| // Démarrer le compte à rebours pour l'autoplay | |
| startAutoplayCountdown(); | |
| } catch (error) { | |
| console.error('Erreur lors de la lecture du film:', error); | |
| alert('Erreur lors du chargement du film. Veuillez réessayer.'); | |
| } | |
| } | |
| // Simuler un ID YouTube basé sur le titre du film et le serveur sélectionné | |
| function getYouTubeVideoId(title, server = null) { | |
| // Dans une vraie application, vous feriez une recherche via l'API du serveur | |
| // Ceci est une simulation avec des vidéos publiques connues | |
| const demoVideos = { | |
| 'Inception': 'YoHD9XIncD8', | |
| 'The Dark Knight': 'EXeTwQWrcwY', | |
| 'Interstellar': 'zSWdZVtXT7E', | |
| 'The Shawshank Redemption': '6hB3S9bIaco', | |
| 'Pulp Fiction': 's7EdQ4FqbhY', | |
| 'The Godfather': 'sY1S34973zA', | |
| 'Fight Club': 'qtRKdVHc-cE', | |
| 'Forrest Gump': 'bLvqoHBptjg', | |
| 'The Matrix': 'm8e-FF8MsqU', | |
| 'Léon': 'aNQqoExfQsg', | |
| 'Amélie': 'sECzJY07oK4', | |
| 'Intouchables': '34WIbmXkewU' | |
| }; | |
| // Si un serveur français est sélectionné, prioriser les films français | |
| if (server && server.country === 'fr') { | |
| const frenchMovies = { | |
| 'Léon': 'aNQqoExfQsg', | |
| 'Amélie': 'sECzJY07oK4', | |
| 'Intouchables': '34WIbmXkewU', | |
| 'Le Fabuleux Destin d\'Amélie Poulain': 'sECzJY07oK4', | |
| 'La Haine': 'yYqi9vc7RYY', | |
| 'Le Dîner de Cons': 'VKq9qNjQfQ0' | |
| }; | |
| for (const [key, value] of Object.entries(frenchMovies)) { | |
| if (title.toLowerCase().includes(key.toLowerCase())) { | |
| return value; | |
| } | |
| } | |
| } | |
| // Trouver la correspondance la plus proche | |
| for (const [key, value] of Object.entries(demoVideos)) { | |
| if (title.toLowerCase().includes(key.toLowerCase())) { | |
| return value; | |
| } | |
| } | |
| // Retourner une vidéo par défaut si aucune correspondance | |
| return 'dQw4w9WgXcQ'; // Rick Astley - Never Gonna Give You Up | |
| } | |
| // Démarrer le compte à rebours pour l'autoplay | |
| function startAutoplayCountdown() { | |
| clearTimeout(autoplayTimeout); | |
| const countdownElement = document.getElementById('countdown'); | |
| const autoplayIndicator = document.getElementById('autoplay-indicator'); | |
| let seconds = 5; | |
| countdownElement.textContent = seconds; | |
| autoplayIndicator.classList.remove('hidden'); | |
| const interval = setInterval(() => { | |
| seconds--; | |
| countdownElement.textContent = seconds; | |
| if (seconds <= 0) { | |
| clearInterval(interval); | |
| autoplayIndicator.classList.add('hidden'); | |
| playNextMovie(); | |
| } | |
| }, 1000); | |
| } | |
| // Jouer le film suivant automatiquement | |
| function playNextMovie() { | |
| if (!currentMovies.length) return; | |
| // Trouver l'index du film actuel | |
| const currentIndex = currentMovies.findIndex(m => m.id === currentMovieDetails?.id); | |
| let nextIndex = currentIndex + 1; | |
| // Si c'est le dernier film, revenir au début | |
| if (nextIndex >= currentMovies.length) { | |
| nextIndex = 0; | |
| } | |
| // Jouer le film suivant | |
| const nextMovie = currentMovies[nextIndex]; | |
| const qualities = ['PM4', 'EMB', 'HD', 'UHD']; | |
| const randomQuality = qualities[Math.floor(Math.random() * qualities.length)]; | |
| playMovie(nextMovie.id, randomQuality); | |
| } | |
| // Configurer les écouteurs d'événements | |
| function setupEventListeners() { | |
| // Navigation par catégorie | |
| document.querySelectorAll('[data-category]').forEach(btn => { | |
| btn.addEventListener('click', function() { | |
| currentCategory = this.dataset.category; | |
| // Mettre à jour le style des boutons | |
| document.querySelectorAll('[data-category]').forEach(el => { | |
| if (el === this) { | |
| el.classList.remove('hover:bg-white', 'hover:bg-opacity-10'); | |
| el.classList.add('bg-primary', 'text-black', 'font-medium'); | |
| } else { | |
| el.classList.add('hover:bg-white', 'hover:bg-opacity-10'); | |
| el.classList.remove('bg-primary', 'text-black', 'font-medium'); | |
| } | |
| }); | |
| // Charger les films de cette catégorie | |
| loadMovies(currentCategory); | |
| }); | |
| }); | |
| // Bouton de recherche | |
| document.getElementById('search-button').addEventListener('click', () => { | |
| const query = document.getElementById('search-input').value.trim(); | |
| if (query) { | |
| loadMovies('', 1, query); | |
| } | |
| }); | |
| // Recherche lors de la pression sur Entrée | |
| document.getElementById('search-input').addEventListener('keypress', (e) => { | |
| if (e.key === 'Enter') { | |
| const query = document.getElementById('search-input').value.trim(); | |
| if (query) { | |
| loadMovies('', 1, query); | |
| } | |
| } | |
| }); | |
| // Filtres | |
| document.getElementById('genre-filter').addEventListener('change', () => { | |
| loadMovies(currentCategory); | |
| }); | |
| document.getElementById('year-filter').addEventListener('change', () => { | |
| loadMovies(currentCategory); | |
| }); | |
| document.getElementById('quality-filter').addEventListener('change', () => { | |
| loadMovies(currentCategory); | |
| }); | |
| document.getElementById('language-filter').addEventListener('change', () => { | |
| loadMovies(currentCategory); | |
| }); | |
| // Film aléatoire | |
| document.getElementById('random-movie').addEventListener('click', async () => { | |
| try { | |
| // Charger une page aléatoire (1-500) | |
| const randomPage = Math.floor(Math.random() * 500) + 1; | |
| const response = await fetch(`${BASE_URL}/movie/popular?api_key=${API_KEY}&language=${LANGUAGE}&page=${randomPage}`); | |
| const data = await response.json(); | |
| if (data.results && data.results.length > 0) { | |
| // Choisir un film aléatoire | |
| const randomMovie = data.results[Math.floor(Math.random() * data.results.length)]; | |
| // Afficher les détails | |
| showMovieDetails(randomMovie.id); | |
| } | |
| } catch (error) { | |
| console.error('Erreur lors du chargement d\'un film aléatoire:', error); | |
| } | |
| }); | |
| // Bouton de lecture dans le panneau de détails | |
| document.getElementById('play-movie-btn').addEventListener('click', () => { | |
| if (currentMovieDetails) { | |
| const qualities = ['PM4', 'EMB', 'HD', 'UHD']; | |
| const randomQuality = qualities[Math.floor(Math.random() * qualities.length)]; | |
| playMovie(currentMovieDetails.id, randomQuality); | |
| } | |
| }); | |
| // Contrôles du lecteur | |
| document.getElementById('play-button').addEventListener('click', () => { | |
| if (youtubePlayer.getPlayerState() === YT.PlayerState.PLAYING) { | |
| youtubePlayer.pauseVideo(); | |
| document.getElementById('play-button').innerHTML = '<i class="fas fa-play text-primary"></i>'; | |
| } else { | |
| youtubePlayer.playVideo(); | |
| document.getElementById('play-button').innerHTML = '<i class="fas fa-pause text-primary"></i>'; | |
| } | |
| }); | |
| document.getElementById('fullscreen-button').addEventListener('click', () => { | |
| youtubePlayer.getIframe().requestFullscreen(); | |
| }); | |
| document.getElementById('settings-button').addEventListener('click', () => { | |
| alert('Paramètres du lecteur'); | |
| }); | |
| document.getElementById('subtitles-button').addEventListener('click', () => { | |
| alert('Gestion des sous-titres'); | |
| }); | |
| // Annuler l'autoplay si l'utilisateur interagit avec le lecteur | |
| document.getElementById('youtube-player').addEventListener('click', () => { | |
| clearTimeout(autoplayTimeout); | |
| document.getElementById('autoplay-indicator').classList.add('hidden'); | |
| }); | |
| } | |
| </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/streamhubpro" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |