Autor Zpráva
fuyos
Profil *
Dobrý den,

jak se řeší to, když kliknu na tlačítko, aby se zvuk přehrál všem co jsou na dané stránce na webu?
například mám chat, kde lidé chatují a když kliknu na tlačítko "přehrát zvuk" tak se přehraje ostatním uživatelům na chatu.
Joker
Profil
fuyos:
Těžko.
Ale v principu by to šlo udělat stejně jako jiné podobné aktualizace: Všechny otevřené stránky by se pravidelně ptaly serveru, jestli bylo stisknuté tlačítko, a pokud ano, přehrály by zvuk.
fuyos
Profil *
Joker:
A když by se odeslala zpráva do chatu, a všem by se zvuk přehrál bylo by to snažší?
Joker
Profil
Čili to má být zvuk při přijetí zprávy?
Pak bude nejjednodušší ho navázat na událost přijetí zprávy.
fuyos
Profil *
Joker:
Ano, někdo odešle zprávu do chatu a zvuk se přehraje všem co jsou na stránce. Zkoušel jsem celé dopoledně hledat něco na googlu, ale nic kloudnýho jsem nenašel.
juriad
Profil
Jelikož neexistuje rozumná možnost komunikace přímo mezi uživateli, musí informace projít skrze server.
Odeslání zprávy na server je trivka (to předpokládám uz máš). Informovat uživatele o nové zprávě snadno nelze - server se nemůže jen tak rozhodout poslat informaci klientům. Iniciativa musí vždy přijít od klienta. Klienti se tedy musí neustále ptát „Ahoj servere, nemáš pro mě něco?“. Obvykle se to řeší AJAXem, ale okamžitě tě napadne, že ptát se ve smyčce pořád dokola by zatěžovalo server, proto se tam dávají nějaké prodlevy (nebo se používají různé triky, jako třeba long polling, ale to obvykle vyžaduje speciální konfigurace serveru). Musíš počítat s tím, že se klient nikdy nedozví o zprávě okamžitě, nějaké zpoždění v řádu sekund tam bude vždy. Pamatuj na to, že prodleva může být různě dlouhá (napřiklad to může být sekunda po dobu první minuty od přijetí poslední zprávy, pak 5 sekund po dobu prvních 10 minut, a pak 30 sekund).
fuyos
Profil *
juriad:
aha díky za vysvětlenou, takže jednoduše musím se smířit, že to neudělám :D
Str4wberry
Profil
Já v tom problém nevidím.

Na serveru se vytvoří záznam, že se má přehrát zvuk. Klienti připojení k chatu si tuto informaci ze serveru stáhnou (podobně jako si stáhnou novou zprávu) a přehrají zvuk.
fuyos
Profil *
Str4wberry:
Ano, ale jak zamezím tomu, aby se už zvuk nepřehrával dokola, ale pouze jednou a aby to bylo real-time?
xROAL
Profil
juriad:
server se nemůže jen tak rozhodout poslat informaci klientům
Dovolil by som si poznamenať, že môže. WebSocket.
Str4wberry
Profil
Opakovanému přehrávání zabráníte časovým razítkem, které se pošle při žádost o nové informace ze serveru. Stejně jako v případě zobrazování nových zpráv.

Jak nyní řešíte zobrazování nových zpráv v chatu? Přehrát zvuk nebo zobrazit zprávu se realisuje prakticky stejně. Jen v případě zvuku se místo přilepení nových zpráv do okna chatu spustí přehrání nějakého zvuku.

Real-time to potom bude stejně jako ty zprávy.
Joker
Profil
fuyos:
jak zamezím tomu, aby se už zvuk nepřehrával dokola, ale pouze jednou a aby to bylo real-time?
Problém s opakovaným přehráváním tam nevidím.

Má představa je, že klient (stránka) se čas od času zeptá serveru, jestli jsou nové zprávy.
Když jsou nové zprávy, zobrazí je a přehraje zvuk.
Jestli ten zvuk má být upozornění na zprávu, navázal bych ho na přijetí zprávy.

