summaryrefslogblamecommitdiff
path: root/baitv.js
blob: 97c7abc3896bf8acf77abb30ecee2618ed2d1636 (plain) (tree)









































































                                                                                                                                                                                                             
                                  










































































































































































































































































































































                                                                                                                            






                                              
                           


                                                













































                                                                                           


                                                          
                              






                                               
                                                                  










                                                                                          
                                                             



















































































































































































































































                                                                                                                                                       
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("<", "&lt;")
         .replace(">", "&gt;")
         .replace("\"", "&quot;")
         .replace("'", "&#039;");
}

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");
}