Download index.html from Adamchab/live: direct link, hf CLI and curl.
- Browser
- Download file 25.7 kB
-
https://huggingface.co/spaces/Adamchab/live/resolve/main/index.html
- Command line
-
hf download hf://spaces/Adamchab/live/index.html
-
curl -L -o index.html https://huggingface.co/spaces/Adamchab/live/resolve/main/index.html
25.7 kB
| <html lang="fr"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Live Vidéo - Système de Partage</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> | |
| .video-box { | |
| aspect-ratio: 16/9; | |
| } | |
| video { | |
| background-color: #222; | |
| } | |
| .username { | |
| background-color: rgba(0, 0, 0, 0.5); | |
| } | |
| .status-indicator { | |
| width: 10px; | |
| height: 10px; | |
| } | |
| .modal { | |
| background-color: rgba(0, 0, 0, 0.5); | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(-20px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| .animate-fade-in { | |
| animation: fadeIn 0.3s ease-out forwards; | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-100 font-sans antialiased"> | |
| <div class="container mx-auto px-4 py-8 max-w-6xl"> | |
| <div class="text-center mb-10"> | |
| <h1 class="text-4xl font-bold bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent"> | |
| <i class="fas fa-video mr-2"></i>Plateforme de Live Vidéo | |
| </h1> | |
| <p class="text-gray-600 mt-2">Connectez-vous et partagez des moments en direct</p> | |
| </div> | |
| <div class="space-y-6"> | |
| <!-- Login Section --> | |
| <div id="login-section" class="bg-white rounded-xl shadow-lg p-6"> | |
| <h2 class="text-2xl font-semibold text-gray-800 mb-6 flex items-center"> | |
| <i class="fas fa-door-open text-blue-500 mr-2"></i>Rejoindre ou créer un live | |
| </h2> | |
| <div class="space-y-4"> | |
| <div> | |
| <label for="username" class="block text-sm font-medium text-gray-700 mb-1"> | |
| <i class="fas fa-user text-blue-500 mr-1"></i>Votre nom | |
| </label> | |
| <input type="text" id="username" placeholder="Entrez votre nom" required | |
| class="w-full px-4 py-3 rounded-lg border border-gray-300 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition"> | |
| </div> | |
| <div> | |
| <label for="room-code" class="block text-sm font-medium text-gray-700 mb-1"> | |
| <i class="fas fa-key text-blue-500 mr-1"></i>Code de la salle | |
| </label> | |
| <div class="flex space-x-2"> | |
| <input type="text" id="room-code" placeholder="Entrez le code de la salle" value="a234" | |
| class="flex-1 px-4 py-3 rounded-lg border border-gray-300 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition"> | |
| <button id="join-btn" class="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition flex items-center"> | |
| <i class="fas fa-sign-in-alt mr-2"></i>Rejoindre | |
| </button> | |
| </div> | |
| </div> | |
| <div class="pt-2"> | |
| <button id="create-btn" class="w-full px-6 py-3 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition flex items-center justify-center"> | |
| <i class="fas fa-plus-circle mr-2"></i>Créer un nouveau live | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Video Section (hidden initially) --> | |
| <div id="video-section" class="hidden bg-white rounded-xl shadow-lg p-6"> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h2 class="text-2xl font-semibold text-gray-800 flex items-center"> | |
| <i class="fas fa-video text-blue-500 mr-2"></i> | |
| Live en cours: <span id="room-display" class="ml-2 bg-blue-100 text-blue-800 px-3 py-1 rounded-full">a234</span> | |
| </h2> | |
| <div id="participant-count" class="flex items-center text-gray-600"> | |
| <i class="fas fa-users mr-2"></i> | |
| <span>1 participant</span> | |
| </div> | |
| </div> | |
| <!-- Video Grid --> | |
| <div id="videos" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> | |
| <div class="video-box relative rounded-xl overflow-hidden"> | |
| <video id="local-video" autoplay muted playsinline class="w-full h-full object-cover"></video> | |
| <div class="username absolute bottom-3 left-3 text-white px-3 py-1 rounded-lg text-sm"> | |
| <i class="fas fa-user-circle mr-1"></i>Vous | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Controls - Modifié pour un meilleur alignement --> | |
| <div class="mt-6 flex flex-wrap gap-3 justify-between items-center"> | |
| <div class="flex flex-wrap gap-3"> | |
| <button id="toggle-video" class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition flex items-center"> | |
| <i class="fas fa-video mr-2"></i>Désactiver vidéo | |
| </button> | |
| <button id="toggle-audio" class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition flex items-center"> | |
| <i class="fas fa-microphone mr-2"></i>Désactiver audio | |
| </button> | |
| <button id="share-screen" class="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition flex items-center"> | |
| <i class="fas fa-desktop mr-2"></i>Partager écran | |
| </button> | |
| </div> | |
| <button id="leave-btn" class="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition flex items-center"> | |
| <i class="fas fa-sign-out-alt mr-2"></i>Quitter | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Host Controls (hidden initially) --> | |
| <div id="host-controls" class="hidden bg-white rounded-xl shadow-lg p-6"> | |
| <h2 class="text-2xl font-semibold text-gray-800 mb-6 flex items-center"> | |
| <i class="fas fa-cogs text-purple-500 mr-2"></i>Contrôles du live | |
| </h2> | |
| <div class="space-y-6"> | |
| <div> | |
| <h3 class="text-lg font-medium text-gray-700 mb-2 flex items-center"> | |
| <i class="fas fa-link text-blue-500 mr-2"></i>Lien d'invitation | |
| </h3> | |
| <div class="flex"> | |
| <input type="text" id="invite-link" readonly | |
| class="flex-1 px-4 py-3 rounded-l-lg border border-gray-300 bg-gray-50"> | |
| <button id="copy-btn" class="px-4 py-3 bg-blue-600 text-white rounded-r-lg hover:bg-blue-700 transition flex items-center"> | |
| <i class="fas fa-copy mr-2"></i>Copier | |
| </button> | |
| </div> | |
| </div> | |
| <div> | |
| <h3 class="text-lg font-medium text-gray-700 mb-2 flex items-center"> | |
| <i class="fas fa-users text-purple-500 mr-2"></i>Participants | |
| </h3> | |
| <div id="participant-list" class="bg-gray-50 rounded-lg p-4 max-h-60 overflow-y-auto space-y-2"> | |
| <div class="flex items-center p-2 bg-white rounded-lg shadow-sm"> | |
| <span class="status-indicator rounded-full bg-blue-500 mr-3"></span> | |
| <span>Vous (hôte)</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Create Room Modal --> | |
| <div id="create-room-modal" class="modal hidden fixed inset-0 flex items-center justify-center z-50"> | |
| <div class="bg-white rounded-xl shadow-2xl p-6 w-full max-w-md animate-fade-in"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h3 class="text-xl font-semibold text-gray-800 flex items-center"> | |
| <i class="fas fa-plus-circle text-purple-500 mr-2"></i>Créer un nouveau live | |
| </h3> | |
| <button class="close text-gray-500 hover:text-gray-700 text-2xl"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <p class="text-gray-600 mb-4"> | |
| Choisissez un code pour votre salle (ou laissez vide pour un code généré automatiquement) | |
| </p> | |
| <div class="mb-6"> | |
| <input type="text" id="new-room-code" placeholder="Code de la salle (optionnel)" | |
| class="w-full px-4 py-3 rounded-lg border border-gray-300 focus:ring-2 focus:ring-purple-500 focus:border-purple-500 transition"> | |
| </div> | |
| <button id="confirm-create" class="w-full px-6 py-3 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition flex items-center justify-center"> | |
| <i class="fas fa-check-circle mr-2"></i>Créer et rejoindre | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Notification Modal --> | |
| <div id="notification-modal" class="modal hidden fixed inset-0 flex items-center justify-center z-50"> | |
| <div class="bg-white rounded-xl shadow-2xl p-6 w-full max-w-md animate-fade-in"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h3 id="notification-title" class="text-xl font-semibold text-gray-800 flex items-center"> | |
| <i class="fas fa-bell text-blue-500 mr-2"></i>Notification | |
| </h3> | |
| <button class="close text-gray-500 hover:text-gray-700 text-2xl"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <p id="notification-message" class="text-gray-600 mb-6"> | |
| Message de notification ici. | |
| </p> | |
| <div class="text-center"> | |
| <button id="notification-confirm" class="px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition"> | |
| OK | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Success Toast --> | |
| <div id="toast" class="hidden fixed bottom-4 right-4 bg-green-500 text-white px-6 py-3 rounded-lg shadow-lg flex items-center"> | |
| <i class="fas fa-check-circle mr-2"></i> | |
| <span id="toast-message">Action réussie!</span> | |
| </div> | |
| <script> | |
| // Variables globales | |
| let localStream = null; | |
| let peers = {}; | |
| let isHost = false; | |
| let roomCode = "a234"; | |
| let username = ""; | |
| let videoEnabled = true; | |
| let audioEnabled = true; | |
| let screenShareStream = null; | |
| // Éléments DOM | |
| const loginSection = document.getElementById('login-section'); | |
| const videoSection = document.getElementById('video-section'); | |
| const hostControls = document.getElementById('host-controls'); | |
| const usernameInput = document.getElementById('username'); | |
| const roomCodeInput = document.getElementById('room-code'); | |
| const joinBtn = document.getElementById('join-btn'); | |
| const createBtn = document.getElementById('create-btn'); | |
| const roomDisplay = document.getElementById('room-display'); | |
| const toggleVideoBtn = document.getElementById('toggle-video'); | |
| const toggleAudioBtn = document.getElementById('toggle-audio'); | |
| const shareScreenBtn = document.getElementById('share-screen'); | |
| const leaveBtn = document.getElementById('leave-btn'); | |
| const inviteLink = document.getElementById('invite-link'); | |
| const copyBtn = document.getElementById('copy-btn'); | |
| const participantCount = document.getElementById('participant-count'); | |
| const participantList = document.getElementById('participant-list'); | |
| const createRoomModal = document.getElementById('create-room-modal'); | |
| const newRoomCodeInput = document.getElementById('new-room-code'); | |
| const confirmCreateBtn = document.getElementById('confirm-create'); | |
| const notificationModal = document.getElementById('notification-modal'); | |
| const notificationTitle = document.getElementById('notification-title'); | |
| const notificationMessage = document.getElementById('notification-message'); | |
| const notificationConfirm = document.getElementById('notification-confirm'); | |
| const localVideo = document.getElementById('local-video'); | |
| const videosContainer = document.getElementById('videos'); | |
| const toast = document.getElementById('toast'); | |
| const toastMessage = document.getElementById('toast-message'); | |
| // Fonction pour générer un code de salle aléatoire | |
| function generateRoomCode() { | |
| return Math.random().toString(36).substring(2, 6).toUpperCase(); | |
| } | |
| // Afficher une notification | |
| function showNotification(title, message) { | |
| notificationTitle.textContent = title; | |
| notificationMessage.textContent = message; | |
| notificationModal.classList.remove('hidden'); | |
| } | |
| // Afficher un toast | |
| function showToast(message, isSuccess = true) { | |
| toastMessage.textContent = message; | |
| toast.className = `fixed bottom-4 right-4 px-6 py-3 rounded-lg shadow-lg flex items-center animate-fade-in ${isSuccess ? 'bg-green-500' : 'bg-red-500'} text-white`; | |
| toast.classList.remove('hidden'); | |
| setTimeout(() => { | |
| toast.classList.add('hidden'); | |
| }, 3000); | |
| } | |
| // Simuler la connexion à une salle | |
| async function joinRoom(code) { | |
| if (!username) { | |
| showNotification("Erreur", "Veuillez entrer votre nom pour rejoindre."); | |
| return; | |
| } | |
| if (!code) { | |
| showNotification("Erreur", "Veuillez entrer un code de salle."); | |
| return; | |
| } | |
| roomCode = code.toUpperCase(); | |
| try { | |
| // Simuler l'accès à la caméra/micro | |
| localStream = await navigator.mediaDevices.getUserMedia({ | |
| video: true, | |
| audio: true | |
| }); | |
| localVideo.srcObject = localStream; | |
| loginSection.classList.add('hidden'); | |
| videoSection.classList.remove('hidden'); | |
| if (isHost) { | |
| hostControls.classList.remove('hidden'); | |
| const currentUrl = window.location.href.split('?')[0]; | |
| inviteLink.value = `${currentUrl}?room=${roomCode}`; | |
| } | |
| roomDisplay.textContent = roomCode; | |
| showToast(`Vous avez rejoint la salle ${roomCode}`, true); | |
| // Simuler l'ajout d'un participant | |
| setTimeout(() => { | |
| const videoBox = document.createElement('div'); | |
| videoBox.className = 'video-box relative rounded-xl overflow-hidden'; | |
| videoBox.id = 'video-container-demo-peer'; | |
| const video = document.createElement('video'); | |
| video.id = 'video-demo-peer'; | |
| video.autoplay = true; | |
| video.playsinline = true; | |
| video.className = 'w-full h-full object-cover'; | |
| // Simuler une vidéo de test | |
| video.srcObject = new MediaStream([localStream.getVideoTracks()[0].clone()]); | |
| const usernameDiv = document.createElement('div'); | |
| usernameDiv.className = 'username absolute bottom-3 left-3 text-white px-3 py-1 rounded-lg text-sm'; | |
| usernameDiv.innerHTML = '<i class="fas fa-user-circle mr-1"></i>Participant Test'; | |
| videoBox.appendChild(usernameDiv); | |
| videoBox.appendChild(video); | |
| videosContainer.appendChild(videoBox); | |
| // Mettre à jour le compteur | |
| participantCount.innerHTML = '<i class="fas fa-users mr-2"></i>2 participants'; | |
| // Ajouter à la liste des participants | |
| const participantItem = document.createElement('div'); | |
| participantItem.className = 'flex items-center p-2 bg-white rounded-lg shadow-sm'; | |
| participantItem.innerHTML = ` | |
| <span class="status-indicator rounded-full bg-green-500 mr-3"></span> | |
| Participant Test | |
| `; | |
| participantList.appendChild(participantItem); | |
| }, 2000); | |
| } catch (error) { | |
| console.error("Erreur simulation:", error); | |
| showNotification("Erreur", "Impossible d'accéder à la caméra ou au microphone. Veuillez vérifier vos autorisations."); | |
| } | |
| } | |
| // Quitter la salle | |
| function leaveRoom() { | |
| if (localStream) { | |
| localStream.getTracks().forEach(track => track.stop()); | |
| } | |
| if (screenShareStream) { | |
| screenShareStream.getTracks().forEach(track => track.stop()); | |
| } | |
| // Supprimer les vidéos des autres participants | |
| const videos = document.querySelectorAll('.video-box:not(:first-child)'); | |
| videos.forEach(video => video.remove()); | |
| // Réinitialiser | |
| localVideo.srcObject = null; | |
| videoSection.classList.add('hidden'); | |
| hostControls.classList.add('hidden'); | |
| loginSection.classList.remove('hidden'); | |
| showToast("Vous avez quitté la salle", true); | |
| } | |
| // Fonction pour partager l'écran | |
| async function shareScreen() { | |
| try { | |
| // Désactiver le partage d'écran si déjà actif | |
| if (screenShareStream) { | |
| stopScreenSharing(); | |
| return; | |
| } | |
| // Obtenir le flux de partage d'écran | |
| screenShareStream = await navigator.mediaDevices.getDisplayMedia({ | |
| video: { | |
| cursor: "always", | |
| displaySurface: "monitor" | |
| }, | |
| audio: false | |
| }); | |
| // Remplacer la vidéo locale par le partage d'écran | |
| localVideo.srcObject = screenShareStream; | |
| shareScreenBtn.innerHTML = '<i class="fas fa-stop-circle mr-2"></i>Arrêter le partage'; | |
| showToast("Partage d'écran activé", true); | |
| // Gérer la fin du partage d'écran | |
| screenShareStream.getVideoTracks()[0].onended = () => { | |
| stopScreenSharing(); | |
| }; | |
| } catch (error) { | |
| console.error("Erreur partage écran:", error); | |
| if (error.name !== 'NotAllowedError') { | |
| showNotification("Erreur", "Impossible de partager l'écran."); | |
| } | |
| } | |
| } | |
| function stopScreenSharing() { | |
| if (screenShareStream) { | |
| screenShareStream.getTracks().forEach(track => track.stop()); | |
| localVideo.srcObject = localStream; | |
| screenShareStream = null; | |
| shareScreenBtn.innerHTML = '<i class="fas fa-desktop mr-2"></i>Partager écran'; | |
| showToast("Partage d'écran arrêté", true); | |
| } | |
| } | |
| // Événements | |
| joinBtn.addEventListener('click', () => { | |
| username = usernameInput.value.trim(); | |
| const code = roomCodeInput.value.trim().toUpperCase(); | |
| if (username && code) { | |
| isHost = false; | |
| joinRoom(code); | |
| } else { | |
| showNotification("Informations manquantes", "Veuillez entrer votre nom et le code de la salle."); | |
| } | |
| }); | |
| createBtn.addEventListener('click', () => { | |
| username = usernameInput.value.trim(); | |
| if (username) { | |
| isHost = true; | |
| createRoomModal.classList.remove('hidden'); | |
| } else { | |
| showNotification("Nom manquant", "Veuillez entrer votre nom pour créer une salle."); | |
| } | |
| }); | |
| confirmCreateBtn.addEventListener('click', () => { | |
| const customCode = newRoomCodeInput.value.trim().toUpperCase(); | |
| const code = customCode || generateRoomCode(); | |
| createRoomModal.classList.add('hidden'); | |
| joinRoom(code); | |
| }); | |
| toggleVideoBtn.addEventListener('click', () => { | |
| if (localStream) { | |
| const videoTracks = localStream.getVideoTracks(); | |
| videoTracks.forEach(track => { | |
| track.enabled = !track.enabled; | |
| }); | |
| videoEnabled = videoTracks[0]?.enabled || false; | |
| toggleVideoBtn.innerHTML = videoEnabled | |
| ? '<i class="fas fa-video mr-2"></i>Désactiver vidéo' | |
| : '<i class="fas fa-video-slash mr-2"></i>Activer vidéo'; | |
| showToast(`Vidéo ${videoEnabled ? 'activée' : 'désactivée'}`, true); | |
| } | |
| }); | |
| toggleAudioBtn.addEventListener('click', () => { | |
| if (localStream) { | |
| const audioTracks = localStream.getAudioTracks(); | |
| audioTracks.forEach(track => { | |
| track.enabled = !track.enabled; | |
| }); | |
| audioEnabled = audioTracks[0]?.enabled || false; | |
| toggleAudioBtn.innerHTML = audioEnabled | |
| ? '<i class="fas fa-microphone mr-2"></i>Désactiver audio' | |
| : '<i class="fas fa-microphone-slash mr-2"></i>Activer audio'; | |
| showToast(`Audio ${audioEnabled ? 'activé' : 'désactivé'}`, true); | |
| } | |
| }); | |
| shareScreenBtn.addEventListener('click', shareScreen); | |
| leaveBtn.addEventListener('click', () => { | |
| leaveRoom(); | |
| }); | |
| copyBtn.addEventListener('click', () => { | |
| inviteLink.select(); | |
| document.execCommand('copy'); | |
| copyBtn.innerHTML = '<i class="fas fa-check mr-2"></i>Copié !'; | |
| showToast("Lien copié dans le presse-papier", true); | |
| setTimeout(() => { | |
| copyBtn.innerHTML = '<i class="fas fa-copy mr-2"></i>Copier'; | |
| }, 2000); | |
| }); | |
| // Fermer les modales | |
| document.querySelectorAll('.close').forEach(closeBtn => { | |
| closeBtn.addEventListener('click', () => { | |
| createRoomModal.classList.add('hidden'); | |
| notificationModal.classList.add('hidden'); | |
| }); | |
| }); | |
| notificationConfirm.addEventListener('click', () => { | |
| notificationModal.classList.add('hidden'); | |
| }); | |
| // Vérifier s'il y a un code de salle dans l'URL | |
| window.addEventListener('load', () => { | |
| const urlParams = new URLSearchParams(window.location.search); | |
| const roomParam = urlParams.get('room'); | |
| if (roomParam) { | |
| roomCodeInput.value = roomParam; | |
| usernameInput.focus(); | |
| } | |
| }); | |
| </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=Adamchab/live" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |