versus.cam 1.0 support added

This commit is contained in:
Steve Seguin 2022-08-04 17:23:46 -04:00 committed by GitHub
parent 10fa7e0a2a
commit fdf5ce970d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 499 additions and 1393 deletions

View File

@ -37,6 +37,11 @@
max-width:300px;
max-height:100px;
}
.container{
max-height: 900px;
overflow-y: auto;
overflow-x: auto;
}
</style>
<script>
@ -44,6 +49,7 @@
var iframe = document.createElement("iframe");
var iframeContainer = document.createElement("div");
iframeContainer.classList.add("container");
var iframesrc = document.getElementById("viewlink").value;
iframe.allow = "document-domain;encrypted-media;sync-xhr;usb;web-share;cross-origin-isolated;accelerometer;midi;geolocation;autoplay;camera;microphone;fullscreen;picture-in-picture;display-capture;";

View File

@ -57,7 +57,7 @@
<meta property="twitter:image" content="./media/vdoNinja_logo_full.png" />
<meta name="msapplication-TileColor" content="#da532c" />
<meta name="theme-color" content="#ffffff" />
<link rel="stylesheet" href="./main.css?ver=169" />
<link rel="stylesheet" href="./main.css?ver=174" />
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/adapter.min.js"></script>
<style id="lightbox-animations" type="text/css"></style>
<!-- <link rel="manifest" href="manifest.json" /> -->
@ -82,7 +82,7 @@
<link itemprop="url" href="./media/vdoNinja_logo_full.png" />
</span>
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/CodecsHandler.js?ver=37"></script>
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=487"></script>
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=493"></script>
<input id="zoomSlider" type="range" style="display: none;" />
<span id="electronDragZone" style="pointer-events: none; z-index:-10; position:absolute;top:0;left:0;width:100%;height:2%;-webkit-app-region: drag;min-height:20px;"></span>
<div id="header">
@ -859,7 +859,7 @@
<font style="color:#daad09;">Welcome to VDO Ninja! We've rebranded! Nothing else is changing and we're staying 100% free.</font>
</h4>
<br />
Site updated May 2022. <a target="_blank" href="https://docs.vdo.ninja/releases/v21">v21 release notes</a>. If having new issues, the previous version <a href="https://vdo.ninja/v20/">is here</a>, and the <a href="https://vdo.ninja/beta/">upcoming next version is here</a>; please test it when possible.
Site updated August 2022. <a target="_blank" href="https://docs.vdo.ninja/releases/v21">v21 release notes</a>. If having new issues, the previous version <a href="https://vdo.ninja/v20/">is here</a>, and the <a href="https://vdo.ninja/beta/">upcoming next version is here</a>. Development <a target="_blank" href='https://updates.vdo.ninja/'>updates are here.</a>
<br />
<br />
<h3>
@ -1897,7 +1897,7 @@
</div>
</div>
<input type="text" id="chatInput" placeholder="Enter chat message to send here" onkeypress="EnterButtonChat(event)" />
<button style="width:60px;background-color:#EEE;top: -1px;position: relative;" onclick="sendChatMessage()" data-translate='send-chat'>Send</button>
<button class="chatBarInputButton" onclick="sendChatMessage()" data-translate='send-chat'>Send</button>
</div>
@ -2208,11 +2208,11 @@
// session.defaultBackgroundImages = ["./media/bg_sample1.webp", "./media/bg_sample2.webp"]; // for &effects=5 (virtual backgrounds)
</script>
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/aes.js"></script>
<script type="text/javascript" crossorigin="anonymous" id="lib-js" src="./lib.js?ver=381"></script>
<script type="text/javascript" crossorigin="anonymous" id="lib-js" src="./lib.js?ver=387"></script>
<!--
// If you wish to change branding, blank offers a good clean start.
<script type="text/javascript" id="main-js" src="./main.js" data-translation="blank"></script>
-->
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=390"></script>
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=401"></script>
</body>
</html>

336
lib.js
View File

