mirror of
https://github.com/eliasstepanik/vdo.ninja.git
synced 2026-01-16 16:18:30 +00:00
versus.cam 1.0 support added
This commit is contained in:
parent
10fa7e0a2a
commit
fdf5ce970d
@ -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;";
|
||||
|
||||
|
||||
12
index.html
12
index.html
@ -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
336
lib.js
@ -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, "<").replace(/>/g, ">").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){
|
||||
|
||||
38
main.css
38
main.css
@ -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
198
main.js
@ -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.
|
||||
}
|
||||
////////////////
|
||||
|
||||
|
||||
71
popout.html
71
popout.html
@ -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, "<").replace(/>/g, ">").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
1229
stats.html
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user