update chat
Deploy / Deploy (push) Successful in 14s Details

This commit is contained in:
www-data 2025-03-27 11:53:08 -03:00
parent 756d2a98b2
commit a00dcc4e70
4 changed files with 144 additions and 70 deletions

View File

@ -76,17 +76,33 @@
console.log("Usuário da live:", streamUser); console.log("Usuário da live:", streamUser);
const videoElement = document.querySelector('video'); const videoElement = document.querySelector('video');
const playerOffElement = document.querySelector('.player-off'); const playerOffElement = document.querySelector('.player-off');
const chatContainer = document.querySelector('.chat-container');
const chatForm = document.querySelector('.chat-input-form');
const usernameInput = document.querySelector('#username-input');
const chatInputField = document.querySelector('.chat-enter');
const url = `https://class.alice.ufsj.edu.br/dash/${streamUser}.mpd`; const url = `https://class.alice.ufsj.edu.br/dash/${streamUser}.mpd`;
videoElement.src = url; videoElement.src = url;
let chatAtivo = false;
fetch(url) fetch(url)
.then(response => { .then(response => {
if (response.ok) { if (response.ok) {
console.log("Arquivo existe."); console.log("Arquivo existe.");
playerOffElement.style.display = "none"; playerOffElement.style.display = "none";
iniciarChat();
} else { } else {
console.log("Arquivo não encontrado."); console.log("Arquivo não encontrado.");
videoElement.style.opacity = "0"; videoElement.style.opacity = "0";
if (chatContainer) {
chatContainer.style.opacity = "0.3";
chatContainer.style.pointerEvents = "none";
}
if (usernameInput) usernameInput.disabled = true;
if (chatInputField) chatInputField.disabled = true;
} }
}); });
@ -94,6 +110,9 @@
// Chat ao vivo // Chat ao vivo
// ===================== // =====================
function iniciarChat() {
chatAtivo = true;
const nomesAlice = [ const nomesAlice = [
'Alice', 'Chapeleiro Maluco', 'Coelho Branco', 'Rainha de Copas', 'Alice', 'Chapeleiro Maluco', 'Coelho Branco', 'Rainha de Copas',
'Gato de Cheshire', 'Lebre de Março', 'Lagarta', 'Dodo', 'Gato de Cheshire', 'Lebre de Março', 'Lagarta', 'Dodo',
@ -107,31 +126,39 @@
let username = nomeAleatorio(); let username = nomeAleatorio();
function setCustomUsername() { function setCustomUsername() {
const customUsername = document.querySelector('#username-input').value.trim(); const customUsername = usernameInput.value.trim();
username = customUsername || nomeAleatorio(); username = customUsername || nomeAleatorio();
} }
const source = new EventSource(`php/chat/relay.php?user=${encodeURIComponent(streamUser)}`); const source = new EventSource(`php/chat/relay.php?user=${encodeURIComponent(streamUser)}`);
let ultimaMensagem = "";
source.onmessage = function (event) { source.onmessage = function (event) {
if (event.data !== ultimaMensagem) {
ultimaMensagem = event.data;
const msg = JSON.parse(event.data); const msg = JSON.parse(event.data);
addMessage(msg); addMessage(msg);
}
}; };
function sendMessage(event) { function sendMessage(event) {
event.preventDefault(); event.preventDefault();
const message = document.querySelector('.chat-enter').value; const message = document.querySelector('.chat-enter').value;
if (!message.trim()) return;
const msgData = { const msgData = {
nome: username, nome: username,
mensagem: message mensagem: message.trim()
}; };
fetch(`php/chat/send.php?user=${encodeURIComponent(streamUser)}`, { fetch(`php/chat/send.php?user=${encodeURIComponent(streamUser)}`, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: 'mensagem=' + encodeURIComponent(JSON.stringify(msgData)) body: 'mensagem=' + encodeURIComponent(JSON.stringify(msgData))
}); })
.catch(err => console.error("Erro ao enviar mensagem:", err));
document.querySelector('.chat-enter').value = ''; document.querySelector('.chat-enter').value = '';
} }
@ -146,6 +173,7 @@
chatLines.scrollTop = chatLines.scrollHeight; chatLines.scrollTop = chatLines.scrollHeight;
} }
document.querySelector('.chat-input-form').addEventListener('submit', sendMessage); chatForm.addEventListener('submit', sendMessage);
document.querySelector('#username-input').addEventListener('change', setCustomUsername); usernameInput.addEventListener('change', setCustomUsername);
}
</script> </script>

View File