Dodatek: Jen samozřejmě server musí poznat, jestli existují zprávy, které ten klient ještě nemá, a případně mu je poslat. Ale bez toho nebude fungovat ani to zobrazování nových zpráv.
fuyos
Profil *
Chat se mi obnovuje právě automaticky každých 5 sekund, takže to nemám vyřešený, když příjde nová zpráva aktualizuje se seznam.
Joker
Profil
fuyos:
Aha, takže chat se neaktualizuje přes AJAX, ale novým načtením stránky?
V tom případě by server musel vědět a do stránky vložit tu informaci, jestli je nějaká nová zpráva od posledně.
fuyos
Profil *
Joker:
Ajax využívám, ale ten se obnovuje každých 5 sekund a né podle toho jestli přijde nová zpráva, neb ose pletu?

function showmessages(){

if(window.XMLHttpRequest){
xmlhttp = new XMLHttpRequest();

xmlhttp.open("GET","/chat-zpravy.php?" + Math.random(),false);
xmlhttp.send(null);
}

document.getElementById('messages').innerHTML = xmlhttp.responseText;

setTimeout('showmessages()',5000);
}
juriad
Profil
Ano, každých 5 sekund. Ve funkci showmessages přece můžeš poznat, zda přibyly nějaké zprávy (třeba podle počtu elementů). Pokud ano spustíš zvuk. Nic víc na tom není. Nebudeš mít zpoždění víc než 5 sekund, ale s tím jsi snad smířený, ne?
fuyos
Profil *
Popravdě, já jsem tenhle kód našel někde na internetu takže jsem byl rád, že mi to funguje, alespoň takto. Vůbec nevím jak bych tam přidal, aby to poznalo jestli je nová zpráva, ajaxu moc nerozumím.
juriad
Profil
No to je těžké, když až teď po několika dnech řekneš, že nějaký kód již máš a že mu nerozumíš. My nevíme, jak vypadá ten chat. To, co máš uvedené v [#15] přepíše vždy všechny zprávy, potom je to trošku obtížnější. Ukaž jak vypadá HTML stránky, pokud už obsahuje nějakou zprávu.
Někde budeš asi mít <div id="messages"> a do něj se budou vlepovat nějaké elementy. To je to místo, které nás zajímá.
fuyos
Profil *
Omlouvám se, nevěděl jsem, že stím budou také problémy... html vypadá takto

<div id="messages"> 
<table>
<tbody><tr>
<td class="chat_left"><img src="/img/status_online.png" alt="online" title="online" style="padding-right:3px;" width="8"><a href="javascript:Smile('Pavel: ')" title="Odpovědět"><span class="chat_span_admin">Pavel</span></a><br><span class="chat_datum">(06.10. - 16:26)</span></td><td class="chat_text">druhý test</td>
</tr>
</tbody></table>
<table>
<tbody><tr>
<td class="chat_left"><img src="/img/status_online.png" alt="online" title="online" style="padding-right:3px;" width="8"><a href="javascript:Smile('Adam: ')" title="Odpovědět"><span class="chat_span_admin">Adam</span></a><br><span class="chat_datum">(06.10. - 16:26)</span></td><td class="chat_text">test</td>
</tr>
</tbody></table>
</div>
juriad
Profil
fuyos:
Takže co zpráva to tabulka, sice to není elegantní, ale když to funguje...

// tady si budeme počítat zprávy
// pokud se jejich počet liší, objevila se nová a budeme chtít něco udělat
var pocetZprav = -1;
// připravíme si zvuk, aby se později mohl snadno přehrát
var audio = new Audio('kvik.mp3');
function showmessages() {
  if (window.XMLHttpRequest){
    xmlhttp = new XMLHttpRequest();
    // toto je elegantnější než náhodné číslo
    xmlhttp.open("GET", "/chat-zpravy.php?" + +new Date(), false);
    xmlhttp.onreadystatechange(function() {
      // pokud dojde k chybě:
      if ( 4 != xmlhttp.readyState ) {
        return;
      }
      if ( 200 != xmlhttp.status ) {
        return;
      }
      // vše ok - nastavíme zprávy
      document.getElementById('messages').innerHTML = xmlhttp.responseText;
      // zjistíme počet tabulek v div#messages
      var novyPocetZprav = document.querySelectorAll('#messages > table').length;
      // pokud je nový počet zpráv větší a zároveň dřívější počet není -1
      // což by bylo jen při prvním načtení (kdy nechceme kvíkat)
      if (novyPocetZprav > pocetZprav && pocetZprav != -1) {
        // přehrajeme zvuk
        audio.play();
      }
      // zapamatujeme si nový počet zpráv
      pocetZprav = novyPocetZprav;
    }
    xmlhttp.send();
  }
  // do timeoutu nedávej jako první argument řetězec, ale funkci
  setTimeout(showmessages, 5000);
}
fuyos
Profil *
Díky vypadá to srozumitelně, nicméně, teďkon se mi nezobrazuje žádná zpráva.
Str4wberry
Profil
Tipoval bych, že ten skript bude vždy vracet pevný počet posledních zpráv, takže to takhle počítat nepůjde.

Nejjednodušší by asi bylo uložit si do proměnné poslední zprávu a určovat změny podle ní.

Teoreticky zde ale bude problém, že momentální HTML kód může vést k duplicitě, když jeden člověk v jedné minutě zašle dvě stejné zprávy. Snadná záplata by byla přidat do toho kódu někam (třeba do atributu) vteřiny. Jméno uživatele + timestamp už by mohlo zajišťovat jistou unikátnost.

Jinak optimální postup by byl takový, že se do požadavků na server přidá ID poslední zprávy. Server potom vrátí pouze zprávy, které mají vyšší ID. V případě, že nevrátí nic nového se potom nemusí zbytečně překreslovat celá tabulka.

Pro zobrazení nových zpráv se potom pouze přidají ty nové ke stávajícím. (Zároveň je od určitého počtu zpráv dobré začít ty staré odstraňovat, aby stránka tolik nebobtnala.)
fuyos
Profil *
takže juriadovo řešení nelze provést v tomto případě?
juriad
Profil
fuyos:
My nevíme, co se děje uvnitř chat-zpravy.php, je možné, že se tam děje něco, co popisoval Str4wberry.
Měl jsem tam chybu, opravím ji (ale stejnu chybu jsi tam měl i ty a fungovalo ti to).
fuyos
Profil *
juriad: Bohužel nepomohlo, ještě jsem si všiml, že předtím jsem měl na konci AJAXu volání funkce showmessages();, ale ani stímhle mi to nefunguje.
teď to mám ve stavu:
chat.php
<div id="messages"></div>

<script type="text/javascript">
// tady si budeme počítat zprávy
// pokud se jejich počet liší, objevila se nová a budeme chtít něco udělat
var pocetZprav = -1;
// připravíme si zvuk, aby se později mohl snadno přehrát
var audio = new Audio('kvik.mp3');
function showmessages() {
  if (window.XMLHttpRequest){
    xmlhttp = new XMLHttpRequest();
    // toto je elegantnější než náhodné číslo
    xmlhttp.open("GET", "/modules/chat-zpravy.php?" + +new Date(), false);
    xmlhttp.onreadystatechange(function() {
      // pokud dojde k chybě:
      if ( 4 != xmlhttp.readyState ) {
        return;
      }
      if ( 200 != xmlhttp.status ) {
        return;
      }
      // vše ok - nastavíme zprávy
      document.getElementById('messages').innerHTML = xmlhttp.responseText;
      // zjistíme počet tabulek v div#messages
      var novyPocetZprav = document.querySelectorAll('#messages > table').length;
      // pokud je nový počet zpráv větší a zároveň dřívější počet není -1
      // což by bylo jen při prvním načtení (kdy nechceme kvíkat)
      if (novyPocetZprav > pocetZprav && pocetZprav != -1) {
        // přehrajeme zvuk
        audio.play();
      }
      // zapamatujeme si nový počet zpráv
      pocetZprav = novyPocetZprav;
    }
    xmlhttp.send();
  }
  // do timeoutu nedávej jako první argument řetězec, ale funkci
  setTimeout(showmessages, 5000);
}


</script>
chat-zpravy.php jsme zjednodušil, odstranil smajlíky apodobně

<?php  
session_start();
require_once '../inc/dibi.min.php';
require_once '../inc/db_connection.php';  
require_once '../inc/login.php';

$sql = dibi::fetchAll("SELECT * FROM chat ORDER BY datum DESC LIMIT 30");
$celkemm = count($sql);
foreach($sql as $row) { 
$uziv_row = dibi::fetch("SELECT id,login FROM users WHERE id = %i", $row->autor); 
       
$comm_obsah = $row["text"];
                    
echo '
<table>
<tr>
<td class="chat_left">';
echo '<span class="chat_span">'.$uziv_row['login'].'</span>';
echo '<br><span class="chat_datum">('.date("d.m. - H:i",strtotime($row["datum"])).')</span></td>';
echo '<td class="chat_text">'.$comm_obsah.'</td>';
echo '</tr>
</table>'; 
}
?>
juriad
Profil
fuyos:
Ano, tu funkci showmessages musíš spustit. To jsem myslel, že děláš. Přidej před </script>:
showmessages();

Aha, server posílá vždy jen posledních 30 zpráv. Můžeš nám ukázat jak vypadá v databázi tabulka chat a users?
Pokud možno příkazem: SHOW CREATE TABLE název-tabulky
Ono v tom souboru je i tak pár chybek, takže ho bude lepší skoro celý přepsat, ale musíme znát to databázové schéma.

Měl jsem chybku v tom SQL dotazu.
fuyos
Profil *
juriad:
ten příkaz mi nefunguje a když dám SHOW TABLES FROM chat; tak mi to píše acces denied...

CREATE TABLE IF NOT EXISTS `chat` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `autor` int(11) NOT NULL,
  `datum` datetime NOT NULL,
  `text` text NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=14 ;

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(20) NOT NULL AUTO_INCREMENT,
  `login` varchar(50) NOT NULL,
  `password` text,
  `datum` date NOT NULL DEFAULT '0000-00-00',
  `email` text NOT NULL,
  `ip` varchar(250) NOT NULL,
  `jmeno` varchar(200) DEFAULT NULL,
  `prijmeni` varchar(100) NOT NULL,
  `telefon` varchar(50) NOT NULL,
  `admin` int(1) NOT NULL DEFAULT '0',
  `avatar` varchar(50) NOT NULL DEFAULT 'no_img.jpg',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1958 ;



CREATE TABLE `chat` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `autor` int(11) NOT NULL,
 `datum` datetime NOT NULL,
 `text` text NOT NULL,
 PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=14 DEFAULT CHARSET=utf8

CREATE TABLE `users` (
 `id` int(20) NOT NULL AUTO_INCREMENT,
 `login` varchar(50) NOT NULL,
 `password` text,
 `datum` date NOT NULL DEFAULT '0000-00-00',
 `email` text NOT NULL,
 `ip` varchar(250) NOT NULL,
 `jmeno` varchar(200) DEFAULT NULL,
 `prijmeni` varchar(100) NOT NULL,
 `telefon` varchar(50) NOT NULL,
 `admin` int(1) NOT NULL DEFAULT '0',
 `avatar` varchar(50) NOT NULL DEFAULT 'no_img.jpg',
 PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=1958 DEFAULT CHARSET=utf8
Venca190
Profil *
Dobrý večer, půjde to nějak vyřešit nebo je to marné?

Vaše odpověď


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: