/* * Copyright (c) 2021 Steve Seguin. All Rights Reserved. * * Use of this source code is governed by the APGLv3 open-source license * that can be found in the LICENSE file in the root of the source * tree. Alternative licencing options can be made available on request. * */ /*jshint esversion: 6 */ var formSubmitting = true; var activatedPreview = false; var screensharebutton = true; var screensharesupport = true; var model = null; var Callbacks = []; var CtrlPressed = false; // global var AltPressed = false; var translation = false; var miscTranslations = { "new-display-name":"Enter a new Display Name for this stream", "submit-error-report": "Press OK to submit any error logs to VDO.Ninja. Error logs may contain private information.", "director-redirect-1": "The director wishes to redirect you to the URL: ", "director-redirect-2": "\n\nPress OK to be redirected.", "add-a-label": "Add a label", "audio-processing-disabled": "Audio processing is disabled with this guest. Can't mute or change volume", "not-the-director": "You are not the director of this room. You will have limited to no control. You can try claiming the room after the first director leaves.", "room-is-claimed": "The room is already claimed by someone else.\n\nOnly the first person to join a room is the assigned director.\n\nRefresh after the first director leaves to claim.", "streamid-already-published": "The stream ID you are publishing to is already in use.\n\nPlease try with a different invite link or refresh to retry again.\n\nYou will now be disconnected.", "director": "Director", "unknown-user": "Unknown User", "room-test-not-good": "The room name 'test' is very commonly used and may not be secure.\n\nAre you sure you wish to proceed?", "load-previous-session":"Would you like to load your previous session's settings?", "enter-password" : "Please enter the password below: \n\n(Note: Passwords are case-sensitive and you will not be alerted if it is incorrect.)", "enter-password-2" : "Please enter the password below: \n\n(Note: Passwords are case-sensitive.)", "password-incorrect" : "The password was incorrect.\n\nRefresh and try again.", "enter-display-name" : "Please enter your display name:", "enter-new-display-name" :"Enter a new Display Name for this stream", "what-bitrate":"What bitrate would you like to record at? (kbps)", "enter-website": "Enter a website URL to share", "press-ok-to-record": "Press OK to start recording. Press again to stop and download.\n\nWarning: Keep this browser tab active to continue recording.\n\nYou can change the default video bitrate if desired below (kbps)", "no-streamID-provided": "No streamID was provided; one will be generated randomily.\n\nStream ID: ", "alphanumeric-only": "Info: Only AlphaNumeric characters should be used for the stream ID.\n\nThe offending characters have been replaced by an underscore", "stream-id-too-long": "The Stream ID should be less than 45 alPhaNuMeric characters long.\n\nWe will trim it to length.", "share-with-trusted":"Share only with those you trust", "pass-recommended" : "A password is recommended", "insecure-room-name" : "Insecure room name.", "allowed-chars" : "Allowed chars", "transfer" : "transfer", "armed" : "armed", "transfer-guest-to-room" : "Transfer guests to room:\n\n(Please note rooms must share the same password)", "transfer-guest-to-url" :"Transfer guests to new website URL.\n\n(Guests will be prompted to accept)", "change-url" : "change URL", "mute-in-scene" : "mute in scene", "unmute-guest": "un-mute guest", "undeafen" : "un-deafen", "deafen" : "deafen guest", "unblind" : "un-blind", "blind" : "blind guest", "unmute" : "un-mute", "mute-guest" : "mute guest", "unhide" : "unhide guest", "hide-guest": "hide guest", "confirm-disconnect-users": "Are you sure you wish to disconnect these users?", "confirm-disconnect-user": "Are you sure you wish to disconnect this user?" }; // function log(msg){ // uncomment to enable logging. // console.log(msg); // } // function warnlog(msg, url=false, lineNumber=false){ // onsole.warn(msg); // if (lineNumber){ // console.warn(lineNumber); // } // } // function errorlog(msg, url=false, lineNumber=false){ // console.error(msg); // if (lineNumber){ // console.error(lineNumber); // } // } if (typeof session === 'undefined') { // make sure to init the WebRTC if not exists. var session = WebRTC.Media; session.streamID = session.generateStreamID(); errorlog("Serious error: WebRTC session didn't load in time"); } (function(w) { w.URLSearchParams = w.URLSearchParams || function(searchString) { var self = this; searchString = searchString.replace("??", "?"); self.searchString = searchString; self.get = function(name) { var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(self.searchString); if (results == null) { return null; } else { return decodeURI(results[1]) || 0; } }; }; })(window); var urlEdited = window.location.search.replace(/\?\?/g, "?"); urlEdited = urlEdited.replace(/\?/g, "&"); urlEdited = urlEdited.replace(/\&/, "?"); if (urlEdited !== window.location.search){ warnlog(window.location.search + " changed to " + urlEdited); window.history.pushState({path: urlEdited.toString()}, '', urlEdited.toString()); } var urlParams = new URLSearchParams(urlEdited); var isIFrame = false; if ( parent && (window.location !== window.parent.location )) { isIFrame = true; } function mapToAll(targets, callback, parentElement = document) { // js helper if (!targets) { return; } if (!parentElement) { return; } const target = parentElement.querySelectorAll(targets); for (let i = 0; i < target.length; i++) { callback(target[i]); } } function changeParam(url, paramName, paramValue) { paramName = paramName.replace("?", ""); var qind = url.indexOf('?'); url = url.replace("?", "&"); var params = url.substring(qind + 1).split('&'); var query = ''; var match = false; for (var i = 0; i < params.length; i++) { var tokens = params[i].split('='); var name = tokens[0]; var value = ""; if (tokens.length > 1 && tokens[1] !== '') { value = tokens[1]; } if (name == paramName) { if (match) { continue; } // already matched the first time. match = true; value = paramValue; } if (value !== "") { value = '=' + value; } if (query == '') { query = "?" + name + value; } else { query = query + '&' + name + value; } } return url.substring(0, qind) + query; } function updateURL(param, force = false, cleanUrl = false) { param = param.replace("?", ""); var para = param.split('='); if (cleanUrl) { if (history.pushState) { var href = new URL(cleanUrl); if (para.length == 1) { href = changeParam(cleanUrl, para[0], ""); } else { href = changeParam(cleanUrl, para[0], para[1]); } log("--" + href.toString()); window.history.pushState({path: href.toString()}, '', href.toString()); } } else if (!(urlParams.has(para[0]))) { // don't need to replace as it doesn't exist. if (history.pushState) { var href = window.location.href; href = href.replace("??", "?"); var arr = href.split('?'); var newurl; if (arr.length > 1 && arr[1] !== '') { newurl = href + '&' + param; } else { newurl = href + '?' + param; } window.history.pushState({path: newurl.toString()}, '', newurl.toString()); } } else if (force) { if (history.pushState) { var href = new URL(window.location.href); if (para.length == 1) { href = changeParam(window.location.href, para[0], ""); } else { href = changeParam(window.location.href, para[0], para[1]); } log("---" + href.toString()); window.history.pushState({path: href.toString()}, '', href.toString()); } } if (session.sticky) { setStorage("settings", encodeURI(window.location.href), 90); } urlParams = new URLSearchParams(window.location.search); } /* function changeGuestSettings(ele){ var eles = ele.querySelectorAll('[data-param]'); var UUID = ele.dataset.UUID; var settings = {}; for (var i = 0;i< eles.length; i++){ if (eles[i].tagName.toLowerCase() == "input"){ if (eles[i].checked===true){ settings[eles[i].dataset.param] = true; } else if (eles[i].checked===false){ settings[eles[i].dataset.param] = false; } else { settings[eles[i].dataset.param] = eles[i].value; } } } warnlog(settings); if (!settings.changepassword){ delete settings.password; } delete settings.changepassword; if (!settings.changeroom){ // send Migration message delete settings.roomid; } delete settings.roomid; delete settings.changeroom; warnlog(UUID); var msg = {}; msg.changeParams = settings; session.sendRequest(msg, UUID); closeModal(); } */ // proper room migration needs to happen; in sync. // updateMixer after settings changed // password needs to be special cased // room shouldn't be sent function applyNewParams(changeParams){ for (var key in changeParams){ session[key] = changeParams[key]; log(key); } log(changeParams); updateMixer(); } function submitDebugLog(msg){ try { appendDebugLog({"connection_type": session.stats.network_type}); if (navigator.userAgent){ var _, userAgent = navigator.userAgent; appendDebugLog({"userAgent": userAgent}); } if (navigator.platform){ appendDebugLog({"userAgent": navigator.platform}); } } catch(e){} window.focus(); var res = confirm(miscTranslations["submit-error-report"]); if (res){ var request = new XMLHttpRequest(); request.open('POST', "https://reports.vdo.ninja/"); // php, well, whatever. request.send(JSON.stringify(errorReport)); errorReport = []; if (document.getElementById("reportbutton")){ getById("reportbutton").style.visibility = "hidden"; } } } function promptUser(eleId, UUID=null){ if (session.beepToNotify){ playtone(); } if (document.getElementById("modalBackdrop")){ getById("promptModal").innerHTML = ''; // Delete modal getById("promptModal").remove(); getById("modalBackdrop").innerHTML = ''; // Delete modal getById("modalBackdrop").remove(); } zindex = 30 + document.querySelectorAll('#promptModal').length; modalTemplate = `
×
`; document.body.insertAdjacentHTML("beforeend", modalTemplate); // Insert modal at body end getById("promptModalMessage").innerHTML = getById(eleId).innerHTML; if (UUID){ getById("promptModalMessage").dataset.UUID = UUID; } document.getElementById("modalBackdrop").addEventListener("click", closeModal); getById("promptModal").addEventListener("click", function(e) { e.stopPropagation(); return false; }); } async function delay(ms) { return await new Promise((resolve, reject) => { setTimeout(resolve, ms); }); } var Prompts = {}; async function promptAlt(inputText, block=false){ var result = null; if (session.beepToNotify){ playtone(); } await new Promise((resolve, reject) => { var promptID = "pid_"+Math.random().toString(36).substr(2, 9); Prompts[promptID] = {}; Prompts[promptID].resolve = resolve; Prompts[promptID].reject = reject; var zindex = 30 + document.querySelectorAll('.promptModal').length; if (block){ var backdropClass = "opaqueBackdrop"; } else { var backdropClass = "modalBackdrop"; } inputText = ""+inputText.replace("\n","
")+""; inputText = inputText.replace(/\n/g,"
"); modalTemplate = `
`; document.body.insertAdjacentHTML("beforeend", modalTemplate); // Insert modal at body end document.getElementById("input_"+promptID).focus(); document.getElementById("input_"+promptID).addEventListener("keyup", function(event) { if (event.key === "Enter") { var pid = event.target.dataset.pid; result = document.getElementById("input_"+pid).value; document.getElementById("modal_"+pid).remove(); document.getElementById("modalBackdrop_"+pid).remove(); Prompts[pid].resolve(); } }); document.getElementById("submit_"+promptID).addEventListener("click", function(event){ var pid = event.target.dataset.pid; result = document.getElementById("input_"+pid).value; document.getElementById("modal_"+pid).remove(); document.getElementById("modalBackdrop_"+pid).remove(); Prompts[pid].resolve(); }); document.getElementById("cancel_"+promptID).addEventListener("click", function(event){ var pid = event.target.dataset.pid; document.getElementById("modal_"+pid).remove(); document.getElementById("modalBackdrop_"+pid).remove(); Prompts[pid].resolve(); }); document.getElementById("close_"+promptID).addEventListener("click", function(event){ var pid = event.target.dataset.pid; document.getElementById("modal_"+pid).remove(); document.getElementById("modalBackdrop_"+pid).remove(); Prompts[pid].resolve(); }); getById("modal_"+promptID).addEventListener("click", function(e) { e.stopPropagation(); return false; }); return; }); return result; } async function confirmAlt(inputText, block=false){ var result = null; if (session.beepToNotify){ playtone(); } await new Promise((resolve, reject) => { var promptID = "pid_"+Math.random().toString(36).substr(2, 9); Prompts[promptID] = {}; Prompts[promptID].resolve = resolve; Prompts[promptID].reject = reject; var zindex = 30 + document.querySelectorAll('.promptModal').length; if (block){ var backdropClass = "opaqueBackdrop"; } else { var backdropClass = "modalBackdrop"; } inputText = ""+inputText.replace("\n","
")+""; inputText = inputText.replace(/\n/g,"
"); modalTemplate = `
`; document.body.insertAdjacentHTML("beforeend", modalTemplate); // Insert modal at body end document.getElementById("submit_"+promptID).focus(); document.getElementById("submit_"+promptID).addEventListener("click", function(event){ var pid = event.target.dataset.pid; result = true; document.getElementById("modalBackdrop_"+pid).remove(); document.getElementById("modal_"+pid).remove(); Prompts[pid].resolve(); }); document.getElementById("cancel_"+promptID).addEventListener("click", function(event){ var pid = event.target.dataset.pid; document.getElementById("modalBackdrop_"+pid).remove(); document.getElementById("modal_"+pid).remove(); Prompts[pid].resolve(); }); document.getElementById("close_"+promptID).addEventListener("click", function(event){ var pid = event.target.dataset.pid; document.getElementById("modalBackdrop_"+pid).remove(); document.getElementById("modal_"+pid).remove(); Prompts[pid].resolve(); }); getById("modal_"+promptID).addEventListener("click", function(e) { e.stopPropagation(); return false; }); return; }); return result; } var warnUserTimeout=null; function warnUser(message, timeout=false){ // Allows for multiple alerts to stack better. // Every modal and backdrop has an increasing z-index // to block the previous modal if (document.getElementById("modalBackdrop")){ getById("alertModal").innerHTML = ''; // Delete modal getById("alertModal").remove(); getById("modalBackdrop").innerHTML = ''; // Delete modal getById("modalBackdrop").remove(); } zindex = 31 + document.querySelectorAll('.alertModal').length; try{ message = message.replace(/\n/g,"
"); } catch(e){ errorlog(message); } modalTemplate = `
× ${message}
`; document.body.insertAdjacentHTML("beforeend", modalTemplate); // Insert modal at body end document.getElementById("modalBackdrop").addEventListener("click", closeModal); clearTimeout(warnUserTimeout); if (timeout){ warnUserTimeout = setTimeout(closeModal, timeout); } getById("alertModal").addEventListener("click", function(e) { e.stopPropagation(); return false; }); } function closeModal(){ getById("modalBackdrop").innerHTML = ''; // Delete modal getById("modalBackdrop").remove(); getById("alertModal").innerHTML = ''; // Delete modal getById("alertModal").remove(); getById("promptModal").innerHTML = ''; // Delete modal getById("promptModal").remove(); } var sanitizeStreamID = function(streamID) { streamID = streamID.trim(); if (streamID.length < 1) { streamID = session.generateStreamID(8); if (!(session.cleanOutput)) { warnUser(miscTranslations["no-streamID-provided"] + streamID); } } var streamID_sanitized = streamID.replace(/[\W]+/g, "_"); if (streamID !== streamID_sanitized) { if (!(session.cleanOutput)) { warnUser(miscTranslations["alphanumeric-only"]); } } if (streamID_sanitized.length > 44) { streamID_sanitized = streamID_sanitized.substring(0, 44); if (!(session.cleanOutput)) { warnUser(miscTranslations["stream-id-too-long"]); } } return streamID_sanitized; }; var checkStrength = function(string) { var matcher = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{7,30}$/; if (string.match(matcher)) { return true; } else if (string.length > 20) { return true; } else { return false; } }; var checkStrengthRoom = function() { var result1 = checkStrength(getById('videoname1').value); var result2 = getById('passwordRoom').value.length; var target = getById('securityLevelRoom'); target.style.display = "block"; if (result1) { if (result2) { target.innerHTML = ""+miscTranslations["share-with-trusted"]+""; } else { target.innerHTML = ""+miscTranslations["pass-recommended"]+""; } } else { target.innerHTML = ""+miscTranslations["insecure-room-name"]+" "+miscTranslations["allowed-chars"]+": A-Z, a-z, 0-9, _"; } }; var emojiShortCodes ={":joy:":"😂",":heart:":"❤️",":heart_eyes:":"😍",":sob:":"😭",":blush:":"😊",":unamused:":"😒",":two_hearts:":"💕",":weary:":"😩",":ok_hand:":"👌",":pensive:":"😔",":smirk:":"😏",":grin:":"😁",":wink:":"😉",":thumbsup:":"👍",":pray:":"🙏",":relieved:":"😌",":notes:":"🎶",":flushed:":"😳",":raised_hands:":"🙌",":see_no_evil:":"🙈",":cry:":"😢",":sunglasses:":"😎",":v:":"✌️",":eyes:":"👀",":sweat_smile:":"😅",":sparkles:":"✨",":sleeping:":"😴",":smile:":"😄",":purple_heart:":"💜",":broken_heart:":"💔",":blue_heart:":"💙",":confused:":"😕",":disappointed:":"😞",":yum:":"😋",":neutral_face:":"😐",":sleepy:":"😪",":clap:":"👏",":cupid:":"💘",":heartpulse:":"💗",":kiss:":"💋",":point_right:":"👉",":scream:":"😱",":fire:":"🔥",":rage:":"😡",":smiley:":"😃",":tada:":"🎉",":tired_face:":"😫",":camera:":"📷",":rose:":"🌹",":muscle:":"💪",":skull:":"💀",":sunny:":"☀️",":yellow_heart:":"💛",":triumph:":"😤",":laughing:":"😆",":sweat:":"😓",":point_left:":"👈",":grinning:":"😀",":mask:":"😷",":green_heart:":"💚",":wave:":"👋",":persevere:":"😣",":heartbeat:":"💓",":crown:":"👑",":innocent:":"😇",":headphones:":"🎧",":confounded:":"😖",":angry:":"😠",":grimacing:":"😬",":star2:":"🌟",":gun:":"🔫",":raising_hand:":"🙋",":thumbsdown:":"👎",":dancer:":"💃",":musical_note:":"🎵",":no_mouth:":"😶",":dizzy:":"💫",":fist:":"✊",":point_down:":"👇",":no_good:":"🙅",":boom:":"💥",":tongue:":"👅",":poop:":"💩",":cold_sweat:":"😰",":gem:":"💎",":ok_woman:":"🙆",":pizza:":"🍕",":joy_cat:":"😹",":leaves:":"🍃",":sweat_drops:":"💦",":penguin:":"🐧",":zzz:":"💤",":walking:":"🚶",":airplane:":"✈️",":balloon:":"🎈",":star:":"⭐",":ribbon:":"🎀",":worried:":"😟",":underage:":"🔞",":fearful:":"😨",":hibiscus:":"🌺",":microphone:":"🎤",":open_hands:":"👐",":ghost:":"👻",":palm_tree:":"🌴",":nail_care:":"💅",":alien:":"👽",":bow:":"🙇",":cloud:":"☁",":soccer:":"⚽",":angel:":"👼",":dancers:":"👯",":snowflake:":"❄️",":point_up:":"☝️",":rainbow:":"🌈",":gift_heart:":"💝",":gift:":"🎁",":beers:":"🍻",":anguished:":"😧",":earth_africa:":"🌍",":movie_camera:":"🎥",":anchor:":"⚓",":zap:":"⚡",":runner:":"🏃",":sunflower:":"🌻",":bouquet:":"💐",":dog:":"🐶",":moneybag:":"💰",":herb:":"🌿",":couple:":"👫",":fallen_leaf:":"🍂",":tulip:":"🌷",":birthday:":"🎂",":cat:":"🐱",":coffee:":"☕",":dizzy_face:":"😵",":point_up_2:":"👆",":open_mouth:":"😮",":hushed:":"😯",":basketball:":"🏀",":ring:":"💍",":astonished:":"😲",":hear_no_evil:":"🙉",":dash:":"💨",":cactus:":"🌵",":hotsprings:":"♨️",":telephone:":"☎️",":maple_leaf:":"🍁",":princess:":"👸",":massage:":"💆",":love_letter:":"💌",":trophy:":"🏆",":blossom:":"🌼",":lips:":"👄",":fries:":"🍟",":doughnut:":"🍩",":frowning:":"😦",":ocean:":"🌊",":bomb:":"💣",":cyclone:":"🌀",":rocket:":"🚀",":umbrella:":"☔",":couplekiss:":"💏",":lollipop:":"🍭",":clapper:":"🎬",":pig:":"🐷",":smiling_imp:":"😈",":imp:":"👿",":bee:":"🐝",":kissing_cat:":"😽",":anger:":"💢",":santa:":"🎅",":earth_asia:":"🌏",":football:":"🏈",":guitar:":"🎸",":panda_face:":"🐼",":strawberry:":"🍓",":smirk_cat:":"😼",":banana:":"🍌",":watermelon:":"🍉",":snowman:":"⛄",":smile_cat:":"😸",":eggplant:":"🍆",":crystal_ball:":"🔮",":calling:":"📲",":iphone:":"📱",":partly_sunny:":"⛅",":warning:":"⚠️",":scream_cat:":"🙀",":baby:":"👶",":feet:":"🐾",":footprints:":"👣",":beer:":"🍺",":wine_glass:":"🍷",":video_camera:":"📹",":rabbit:":"🐰",":smoking:":"🚬",":peach:":"🍑",":snake:":"🐍",":turtle:":"🐢",":cherries:":"🍒",":kissing:":"😗",":frog:":"🐸",":milky_way:":"🌌",":closed_book:":"📕",":candy:":"🍬",":hamburger:":"🍔",":bear:":"🐻",":tiger:":"🐯",":icecream:":"🍦",":pineapple:":"🍍",":ear_of_rice:":"🌾",":syringe:":"💉",":tv:":"📺",":pill:":"💊",":octopus:":"🐙",":grapes:":"🍇",":smiley_cat:":"😺",":cd:":"💿",":cocktail:":"🍸",":cake:":"🍰",":video_game:":"🎮",":lipstick:":"💄",":whale:":"🐳",":cookie:":"🍪",":dolphin:":"🐬",":loud_sound:":"🔊",":man:":"👨",":monkey:":"🐒",":books:":"📚",":guardsman:":"💂",":loudspeaker:":"📢",":scissors:":"✂️",":girl:":"👧",":mortar_board:":"🎓",":baseball:":"⚾️",":woman:":"👩",":fireworks:":"🎆",":stars:":"🌠",":mushroom:":"🍄",":pouting_cat:":"😾",":left_luggage:":"🛅",":high_heel:":"👠",":dart:":"🎯",":swimmer:":"🏊",":key:":"🔑",":bikini:":"👙",":family:":"👪",":pencil2:":"✏",":elephant:":"🐘",":droplet:":"💧",":seedling:":"🌱",":apple:":"🍎",":dollar:":"💵",":book:":"📖",":haircut:":"💇",":computer:":"💻",":bulb:":"💡",":boy:":"👦",":tangerine:":"🍊",":sunrise:":"🌅",":poultry_leg:":"🍗",":shaved_ice:":"🍧",":bird:":"🐦",":eyeglasses:":"👓",":goat:":"🐐",":older_woman:":"👵",":new_moon:":"🌑",":customs:":"🛃",":house:":"🏠",":full_moon:":"🌕",":lemon:":"🍋",":baby_bottle:":"🍼",":spaghetti:":"🍝",":wind_chime:":"🎐",":fish_cake:":"🍥",":nose:":"👃",":pig_nose:":"🐽",":fish:":"🐟",":koala:":"🐨",":ear:":"👂",":shower:":"🚿",":bug:":"🐛",":ramen:":"🍜",":tophat:":"🎩",":fuelpump:":"⛽",":horse:":"🐴",":watch:":"⌚",":monkey_face:":"🐵",":baby_symbol:":"🚼",":sparkler:":"🎇",":corn:":"🌽",":tennis:":"🎾",":battery:":"🔋",":wolf:":"🐺",":moyai:":"🗿",":cow:":"🐮",":mega:":"📣",":older_man:":"👴",":dress:":"👗",":link:":"🔗",":chicken:":"🐔",":whale2:":"🐋",":bento:":"🍱",":pushpin:":"📌",":dragon:":"🐉",":hamster:":"🐹",":golf:":"⛳",":surfer:":"🏄",":mouse:":"🐭",":blue_car:":"🚙",":bread:":"🍞",":cop:":"👮",":tea:":"🍵",":bike:":"🚲",":rice:":"🍚",":radio:":"📻",":baby_chick:":"🐤",":sheep:":"🐑",":lock:":"🔒",":green_apple:":"🍏",":racehorse:":"🐎",":fried_shrimp:":"🍤",":volcano:":"🌋",":rooster:":"🐓",":inbox_tray:":"📥",":wedding:":"💒",":sushi:":"🍣",":ice_cream:":"🍨",":tomato:":"🍅",":rabbit2:":"🐇",":beetle:":"🐞",":bath:":"🛀",":no_entry:":"⛔",":crocodile:":"🐊",":dog2:":"🐕",":cat2:":"🐈",":hammer:":"🔨",":meat_on_bone:":"🍖",":shell:":"🐚",":poodle:":"🐩",":stew:":"🍲",":jeans:":"👖",":honey_pot:":"🍯",":unlock:":"🔓",":black_nib:":"✒",":snowboarder:":"🏂",":white_flower:":"💮",":necktie:":"👔",":womens:":"🚺",":ant:":"🐜",":city_sunset:":"🌇",":dragon_face:":"🐲",":snail:":"🐌",":dvd:":"📀",":shirt:":"👕",":game_die:":"🎲",":dolls:":"🎎",":8ball:":"🎱",":bus:":"🚌",":custard:":"🍮",":camel:":"🐫",":curry:":"🍛",":hospital:":"🏥",":bell:":"🔔",":pear:":"🍐",":door:":"🚪",":saxophone:":"🎷",":church:":"⛪",":bicyclist:":"🚴",":dango:":"🍡",":office:":"🏢",":rowboat:":"🚣",":womans_hat:":"👒",":mans_shoe:":"👞",":love_hotel:":"🏩",":mount_fuji:":"🗻",":handbag:":"👜",":hourglass:":"⌛",":trumpet:":"🎺",":school:":"🏫",":cow2:":"🐄",":toilet:":"🚽",":pig2:":"🐖",":violin:":"🎻",":credit_card:":"💳",":ferris_wheel:":"🎡",":bowling:":"🎳",":barber:":"💈",":purse:":"👛",":rat:":"🐀",":date:":"📅",":ram:":"🐏",":tokyo_tower:":"🗼",":kimono:":"👘",":ship:":"🚢",":mag_right:":"🔎",":mag:":"🔍",":fire_engine:":"🚒",":police_car:":"🚓",":black_joker:":"🃏",":package:":"📦",":calendar:":"📆",":horse_racing:":"🏇",":tiger2:":"🐅",":boot:":"👢",":ambulance:":"🚑",":boar:":"🐗",":pound:":"💷",":ox:":"🐂",":rice_ball:":"🍙",":sandal:":"👡",":tent:":"⛺",":seat:":"💺",":taxi:":"🚕",":briefcase:":"💼",":newspaper:":"📰",":circus_tent:":"🎪",":mens:":"🚹",":flashlight:":"🔦",":foggy:":"🌁",":bamboo:":"🎍",":ticket:":"🎫",":helicopter:":"🚁",":minidisc:":"💽",":oncoming_bus:":"🚍",":melon:":"🍈",":notebook:":"📓",":no_bell:":"🔕",":oden:":"🍢",":flags:":"🎏",":blowfish:":"🐡",":sweet_potato:":"🍠",":ski:":"🎿",":construction:":"🚧",":satellite:":"📡",":euro:":"💶",":ledger:":"📒",":leopard:":"🐆",":truck:":"🚚",":sake:":"🍶",":railway_car:":"🚃",":speedboat:":"🚤",":vhs:":"📼",":yen:":"💴",":mute:":"🔇",":wheelchair:":"♿",":paperclip:":"📎",":atm:":"🏧",":telescope:":"🔭",":rice_scene:":"🎑",":blue_book:":"📘",":postbox:":"📮",":e-mail:":"📧",":mouse2:":"🐁",":nut_and_bolt:":"🔩",":hotel:":"🏨",":wc:":"🚾",":green_book:":"📗",":tractor:":"🚜",":fountain:":"⛲",":metro:":"🚇",":clipboard:":"📋",":no_smoking:":"🚭",":slot_machine:":"🎰",":bathtub:":"🛁",":scroll:":"📜",":station:":"🚉",":rice_cracker:":"🍘",":bank:":"🏦",":wrench:":"🔧",":bar_chart:":"📊",":minibus:":"🚐",":tram:":"🚊",":microscope:":"🔬",":bookmark:":"🔖",":pouch:":"👝",":fax:":"📠",":sound:":"🔉",":chart:":"💹",":floppy_disk:":"💾",":post_office:":"🏣",":speaker:":"🔈",":japan:":"🗾",":mahjong:":"🀄",":orange_book:":"📙",":restroom:":"🚻",":train:":"🚋",":trolleybus:":"🚎",":postal_horn:":"📯",":factory:":"🏭",":train2:":"🚆",":pager:":"📟",":outbox_tray:":"📤",":mailbox:":"📫",":light_rail:":"🚈",":busstop:":"🚏",":file_folder:":"📁",":card_index:":"📇",":monorail:":"🚝",":no_bicycles:":"🚳",":hugging:":"🤗",":thinking:":"🤔",":nerd:":"🤓",":zipper_mouth:":"🤐",":rolling_eyes:":"🙄",":upside_down:":"🙃",":slight_smile:":"🙂",":writing_hand:":"✍",":eye:":"👁",":man_in_suit:":"🕴",":golfer:":"🏌",":golfer_woman:":"🏌‍♀",":anger_right:":"🗯",":coffin:":"⚰",":gear:":"⚙",":alembic:":"⚗",":scales:":"⚖",":keyboard:":"⌨",":shield:":"🛡",":bed:":"🛏",":ballot_box:":"🗳",":compression:":"🗜",":wastebasket:":"🗑",":file_cabinet:":"🗄",":trackball:":"🖲",":printer:":"🖨",":joystick:":"🕹",":hole:":"🕳",":candle:":"🕯",":prayer_beads:":"📿",":amphora:":"🏺",":label:":"🏷",":film_frames:":"🎞",":level_slider:":"🎚",":thermometer:":"🌡",":motorway:":"🛣",":synagogue:":"🕍",":mosque:":"🕌",":kaaba:":"🕋",":stadium:":"🏟",":desert:":"🏜",":cityscape:":"🏙",":camping:":"🏕",":rosette:":"🏵",":volleyball:":"🏐",":medal:":"🏅",":popcorn:":"🍿",":champagne:":"🍾",":hot_pepper:":"🌶",":burrito:":"🌯",":taco:":"🌮",":hotdog:":"🌭",":shamrock:":"☘",":comet:":"☄",":turkey:":"🦃",":scorpion:":"🦂",":lion_face:":"🦁",":crab:":"🦀",":spider_web:":"🕸",":spider:":"🕷",":chipmunk:":"🐿",":fog:":"🌫",":chains:":"⛓",":pick:":"⛏",":stopwatch:":"⏱",":ferry:":"⛴",":mountain:":"⛰",":ice_skate:":"⛸",":skier:":"⛷",":sad:":"😥",":egg:":"🥚",":drum:":"🥁"}; function convertShortcodes(string){ if (string.split(":").length>2){ for (var i in emojiShortCodes) { if (string.includes(i)) { string = string.replaceAll(i, emojiShortCodes[i]); } } } return string; } var sanitizeChat = function(string) { var temp = document.createElement('div'); temp.innerText = string; temp.innerText = temp.innerHTML; temp = temp.textContent || temp.innerText || ""; temp = temp.substring(0, Math.min(temp.length, 500)); return temp.trim(); }; var sanitizeString = function(str) { str = str.replace(/[^a-z0-9áéíóúñü \.,_-]/gim, ""); return str.trim(); }; var sanitizeLabel = function(string) { let temp = document.createElement("div"); temp.innerText = string; temp.innerText = temp.innerHTML; temp = temp.textContent || temp.innerText || ""; temp = temp.substring(0, Math.min(temp.length, 50)); return temp.trim(); }; var sanitizeRoomName = function(roomid) { roomid = roomid.trim(); if (roomid === "") { return roomid; } else if (roomid === false) { return roomid; } var sanitized = roomid.replace(/[\W]+/g, "_"); if (sanitized !== roomid) { if (!(session.cleanOutput)) { warnUser("Info: Only AlphaNumeric characters should be used for the room name.\n\nThe offending characters have been replaced by an underscore"); } } if (sanitized.length > 30) { sanitized = sanitized.substring(0, 30); if (!(session.cleanOutput)) { warnUser("The Room name should be less than 31 alPhaNuMeric characters long.\n\nWe will trim it to length."); } } return sanitized; }; var sanitizePassword = function(passwrd) { if (passwrd === "") { return passwrd; } else if (passwrd === false) { return passwrd; } else if (passwrd === null) { return passwrd; } passwrd = passwrd.trim(); if (passwrd.length < 1) { if (!(session.cleanOutput)) { warnUser("The password provided was blank."); } } var sanitized = encodeURIComponent(passwrd);//.replace(/[\W]+/g, "_"); //if (sanitized !== passwrd) { // if (!(session.cleanOutput)) { // warnUser("Info: Only AlphaNumeric characters should be used in the password.\n\nThe offending characters have been replaced by an underscore"); // } //} return sanitized; }; function isOperaGX(){ return (!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(' OPR/75') >= 0; } function getChromeVersion() { var raw = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./); return raw ? parseInt(raw[2], 10) : false; } function checkConnection() { if (session.ws === null) { return; } if (!session.cleanOutput){ if (document.getElementById("qos")) { // true or false; null might cause problems? getById("logoname").style.display = "unset"; if ((session.ws) && (session.ws.readyState === WebSocket.OPEN)) { getById("qos").style.color = "white"; } else { getById("qos").style.color = "red"; } } } } function safariVersion() { var ver = 0; try { ver = navigator.appVersion.split("Version/"); if (ver.length > 1) { ver = ver[1].split(" Safari"); } if (ver.length > 1) { ver = ver[0].split("."); } if (ver.length > 1) { ver = parseInt(ver[0]); } else { ver = 0; } } catch (e) { return 0; } return ver; } function obsSceneChanged(event){ log(event.detail.name); window.obsstudio.getCurrentScene(function(scene) { log("OBS SCENE"); log(scene); }); } function obsStreamingStarted(event){ session.obsState.streaming = true; session.obsStateSync(); } function obsStreamingStopped(event){ session.obsState.streaming = false; session.obsStateSync(); } function obsRecordingStarted(event){ session.obsState.recording = true; session.obsStateSync(); } function obsRecordingStopped(event){ session.obsState.recording = false; session.obsStateSync(); } function obsSourceActiveChanged(event){ warnlog("obsSourceActiveChanged"); warnlog( event.detail); try { if (typeof event==="boolean"){var sourceActive = event;} else if (typeof event.detail === "boolean"){var sourceActive = event.detail;} else if (typeof event.detail.active === "boolean"){var sourceActive = event.detail.active;} else {var sourceActive = event.detail.active;} if (typeof sourceActive === "undefined"){return;} // Just fail. if (session.obsState.sourceActive!==sourceActive){ // only move forward if there is a change; the event likes to double fire you see. session.obsState.sourceActive = sourceActive; session.obsStateSync(); } } catch (e){errorlog(e);} } function obsSourceVisibleChanged(event){ // accounts for visible in VDO.Ninja scene AND visible in OBS scene warnlog("obsSourceVisibleChanged"); warnlog(event.detail); try { if (typeof event==="boolean"){var visibility = event;} else if (typeof event.detail === "boolean"){var visibility = event.detail;} else if (typeof event.detail.visible === "boolean"){var visibility = event.detail.visible;} else {var visibility = event.detail.visible;} if (typeof visibility === "undefined"){ // fall back if (typeof document.visibilityState !== "undefined"){ visibility = document.visibilityState==="visible"; // modern } else if (typeof document.hidden !== "undefined"){ visibility = !document.hidden; // legacy } else { return; // ... unknown input? fail. } } errorlog("visibility: "+visibility); if (session.obsState.visibility!==visibility){ // only move forward if there is a change; the event likes to double fire you see. session.obsState.visibility = visibility; session.obsStateSync(); } } catch (e){errorlog(e);} } function manageSceneState(data, UUID){ if (session.disableOBS){return;} var processNeeded = false try{ if ("sceneDisplay" in data){ processNeeded=true; session.pcs[UUID].sceneDisplay = data.sceneDisplay; } if ("sceneMute" in data){ processNeeded=true; session.pcs[UUID].sceneMute = data.sceneMute; } if ("obsSourceActive" in data){ processNeeded=true; session.pcs[UUID].obsSourceActive = data.obsSourceActive; } if ("obsVisibility" in data){ processNeeded=true; session.pcs[UUID].obsVisibility = data.obsVisibility; session.optimizeBitrate(UUID); // &optimize flag; sets video bitrate to target value if this flag == HIDDEN (if optimize=0, disables both audio and video) } if ("obsStreaming" in data){ processNeeded=true; session.pcs[UUID].obsStreaming = data.obsStreaming; } if ("obsRecording" in data){ processNeeded=true; session.pcs[UUID].obsRecording = data.obsRecording; } } catch(e){} // just in case the client has disconnected. if (processNeeded){ applySceneState(); } } function applySceneState(){ if (session.disableOBS){return;} if (session.cleanOutput===false){ if (document.getElementById("videosource")){ var visibility = false; var ondeck = false; var recording = false; for (var uid in session.pcs){ if (session.pcs[uid].obsSourceActive!==false && session.pcs[uid].obsVisibility && (session.pcs[uid].sceneDisplay!==false)){ visibility=true; } else if (session.pcs[uid].obsVisibility && (session.pcs[uid].sceneDisplay!==false)){ ondeck=true; } if ((session.pcs[uid].obsRecording || session.pcs[uid].obsStreaming) && (session.pcs[uid].obsSourceActive!==false && session.pcs[uid].obsVisibility && (session.pcs[uid].sceneDisplay!==false))){ // the scene that is recording must be visible also. recording=true; } } if (recording){ getById("obsState").classList.remove("ondeck"); getById("obsState").classList.add("recording"); // TODO: this needs to check all peers to make sure it's valid getById("obsState").innerHTML = "ON AIR"; } else if (ondeck && !visibility){ getById("obsState").classList.remove("recording"); getById("obsState").classList.add("ondeck"); // TODO: this needs to check all peers to make sure it's valid getById("obsState").innerHTML = "STAND BY"; } else { getById("obsState").classList.remove("recording"); getById("obsState").classList.remove("ondeck"); getById("obsState").innerHTML = "ACTIVE"; } if (visibility){ // BASIC TALLY LIGHT (on deck disabled) getById("obsState").classList.add("onair"); // LIVE } else { getById("obsState").classList.remove("onair"); } } } } window.onpopstate = function() { if (session.firstPlayTriggered) { window.location.reload(true); } }; var miniPerformerX = null; var miniPerformerY = null; function makeMiniDraggableElement(elmnt) { try { elmnt.dragElement = false; elmnt.style.bottom = "auto"; elmnt.style.cursor = "grab"; elmnt.stashonmouseup = null; elmnt.stashonmousemove = null; } catch (e) { errorlog(e); return; } var pos1 = 0; var pos2 = 0; var pos3 = 0; var pos4 = 0; var timestamp = false; function elementDrag(e) { // ON DRAG timestamp = false; if (session.infocus){return;} try { e = e || window.event; if (e.type !== "touchmove"){ if (e.button !== 0){return;} e.preventDefault(); } e.stopPropagation(); elmnt.dragElement = true; if (e.type === "touchmove"){ pos1 = pos3 - e.touches[0].clientX; pos2 = pos4 - e.touches[0].clientY; pos3 = e.touches[0].clientX; pos4 = e.touches[0].clientY; } else { pos1 = pos3 - e.clientX; pos2 = pos4 - e.clientY; pos3 = e.clientX; pos4 = e.clientY; } var topDrag = (elmnt.offsetTop - pos2 ); if (topDrag > (-3 + (window.innerHeight - elmnt.clientHeight))){ topDrag = (-3 + (window.innerHeight - elmnt.clientHeight)); } miniPerformerY = topDrag; miniPerformerX = elmnt.offsetLeft - pos1; if (miniPerformerY > window.innerHeight-elmnt.clientHeight){ miniPerformerY = window.innerHeight-elmnt.clientHeight; } if (miniPerformerX > window.innerWidth-elmnt.clientWidth){ miniPerformerX = window.innerWidth-elmnt.clientWidth; } miniPerformerX = 100 * miniPerformerX/window.innerWidth; miniPerformerY = 100 * miniPerformerY/window.innerHeight; if (miniPerformerY<0){ miniPerformerY=0; } else if (miniPerformerY>100){ miniPerformerY=100; } if (miniPerformerX<0){ miniPerformerX=0; } else if (miniPerformerX>100){ miniPerformerX=100; } elmnt.style.right = "unset"; elmnt.style.top = miniPerformerY + "%"; elmnt.style.left = miniPerformerX + "%"; } catch(e){errorlog(e);} } function closeDragElement(e) { // TOUCH END e = e || window.event; if (e.type !== "touchend"){ if (e.button !== 0){return;} document.onmouseup = elmnt.stashonmouseup; document.onmousemove = elmnt.stashonmousemove; } if (session.infocus){return;} e.preventDefault(); if (timestamp && (Date.now()- timestamp>500)){ // long hold, so this is a drag e.stopPropagation(); if (e.type === "touchend"){ if (session.infocus === true){ session.infocus = false; } else { session.infocus = true; log("session: myself"); } setTimeout(()=>updateMixer(),10); } } else if (timestamp && (e.type !== "touchend")){ if (session.infocus === true){ session.infocus = false; } else { session.infocus = true; log("session: myself"); } setTimeout(()=>updateMixer(),10); } } function dragMouseDown(e) { ////// TOUCH START if (event.ctrlKey || event.metaKey) {return;} timestamp = Date.now(); e = e || window.event; if (session.infocus){return;} e.preventDefault(); if (e.type === "touchstart"){ pos3 = e.touches[0].clientX; pos4 = e.touches[0].clientY; elmnt.ontouchend = closeDragElement; elmnt.ontouchmove = elementDrag; } else { if (e.button !== 0){return;} pos3 = e.clientX; pos4 = e.clientY; elmnt.stashonmouseup = document.onmouseup; // I don't want to interfere with other drag events. elmnt.stashonmousemove = document.onmousemove; document.onmouseup = closeDragElement; document.onmousemove = elementDrag; } } elmnt.onmousedown = dragMouseDown; elmnt.ontouchstart = dragMouseDown; } function makeDraggableElement(elmnt, absolute=false) { try { elmnt.dragElement = false; elmnt.style.bottom = "auto"; elmnt.style.cursor = "grab"; elmnt.stashonmouseup = null; elmnt.stashonmousemove = null; } catch (e) { errorlog(e); return; } var pos1 = 0; var pos2 = 0; var pos3 = 0; var pos4 = 0; var timestamp = false; function dragMouseDown(e) { timestamp = Date.now(); e = e || window.event; e.preventDefault(); pos3 = e.clientX; pos4 = e.clientY; elmnt.stashonmouseup = document.onmouseup; // I don't want to interfere with other drag events. elmnt.stashonmousemove = document.onmousemove; document.onmouseup = closeDragElement; document.onmousemove = elementDrag; } function elementDrag(e) { e = e || window.event; e.preventDefault(); elmnt.dragElement = true; pos1 = pos3 - e.clientX; pos2 = pos4 - e.clientY; pos3 = e.clientX; pos4 = e.clientY; var topDrag = (elmnt.offsetTop - pos2 ); if (absolute){ if (topDrag > (-3 + (window.innerHeight - elmnt.clientHeight))){ topDrag = (-3 + (window.innerHeight - elmnt.clientHeight)); } } else { if (topDrag > -3){ topDrag = -3; } } elmnt.style.top = topDrag + "px"; elmnt.style.left = (elmnt.offsetLeft - pos1) + "px"; } elmnt.onmousedown = dragMouseDown; function closeDragElement(e) { document.onmouseup = elmnt.stashonmouseup; document.onmousemove = elmnt.stashonmousemove; } } function setStorage(cname, cvalue, exdays=999){ // not actually a cookie var now = new Date(); var item = { value: cvalue, expiry: now.getTime() + (exdays * 24 * 60 * 60 * 1000), }; localStorage.setItem(cname, JSON.stringify(item)); } function getStorage(cname) { var itemStr = localStorage.getItem(cname); if (!itemStr) { return ""; } var item = JSON.parse(itemStr); var now = new Date(); if (now.getTime() > item.expiry) { localStorage.removeItem(cname); return ""; } return item.value; } function setupIncomingVideoTracking(v, UUID){ // video element. if (session.directorUUID===UUID){ v.muted=false; } else { v.muted = session.speakerMuted; } v.onpause = (event) => { // prevent things from pausing; human or other if (!((event.ctrlKey) || (event.metaKey) )){ warnlog("Video paused; force it to play again"); //return; //session.audioCtx.resume(); //log("ctx resume"); event.currentTarget.play().then(_ => { log("playing"); }).catch(error => { warnlog("didnt play 1"); }); } } v.onplay = function(){ try { var bigPlayButton = document.getElementById("bigPlayButton"); if (bigPlayButton){ bigPlayButton.parentNode.removeChild(bigPlayButton); } } catch(e){} if (session.pip){ if (v.readyState >= 3){ if (!(v.pip)){ v.pip=true; toggleSystemPip(v, true); } } } } if (session.pip){ v.onloadedmetadata = function(){ if (!v.paused){ if (!(v.pip)){ v.pip=true; toggleSystemPip(v, true); } } } } v.addEventListener('resize', (e) => { log("resize event"); var aspectRatio = parseFloat(e.target.videoWidth/e.target.videoHeight); if (v.dataset.aspectRatio){ if (aspectRatio != v.dataset.aspectRatio){ setTimeout(function(){updateMixer();},1); // We don't want to run this on the first resize? just subsequent ones. } } else { log("ASPECT RATIO CHANGED"); setTimeout(function(){updateMixer();},1); } v.dataset.aspectRatio = parseFloat(e.target.videoWidth/e.target.videoHeight); }); v.volume = 1.0; // play audio automatically v.autoplay = true; v.controls = false; v.classList.add("tile"); v.setAttribute("playsinline",""); v.controlTimer = null; changeAudioOutputDevice(v); // if enabled, changes to desired output audio device. if (document.getElementById("mainmenu")){ var m = getById("mainmenu"); m.remove(); } if (session.director){ v.controls = true; var container = getById("videoContainer_"+UUID); v.disablePictureInPicture = false v.setAttribute("controls","controls") container.appendChild(v); session.requestRateLimit(session.directorViewBitrate,UUID); /// limit resolution for director if (session.beepToNotify) { playtone(); } } else if (session.scene!==false){ v.controls = false; if (session.view){ // specific video to be played v.style.display="block"; } else if (session.scene==="0"){ v.style.display="block"; } else { // group scene I guess; needs to be added manually v.style.display="none"; v.muted= true; } setTimeout(function(){updateMixer();},1); } else if (session.roomid!==false){ if (session.cleanOutput){ v.controls = false; } else if (window.obsstudio) { v.controls = false; } else { v.controls = true; } if ((session.roomid==="") && (session.bitrate)){ // let's keep the default bitrates, since this isn't a real room and bitrates are specified. } else if (session.novideo !== false){ if (session.novideo.includes(session.rpcs[UUID].streamID)){ session.requestRateLimit(0,UUID);// limit resolution for guests see ln: 1804 in main.js also } } else { session.requestRateLimit(0,UUID);// limit resolution for guests see ln: 1804 in main.js also } setTimeout(function(){updateMixer();},1); } else { v.style.display="block"; if (window.obsstudio) { v.controls = false; } setTimeout(function(){updateMixer();},1); } v.addEventListener('click', function(e) { // show stats of video if double clicked log("clicked"); try { if ((e.ctrlKey)||(e.metaKey)){ e.preventDefault(); var uid = e.currentTarget.dataset.UUID; if ("stats" in session.rpcs[uid]){ var [menu, innerMenu] = statsMenuCreator(); printViewStats(innerMenu, uid ); menu.interval = setInterval(printViewStats,3000, innerMenu, uid); } e.stopPropagation(); return false; } } catch(e){errorlog(e);} }); if (session.statsMenu){ if ("stats" in session.rpcs[UUID]){ if (getById("menuStatsBox")){ clearInterval(getById("menuStatsBox").interval); getById("menuStatsBox").remove(); } var [menu, innerMenu] = statsMenuCreator(); printViewStats(innerMenu, UUID ); menu.interval = setInterval(printViewStats,3000, innerMenu, UUID); } } v.touchTimeOut = null; v.touchLastTap = 0; v.touchCount = 0; v.addEventListener('touchend', function(event) { log("touched"); document.ontouchup = null; document.onmouseup = null; document.onmousemove = null; document.ontouchmove = null; var currentTime = new Date().getTime(); var tapLength = currentTime - v.touchLastTap; clearTimeout(v.touchTimeOut); if (tapLength < 500 && tapLength > 0) { /// log("double touched"); v.touchCount+=1; event.preventDefault(); if (v.touchCount<5){ v.touchLastTap = currentTime; return false; } v.touchLastTap = 0; v.touchCount=0; log("double touched"); var uid = event.currentTarget.dataset.UUID; if ("stats" in session.rpcs[uid]){ var [menu, innerMenu] = statsMenuCreator(); printViewStats(innerMenu, uid ); menu.interval = setInterval(printViewStats,3000, innerMenu, uid); } event.stopPropagation(); return false; ////// } else { v.touchCount=1; v.touchTimeOut = setTimeout(function(vv) { clearTimeout(vv.touchTimeOut); vv.touchLastTap = 0; vv.touchCount=0; }, 5000, v); v.touchLastTap = currentTime; } }); if (session.remote){ v.addEventListener("wheel", session.remoteControl); } if (v.controls == false){ v.addEventListener("click", function () { if (v.paused){ log("PLAYING MANUALLY?"); v.play().then(_ => { log("playing"); }).catch(warnlog); } }); if (session.nocursor==false){ // we do not want to show the controls. This is because MacOS + OBS does not work; so electron app needs this. if (!(session.cleanOutput)){ if (!(window.obsstudio)){ if (session.scene===false){ if (session.permaid!==false){ if (v.controlTimer){ clearInterval(v.controlTimer); } v.controlTimer = setTimeout(showControlBar.bind(null,v),3000); //v.controlTimer = setTimeout(function (){v.controls=true;},3000); // 3 seconds before I enable the controls automatically. This way it doesn't auto appear during loading. 3s enough, right? } } } } } } if (session.fadein){ v.addEventListener('animationend', function(e) { v.classList.remove("fadein"); // allows the video to fade in. }); v.classList.add("fadein"); // allows the video to fade in. } setTimeout(session.processStats, 1000, UUID); } function showControlBar(vel){ try { vel.controls=true; } catch(e){errorlog(e);} } function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a giant function that runs when there are changes to screensize, video track statuses, etc. if (getById("subControlButtons").dragElement){ if (parseInt(getById("subControlButtons").style.top) > 0){ getById("subControlButtons").style.top = "0px"; } else if (parseInt(getById("subControlButtons").style.top) < parseInt(50 - window.innerHeight) ){ getById("subControlButtons").style.top = parseInt( 50 - window.innerHeight)+"px"; } if (parseInt(getById("subControlButtons").style.left) < 0){ getById("subControlButtons").style.left = "0px"; } else if (parseInt(getById("subControlButtons").style.left) > parseInt( window.innerWidth - getById("subControlButtons").offsetWidth) ){ getById("subControlButtons").style.left = parseInt( window.innerWidth -getById("subControlButtons").offsetWidth )+"px"; } } if (session.director){return;} if (session.manual === true){return;} var header = getById("header"); var hi = header.offsetHeight ; var w = window.innerWidth; var h = window.innerHeight - hi; if ( window.innerHeight<=700 ){ if (document.getElementById("controlButtons")){ var h = window.innerHeight - hi - document.getElementById("controlButtons").offsetHeight; } else { var h = window.innerHeight - hi; } } var arW = 16.0; var arH = 9.0; if (session.aspectratio){ if (session.aspectratio==1){ arW = 9.0; arH = 16.0; } else if (session.aspectratio==2){ arW = 12.0; // square root; cause why not. arH = 12.0; } } var ww = w/arW; var hh = h/arH; var mediaPool = []; var mediaPool_invisible = []; if (session.videoElement){ // I, myself, exist if (session.videoElement.style.display!="none"){ // local feed if (session.minipreview && (session.infocus!==true)){ /* session.videoElement.onclick = function(){ if (session.infocus === true){ session.infocus = false; } else { session.infocus = true; log("session: myself"); } setTimeout(()=>updateMixer(),10); }; */ } else { if (session.order!==false){ session.videoElement.order=session.order; } else { session.videoElement.order=0; } if (session.activeSpeaker && (!session.activelySpeaking)){ mediaPool_invisible.push(session.videoElement); } else { mediaPool.push(session.videoElement); } } } } if (session.screenShareElement){ // I, myself, exist if (session.screenShareElement.style.display!="none"){ // local feed if (session.order!==false){ session.screenShareElement.order=session.order; } else { session.screenShareElement.order=0; } if (session.infocus!==false){ mediaPool_invisible.push(session.screenShareElement); } else if (session.activeSpeaker && (!session.activelySpeaking)){ mediaPool_invisible.push(session.screenShareElement); } else { mediaPool.push(session.screenShareElement); } } } if (session.iframeEle){ // I, myself, exist if (session.iframeEle.style.display!="none"){ // local feed if (session.order!==false){ session.iframeEle.order=session.order; } else { session.iframeEle.order=0; } if (session.activeSpeaker && (!session.activelySpeaking)){ mediaPool_invisible.push(session.iframeEle); } else { mediaPool.push(session.iframeEle); } } } if ((session.infocus) && (session.infocus in session.rpcs)){ // remote guest being full screened; infocus == UUID log(session.infocus+" set fullscreen"); mediaPool = []; // remove myself from fullscreen for (var j in session.rpcs){ if (j != session.infocus){ session.requestRateLimit(0, j); // disable the video of non-fullscreen videos try { if (session.rpcs[j].videoElement.style.display!="none"){ // Add it if not hidden mediaPool_invisible.push(session.rpcs[j].videoElement); } } catch(e){} } else { // in focus video //////// try { if (session.rpcs[j].order!==false){ session.rpcs[j].videoElement.order=session.rpcs[j].order; } else { session.rpcs[j].videoElement.order=0; } /////////// if (session.activeSpeaker && (!session.rpcs[j].activelySpeaking)){ mediaPool_invisible.push(session.rpcs[j].videoElement); } else { mediaPool.push(session.rpcs[j].videoElement); } session.rpcs[j].videoElement.style.visibility = "visible"; if ((session.rpcs[j].targetBandwidth!==-1) && (session.rpcs[j].targetBandwidth