@ -538,6 +538,10 @@ function createVideoElement(){
} catch(e){errorlog(e);}
var v = document.createElement("video");
videoElements.push(v);
if (session.volume!==false){
v.volume = session.volume; // setting default volume
log("setting volume to manual");
}
return v;
}
@ -872,7 +876,7 @@ async function confirmAlt(inputText, block=false){
}
var modalTimeout=null;
function warnUser(message, timeout=false){
function warnUser(message, timeout=false, sanitize=true){
// Allows for multiple alerts to stack better.
// Every modal and backdrop has an increasing z-index
// to block the previous modal
@ -885,7 +889,9 @@ function warnUser(message, timeout=false){
zindex = 31 + document.querySelectorAll('.alertModal').length;
try{
message = sanitizeChat(message,2000);
if (sanitize){
message = sanitizeChat(message,2000);
}
message = message.replace(/\n/g,"<br />");
} catch(e){
errorlog(message);
@ -928,19 +934,19 @@ var sanitizeStreamID = function(streamID) {
if (streamID.length < 1) {
streamID = session.generateStreamID(8);
if (!(session.cleanOutput)) {
warnUser(miscTranslations["no-streamID-provided"] + streamID);
warnUser(miscTranslations["no-streamID-provided"] + streamID, false, false);
}
}
var streamID_sanitized = streamID.replace(/[\W]+/g, "_");
if (streamID !== streamID_sanitized) {
if (!(session.cleanOutput)) {
warnUser(miscTranslations["alphanumeric-only"]);
warnUser(miscTranslations["alphanumeric-only"], false, false);
}
}
if (streamID_sanitized.length > 44) {
streamID_sanitized = streamID_sanitized.substring(0, 50);
if (!(session.cleanOutput)) {
warnUser(miscTranslations["stream-id-too-long"]);
warnUser(miscTranslations["stream-id-too-long"], false, false);
}
}
return streamID_sanitized;
@ -2257,8 +2263,11 @@ function setupIncomingScreenTracking(v, UUID){ // SCREEN element.
setTimeout(function(){updateMixer();},1);
}
});
v.volume = 1.0; // play audio automatically
if (session.volume!==false){
v.volume = session.volume;
} else {
v.volume = 1.0; // play audio automatically
}
v.autoplay = true;
v.controls = session.showControls || false;
v.classList.add("tile");
@ -2608,7 +2617,11 @@ function setupIncomingVideoTracking(v, UUID){ // video element.
}
});
v.volume = 1.0; // play audio automatically
if (session.volume!==false){
v.volume = session.volume;
} else {
v.volume = 1.0; // play audio automatically
}
v.autoplay = true;
v.controls = session.showControls || false;
v.classList.add("tile");
@ -2955,7 +2968,8 @@ var updateMixerActive = false;
//var cleanupTimeout = null;
function updateMixer(e=false){
if (session.manual === true){return;}
if (session.director){return;}
else if (session.director){return;}
else if (session.windowed){return;}
clearInterval(updateMixerTimer);
if (updateMixerActive){
@ -3762,9 +3776,9 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
for (var i = 0; i<mediaPool.length; i++){
if (mediaPool[i].dataset.sid === sssid){continue;}
if (mediaPool.length==2){
customLayout[mediaPool[i].dataset.sid] = {"x":66.667,"y":33.333,"w":33.333,"h":33.333, "c":true};
customLayout[mediaPool[i].dataset.sid] = {"x":66.667,"y":0,"w":33.333,"h":100, "c":false};
} else if (mediaPool.length==3){
customLayout[mediaPool[i].dataset.sid] = {"x":66.667,"y":posCount*33.333+16.667,"w":33.333,"h":33.333, "c":true};
customLayout[mediaPool[i].dataset.sid] = {"x":66.667,"y":posCount*41+9,"w":33.333,"h":41, "c":false};
} else if (mediaPool.length==4){
customLayout[mediaPool[i].dataset.sid] = {"x":66.667,"y":posCount*33.333,"w":33.333,"h":33.333, "c":true};
} else if (mediaPool.length==5){
@ -5037,7 +5051,6 @@ function requestKeyframeScene(ele) {
function pokeIframeAPI(action, value = null, UUID = null) {
if (!isIFrame){return;}
log("poke iframe");
try {
var data = {};
@ -5763,7 +5776,7 @@ function applyEffects(track) { // video only please. do not touch audio. Run up
return session.canvas.captureStream().getVideoTracks()[0];
} catch(e){
if (!session.cleanOutput){
warnUser(miscTranslations["not-clean-session"]);
warnUser(miscTranslations["not-clean-session"], false, false);
}
}
}
@ -6861,8 +6874,6 @@ function selfDestructElement(UUID, uid){
}
function remoteStats(msg, UUID){
log(msg);
if (isIFrame){
parent.postMessage({"remoteStats": msg.remoteStats , "streamID": session.rpcs[UUID].streamID, "UUID": UUID}, session.iframetarget);
}
@ -8750,7 +8761,7 @@ function toggleFileshare(UUID=false, event = null){
} else {
var string = 'Someone has requested you share a file with them.<br /><input id="fileselector3" onchange="session.shareFile(this, `'+UUID+'`, event);" type="file" title="Transfer a file to person"/><div id="activeShares"></div>';
}
warnUser(string);
warnUser(string, false, false);
if (session.hostedFiles){
if (session.hostedFiles.length){
getById("activeShares").innerHTML += "<div><u>Files being shared:</u></div>";
@ -10611,24 +10622,25 @@ function publishWebcam(btn = false) {
getById("head2").className = 'hidden';
if (session.roomid !== false) { // they are in a room or a faux room
window.onresize = updateMixer;
window.onorientationchange = function(){setTimeout(async function(){
if (session.forceAspectRatio){
if (window.matchMedia("(orientation: portrait)").matches){
await updateCameraConstraints("aspectRatio", 1.0/session.forceAspectRatio);
} else {
await updateCameraConstraints("aspectRatio", session.forceAspectRatio);
}
}
updateForceRotate();
updateMixer();
}, 200);};
if ((session.roomid === "") && ((!(session.view)) || (session.view === ""))) {
// no room, no viewing, viewing disabled
if (session.manual===null){
session.manual = true;
}
window.onresize = updateMixer;
window.onorientationchange = function(){setTimeout(async function(){
if (session.forceAspectRatio){
if (window.matchMedia("(orientation: portrait)").matches){
await updateCameraConstraints("aspectRatio", 1.0/session.forceAspectRatio);
} else {
await updateCameraConstraints("aspectRatio", session.forceAspectRatio);
}
}
updateForceRotate();
updateMixer();
}, 200);};
if (!(session.cleanOutput)) {
var showReshare = getStorage("showReshare");
if (showReshare){
@ -10644,18 +10656,6 @@ function publishWebcam(btn = false) {
} else {
log("ROOM ID ENABLED");
log("Update Mixer Event on REsize SET");
window.onresize = updateMixer;
window.onorientationchange = function(){setTimeout(async function(){
if (session.forceAspectRatio){
if (window.matchMedia("(orientation: portrait)").matches){
await updateCameraConstraints("aspectRatio", 1.0/session.forceAspectRatio);
} else {
await updateCameraConstraints("aspectRatio", session.forceAspectRatio);
}
}
updateForceRotate();
updateMixer();
}, 200);};
getById("main").style.overflow = "hidden";
//session.cbr=0; // we're just going to override it
@ -11377,7 +11377,7 @@ function outboundAudioPipeline() { // this function isn't letting me change the
session.videoElement.srcObject.getVideoTracks().forEach(function(track) { // this seems to fix a bug with macbooks.
newStream.addTrack(track, session.videoElement.srcObject);
});
} else {
} else if (session.streamSrc){
session.streamSrc.getVideoTracks().forEach(function(track) { // this seems to fix a bug with macbooks.
newStream.addTrack(track, session.streamSrc);
});
@ -11582,7 +11582,7 @@ function outboundAudioPipeline() { // this function isn't letting me change the
webAudio.destination.stream.addTrack(track, session.videoElement.srcObject);
}
});
} else {
} else if (session.streamSrc){
session.streamSrc.getVideoTracks().forEach(function(track) {
if (webAudio.id != track.id) {
webAudio.destination.stream.addTrack(track, session.streamSrc);
@ -11609,9 +11609,11 @@ function outboundAudioPipeline() { // this function isn't letting me change the
}
var newStream = createMediaStream();
session.streamSrc.getVideoTracks().forEach(function(track) { // this seems to fix a bug with macbooks.
newStream.addTrack(track, session.streamSrc);
});
if (session.streamSrc){
session.streamSrc.getVideoTracks().forEach(function(track) { // this seems to fix a bug with macbooks.
newStream.addTrack(track, session.streamSrc);
});
}
return newStream;
}
} catch (e) {
@ -12159,16 +12161,16 @@ function joinRoom(roomname) {
if (session.defaultPassword===false){
if (session.password === false){
var invite = "https://"+location.host+location.pathname+"?room="+session.roomid+"&password=false";
warnUser("You can invite others with:\n\n<a target='_blank' title='Copy this link to the clipboard' style='cursor:pointer' onclick='copyFunction(this.innerText,event);' href='"+invite+"'>"+invite+"</a>");
warnUser("You can invite others with:\n\n<a target='_blank' title='Copy this link to the clipboard' style='cursor:pointer' onclick='copyFunction(this.innerText,event);' href='"+invite+"'>"+invite+"</a>", false, false);
} else {
generateHash(session.password + session.salt, 4).then(function(hash) {
var invite = "https://"+location.host+location.pathname+"?room="+session.roomid+"&hash="+hash;
warnUser("You can invite others with:\n\n<a target='_blank' title='Copy this link to the clipboard' style='cursor:pointer' onclick='copyFunction(this.innerText,event)' href='"+invite+"'>"+invite+"</a>");
warnUser("You can invite others with:\n\n<a target='_blank' title='Copy this link to the clipboard' style='cursor:pointer' onclick='copyFunction(this.innerText,event)' href='"+invite+"'>"+invite+"</a>", false, false);
});
}
} else {
var invite = "https://"+location.host+location.pathname+"?room="+session.roomid;
warnUser("You can invite others with:\n\n<a target='_blank' title='Copy this link to the clipboard' style='cursor:pointer' onclick='copyFunction(this.innerText,event)' href='"+invite+"'>"+invite+"</a>");
warnUser("You can invite others with:\n\n<a target='_blank' title='Copy this link to the clipboard' style='cursor:pointer' onclick='copyFunction(this.innerText,event)' href='"+invite+"'>"+invite+"</a>", false, false);
}
}
@ -14482,17 +14484,16 @@ function gotDevices2(deviceInfos) {
option.value = deviceInfo.deviceId || "default";
option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`;
try {
if (!knownTrack){
if (session.canvasSource){
session.canvasSource.srcObject.getVideoTracks().forEach(function(track) {
if (option.text == track.label) {
option.selected = "true";
knownTrack = true;
}
});
}
if (!knownTrack && session.canvasSource){
session.canvasSource.srcObject.getVideoTracks().forEach(function(track) {
if (option.text == track.label) {
option.selected = "true";
knownTrack = true;
}
});
}
if (!knownTrack){
if (!knownTrack && session.streamSrc){
session.streamSrc.getVideoTracks().forEach(function(track) {
if (option.text == track.label) {
option.selected = "true";
@ -15707,23 +15708,26 @@ async function toggleScreenShare(reload = false) { ////////////////////////////
}
var addedAlready = false;
session.streamSrc.getVideoTracks().forEach(function(track) {
if (beforeScreenShare && (track.id == beforeScreenShare.id)){
addedAlready=true;
} else {
session.streamSrc.removeTrack(track);
track.stop();
}
});
session.videoElement.srcObject.getVideoTracks().forEach(function(track) {
if (beforeScreenShare && (track.id == beforeScreenShare.id)){
addedAlready=true;
} else {
session.videoElement.srcObject.removeTrack(track);
track.stop();
}
});
if (session.streamSrc){
session.streamSrc.getVideoTracks().forEach(function(track) {
if (beforeScreenShare && (track.id == beforeScreenShare.id)){
addedAlready=true;
} else {
session.streamSrc.removeTrack(track);
track.stop();
}
});
}
if (session.videoElement.srcObject){
session.videoElement.srcObject.getVideoTracks().forEach(function(track) {
if (beforeScreenShare && (track.id == beforeScreenShare.id)){
addedAlready=true;
} else {
session.videoElement.srcObject.removeTrack(track);
track.stop();
}
});
}
getById("screensharebutton").classList.add("float"); // disable the button after we know the tracks are disabled
getById("screensharebutton").classList.remove("float2");
@ -16059,11 +16063,11 @@ async function grabScreen(quality = 0, audio = true, videoOnEnd = false) {
if (!(session.cleanOutput)) {
setTimeout(function() {
if (iOS || iPad){
warnUser(miscTranslations["ios-no-screen-share"]);
warnUser(miscTranslations["ios-no-screen-share"], false, false);
} else if (session.mobile){
warnUser(miscTranslations["android-no-screen-share"]);
warnUser(miscTranslations["android-no-screen-share"], false, false);
} else {
warnUser(miscTranslations["no-screen-share-supported"]);
warnUser(miscTranslations["no-screen-share-supported"], false, false);
}
}, 1);
}
@ -16234,17 +16238,18 @@ async function grabScreen(quality = 0, audio = true, videoOnEnd = false) {
try {
stream.getVideoTracks()[0].onended = function(e) { // if screen share stops,
warnlog(e);
session.streamSrc.getVideoTracks().forEach(function(track) {
session.streamSrc.removeTrack(track);
track.stop();
log("stopping video track 3");
if (beforeScreenShare && (beforeScreenShare.id == track.id)){
beforeScreenShare.stop();
beforeScreenShare=null;
}
});
if (session.streamSrc){
session.streamSrc.getVideoTracks().forEach(function(track) {
session.streamSrc.removeTrack(track);
track.stop();
log("stopping video track 3");
if (beforeScreenShare && (beforeScreenShare.id == track.id)){
beforeScreenShare.stop();
beforeScreenShare=null;
}
});
}
if (session.videoElement.srcObject){
session.videoElement.srcObject.getVideoTracks().forEach(function(track) {
@ -16258,12 +16263,14 @@ async function grabScreen(quality = 0, audio = true, videoOnEnd = false) {
}
if (screenShareAudioTrack){
session.streamSrc.getAudioTracks().forEach(function(track) { // previous video track; saving it. Must remove the track at some point.
if (screenShareAudioTrack.id == track.id) { // since there are more than one audio track, lets see if we can remove JUST the audio track for the screen share.
session.streamSrc.removeTrack(track);
track.stop();
}
});
if (session.streamSrc){
session.streamSrc.getAudioTracks().forEach(function(track) { // previous video track; saving it. Must remove the track at some point.
if (screenShareAudioTrack.id == track.id) { // since there are more than one audio track, lets see if we can remove JUST the audio track for the screen share.
session.streamSrc.removeTrack(track);
track.stop();
}
});
}
screenShareAudioTrack=null;
senderAudioUpdate();
}
@ -16324,13 +16331,13 @@ async function grabScreen(quality = 0, audio = true, videoOnEnd = false) {
if ((err.name == "NotAllowedError") || (err.name == "PermissionDeniedError")) {
// User Stopped it.
if (macOS){
warnUser(miscTranslations["screen-permissions-denied"]);
warnUser(miscTranslations["screen-permissions-denied"], false, false);
}
} else {
if (audio == true) {
if (err.name == "NotReadableError"){
if (!(session.cleanOutput)){
warnUser(miscTranslations["change-audio-output-device"]);
warnUser(miscTranslations["change-audio-output-device"], false, false);
}
return false;
} else {
@ -16594,12 +16601,13 @@ async function grabVideo(quality = 0, eleName = 'previewWebcam', selector = "sel
wasDisabled=false;
});
}
session.streamSrc.getVideoTracks().forEach(function(track) {
session.streamSrc.removeTrack(track);
track.stop();
wasDisabled=false;
});
if (session.streamSrc){
session.streamSrc.getVideoTracks().forEach(function(track) {
session.streamSrc.removeTrack(track);
track.stop();
wasDisabled=false;
});
}
if (session.videoElement.srcObject) {
session.videoElement.srcObject.getVideoTracks().forEach(function(track) {
@ -17126,9 +17134,9 @@ async function grabVideo(quality = 0, eleName = 'previewWebcam', selector = "sel
}
if (!(session.cleanOutput)) {
if (session.width || session.height || session.frameRate) {
warnUser("<i class='las la-exclamation-circle'></i> Camera failed to load.\n\nPlease ensure your camera supports the resolution and frameRate that has been manually specified. Perhaps use &quality=0 instead.");
warnUser("<i class='las la-exclamation-circle'></i> Camera failed to load.\n\nPlease ensure your camera supports the resolution and frameRate that has been manually specified. Perhaps use &quality=0 instead.", false, false);
} else {
warnUser("<i class='las la-exclamation-circle'></i> Camera failed to load.\n\nPlease make sure it is not already in use by another application.\n\nPlease make sure you have accepted the camera permissions.");
warnUser("<i class='las la-exclamation-circle'></i> Camera failed to load.\n\nPlease make sure it is not already in use by another application.\n\nPlease make sure you have accepted the camera permissions.", false, false);
}
}
}
@ -17942,9 +17950,9 @@ async function publishScreen2(constraints, audioList=[], audio=true, overrideFra
if (!navigator.mediaDevices.getDisplayMedia){
setTimeout(function(){
if (iOS || iPad){
warnUser("Sorry, but your iOS browser does not support screen-sharing.\n\nPlease see <a href='https://docs.vdo.ninja/guides/screen-share-your-iphone-ipad' target='_blank'>this guide</a> for an alternative method to do so.");
warnUser("Sorry, but your iOS browser does not support screen-sharing.\n\nPlease see <a href='https://docs.vdo.ninja/guides/screen-share-your-iphone-ipad' target='_blank'>this guide</a> for an alternative method to do so.", false, false);
} else if (session.mobile){
warnUser("Sorry, your browser does not support screen-sharing.\n\nThe <a href='https://docs.vdo.ninja/getting-started/native-mobile-app-versions#android-download-link' target='_blank'>Android native app</a> should support it though.");
warnUser("Sorry, your browser does not support screen-sharing.\n\nThe <a href='https://docs.vdo.ninja/getting-started/native-mobile-app-versions#android-download-link' target='_blank'>Android native app</a> should support it though.", false, false);
} else {
warnUser("Sorry, your browser does not support screen-sharing.\n\nPlease use the desktop versions of Firefox or Chrome instead.");
}
@ -18214,7 +18222,7 @@ async function publishScreen2(constraints, audioList=[], audio=true, overrideFra
} else {
getById("mutespeakerbutton").classList.add("hidden");
if (session.fullscreen){
if (session.fullscreen){
session.windowed = false;
if (session.mirrored && session.flipped){
v.style.transform = " scaleX(-1) scaleY(-1)";
@ -18252,6 +18260,21 @@ async function publishScreen2(constraints, audioList=[], audio=true, overrideFra
container.style.alignItems = "center";
container.backgroundColor = "#666";
}
if (!session.windowed){
window.onresize = updateMixer;
window.onorientationchange = function(){setTimeout(async function(){
if (session.forceAspectRatio){
if (window.matchMedia("(orientation: portrait)").matches){
await updateCameraConstraints("aspectRatio", 1.0/session.forceAspectRatio);
} else {
await updateCameraConstraints("aspectRatio", session.forceAspectRatio);
}
}
updateForceRotate();
updateMixer();
}, 200);};
}
v.autoplay = true;
v.controls = session.showControls || false;
@ -18338,14 +18361,14 @@ async function publishScreen2(constraints, audioList=[], audio=true, overrideFra
notifyOfScreenShare();
if (macOS){
warnUser(miscTranslations["screen-permissions-denied"]);
warnUser(miscTranslations["screen-permissions-denied"], false, false);
}
return false;
} else {
if (audio==true){
if (err.name == "NotReadableError"){
if (!(session.cleanOutput)){
warnUser(miscTranslations["change-audio-output-device"]);
warnUser(miscTranslations["change-audio-output-device"], false, false);
}
return false;
} else {
@ -19561,7 +19584,7 @@ function setupClosedCaptions() {
Recognition.start();
} else if (!session.cleanOutput){
warnUser(miscTranslations["speech-not-suppoted"]);
warnUser(miscTranslations["speech-not-suppoted"], false, false);
}
}
@ -22336,6 +22359,16 @@ function createIframePopup() {
if (session.meshcast){
extras += "&meshcast";
}
if (session.remote){
if (session.remote===true){
extras += "&remote";
} else {
extras += "&remote="+session.remote;
}
}
if (session.salt){
extras += "&salt="+session.salt;
}
if (session.meshcastBitrate){
extras += "&mcb="+session.meshcastBitrate;
}
@ -22625,7 +22658,7 @@ async function requestBasicPermissions(constraint = {video: true, audio: true},
if (!(session.cleanOutput)) {
setTimeout(function() {
if (window.obsstudio){
warnUser("Permissions denied.\n\nTo access the camera or microphone from within OBS, please refer to:\n<a href='https://docs.vdo.ninja/guides/share-webcam-from-inside-obs'>docs.vdo.ninja/guides/share-webcam-from-inside-obs</a>.");
warnUser("Permissions denied.\n\nTo access the camera or microphone from within OBS, please refer to:\n<a href='https://docs.vdo.ninja/guides/share-webcam-from-inside-obs'>docs.vdo.ninja/guides/share-webcam-from-inside-obs</a>.", false, false);
} else {
warnUser("Permissions denied. Please ensure you have allowed the mic/camera permissions.");
}
@ -23272,7 +23305,7 @@ function pauseVideo(videoEle, update=true){
var deviceListElement = gotDevices3(deviceInfo, ele);
if (deviceListElement){
warnUser("Select the audio playback destination for this media:<br /><br />");
warnUser("Select the audio playback destination for this media:\n\n");
getById("alertModalMessage").appendChild(deviceListElement);
} else {
warnUser("No output devices available");
@ -23551,7 +23584,7 @@ function timeSince(date) {
}
var messageList = []
function sendChatMessage(chatMsg = false) { // filtered + visual
function sendChatMessage(chatMsg = false, bc = false) { // filtered + visual
var data = {};
if (chatMsg === false) {
var msg = document.getElementById('chatInput').value;
@ -23725,7 +23758,7 @@ function sendChatMessage(chatMsg = false) { // filtered + visual
document.getElementById('chatInput').value = "";
messageList = messageList.slice(-100);
if (session.broadcastChannel !== false) {
if (!bc && session.broadcastChannel !== false) {
log(session.broadcastChannel);
session.broadcastChannel.postMessage(data);
}
@ -23831,12 +23864,63 @@ function createPopoutChat() {
messageList: messageList
});
} else if ("msg" in e.data) {
sendChatMessage(e.data.msg);
sendChatMessage(e.data.msg, true);
}
}
return false;
}
function replaceURLs(message) {
if(!message) return;
var urlRegex = /(((https?:\/\/)|(www\.))[^\s]+)/g;
return message.replace(urlRegex, function (url) {
url = url.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/["']/g, ""); // try to sanitize things, just in case.
var punc = "";
while (url[url.length-1] === "."){
url = url.slice(0,-1);
punc += ".";
}
while (url[url.length-1] === ";"){
url = url.slice(0,-1);
punc += ";";
}
while (url[url.length-1] === ","){
url = url.slice(0,-1);
punc += ",";
}
while (url[url.length-1] === "!"){
url = url.slice(0,-1);
punc += "!";
}
while (url[url.length-1] === ":"){
url = url.slice(0,-1);
punc += ":";
}
while (url[url.length-1] === "*"){
url = url.slice(0,-1);
punc += "*";
}
while (url[url.length-1] === ")"){
url = url.slice(0,-1);
punc += ")";
}
while (url[url.length-1] === "?"){
url = url.slice(0,-1);
punc += "?";
}
var hyperlink = url;
if (!hyperlink.match('^https?:\/\/')) {
hyperlink = 'http://' + hyperlink;
}
if (url.length>35){
url = url.substring(0, 35)+"...";
}
return '<a href="' + hyperlink + '" title="Click to open the link in a new tab" target="_blank" rel="noopener noreferrer">' + url + '</a>'+punc;
});
}
function getChatMessage(msg, label = false, director = false, overlay = false) {
msg = sanitizeChat(msg); // keep it clean.
@ -23918,7 +24002,6 @@ function getChatMessage(msg, label = false, director = false, overlay = false) {
getById("chatNotification").value = 1;
}
getById("chatNotification").classList.add("notification");
}
@ -23994,22 +24077,23 @@ function updateMessages(){
var time = timeSince(messageList[i].time) || "";
var msg = document.createElement("div");
var message = replaceURLs(messageList[i].msg);
if (messageList[i].type == "sent") {
msg.innerHTML = messageList[i].msg + " <i><small> <small>- " + time + "</small></small></i>";
msg.innerHTML = message + " <i><small> <small>- " + time + "</small></small></i>";
msg.classList.add("outMessage");
} else if ((messageList[i].type == "recv") || (messageList[i].type == "action")) {
var label = "";
if (messageList[i].label) {
label = messageList[i].label;
}
msg.innerHTML = label + messageList[i].msg + " <i><small> <small>- " + time + "</small></small></i>";
msg.innerHTML = label + message + " <i><small> <small>- " + time + "</small></small></i>";
msg.classList.add("inMessage");
} else if (messageList[i].type == "alert") {
msg.innerHTML = messageList[i].msg + " <i><small> <small>- " + time + "</small></small></i>";
msg.innerHTML = message + " <i><small> <small>- " + time + "</small></small></i>";
msg.classList.add("inMessage");
} else {
msg.innerHTML = messageList[i].msg;
msg.innerHTML = message;
msg.classList.add("outMessage");
}
@ -25898,12 +25982,12 @@ function effectsDynamicallyUpdate(event, ele){
} else if (session.effects === "6"){
if (!gpgpuSupport){
if (!session.cleanOutput){
warnUser("Hardware acceleration isn't detected.<br /><br />This effect will not work",4000);
warnUser("Hardware acceleration isn't detected.<br /><br />This effect will not work",4000,false);
return;
}
} else if (gpgpuSupport == "Google SwiftShader"){
if (!session.cleanOutput){
warnUser("Hardware acceleration isn't detected.<br /><br />Please enable it for this effect to work correctly.<br /><br /><i>Settings -> Advanced -> System -> Use hardware-accleration</i>");
warnUser("Hardware acceleration isn't detected.<br /><br />Please enable it for this effect to work correctly.<br /><br /><i>Settings -> Advanced -> System -> Use hardware-accleration</i>", false, false);
}
return;
}
@ -25977,7 +26061,7 @@ function loadEffect(effect){
if (gpgpuSupport == "Google SwiftShader"){
if (!session.cleanOutput){
warnUser("Hardware acceleration isn't detected.<br /><br />Please enable it for better performance.<br /><br /><i>Settings -> Advanced -> System -> Use hardware-accleration</i>");
warnUser("Hardware acceleration isn't detected.<br /><br />Please enable it for better performance.<br /><br /><i>Settings -> Advanced -> System -> Use hardware-accleration</i>", false, false);
}
}
}
@ -26104,7 +26188,7 @@ async function loadTFLiteModel(){
if (LaunchTFWorkerCallback){TFLiteWorker();}
}
function smdInfo(){
warnUser("For improved performance, use Chrome v87 or newer with SIMD support enabled.<br />Enable SIMD here: <a href='chrome://flags/#enable-webassembly-simd' onclick='copyFunction(this,event)' target='_blank'>chrome://flags/#enable-webassembly-simd</a>");
warnUser("For improved performance, use Chrome v87 or newer with SIMD support enabled.<br />Enable SIMD here: <a href='chrome://flags/#enable-webassembly-simd' onclick='copyFunction(this,event)' target='_blank'>chrome://flags/#enable-webassembly-simd</a>", false, false);
}
function getGuestTarget(type, id){

View File

@ -24,6 +24,7 @@
--video-background-image: url("data:image/svg+xml,%3Csvg viewBox='-42 0 512 512.002' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='m210.351562 246.632812c33.882813 0 63.222657-12.152343 87.195313-36.128906 23.972656-23.972656 36.125-53.304687 36.125-87.191406 0-33.875-12.152344-63.210938-36.128906-87.191406-23.976563-23.96875-53.3125-36.121094-87.191407-36.121094-33.886718 0-63.21875 12.152344-87.191406 36.125s-36.128906 53.308594-36.128906 87.1875c0 33.886719 12.15625 63.222656 36.132812 87.195312 23.976563 23.96875 53.3125 36.125 87.1875 36.125zm0 0'/%3E%3Cpath d='m426.128906 393.703125c-.691406-9.976563-2.089844-20.859375-4.148437-32.351563-2.078125-11.578124-4.753907-22.523437-7.957031-32.527343-3.308594-10.339844-7.808594-20.550781-13.371094-30.335938-5.773438-10.15625-12.554688-19-20.164063-26.277343-7.957031-7.613282-17.699219-13.734376-28.964843-18.199219-11.226563-4.441407-23.667969-6.691407-36.976563-6.691407-5.226563 0-10.28125 2.144532-20.042969 8.5-6.007812 3.917969-13.035156 8.449219-20.878906 13.460938-6.707031 4.273438-15.792969 8.277344-27.015625 11.902344-10.949219 3.542968-22.066406 5.339844-33.039063 5.339844-10.972656 0-22.085937-1.796876-33.046874-5.339844-11.210938-3.621094-20.296876-7.625-26.996094-11.898438-7.769532-4.964844-14.800782-9.496094-20.898438-13.46875-9.75-6.355468-14.808594-8.5-20.035156-8.5-13.3125 0-25.75 2.253906-36.972656 6.699219-11.257813 4.457031-21.003906 10.578125-28.96875 18.199219-7.605469 7.28125-14.390625 16.121094-20.15625 26.273437-5.558594 9.785157-10.058594 19.992188-13.371094 30.339844-3.199219 10.003906-5.875 20.945313-7.953125 32.523437-2.058594 11.476563-3.457031 22.363282-4.148437 32.363282-.679688 9.796875-1.023438 19.964844-1.023438 30.234375 0 26.726562 8.496094 48.363281 25.25 64.320312 16.546875 15.746094 38.441406 23.734375 65.066406 23.734375h246.53125c26.625 0 48.511719-7.984375 65.0625-23.734375 16.757813-15.945312 25.253906-37.585937 25.253906-64.324219-.003906-10.316406-.351562-20.492187-1.035156-30.242187zm0 0'/%3E%3C/svg%3E");
--advanced-mode: inline-block;
--background-main-image: unset;
--show-codirectors: inline-block;
}
* {
@ -570,13 +571,23 @@ hr {
}
.directorsgrid .vidcon {
display: inline-block !important;
display: inline-block;
width: 269.7px !important;
background: #7E7E7E;
color: #FCFCFC;
vertical-align: top;
}
.directorBox {
background-color: #606383 !important;
display: var(--show-codirectors) !important;
}
.directorBlue {
background-color: #5c7785 !important;
display: var(--show-codirectors) !important;
}
.directorsgrid .vidcon>.las {
color: black;
background: #999999;
@ -726,7 +737,6 @@ hr {
top: 1px;
background-color: #FFF2;
font-size: 1.5em;
display:none;
z-index: 2;
cursor: help;
}
@ -2808,6 +2818,7 @@ input[type=checkbox] {
overflow-y:scroll;
overflow-wrap: anywhere;
max-height: 800px;
line-height: 22px;
}
#chatBody::-webkit-scrollbar {
@ -2815,12 +2826,23 @@ input[type=checkbox] {
background: transparent; /* make scrollbar transparent */
}
div#chatBody a {
color: blue;
text-decoration: underline;
background-color: #c9c9c9;
border: 2px solid black;
padding: 2px 10px;
border-radius: 6px;
cursor: pointer;
}
#chatModule {
bottom: 50px;
position: fixed;
margin: 10px;
align-self: center;
width: 400px;
width: 574px;
min-width: 300px;
max-width: 100%;
z-index:3;
}
@ -2829,11 +2851,19 @@ input[type=checkbox] {
background-color: #FFFE;
max-width: 700px;
min-width: 320px;
width: calc(100% - 89px);
font-size: 105%;
margin-left: 7px;
padding: 3px;
border: 3px solid black;
}
.chatBarInputButton {
width:60px;
background-color:#EEE;
top: -1px;
position: relative;
margin-right: 10px;
}
.debugStats {
font-size: 0.8rem;
list-style-type: none;

198
main.js
View File

@ -25,8 +25,8 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
}
}
if (urlParams.has('ln')) {
ln_template = urlParams.get('ln') || null;
if (urlParams.has('ln') || urlParams.has('language')) {
ln_template = urlParams.get('ln') || urlParams.get('language') || null;
}
} catch (e) {
errorlog(e);
@ -273,7 +273,14 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
session.pushEffectsData=true;
}
if (iOS || iPad) {
if (urlParams.has('notmobile')){
session.mobile = false;
} else if (urlParams.has('mobile')){
session.mobile = true;
session.audioEffects = false; // disable audio inbound effects also.
session.audioMeterGuest = false;
} else if (iOS || iPad) {
session.mobile = true;
session.audioEffects = false; // disable audio inbound effects also.
session.audioMeterGuest = false;
@ -316,6 +323,11 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
}
}
// flagship
if (urlParams.has('broadcast') || urlParams.has('bc')) {
log("Broadcast flag set");
session.broadcast = urlParams.get('broadcast') || urlParams.get('bc') || null;
@ -517,6 +529,10 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
getById("hangupbutton").style.display = "none";
}
if (urlParams.has('socialstream')){
session.socialstream = urlParams.get('socialstream') || false;
}
if (urlParams.has('midioffset')){
session.midiOffset = urlParams.get('midioffset') || 0;
session.midiOffset = parseInt(session.midiOffset);
@ -632,7 +648,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
session.hidesololinks=true;
}
if (urlParams.has('ssb')) {
if (urlParams.has('ssb') || urlParams.has('screensharebutton')) {
session.screensharebutton = true;
}
@ -1097,6 +1113,9 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
getById("addPasswordBasic").style.display = "none";
}
if (urlParams.has('salt') && urlParams.get('salt')){
session.salt = urlParams.get('salt');
}
if (urlParams.has('hash') || urlParams.has('crc') || urlParams.has('check')) { // could be brute forced in theory, so not as safe as just not using a hash check.
@ -1331,9 +1350,9 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
}
if (urlParams.has("aec") || urlParams.has("ec")) {
if (urlParams.has("echocancellation") || urlParams.has("aec") || urlParams.has("ec")) {
session.echoCancellation = urlParams.get('aec') || urlParams.get('ec');
session.echoCancellation = urlParams.get("echocancellation") || urlParams.get('aec') || urlParams.get('ec');
if (session.echoCancellation) {
session.echoCancellation = session.echoCancellation.toLowerCase();
@ -1663,6 +1682,12 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
session.audioGain = parseInt(session.audioGain) || 0;
session.disableWebAudio = false;
}
if (urlParams.has('volume') || urlParams.has('vol') ) { // This sets the default volume for all new video playback elements; 0 to 100.
log("setting default volume for playback");
session.volume = urlParams.get('volume') || urlParams.get('vol') || 100;
session.volume = parseInt(session.volume) || 0;
session.volume = session.volume/100; // 0 to 1.0
}
if (urlParams.has('compressor') || urlParams.has('comp')) {
log("audio gain ENABLED");
session.compressor = 1;
@ -1699,6 +1724,10 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
getById("obsState").style.setProperty("display", "none", "important");
}
if (urlParams.has('hidecodirectors')){
document.querySelector(':root').style.setProperty("--show-codirectors", "none", "important");
}
if (urlParams.has('obscontrols') || urlParams.has('remoteobs') || urlParams.has('obsremote') || urlParams.has('obs') || urlParams.has('controlobs')) {
session.obsControls = urlParams.get('obscontrols') || urlParams.get('remoteobs') || urlParams.get('obsremote') || urlParams.get('obs') || urlParams.get('controlobs');
if (session.obsControls) { // whether to show the button or not; that's it.
@ -2399,8 +2428,8 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
session.meshcastScreenShareCodec = session.meshcastScreenShareCodec.toLowerCase();
}
if (urlParams.has('mcab') || urlParams.has('mcaudiobitrate') || urlParams.has('meshcastab')){
session.meshcastAudioBitrate = urlParams.get('mcab') || urlParams.get('mcaudiobitrate') || urlParams.get('meshcastab') || 32;
if (urlParams.has('mcab') || urlParams.has('mcaudiobitrate') || urlParams.has('meshcastab') || urlParams.has('meshcastaudiobitrate ')){
session.meshcastAudioBitrate = urlParams.get('mcab') || urlParams.get('mcaudiobitrate') || urlParams.get('meshcastab') || urlParams.get('meshcastaudiobitrate ') || 32;
session.meshcastAudioBitrate = parseInt(session.meshcastAudioBitrate);
}
@ -2929,7 +2958,6 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
} else {
session.sendframes = session.iframetarget || "*";
}
}
if (urlParams.has('tcp')){ // forces the TURN servers to use TCP mode; still need to add &private to force TURN also tho
@ -3516,7 +3544,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
} else if (session.chatbutton === false) {
getById("chatbutton").classList.add("hidden");
}
}
}
if (urlParams.has('nofileshare') || urlParams.has('nodownloads') || urlParams.has('nofiles')){
session.hostedFiles = false;
@ -3693,7 +3721,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
if (location.protocol !== 'https:') {
if (!(session.cleanOutput)) {
warnUser("SSL (https) is not enabled. This site will not work without it!<br /><br /><a href='https://"+window.location.host+window.location.pathname+window.location.search+"'>Try accessing the site from here instead.</a>");
warnUser("SSL (https) is not enabled. This site will not work without it!<br /><br /><a href='https://"+window.location.host+window.location.pathname+window.location.search+"'>Try accessing the site from here instead.</a>", false, false);
}
}
@ -3723,6 +3751,12 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
session.limitTotalBitrate = session.totalRoomBitrate_default; // 500, with the max per guest stream out at maxMobileBitrate (350kbps) or 35-kbps if more than X in the room.
}
if (urlParams.has('maxmobilebitrate')) {
session.maxMobileBitrate = parseInt(urlParams.has('maxmobilebitrate')) || 0;
}
if (urlParams.has('lowmobilebitrate')) {
session.lowMobileBitrate = parseInt(urlParams.has('lowmobilebitrate')) || 0;
}
// Please contact steve on discord.vdo.ninja if you'd like this iFRAME tweaked, expanded, etc -- it's updated based on user request
@ -3871,16 +3905,25 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
if ("volume" in e.data) { // might not work with iframes or meshcast currently.
session.volume = parseFloat(e.data.volume) || 0;
if (session.volume > 1.0){ // this is a bit quasi improper. But the API is official 0 to 1.0; not 0 to 100, so this is mainly a catch for those not using the API right.
session.volume = session.volume/100.0;
}
if (!("target" in e.data) || (e.data.target == "*")){
if (session.videoElement){
session.videoElement.volume = session.volume;
}
}
for (var i in session.rpcs) {
try {
if (!session.rpcs[i].videoElement){continue;}
if ("streamID" in session.rpcs[i]) {
if ("target" in e.data) {
if ((session.rpcs[i].streamID == e.data.target) || (e.data.target == "*")) { // specify a stream ID or let it apply to all videos
session.rpcs[i].videoElement.volume = parseFloat(e.data.volume);
session.rpcs[i].videoElement.volume = session.volume;
}
} else {
session.rpcs[i].videoElement.volume = parseFloat(e.data.volume);
session.rpcs[i].videoElement.volume = session.volume;
}
}
} catch (e) {
@ -3909,17 +3952,92 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
}
}
if (("targetBitrate" in e.data) || ("targetAudioBitrate" in e.data)) { // this sets the fundemental bitrate target, but does not necessarily "lock" .
if ("bitrate" in e.data) { /// set a video bitrate for a video; scene or view link; kbps
var msg = {};
if ("targetBitrate" in e.data){
msg.targetBitrate = e.data.targetBitrate;
}
if ("targetAudioBitrate" in e.data){
msg.targetAudioBitrate = e.data.targetAudioBitrate;
}
if (e.data.requestAs){
msg.requestAs = e.data.requestAs;
}
if (e.data.remote){
msg.remote = e.data.remote;
}
for (var i in session.rpcs) {
try {
if ("streamID" in session.rpcs[i]) {
if ("target" in e.data) {
if ((session.rpcs[i].streamID == e.data.target) || (e.data.target == "*")) { // specify a stream ID or let it apply to all videos
session.requestRateLimit(parseInt(e.data.bitrate), i);
session.sendRequest(msg, i);
}
} else if (e.data.UUID && (e.data.UUID===i)) {
session.sendRequest(msg, i);
} else if (e.data.streamID) {
if (session.rpcs[i].streamID == e.data.streamID) { // specify a stream ID or let it apply to all videos
session.sendRequest(msg, i);
}
} else {
session.requestRateLimit(parseInt(e.data.bitrate), i); // bitrate = 0 pauses the video
session.sendRequest(msg, i); // bitrate = 0 pauses the video
}
}
} catch (e) {
errorlog(e);
}
}
}
if ("manualBitrate" in e.data){
for (var i in session.rpcs) {
try {
if ("streamID" in session.rpcs[i]) {
if ("target" in e.data) {
if ((session.rpcs[i].streamID == e.data.target) || (e.data.target == "*")) { // specify a stream ID or let it apply to all videos
session.rpcs[i].manualBitrate = e.data.manualBitrate;
session.requestRateLimit(false, i);
}
} else if (e.data.UUID && (e.data.UUID===i)) {
session.rpcs[i].manualBitrate = e.data.manualBitrate;
session.requestRateLimit(false, i);
} else if (e.data.streamID) {
if (session.rpcs[i].streamID == e.data.streamID) { // specify a stream ID or let it apply to all videos
session.rpcs[i].manualBitrate = e.data.manualBitrate
session.requestRateLimit(false, i);
}
} else {
session.rpcs[i].manualBitrate = e.data.manualBitrate;
session.requestRateLimit(false, i);
}
}
} catch (e) {
errorlog(e);
}
}
}
if ("bitrate" in e.data) { /// set a video bitrate for a video; scene or view link; kbps
var lock = true;
if ("lock" in e.data){ // since this is the iframe API, we're going to assume the default is manual over-ride. VDO.Ninja's automixer logic won't override a locked bitrate.
lock = e.data.lock;
}
for (var i in session.rpcs) {
try {
if ("streamID" in session.rpcs[i]) { // we only target publishers with this call
if ("target" in e.data) {
if ((session.rpcs[i].streamID == e.data.target) || (e.data.target == "*")) { // specify a stream ID or let it apply to all videos
session.requestRateLimit(e.data.bitrate, i, false, lock);
}
} else if (e.data.UUID && (e.data.UUID===i)) {
session.requestRateLimit(e.data.bitrate, i, false, lock);
} else if (e.data.streamID) {
if (session.rpcs[i].streamID == e.data.streamID) { // specify a stream ID or let it apply to all videos
session.requestRateLimit(e.data.bitrate, i, false, lock);
}
} else {
session.requestRateLimit(e.data.bitrate, i, false, lock); // bitrate = 0 pauses the video
}
}
} catch (e) {
@ -3929,17 +4047,27 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
}
if ("audiobitrate" in e.data) { // changes the audio bitrate of a specific or all inbound media tracks. kbps
var lock = true;
if ("lock" in e.data){ // since this is the iframe API, we're going to assume the default is manual over-ride. VDO.Ninja's automixer logic won't override a locked bitrate.
lock = e.data.lock;
}
for (var i in session.rpcs) {
try {
if ("streamID" in session.rpcs[i]) {
if ("streamID" in session.rpcs[i]) { // we only target publishers with this call
if ("target" in e.data) {
if ((session.rpcs[i].streamID == e.data.target) || (e.data.target == "*")) { // specify a stream ID or let it apply to all videos
session.requestAudioRateLimit(parseInt(e.data.audiobitrate), i);
session.requestAudioRateLimit(parseInt(e.data.bitrate), i, lock);
}
} else if (e.data.UUID && (e.data.UUID===i)) {
session.requestAudioRateLimit(parseInt(e.data.bitrate), i, lock);
} else if (e.data.streamID) {
if (session.rpcs[i].streamID == e.data.streamID) { // specify a stream ID or let it apply to all videos
session.requestAudioRateLimit(parseInt(e.data.bitrate), i, lock);
}
} else {
session.requestAudioRateLimit(parseInt(e.data.audiobitrate), i); // bitrate = 0 pauses the video
session.requestAudioRateLimit(parseInt(e.data.bitrate), i, lock); // bitrate = 0 pauses the video
}
}
}
} catch (e) {
errorlog(e);
}
@ -4137,7 +4265,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
}
if ("getStreamIDs" in e.data) { // get a list of stream Ids, with a label if it is present. label = false if not there
if (e.data.getStreamIDs == true) {
if (e.data.getStreamIDs) {
var streamIDs = {};
for (var i in session.rpcs) {
streamIDs[session.rpcs[i].streamID] = session.rpcs[i].label;
@ -4145,7 +4273,27 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
parent.postMessage({
"streamIDs": streamIDs
}, session.iframetarget);
}
}
if ("getStreamInfo" in e.data) { // get a list of stream Ids, with a label if it is present. label = false if not there
try {
var UUIDS = {};
for (var i in session.rpcs){
UUIDS[i] = {};
UUIDS[i].label = session.rpcs[i].label || false;
UUIDS[i].streamID = session.rpcs[i].streamID || false;
if (session.rpcs[i].stats && session.rpcs[i].stats.info){
UUIDS[i].info = session.rpcs[i].stats.info;
} else {
UUIDS[i].info = {};
}
}
parent.postMessage({
"streamInfo": UUIDS
}, session.iframetarget);
} catch(e){
errorlog(e);
}
}
@ -4234,7 +4382,11 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
}
// session.viewheight or session.viewwidth
if ((targetWidth || targetHeight) && e.data.UUID){
session.requestResolution(e.data.UUID, wrw || 4096 , hrh || 2160 ); // this is fine.
var requestAs = false;
if (e.data.requestAs){
requestAs = e.data.requestAs;
}
session.requestResolution(e.data.UUID, targetWidth || 4096 , targetHeight || 2160 , false, requestAs); // this is fine.
}
////////////////

View File

@ -1,7 +1,6 @@
<html>
<head>
<meta name="theme-color" content="#ffffff" />
<!-- <script src="//console.re/connector.js" data-channel="vdoninjadev" type="text/javascript" id="consolerescript"></script>-->
<link rel="stylesheet" href="./main.css?ver=22" />
<style>
#chatModule{
@ -68,6 +67,58 @@ var messageList = [];
})(window);
var urlParams = new URLSearchParams(window.location.search);
function replaceURLs(message) {
if(!message) return;
var urlRegex = /(((https?:\/\/)|(www\.))[^\s]+)/g;
return message.replace(urlRegex, function (url) {
url = url.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/["']/g, ""); // try to sanitize things, just in case.
var punc = "";
while (url[url.length-1] === "."){
url = url.slice(0,-1);
punc += ".";
}
while (url[url.length-1] === ";"){
url = url.slice(0,-1);
punc += ";";
}
while (url[url.length-1] === ","){
url = url.slice(0,-1);
punc += ",";
}
while (url[url.length-1] === "!"){
url = url.slice(0,-1);
punc += "!";
}
while (url[url.length-1] === ":"){
url = url.slice(0,-1);
punc += ":";
}
while (url[url.length-1] === "*"){
url = url.slice(0,-1);
punc += "*";
}
while (url[url.length-1] === ")"){
url = url.slice(0,-1);
punc += ")";
}
while (url[url.length-1] === "?"){
url = url.slice(0,-1);
punc += "?";
}
var hyperlink = url;
if (!hyperlink.match('^https?:\/\/')) {
hyperlink = 'http://' + hyperlink;
}
if (url.length>35){
url = url.substring(0, 35)+"...";
}
return '<a href="' + hyperlink + '" title="Click to open the link in a new tab" target="_blank" rel="noopener noreferrer">' + url + '</a>'+punc;
});
}
if (urlParams.has("id")){
var bid = urlParams.get("id");
}
@ -111,6 +162,10 @@ function sendChatMessage(chatMsg = false){ // filtered + visual
console.log(msg);
bc.postMessage({"msg":msg})
document.getElementById('chatInput').value = "";
messageList.push({"msg":msg, type: "sent"});
messageList = messageList.slice(-100);
updateMessages({"msg":msg, type: "sent"});
}
function timeSince(date) {
@ -155,6 +210,8 @@ function updateMessages(message = false){
label = message.label;
}
message.msg = replaceURLs(message.msg);
if (message.type == "sent"){
msg.innerHTML = "<span class='chat_message chat_sent'>"+message.msg + " </span><i><small> <small>- "+time+"</small></small></i><span style='display:none'>"+label+"</span>";
msg.classList.add("outMessage");
@ -185,20 +242,22 @@ function updateMessages(message = false){
label = messageList[i].label;
}
var message = replaceURLs(messageList[i].msg);
if (messageList[i].type == "sent"){
msg.innerHTML = "<span class='chat_message chat_sent'>"+messageList[i].msg + " </span><i><small> <small>- "+time+"</small></small></i><span style='display:none'>"+label+"</span>";
msg.innerHTML = "<span class='chat_message chat_sent'>"+message + " </span><i><small> <small>- "+time+"</small></small></i><span style='display:none'>"+label+"</span>";
msg.classList.add("outMessage");
} else if (messageList[i].type == "recv"){
msg.innerHTML = label+"<span class='chat_message chat_recv'>"+messageList[i].msg + " </span><i><small> <small>- "+time+"</small></small></i>";
msg.innerHTML = label+"<span class='chat_message chat_recv'>"+message + " </span><i><small> <small>- "+time+"</small></small></i>";
msg.classList.add("inMessage");
} else if (messageList[i].type == "action"){
msg.innerHTML = label+"<span class='chat_message chat_action'>"+messageList[i].msg + " </span><i><small> <small>- "+time+"</small></small></i>";
msg.innerHTML = label+"<span class='chat_message chat_action'>"+message + " </span><i><small> <small>- "+time+"</small></small></i>";
msg.classList.add("actionMessage");
} else if (messageList[i].type == "alert"){
msg.innerHTML = "<span class='chat_message chat_alert'>"+messageList[i].msg + " </span><i><small> <small>- "+time+"</small></small></i>";
msg.innerHTML = "<span class='chat_message chat_alert'>"+message + " </span><i><small> <small>- "+time+"</small></small></i>";
msg.classList.add("inMessage");
} else {
msg.innerHTML = "<span class='chat_message chat_other'>"+messageList[i].msg + " </span><i><small> <small>- "+time+"</small></small></i>";
msg.innerHTML = "<span class='chat_message chat_other'>"+message + " </span><i><small> <small>- "+time+"</small></small></i>";
msg.classList.add("inMessage");
}

1229
stats.html

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long