var s; var antiflood = false; var is_connected = false; var chat_num = 0; var focused = true; var comments_hidden = false; var video, hls, dash; var current_source; var notice_audio; var loading_timer; var live_mode = "hls"; var live_time = -1; var modpanel = null; var mod = false; var mod_name = ""; var is_fullscreen; var fullscreen_activity = {on: false, hide: null}; var notice_activity = {on: false, hide: null, blink: null}; var CHAT_FACTOR = (ANIM_MAX - ANIM_MIN) / MAXCHAR; function removeThis(e) { e.target.parentElement.removeChild(e.target); } const formatTime = (seconds, h = Math.floor(seconds / 3600), m = Math.floor((seconds % 3600) / 60), s = Math.floor(seconds) % 60) => [h, m > 9 ? m : '0' + m, s > 9 ? s : '0' + s].filter(s => s).join(':'); function escapeColon(msg) { return msg ? msg.replace(/:/g, "%3A") : ""; } function translateColon(msg) { return msg ? msg.replace(/%3A/g, ":") : ""; } function escapeHTML(unsafe) { return unsafe .replace("&", "&") .replace("<", "<") .replace(">", ">") .replace("\"", """) .replace("'", "'"); } function show_chat(msg, color, own) { if(!focused) return; var chat = document.getElementById("chat"); var chats = chat.children; var chat_rect = chat.getBoundingClientRect(); var line = 0; for(var i = 0; i < chats.length; i++) { var el = chats[i]; var rect = el.getBoundingClientRect(); if( el.dataset.line == line && (rect.left - chat_rect.left + rect.width) > (chat_rect.width - CHAT_SEP) ) { i = 0; line++; } } var obj = document.createElement('span'); obj.style.boxSizing = "content-box"; obj.textContent = msg; obj.dataset.line = line; obj.addEventListener("transitionend", removeThis); obj.classList.add("c"+color); chat.appendChild(obj); if(own) obj.classList.add("own"); var width = Math.round(obj.getBoundingClientRect().width); var height = parseFloat(getComputedStyle(obj).getPropertyValue("height")); obj.style.top = ((height+LINE_SEP)*line) + "px"; obj.style.transitionDuration = (ANIM_MIN + (msg.length * CHAT_FACTOR)) + "s"; obj.style.left = "-" + width + "px"; } function show_notice(name, msg) { document.getElementById("noticebox").style.backgroundImage = "none"; document.getElementById("notice").innerHTML = anchorme(escapeHTML(msg), {truncate: 20}); document.getElementById("notice").style.animation = "blinker 0.2s step-start infinite"; document.getElementById("author").textContent = (name ? name : "Streamer"); if(is_fullscreen) document.getElementById("noticebox").style.display = "block"; if(!video.muted) { if(typeof variable === 'undefined') notice_sound = new Audio("notice.opus"); notice_sound.volume = video.volume; notice_sound.play(); } clearTimeout(notice_activity.hide); clearTimeout(notice_activity.blink); notice_activity.hide = setTimeout(hide_notice, NOTICE_TIME); notice_activity.blink = setTimeout(stop_notice_blink, NOTICE_BLINK_TIME); notice_activity.on = true; } function stop_notice_blink() { document.getElementById("notice").style.animation = "none"; } function hide_notice() { document.getElementById("noticebox").style.backgroundImage = "url('baitvlogo.png')"; document.getElementById("notice").textContent = ""; document.getElementById("author").textContent = ""; if(is_fullscreen) document.getElementById("noticebox").style.display = "none"; notice_activity.on = false; } function get_time() { var time = new Date(); return ( ("0" + time.getHours()).slice(-2) + ":" + ("0" + time.getMinutes()).slice(-2) + ":" + ("0" + time.getSeconds()).slice(-2)); } function show_tt(e) { var tt = document.getElementById("tt"); tt.style.visibility = "visible"; tt.textContent = this.children[0].textContent; tt.style.left = (e.pageX + 10) + "px"; tt.style.top = (e.pageY + 10) + "px"; } function hide_tt(e) { var tt = document.getElementById("tt"); tt.style.visibility = "hidden"; } function show_chatbox(msg, classname) { var chatbox = document.getElementById("chatbox"); var chatbox_length = chatbox.children.length; if(chatbox_length >= CHATBOX_MAX) chatbox.removeChild(chatbox.firstChild); var line = document.createElement('div'); var content = document.createElement('span'); var time = document.createElement('span'); //line.classList.add("l" + (chat_num ^= 1)); line.addEventListener("mousemove", show_tt); line.addEventListener("mouseout", hide_tt); if(classname) line.classList.add(classname); content.textContent = msg; content.className = "msg"; line.appendChild(content); //time.textContent = get_time(); time.textContent = get_live_time(); time.className = "time"; line.appendChild(time); chatbox.appendChild(line); chatbox.scrollTop = chatbox.scrollHeight; } function on_msg(line) { console.log("<< " + line); var args = line.split(':'); if(args[0] == "MSG") { var color = args[1]; var msg = translateColon(args[2]); show_chat(msg, color, false); show_chatbox(msg, null); } else if (args[0] == "FMSG") { var id = args[1]; var color = args[2]; var msg = translateColon(args[3]); show_chat(msg, color, false); show_chatbox("["+id+"] " + msg, null); } else if (args[0] == "NOTICE") { var name = args[1]; var msg = translateColon(args[2]); show_notice(name, msg); show_chatbox((name ? "["+name+"] "+msg : msg), "mod"); } else if (args[0] == "COUNT") { document.getElementById("viewers").textContent = args[1]; } else if (args[0] == "SOURCE") { switch_source(args[1], parseInt(args[2])); } else if (args[0] == "TITLE") { var title = translateColon(args[1]); set_title(title); } else if (args[0] == "KICKED" || args[0] == "BANNED") { show_chatbox("Un usuario fue expulsado.", "warn"); } else if (args[0] == "YOU_KICKED" || args[0] == "YOU_BANNED") { show_chatbox("¡Fuiste expulsado!", "warn"); } else if (args[0] == "BADPASS") { set_status("Mod: PSK erróneo."); } else if (args[0] == "LOGIN_OK") { set_status("Mod: Log in suceso."); enable_modpanel(true, args[1]); } else if (args[0] == "LOGOUT_OK") { set_status("Mod: Log out suceso."); enable_modpanel(false, ""); } else { if(mod) set_status(line); } } function set_title(title) { document.getElementById("title").textContent = title ? title : "Sin título"; } function set_status(msg) { show_chatbox(msg, "sys"); console.log(msg); } function video_play() { video.muted = false; if(typeof Promise === "function") { var promise = video.play(); promise.catch(function(e) { console.log("Your browser is rejecting autoplay; attempting to play muted."); video.muted = true; video.play(); }); } else { console.log("Promise not supported; muting just in case."); video.muted = true; video.play(); } } function video_volume() { if(video.muted) video.muted = false; video.volume = this.value; } function parse_state(msg) { var state = JSON.parse(msg); switch_source(state.source, state.source_time); set_title(translateColon(state.title)); if(state.welcome) show_chatbox(state.welcome, "sys"); } function switch_source(source, src_time) { if(!PLAY) return; if(current_source == source) return; console.log("Switching source to: " + source); if(source == "live") { console.log(src_time); // hls.js video.src = ""; video.loop = false; video.addEventListener("waiting", event_waiting); video.addEventListener("canplay", event_canplay); source_time = src_time if(live_mode == "hls") { if(Hls.isSupported()) { hls = new Hls(HLS_CONFIG); hls.loadSource(MEDIA_HLS_URL); hls.attachMedia(video); video_play(); hls.on(Hls.Events.MANIFEST_PARSED,function() {video_play();}); hls.on(Hls.Events.ERROR, on_hls_error); hls.on(Hls.Events.FRAG_CHANGED,function(event,data) { live_time = Math.floor((data.frag.programDateTime / 1000) - data.frag.start) - source_time; }); } else { set_status("Tu navegador no soporta HLS. Cancelando."); return; } } else if(live_mode == "dash") { if ( typeof ( window.MediaSource || window.WebKitMediaSource ) === "function" ) { if(!dash) dash = dashjs.MediaPlayer().create(); dash.initialize(); //dash.getDebug().setLogToBrowserConsole(true); dash.setAutoPlay(false); dash.setManifestLoaderRetryAttempts(7); dash.setManifestLoaderRetryInterval(5); dash.on(dashjs.MediaPlayer.events.CAN_PLAY, video_play); dash.attachView(video); dash.attachSource(MEDIA_DASH_URL); event_waiting(); live_time = 0; set_status("Nota: Utilizando DASH. ¡Experimental!"); } else { set_status("Tu navegador no soporta MediaSource. Cancelando."); return; } } else if(live_mode == "rx") { if ( typeof ( window.MediaSource || window.WebKitMediaSource ) === "function" ) { var rx = new RxPlayer({videoElement: video}); rx.loadVideo({url: MEDIA_DASH_URL, transport:"dash", autoPlay:false}); live_time = 0; set_status("Nota: Utilizando DASH (rx). ¡Experimental!"); video_play(); } else { set_status("Tu navegador no soporta MediaSource. Cancelando."); return; } } else if(live_mode == "shaka") { shaka.polyfill.installAll(); if(shaka.Player.isBrowserSupported()) { var player = shaka.Player(video); player.load(MEDIA_DASH_URL).then(video_play); live_time = 0; set_status("Nota: Utilizando DASH (shaka). ¡Experimental!"); } else { set_status("Tu navegador no soporta Shaka. Cancelando."); return; } } document.getElementById("livestatus").classList.add("live"); } else { if(current_source == "live") { if(hls) { hls.detachMedia(); hls.destroy(); console.log("hls.js destroyed"); } if(dash) { dash.reset(); console.log("dash.js destroyed"); } } source_time = -1 live_time = -1; document.getElementById("time").textContent = "--:--"; video.src = IDLE_VIDEO; video.loop = true; video.muted = true; video.removeEventListener("waiting", event_waiting); video.removeEventListener("canplay", event_canplay); event_canplay(); video.play(); document.getElementById("livestatus").classList.remove("live"); } current_source = source; } function on_hls_error(e, data) { console.log(data['type']); console.log(data['details']); } function update_controls() { document.getElementById("volume").style.opacity = video.muted ? 0.5 : 1; document.getElementById("mute").children[0].style.display = video.muted ? "none" : "block"; document.getElementById("mute").children[1].style.display = video.muted ? "block" : "none"; document.getElementById("volume").value = video.volume; } function get_live_time() { if(current_source == "live") { return formatTime(live_time + video.currentTime); } else { return "--:--" } } function update_time() { if(current_source == "live") document.getElementById("time").textContent = get_live_time(); } function on_play() { if(video.paused) video.play() else video.pause() } function on_mute() { video.muted = !video.muted; } function on_hidecomments() { if(comments_hidden) { document.getElementById("chat").style.visibility = "visible"; document.getElementById("hidecomments").children[0].style.display = "block"; document.getElementById("hidecomments").children[1].style.display = "none"; comments_hidden = false; } else { document.getElementById("chat").style.visibility = "hidden"; document.getElementById("hidecomments").children[0].style.display = "none"; document.getElementById("hidecomments").children[1].style.display = "block"; comments_hidden = true; } } function fullscreenElement() { return (document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement); } function on_fullscreen() { var elem = document.getElementById("player"); if (fullscreenElement()) { if (document.exitFullscreen) { document.exitFullscreen(); } else if (document.mozCancelFullScreen) { /* Firefox */ document.mozCancelFullScreen(); } else if (document.webkitExitFullscreen) { /* Chrome, Safari and Opera */ document.webkitExitFullscreen(); } else if (document.msExitFullscreen) { /* IE/Edge */ document.msExitFullscreen(); } } else { console.log("requesting full screen"); if (elem.requestFullscreen) { elem.requestFullscreen(); } else if (elem.mozRequestFullScreen) { /* Firefox */ elem.mozRequestFullScreen(); } else if (elem.webkitRequestFullscreen) { /* Chrome, Safari and Opera */ elem.webkitRequestFullscreen(); } else if (elem.msRequestFullscreen) { /* IE/Edge */ elem.msRequestFullscreen(); } } } function fullscreen_clear() { fullscreen_base(false); clearTimeout(fullscreen_activity.hide); fullscreen_activity.on = false; } function fullscreen_base(show) { var base = document.getElementById("base"); base.style.visibility = show ? "" : "hidden"; document.getElementById("player").style.cursor = show ? "" : "none"; } function fullscreen_move(e) { if(!fullscreen_activity.on) { fullscreen_base(true); fullscreen_activity.on = true; } clearInterval(fullscreen_activity.hide); fullscreen_activity.hide = setInterval(fullscreen_clear, BASE_SHOW_TIME); } function fullscreen_event() { var noticebox = document.getElementById("noticebox"); var base = document.getElementById("base"); if(fullscreenElement()) { base.style.position = "absolute"; base.style.opacity = "0.7"; noticebox.style.position = "absolute"; if(!notice_activity.on) { noticebox.style.display = "none"; } fullscreen_move(null); document.getElementById("chat").style.fontSize = "4.6vw"; document.getElementById("player").addEventListener("mousemove", fullscreen_move); document.getElementById("player").addEventListener("keypress", fullscreen_move); document.getElementById("chat_msg").focus(); is_fullscreen = true; } else { base.style.position = ""; base.style.opacity = ""; noticebox.style.position = ""; noticebox.style.display = ""; clearInterval(fullscreen_activity.hide); fullscreen_base(true); document.getElementById("chat").style.fontSize = ""; document.getElementById("player").removeEventListener("mousemove", fullscreen_move); document.getElementById("player").removeEventListener("keypress", fullscreen_move); is_fullscreen = false; } } function event_waiting() { loading_timer = setTimeout(show_loading, 1000); } function show_loading() { document.getElementById("loading").style.display="block"; } function event_canplay() { clearInterval(loading_timer); document.getElementById("loading").style.display="none"; } function start() { console.log("baitv.js 0.4"); if(window.location.href.endsWith("?dash")) live_mode = "dash"; if(window.location.href.endsWith("?rx")) live_mode = "rx"; if(window.location.href.endsWith("?shaka")) live_mode = "shaka"; video = document.getElementById('video'); if(PLAY) { var req = new XMLHttpRequest(); req.onload = function(e) { parse_state(req.response); } req.open("GET", STATE_URL + "?t=" + Date.now()); req.send(); } if(CONNECT) { s = new WebSocket(ADDRESS); s.addEventListener("message", function(e) { on_msg(e.data); }); s.addEventListener("open", function(e) { set_status("Conectado al chat."); is_connected = true; enable_chat(); }); s.addEventListener("close", function(e) { set_status("Desconectado del chat. " + (e.reason ? "Razón: "+e.reason : "Código: "+e.code)); is_connected = false; document.getElementById("viewers").textContent = "-"; }); } document.getElementById("sendchat").addEventListener("click", on_send); //document.getElementById("playbtn").addEventListener("click", on_play); document.getElementById("mute").addEventListener("click", on_mute); document.getElementById("hidecomments").addEventListener("click", on_hidecomments); document.getElementById("fullscreen").addEventListener("click", on_fullscreen); var vol = document.getElementById("volume"); vol.min = 0; vol.max = 1; vol.step = 0.01; vol.addEventListener("input", video_volume); video.addEventListener("volumechange", update_controls); video.addEventListener("timeupdate", update_time); //video.addEventListener("stalled", function() {console.log("stalled");}); //video.addEventListener("playing", function() {console.log("playing");}); document.getElementById("chat_msg").focus(); } function send_msg(msg) { console.log(">> " + msg); s.send(msg); } function enable_chat() { antiflood = false; document.getElementById("sendchat").disabled = false; } function on_send(e) { e.preventDefault(); if(!is_connected) return; if(antiflood) return; var msg = document.getElementById("chat_msg"); var msg_str = msg.value.trim().substr(0, MAXCHAR); var send = document.getElementById("sendchat"); var colors = document.getElementById("colors"); if(!msg_str) return; if(is_connected) send_msg("MSG:" + colors.value + ":" + escapeColon(msg_str)); show_chat(msg_str, colors.value, true); show_chatbox(msg_str, "own"); if(is_fullscreen) fullscreen_clear(); msg.value = ""; antiflood = true; send.disabled = true; setTimeout(enable_chat, FLOOD_TIME); } window.addEventListener("load", start); window.onfocus = function() {focused = true;}; window.onblur = function() {focused = false;}; window.addEventListener ("keydown", function (e) { if (e.ctrlKey && e.key === ",") { console.log("Showing mod panel"); toggle_modpanel(); } }); document.addEventListener("fullscreenchange", fullscreen_event); document.addEventListener("mozfullscreenchange", fullscreen_event); document.addEventListener("webkitfullscreenchange", fullscreen_event); document.addEventListener("msfullscreenchange", fullscreen_event); function enable_modpanel(val, name) { mod = val; mod_name = name; document.getElementById("txt_psk").disabled = val; document.getElementById("btn_psk").textContent = val ? "Salir" : "Identificarse"; document.getElementById("txt_notice").disabled = !val; document.getElementById("btn_notice").disabled = !val; document.getElementById("chk_showname").disabled = !val; document.getElementById("txt_mod").disabled = !val; document.getElementById("btn_kick").disabled = !val; document.getElementById("btn_ban").disabled = !val; document.getElementById("txt_title").disabled = !val; document.getElementById("btn_title").disabled = !val; document.getElementById("lbl_subtitle").textContent = name ? "Identificado como: " + name : "Sin permisos" } function toggle_modpanel() { if(modpanel == null) { modpanel = document.createElement("div"); modpanel.className = "modpanel"; modpanel.style.display = "none"; var title = document.createElement("h3"); title.textContent = "Panel de streamer"; modpanel.appendChild(title); var subtitle = document.createElement("h4"); subtitle.id = "lbl_subtitle"; subtitle.textContent = "Sin permisos"; modpanel.appendChild(subtitle); var line1 = document.createElement("div"); var line2 = document.createElement("div"); var line3 = document.createElement("div"); var line4 = document.createElement("div"); line1.appendChild(document.createTextNode("PSK: ")); var txt_psk = document.createElement("input"); txt_psk.id = "txt_psk"; txt_psk.type = "password"; txt_psk.size = "20"; txt_psk.addEventListener("keydown", function(e) {if (e.keyCode === 13) btn_psk.click();}); line1.appendChild(txt_psk); var btn_psk = document.createElement("button"); btn_psk.id = "btn_psk"; btn_psk.type = "button"; btn_psk.textContent = "Identificarse"; btn_psk.onclick = function() { if(txt_psk.value && is_connected) {send_msg(mod ? "LOGOUT" : "LOGIN:" + txt_psk.value); txt_psk.value = "";} }; line1.appendChild(btn_psk); line2.appendChild(document.createTextNode("Noticia: ")); var txt_notice = document.createElement("input"); txt_notice.id = "txt_notice"; txt_notice.type = "text"; txt_notice.size = "40"; txt_notice.maxlength = "80"; txt_notice.disabled = true; txt_notice.addEventListener("keydown", function(e) {if (e.keyCode === 13) btn_notice.click();}); line2.appendChild(txt_notice); var chk_showname = document.createElement("input"); chk_showname.id = "chk_showname"; chk_showname.type = "checkbox"; chk_showname.disabled = true; var lbl_showname = document.createElement("label"); lbl_showname.appendChild(chk_showname); var lbl_lbl = document.createElement("small"); lbl_lbl.textContent = "Usar nombre"; lbl_showname.appendChild(lbl_lbl); line2.appendChild(lbl_showname); var btn_notice = document.createElement("button"); btn_notice.id = "btn_notice"; btn_notice.type = "button"; btn_notice.disabled = true; btn_notice.textContent = "Enviar"; btn_notice.onclick = function() { if(txt_notice.value && is_connected) { var msg = txt_notice.value; var showname = chk_showname.checked; send_msg("NOTICE:" + (showname?"1":"0") + ":" + escapeColon(msg)); show_notice((showname?mod_name:""), msg); show_chatbox((showname ? "["+mod_name+"] "+msg : msg), "mod"); txt_notice.value = ""; }}; line2.appendChild(btn_notice); line3.appendChild(document.createTextNode("Moderación: ")); var txt_mod = document.createElement("input"); txt_mod.id = "txt_mod"; txt_mod.type = "text"; txt_mod.disabled = true; line3.appendChild(txt_mod); var btn_kick = document.createElement("button"); btn_kick.id = "btn_kick"; btn_kick.type = "button"; btn_kick.disabled = true; btn_kick.textContent = "Kickear"; btn_kick.onclick = function() { if(txt_mod.value && is_connected) {send_msg("KICK:" + txt_mod.value); txt_mod.value = "";} }; line3.appendChild(btn_kick); var btn_ban = document.createElement("button"); btn_ban.id = "btn_ban"; btn_ban.type = "button"; btn_ban.disabled = true; btn_ban.textContent = "Banear"; line3.appendChild(btn_ban); line4.appendChild(document.createTextNode("Título: ")); var txt_title = document.createElement("input"); txt_title.id = "txt_title"; txt_title.type = "text"; txt_title.size = "30"; txt_title.maxlength = "35"; txt_title.disabled = true; txt_title.addEventListener("keydown", function(e) {if (e.keyCode === 13) btn_title.click();}); line4.appendChild(txt_title); var btn_title = document.createElement("button"); btn_title.id = "btn_title"; btn_title.type = "button"; btn_title.disabled = true; btn_title.textContent = "Cambiar"; btn_title.onclick = function() { if(is_connected) send_msg("SETTITLE:" + escapeColon(txt_title.value)); set_title(txt_title.value); txt_title.value = ""; }; line4.appendChild(btn_title); modpanel.appendChild(line1); modpanel.appendChild(line2); modpanel.appendChild(line3); modpanel.appendChild(line4); document.getElementById("bottompanel").appendChild(modpanel); } modpanel.style.display = (modpanel.style.display == "block" ? "none" : "block"); }