live / prompts.txt
Adamchab's picture
Add 3 files
8fd4798 verified
<!DOCTYPE html> <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> <style> body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 0; background-color: #f5f5f5; } .container { max-width: 1200px; margin: 0 auto; padding: 20px; } .header { text-align: center; margin-bottom: 30px; } .main-content { display: flex; flex-direction: column; gap: 20px; } .login-section, .video-section, .control-section { background-color: white; border-radius: 8px; padding: 20px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); } .video-container { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 15px; margin-top: 20px; } .video-box { position: relative; border-radius: 8px; overflow: hidden; aspect-ratio: 16/9; } video { width: 100%; height: 100%; object-fit: cover; background-color: #222; } .username { position: absolute; bottom: 10px; left: 10px; background-color: rgba(0, 0, 0, 0.5); color: white; padding: 5px 10px; border-radius: 4px; font-size: 14px; } .input-group { display: flex; margin-bottom: 15px; } input { flex-grow: 1; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 16px; } button { padding: 10px 20px; background-color: #4285f4; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; transition: background-color 0.3s; } button:hover { background-color: #3367d6; } .controls { display: flex; gap: 10px; margin-top: 15px; } .btn-danger { background-color: #ea4335; } .btn-danger:hover { background-color: #d33426; } .copy-link { display: flex; margin-top: 15px; background-color: #f8f9fa; padding: 10px; border-radius: 4px; align-items: center; } .copy-link input { margin-right: 10px; } .participants { margin-top: 15px; } .participant-list { max-height: 200px; overflow-y: auto; } .status-indicator { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: 5px; } .status-online { background-color: #34a853; } .status-offline { background-color: #ea4335; } .hidden { display: none; } .modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center; z-index: 1000; } .modal-content { background-color: white; padding: 30px; border-radius: 8px; max-width: 500px; width: 100%; } .modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } .close { cursor: pointer; font-size: 24px; } .text-center { text-align: center; } .text-success { color: #34a853; } </style> </head> <body> <div class="container"> <div class="header"> <h1>Plateforme de Live Vidéo</h1> </div> <div class="main-content"> <!-- Section de connexion --> <div class="login-section" id="login-section"> <h2>Rejoindre ou créer un live</h2> <div class="input-group"> <input type="text" id="username" placeholder="Votre nom" required> </div> <div class="input-group"> <input type="text" id="room-code" placeholder="Code de la salle"> <button id="join-btn" style="margin-left: 10px;">Rejoindre</button> </div> <div> <button id="create-btn">Créer un nouveau live</button> </div> </div> <!-- Section vidéo - cachée au départ --> <div class="video-section hidden" id="video-section"> <h2>Live en cours: <span id="room-display"></span></h2> <div class="video-container" id="videos"> <div class="video-box"> <video id="local-video" autoplay muted playsinline></video> <div class="username">Vous</div> </div> </div> <div class="controls"> <button id="toggle-video">Désactiver vidéo</button> <button id="toggle-audio">Désactiver audio</button> <button id="share-screen">Partager écran</button> <button class="btn-danger" id="leave-btn">Quitter</button> </div> </div> <!-- Section contrôle (uniquement pour le créateur) --> <div class="control-section hidden" id="host-controls"> <h2>Contrôles du live</h2> <div class="copy-link"> <input type="text" id="invite-link" readonly> <button id="copy-btn">Copier le lien</button> </div> <div class="participants"> <h3>Participants (<span id="participant-count">1</span>)</h3> <div class="participant-list" id="participant-list"> <!-- Les participants seront ajoutés ici dynamiquement --> </div> </div> </div> </div> </div> <!-- Modales --> <div id="create-room-modal" class="modal hidden"> <div class="modal-content"> <div class="modal-header"> <h2>Créer un nouveau live</h2> <span class="close">&times;</span> </div> <p>Choisissez un code pour votre salle (ou laissez vide pour un code généré automatiquement)</p> <div class="input-group"> <input type="text" id="new-room-code" placeholder="Code de la salle (optionnel)"> </div> <button id="confirm-create">Créer et rejoindre</button> </div> </div> <div id="notification-modal" class="modal hidden"> <div class="modal-content"> <div class="modal-header"> <h2 id="notification-title">Notification</h2> <span class="close">&times;</span> </div> <p id="notification-message"></p> <div class="text-center"> <button id="notification-confirm">OK</button> </div> </div> </div> <!-- Inclusion de Firebase et PeerJS --> <script src="https://cdnjs.cloudflare.com/ajax/libs/firebase/9.17.1/firebase-app-compat.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/firebase/9.17.1/firebase-database-compat.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/peerjs/1.4.7/peerjs.min.js"></script> <script> // Configuration de Firebase - À REMPLACER PAR VOS PROPRES IDENTIFIANTS const firebaseConfig = { apiKey: "VOTRE_API_KEY", authDomain: "VOTRE_AUTH_DOMAIN", databaseURL: "VOTRE_DATABASE_URL", projectId: "VOTRE_PROJECT_ID", storageBucket: "VOTRE_STORAGE_BUCKET", messagingSenderId: "VOTRE_MESSAGING_SENDER_ID", appId: "VOTRE_APP_ID" }; // Initialisation de Firebase firebase.initializeApp(firebaseConfig); const database = firebase.database(); // Variables globales let localStream = null; let peers = {}; let isHost = false; let roomCode = ""; let username = ""; let myPeer = null; 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'); // Fonction pour générer un code de salle aléatoire function generateRoomCode() { return Math.random().toString(36).substring(2, 8).toUpperCase(); } // Afficher une notification function showNotification(title, message) { notificationTitle.textContent = title; notificationMessage.textContent = message; notificationModal.classList.remove('hidden'); } // Rejoindre 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(); // Vérifier si la salle existe const roomRef = database.ref(`rooms/${roomCode}`); const snapshot = await roomRef.once('value'); if (!snapshot.exists() && !isHost) { showNotification("Erreur", "Cette salle n'existe pas. Veuillez vérifier le code."); return; } // Initialiser le flux vidéo local try { localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true }); // Afficher la vidéo locale localVideo.srcObject = localStream; // Masquer la section de connexion et afficher la section vidéo loginSection.classList.add('hidden'); videoSection.classList.remove('hidden'); if (isHost) { hostControls.classList.remove('hidden'); // Créer la salle dans Firebase await roomRef.set({ host: username, created: firebase.database.ServerValue.TIMESTAMP }); // Générer le lien d'invitation const currentUrl = window.location.href.split('?')[0]; inviteLink.value = `${currentUrl}?room=${roomCode}`; } // Mettre à jour l'affichage du code de salle roomDisplay.textContent = roomCode; // Initialiser PeerJS initializePeerConnection(); // S'inscrire comme participant const participantRef = database.ref(`rooms/${roomCode}/participants/${myPeer.id}`); participantRef.set({ username: username, joined: firebase.database.ServerValue.TIMESTAMP }); // Supprimer le participant lorsqu'il se déconnecte participantRef.onDisconnect().remove(); // Si c'est l'hôte, supprimer la salle lorsqu'il se déconnecte if (isHost) { roomRef.onDisconnect().remove(); } // Écouter les participants listenForParticipants(); } catch (error) { console.error("Erreur lors de l'accès à la caméra et au micro:", error); showNotification("Erreur", "Impossible d'accéder à la caméra ou au microphone. Veuillez vérifier vos autorisations."); } } // Initialiser la connexion PeerJS function initializePeerConnection() { // Générer un ID unique pour ce peer const peerId = `${roomCode}-${Date.now()}-${Math.random().toString(36).substring(2, 10)}`; myPeer = new Peer(peerId, { debug: 3 }); myPeer.on('open', (id) => { console.log('Mon ID PeerJS:', id); }); // Gérer les appels entrants myPeer.on('call', (call) => { // Répondre avec notre flux vidéo call.answer(localStream); // Ajouter la vidéo distante à notre interface call.on('stream', (remoteStream) => { addVideoStream(call.peer, remoteStream); }); // Gérer la déconnexion call.on('close', () => { removeVideoStream(call.peer); }); // Stocker l'appel peers[call.peer] = call; }); myPeer.on('error', (err) => { console.error('Erreur PeerJS:', err); showNotification("Erreur de connexion", `Une erreur s'est produite: ${err.message}`); }); } // Appeler un nouveau participant function connectToNewUser(userId, stream) { const call = myPeer.call(userId, stream); call.on('stream', (remoteStream) => { addVideoStream(userId, remoteStream); }); call.on('close', () => { removeVideoStream(userId); }); peers[userId] = call; } // Ajouter un flux vidéo à l'interface function addVideoStream(userId, stream) { // Vérifier si ce flux existe déjà if (document.getElementById(`video-${userId}`)) { return; } // Créer les éléments pour la vidéo const videoBox = document.createElement('div'); videoBox.className = 'video-box'; videoBox.id = `video-container-${userId}`; const video = document.createElement('video'); video.id = `video-${userId}`; video.srcObject = stream; video.autoplay = true; video.playsinline = true; // Obtenir le nom du participant database.ref(`rooms/${roomCode}/participants/${userId}`).once('value', (snapshot) => { const participant = snapshot.val(); if (participant) { const usernameDiv = document.createElement('div'); usernameDiv.className = 'username'; usernameDiv.textContent = participant.username; videoBox.appendChild(usernameDiv); } }); videoBox.appendChild(video); videosContainer.appendChild(videoBox); } // Supprimer un flux vidéo de l'interface function removeVideoStream(userId) { const videoContainer = document.getElementById(`video-container-${userId}`); if (videoContainer) { videoContainer.remove(); } // Supprimer l'appel if (peers[userId]) { peers[userId].close(); delete peers[userId]; } } // Écouter les participants function listenForParticipants() { const participantsRef = database.ref(`rooms/${roomCode}/participants`); participantsRef.on('child_added', (snapshot) => { const participant = snapshot.val(); const participantId = snapshot.key; // Mettre à jour la liste des participants updateParticipantList(); // Si c'est un nouveau participant et que je suis déjà connecté if (participantId !== myPeer.id && localStream) { // L'appeler pour établir la connexion connectToNewUser(participantId, localStream); } }); participantsRef.on('child_removed', (snapshot) => { const participantId = snapshot.key; // Mettre à jour la liste des participants updateParticipantList(); // Supprimer la vidéo removeVideoStream(participantId); }); } // Mettre à jour la liste des participants function updateParticipantList() { const participantsRef = database.ref(`rooms/${roomCode}/participants`); participantsRef.once('value', (snapshot) => { // Vider la liste participantList.innerHTML = ''; const participants = snapshot.val() || {}; const count = Object.keys(participants).length; // Mettre à jour le compteur participantCount.textContent = count; // Ajouter chaque participant à la liste Object.entries(participants).forEach(([id, data]) => { const participantItem = document.createElement('div'); participantItem.innerHTML = ` <span class="status-indicator status-online"></span> ${data.username} ${id === myPeer.id ? '(vous)' : ''} `; participantList.appendChild(participantItem); }); }); } // Quitter la salle function leaveRoom() { // Arrêter tous les flux if (localStream) { localStream.getTracks().forEach(track => track.stop()); } if (screenShareStream) { screenShareStream.getTracks().forEach(track => track.stop()); } // Fermer toutes les connexions Object.values(peers).forEach(call => call.close()); peers = {}; // Supprimer le participant if (myPeer && roomCode) { database.ref(`rooms/${roomCode}/participants/${myPeer.id}`).remove(); } // Fermer la connexion PeerJS if (myPeer) { myPeer.destroy(); } // Réinitialiser les variables myPeer = null; localStream = null; screenShareStream = null; isHost = false; roomCode = ""; // Réafficher la section de connexion videoSection.classList.add('hidden'); hostControls.classList.add('hidden'); loginSection.classList.remove('hidden'); // Vider le conteneur de vidéos (sauf la vidéo locale) const videos = document.querySelectorAll('.video-box:not(:first-child)'); videos.forEach(video => video.remove()); // Réinitialiser la vidéo locale localVideo.srcObject = null; } // É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.textContent = videoEnabled ? "Désactiver vidéo" : "Activer vidéo"; } }); toggleAudioBtn.addEventListener('click', () => { if (localStream) { const audioTracks = localStream.getAudioTracks(); audioTracks.forEach(track => { track.enabled = !track.enabled; }); audioEnabled = audioTracks[0]?.enabled || false; toggleAudioBtn.textContent = audioEnabled ? "Désactiver audio" : "Activer audio"; } }); shareScreenBtn.addEventListener('click', async () => { try { if (!screenShareStream) { // Commencer le partage d'écran screenShareStream = await navigator.mediaDevices.getDisplayMedia({ video: true }); // Remplacer le flux vidéo local par le partage d'écran const videoTrack = screenShareStream.getVideoTracks()[0]; const sender = Object.values(peers).forEach(peer => { const senders = peer._pc.getSenders(); const videoSender = senders.find(s => s.track && s.track.kind === 'video'); if (videoSender) { videoSender.replaceTrack(videoTrack); } }); // Mettre à jour l'affichage local localVideo.srcObject = screenShareStream; // Arrêter le partage d'écran lorsque l'utilisateur arrête videoTrack.onended = () => { stopScreenSharing(); }; shareScreenBtn.textContent = "Arrêter le partage"; } else { stopScreenSharing(); } } catch (error) { console.error("Erreur lors du partage d'écran:", error); showNotification("Erreur", "Impossible de partager l'écran. Veuillez réessayer."); } }); function stopScreenSharing() { if (screenShareStream) { screenShareStream.getTracks().forEach(track => track.stop()); // Rétablir la vidéo de la caméra const videoTrack = localStream.getVideoTracks()[0]; if (videoTrack) { Object.values(peers).forEach(peer => { const senders = peer._pc.getSenders(); const videoSender = senders.find(s => s.track && s.track.kind === 'video'); if (videoSender) { videoSender.replaceTrack(videoTrack); } }); // Rétablir l'affichage local localVideo.srcObject = localStream; } screenShareStream = null; shareScreenBtn.textContent = "Partager écran"; } } leaveBtn.addEventListener('click', () => { leaveRoom(); }); copyBtn.addEventListener('click', () => { inviteLink.select(); document.execCommand('copy'); // Afficher une confirmation copyBtn.textContent = "Copié !"; setTimeout(() => { copyBtn.textContent = "Copier le lien"; }, 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; // Focus sur le champ nom usernameInput.focus(); } }); // Gérer la déconnexion à la fermeture de la page window.addEventListener('beforeunload', () => { leaveRoom(); }); </script> </body> </html> ...Le code pour intégrer le live est 1234
Corrigé les erreurs et fait en sorte que tout les boutons fonctionnent code a234
Les boutons ne sont pas aligné et partage d'écran ne fonctionne pas