@ -578,7 +578,6 @@ h1, h2, h3, h4, h5, h6 {
.player-off{ .player-off{
height: 80vh; height: 80vh;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@ -590,10 +589,9 @@ h1, h2, h3, h4, h5, h6 {
.player-container { .player-container {
position: relative; position: relative;
/* width: 100%;
height: 100%; */
flex-grow: 10; flex-grow: 10;
/* Em telas grandes, pode ser interessante adicionar margem para separar do chat */
/* margin: 15px; */
} }
.player { .player {
@ -608,14 +606,13 @@ h1, h2, h3, h4, h5, h6 {
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: rgba(0, 0, 0, 0.6); /* Cor de fundo semitransparente */ background-color: rgba(0, 0, 0, 0.6); /* Fundo semitransparente */
color: #fff; color: #fff;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
border-radius: 15px; border-radius: 15px;
z-index: 10; /* Garante que a mensagem "Offline" apareça em cima do vídeo */ z-index: 10; /* Garante que a mensagem "Offline" fique acima do player */
} }
.player-info { .player-info {
@ -623,7 +620,7 @@ h1, h2, h3, h4, h5, h6 {
background-color: #0b1a33; background-color: #0b1a33;
} }
/* Estilos específicos para o player, se necessário */ /* Estilos específicos para o player */
video::-webkit-media-controls { video::-webkit-media-controls {
background-color: hsl(0, 0%, 14%); background-color: hsl(0, 0%, 14%);
} }
@ -632,22 +629,24 @@ video::-webkit-media-controls-play-button {
color: #fff; color: #fff;
} }
/* Container que engloba o player e o chat */
.live-container{ .live-container{
display: flex; display: flex;
flex-direction: row; flex-direction: column; /* Padrão: empilha o player e o chat (telas pequenas) */
height: 70vh; height: 70vh;
padding: 15px;
width: 100%; width: 100%;
} }
/* Estilos do chat */
.chat { .chat {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex-grow: 1; flex-grow: 1;
margin: 15px; margin: 15px;
background-color: var(--background-color); background-color: var(--background-color);
border-radius: 10px; border-radius: 10px;
color: #fff; color: #fff;
} }
.chat-container { .chat-container {
@ -682,6 +681,7 @@ color: #fff;
.chat-line p { .chat-line p {
margin: 0; margin: 0;
color: #fff; color: #fff;
overflow-wrap: break-word;
} }
.username { .username {
@ -714,6 +714,45 @@ color: #fff;
background-color: #243b65; background-color: #243b65;
} }
/* ===== Regras responsivas ===== */
/* Para telas grandes: layout em linha com chat à direita */
@media (min-width: 768px) {
.live-container {
flex-direction: row; /* Player e chat lado a lado */
align-items: stretch; /* Garante que ambos tenham a mesma altura */
}
.player-container {
flex-grow: 1;
margin: 15px; /* Opcional: ajuste de espaçamento */
}
.chat {
width: 400px; /* Largura fixa, semelhante à do chat da Twitch */
height: 95%; /* Alinha a altura do chat à do contêiner (e do player) */
margin: 15px;
}
}
/* Para telas pequenas: layout em coluna com chat abaixo do player */
@media (max-width: 767px) {
.live-container {
flex-direction: column;
height: auto;
}
.player-container, .chat {
width: 100%;
margin: 15px 0; /* Espaçamento vertical */
}
.chat {
height: 500px; /* Altura ajustada para um tamanho adequado */
}
}
.page-aula{ .page-aula{
font-family: var(--font-family); font-family: var(--font-family);
} }

21
php/chat/relay.php Normal file → Executable file
View File

@ -5,31 +5,38 @@ if (!isset($_GET['user'])) {
} }
$user = preg_replace('/[^a-zA-Z0-9_-]/', '', $_GET['user']); $user = preg_replace('/[^a-zA-Z0-9_-]/', '', $_GET['user']);
// Verifica se a live está online (arquivo .mpd existe)
$mpdPath = "/var/www/html/stream/{$user}.mpd";
if (!file_exists($mpdPath)) {
http_response_code(404);
exit("Live offline");
}
header("Content-Type: text/event-stream"); header("Content-Type: text/event-stream");
header("Cache-Control: no-cache"); header("Cache-Control: no-cache");
header("Connection: keep-alive"); header("Connection: keep-alive");
$tmp_file = sys_get_temp_dir() . "/relay_chat_{$user}.txt"; $tmp_file = sys_get_temp_dir() . "/relay_chat_{$user}.txt";
// Cria o arquivo se ainda não existir
if (!file_exists($tmp_file)) { if (!file_exists($tmp_file)) {
file_put_contents($tmp_file, ''); file_put_contents($tmp_file, '');
} }
$last_modif = 0; $lastMessage = '';
while (true) { while (true) {
clearstatcache(); clearstatcache();
$current_modif = filemtime($tmp_file); $currentMessage = trim(file_get_contents($tmp_file));
if ($current_modif > $last_modif) { if ($currentMessage !== '' && $currentMessage !== $lastMessage) {
$last_modif = $current_modif; echo "data: " . $currentMessage . "\n\n";
$data = file_get_contents($tmp_file);
echo "data: " . trim($data) . "\n\n";
ob_flush(); ob_flush();
flush(); flush();
$lastMessage = $currentMessage;
} }
sleep(1); sleep(1);
} }
?> ?>

4
php/chat/send.php Normal file → Executable file
View File

@ -1,11 +1,11 @@
<?php <?php
if (isset($_POST['mensagem']) && isset($_GET['user'])) { if (isset($_POST['mensagem']) && isset($_GET['user'])) {
$mensagem = trim($_POST['mensagem']); $mensagem = trim($_POST['mensagem']);
$user = preg_replace('/[^a-zA-Z0-9_-]/', '', $_GET['user']); // sanitiza o nome do usuário $user = preg_replace('/[^a-zA-Z0-9_-]/', '', $_GET['user']);
if ($mensagem !== '') { if ($mensagem !== '') {
$tmp_file = sys_get_temp_dir() . "/relay_chat_{$user}.txt"; $tmp_file = sys_get_temp_dir() . "/relay_chat_{$user}.txt";
file_put_contents($tmp_file, $mensagem); file_put_contents($tmp_file, $mensagem); // sobrescreve, não acumula
} }
} }
?> ?>