live / index.html
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>
<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>