mirror of
https://github.com/eliasstepanik/vdo.ninja.git
synced 2026-01-11 21:58:35 +00:00
Add files via upload
This commit is contained in:
parent
ad4d5585b6
commit
a1b2cea991
16
convert.html
16
convert.html
@ -92,14 +92,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>MKV to MP4 (no transcoding)</h2>
|
||||
<div>
|
||||
<small>The same as: fmpeg -i INPUTFILE -vcodec copy -acodec copy output.mp4</small>
|
||||
<input type="file" id="uploader2" accept=".mkv" title="Convert MKV to MP4">
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>WebM MP4 files (no transcoding, attempts to force high resolutions)</h2>
|
||||
<h2>WebM to MP4 files (no transcoding, attempts to force high resolutions)</h2>
|
||||
<div>
|
||||
<input type="file" id="uploader3" accept=".webm" title="Convert WebM to MP4">
|
||||
</div>
|
||||
@ -110,6 +103,13 @@
|
||||
<input type="file" id="uploader4" accept=".webm" title="Convert WebM to OPUS">
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>MKV to MP4 (no transcoding)</h2>
|
||||
<div>
|
||||
<small>The same as: fmpeg -i INPUTFILE -vcodec copy -acodec copy output.mp4</small>
|
||||
<input type="file" id="uploader2" accept=".mkv" title="Convert MKV to MP4">
|
||||
</div>
|
||||
</div>
|
||||
<div id="processing">
|
||||
<span id="message"></span>
|
||||
<video id="player" controls style="display:none"></video>
|
||||
|
||||
@ -277,7 +277,7 @@
|
||||
</head>
|
||||
<body >
|
||||
|
||||
<div id="header" style="-webkit-app-region: drag;color:#6f6f6f;font-size:40px; line-height: 40px; padding: 20px; letter-spacing: 3; font-weight: bold;">Electron Capture</div>
|
||||
<div id="header" style="-webkit-app-region: drag;color:#6f6f6f;font-size:40px; line-height: 40px; padding: 5px 10px; letter-spacing: 3; font-weight: bold;">Electron Capture</div>
|
||||
<div class="container" >
|
||||
|
||||
<div id='warning4mac' style="display:none;"> ✨ Great News! OBS v26.1.2 <a href="https://github.com/obsproject/obs-browser/issues/209#issuecomment-748683083">now supports</a> VDO.Ninja without needing the Electron Capture app! 🥳</div>
|
||||
@ -400,15 +400,16 @@ if ((location.hostname.toLowerCase() == "vdo.ninja") || (location.hostname.toLow
|
||||
var checkVersion = setTimeout(function(){ // pre 1.5.2
|
||||
compareVersions("0.0.0");
|
||||
},500);
|
||||
|
||||
const ipcRenderer = require('electron').ipcRenderer;
|
||||
console.log("ELECTRON DETECTED");
|
||||
ipcRenderer.on('appVersion', function(event, version) {
|
||||
clearTimeout(checkVersion);
|
||||
console.log("version: "+version);
|
||||
compareVersions(version);
|
||||
})
|
||||
ipcRenderer.send('getAppVersion');
|
||||
try{
|
||||
const ipcRenderer = require('electron').ipcRenderer;
|
||||
console.log("ELECTRON DETECTED");
|
||||
ipcRenderer.on('appVersion', function(event, version) {
|
||||
clearTimeout(checkVersion);
|
||||
console.log("version: "+version);
|
||||
compareVersions(version);
|
||||
})
|
||||
ipcRenderer.send('getAppVersion');
|
||||
} catch(e){}
|
||||
}
|
||||
}
|
||||
} catch(e){console.error(e);}
|
||||
@ -549,6 +550,20 @@ function modURL(){
|
||||
var url = document.getElementById('changeText').value;
|
||||
if (url.startsWith("obs.ninja")){
|
||||
url = "https://"+url;
|
||||
} else if (url.startsWith("youtube.com")){
|
||||
url = "https://"+url;
|
||||
} else if (url.startsWith("twitch.tv")){
|
||||
url = "https://"+url;
|
||||
} else if (url.startsWith("vdo.ninja")){
|
||||
url = "https://"+url;
|
||||
} else if (url.startsWith("http://")){
|
||||
// pass
|
||||
} else if (url.startsWith("https://")){
|
||||
// pass
|
||||
} else if (url.startsWith("file:")){
|
||||
// pass
|
||||
} else {
|
||||
url = "https://"+url;
|
||||
}
|
||||
console.log(url);
|
||||
return url;
|
||||
@ -558,7 +573,7 @@ function gohere(){
|
||||
localStorage.setItem('lastUrls', JSON.stringify(lastUrls));
|
||||
var url = modURL();
|
||||
if ((document.getElementById('changeText').value.includes("obs.ninja")) && (document.getElementById('changeText').value.includes("http")) && (document.getElementById('changeText').value.includes("&sink"))){
|
||||
alert("Notice: OBS.Ninja has been replaced by VDO.Ninja.\n\nPlease update your links accordingly for audio output to work correctly.");
|
||||
alert("Notice: OBS.Ninja has been renamed to VDO.Ninja.\n\nPlease update your links accordingly for audio output to work correctly.");
|
||||
} else if (!(document.getElementById('changeText').value.includes(window.location.hostname)) && (document.getElementById('changeText').value.includes("http")) && (document.getElementById('changeText').value.includes("&sink"))){
|
||||
alert("Notice: The &sink command is domain specific.\nVisit https://YOURDOMAIN.com/electron instead.");
|
||||
}
|
||||
|
||||
159
examples/chat.html
Normal file
159
examples/chat.html
Normal file
@ -0,0 +1,159 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>OBSN Chat Overlay</title>
|
||||
<style>
|
||||
|
||||
@font-face {
|
||||
font-family: 'Cousine';
|
||||
src: url('fonts/Cousine-Bold.ttf') format('truetype');
|
||||
}
|
||||
|
||||
body {
|
||||
margin:0;
|
||||
padding:0 10px;
|
||||
height:100%;
|
||||
border: 0;
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
position:absolute;
|
||||
bottom:0;
|
||||
overflow:hidden;
|
||||
max-width:100%;
|
||||
}
|
||||
|
||||
div {
|
||||
margin:0;
|
||||
background-color: black;
|
||||
padding: 8px 8px 0px 8px;
|
||||
color: white;
|
||||
font-family: Cousine, monospace;
|
||||
font-size: 3.2em;
|
||||
line-height: 1.1em;
|
||||
letter-spacing: 0.0em;
|
||||
text-transform: uppercase;
|
||||
text-shadow: 0.05em 0.05em 0px rgba(0,0,0,1);
|
||||
max-width:100%;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
word-break: break-all;
|
||||
hyphens: auto;
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
|
||||
|
||||
a {
|
||||
color:white;
|
||||
font-size:1.2em;
|
||||
text-transform: none;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
hyphens: auto;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
|
||||
|
||||
(function (w) {
|
||||
w.URLSearchParams =
|
||||
w.URLSearchParams ||
|
||||
function (searchString) {
|
||||
var self = this;
|
||||
self.searchString = searchString;
|
||||
self.get = function (name) {
|
||||
var results = new RegExp("[\?&]" + name + "=([^&#]*)").exec(
|
||||
self.searchString
|
||||
);
|
||||
if (results == null) {
|
||||
return null;
|
||||
} else {
|
||||
return decodeURI(results[1]) || 0;
|
||||
}
|
||||
};
|
||||
};
|
||||
})(window);
|
||||
var urlParams = new URLSearchParams(window.location.search);
|
||||
|
||||
|
||||
function loadIframe() {
|
||||
|
||||
var iframe = document.createElement("iframe");
|
||||
|
||||
var view= "";
|
||||
if (urlParams.has("view")) {
|
||||
view = "&view="+(urlParams.get("view") || "");
|
||||
}
|
||||
var room="";
|
||||
if (urlParams.has("room")) {
|
||||
room = "&room="+urlParams.get("room");
|
||||
}
|
||||
|
||||
var password="";
|
||||
if (urlParams.has("password")) {
|
||||
password = "&password="+urlParams.get("password");
|
||||
}
|
||||
|
||||
iframe.allow = "autoplay";
|
||||
var srcString = "./?novideo&noaudio&label=chatOverlay&scene"+room+view+password;
|
||||
|
||||
iframe.src = srcString;
|
||||
iframe.style.width="0";
|
||||
iframe.style.height="0";
|
||||
iframe.style.border="0";
|
||||
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
//////////// LISTEN FOR EVENTS
|
||||
|
||||
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
|
||||
var eventer = window[eventMethod];
|
||||
var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";
|
||||
|
||||
|
||||
/// If you have a routing system setup, you could have just one global listener for all iframes instead.
|
||||
|
||||
eventer(messageEvent, function (e) {
|
||||
if (e.source != iframe.contentWindow){return} // reject messages send from other iframes
|
||||
|
||||
console.log(e);
|
||||
if ("gotChat" in e.data){
|
||||
logData(e.data.gotChat.label,e.data.gotChat.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function printValues(obj) {
|
||||
var out = "";
|
||||
for (var key in obj) {
|
||||
if (typeof obj[key] === "object") {
|
||||
out += "<br />";
|
||||
out += printValues(obj[key]);
|
||||
} else {
|
||||
if (key.startsWith("_")) {
|
||||
} else {
|
||||
out += "<b>" + key + "</b>: " + obj[key] + "<br />";
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function logData(type, data) {
|
||||
var span = document.createElement('span');
|
||||
var entry = document.createElement('div');
|
||||
if (type){
|
||||
type = "<i>"+type.replace(/_/g, ' ')+"</i>";
|
||||
}
|
||||
entry.innerHTML = type + data;
|
||||
span.appendChild(entry);
|
||||
document.body.prepend(span);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="loadIframe();">
|
||||
</body>
|
||||
</html>
|
||||
331
examples/draggable.html
Normal file
331
examples/draggable.html
Normal file
@ -0,0 +1,331 @@
|
||||
<html>
|
||||
<head><title>Dual Input</title>
|
||||
<style>
|
||||
body{
|
||||
padding:0;
|
||||
margin:0;
|
||||
}
|
||||
iframe {
|
||||
border:0;
|
||||
margin:0;
|
||||
padding:0;
|
||||
display:block;
|
||||
margin:0px;
|
||||
min-height: 100px;
|
||||
min-width: 100px;
|
||||
max-height: 95%;
|
||||
max-width: 99%%;
|
||||
float: left;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
#viewlink {
|
||||
width:400px;
|
||||
}
|
||||
|
||||
|
||||
input{
|
||||
padding:5px;
|
||||
margin:5px;
|
||||
}
|
||||
button{
|
||||
padding:5px;
|
||||
margin:5px;
|
||||
position:relative;
|
||||
|
||||
}
|
||||
|
||||
.menu {
|
||||
z-index: 10;
|
||||
float:right;
|
||||
right: 20px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.close {
|
||||
background-color: #d33;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.reload {
|
||||
background-color: #0a0;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.popup {
|
||||
z-index: 9;
|
||||
background-color: #f1f1f1;
|
||||
border: 1px solid #d3d3d3;
|
||||
text-align: center;
|
||||
min-height: 100px;
|
||||
min-width: 100px;
|
||||
max-height: 95%;
|
||||
max-width: 99%;
|
||||
scale: 0.5;
|
||||
}
|
||||
|
||||
.popup {
|
||||
position: absolute;
|
||||
/*resize: both; !*enable this to css resize*! */
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.popup-header {
|
||||
cursor: move;
|
||||
background-color: #2196f3;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.popup .resizer-right {
|
||||
width: 5px;
|
||||
height: 100%;
|
||||
background: transparent;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
cursor: e-resize;
|
||||
}
|
||||
|
||||
.popup .resizer-bottom {
|
||||
width: 100%;
|
||||
height: 5px;
|
||||
background: transparent;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
cursor: n-resize;
|
||||
}
|
||||
|
||||
.popup .resizer-both {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
background: transparent;
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
cursor: nw-resize;
|
||||
}
|
||||
|
||||
|
||||
/*NOSELECT*/
|
||||
|
||||
.popup * {
|
||||
-webkit-touch-callout: none; /* iOS Safari */
|
||||
-webkit-user-select: none; /* Safari */
|
||||
-khtml-user-select: none; /* Konqueror HTML */
|
||||
-moz-user-select: none; /* Firefox */
|
||||
-ms-user-select: none; /* Internet Explorer/Edge */
|
||||
user-select: none; /* Non-prefixed version, currently
|
||||
supported by Chrome and Opera */
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<input placeholder="Enter an OBS.Ninja Room Link" id="viewlink" />
|
||||
|
||||
<button onclick="loadIframe();">Load URL</button>You can drag and resize the generated windows; multiple can be created.
|
||||
|
||||
<div id="container"></div>
|
||||
|
||||
<script>
|
||||
var currentZIndex = 100;
|
||||
function initDragElement(popup){
|
||||
|
||||
var pos1 = 0,
|
||||
pos2 = 0,
|
||||
pos3 = 0,
|
||||
pos4 = 0;
|
||||
|
||||
var elmnt = null;
|
||||
|
||||
var header = getHeader(popup);
|
||||
var iframe = getIFrame(popup);
|
||||
|
||||
popup.onmousedown = function() {
|
||||
this.style.zIndex = "" + ++currentZIndex;
|
||||
};
|
||||
|
||||
if (header) {
|
||||
header.parentPopup = popup;
|
||||
header.onmousedown = dragMouseDown;
|
||||
}
|
||||
|
||||
|
||||
function dragMouseDown(e) {
|
||||
elmnt = this.parentPopup;
|
||||
elmnt.style.zIndex = "" + ++currentZIndex;
|
||||
|
||||
e = e || window.event;
|
||||
// get the mouse cursor position at startup:
|
||||
pos3 = e.clientX;
|
||||
pos4 = e.clientY;
|
||||
document.onmouseup = closeDragElement;
|
||||
// call a function whenever the cursor moves:
|
||||
document.onmousemove = elementDrag;
|
||||
}
|
||||
|
||||
function elementDrag(e) {
|
||||
if (!elmnt) {
|
||||
return;
|
||||
}
|
||||
|
||||
e = e || window.event;
|
||||
// calculate the new cursor position:
|
||||
pos1 = pos3 - e.clientX;
|
||||
pos2 = pos4 - e.clientY;
|
||||
pos3 = e.clientX;
|
||||
pos4 = e.clientY;
|
||||
// set the element's new position:
|
||||
elmnt.style.top = elmnt.offsetTop - pos2 + "px";
|
||||
elmnt.style.left = elmnt.offsetLeft - pos1 + "px";
|
||||
|
||||
iframe.style.top = elmnt.offsetTop - pos2 + "px";
|
||||
iframe.style.left = elmnt.offsetLeft - pos1 + "px";
|
||||
}
|
||||
|
||||
function closeDragElement() {
|
||||
/* stop moving when mouse button is released:*/
|
||||
document.onmouseup = null;
|
||||
document.onmousemove = null;
|
||||
}
|
||||
|
||||
function getHeader(element) {
|
||||
var headerItems = element.getElementsByClassName("popup-header");
|
||||
|
||||
if (headerItems.length === 1) {
|
||||
return headerItems[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getIFrame(element) {
|
||||
var headerItems = element.getElementsByTagName("iframe");
|
||||
|
||||
if (headerItems.length === 1) {
|
||||
return headerItems[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function initResizeElement(p) {
|
||||
|
||||
var iframe = getIFrame(p);
|
||||
var element = null;
|
||||
var startX, startY, startWidth, startHeight;
|
||||
|
||||
var right = document.createElement("div");
|
||||
right.className = "resizer-right";
|
||||
p.appendChild(right);
|
||||
right.addEventListener("mousedown", initDrag, false);
|
||||
right.parentPopup = p;
|
||||
|
||||
var bottom = document.createElement("div");
|
||||
bottom.className = "resizer-bottom";
|
||||
p.appendChild(bottom);
|
||||
bottom.addEventListener("mousedown", initDrag, false);
|
||||
bottom.parentPopup = p;
|
||||
|
||||
var both = document.createElement("div");
|
||||
both.className = "resizer-both";
|
||||
p.appendChild(both);
|
||||
both.addEventListener("mousedown", initDrag, false);
|
||||
both.parentPopup = p;
|
||||
|
||||
|
||||
function initDrag(e) {
|
||||
element = this.parentPopup;
|
||||
|
||||
startX = e.clientX;
|
||||
startY = e.clientY;
|
||||
startWidth = parseInt(
|
||||
document.defaultView.getComputedStyle(element).width,
|
||||
10
|
||||
);
|
||||
startHeight = parseInt(
|
||||
document.defaultView.getComputedStyle(element).height,
|
||||
10
|
||||
);
|
||||
document.documentElement.addEventListener("mousemove", doDrag, false);
|
||||
document.documentElement.addEventListener("mouseup", stopDrag, false);
|
||||
document.documentElement.addEventListener("click", stopDrag, false)
|
||||
}
|
||||
|
||||
function doDrag(e) {
|
||||
if (e.buttons==0){
|
||||
stopDrag(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
element.style.width = startWidth + e.clientX - startX + "px";
|
||||
element.style.height = startHeight + e.clientY - startY + "px";
|
||||
|
||||
iframe.style.width = startWidth + e.clientX - startX + "px";
|
||||
iframe.style.height = startHeight + e.clientY - startY + "px";
|
||||
}
|
||||
|
||||
function stopDrag(e) {
|
||||
document.documentElement.removeEventListener("mousemove", doDrag, false);
|
||||
document.documentElement.removeEventListener("mouseup", stopDrag, false);
|
||||
}
|
||||
|
||||
function getIFrame(element) {
|
||||
var headerItems = element.getElementsByTagName("iframe");
|
||||
|
||||
if (headerItems.length === 1) {
|
||||
return headerItems[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function loadIframe(){
|
||||
|
||||
var iframeContainer = document.createElement("div");
|
||||
iframeContainer.className="popup";
|
||||
iframeContainer.style.zIndex = "" + ++currentZIndex;
|
||||
iframeContainer.style.width="325px";
|
||||
iframeContainer.style.height="420px";
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Move";
|
||||
button.className = "popup-header menu";
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Close";
|
||||
button.className = "menu close";
|
||||
button.onclick = function(){iframe.contentWindow.postMessage({"close":true}, '*');iframe.parentNode.parentNode.removeChild(iframeContainer);}
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Reload";
|
||||
button.className = "menu reload";
|
||||
button.onclick = function(){iframe.contentWindow.postMessage({"reload":true}, '*');}
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.allow="autoplay";
|
||||
iframe.src = document.getElementById("viewlink").value || "https://obs.ninja";
|
||||
iframe.style.width="325px";
|
||||
iframe.style.height="420px";
|
||||
|
||||
iframeContainer.appendChild(iframe);
|
||||
|
||||
document.getElementById("container").appendChild(iframeContainer);
|
||||
|
||||
initDragElement(iframeContainer);
|
||||
initResizeElement(iframeContainer);
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,328 +1,73 @@
|
||||
<html>
|
||||
<head><title>Dual Input</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
|
||||
<style>
|
||||
body{
|
||||
padding:0;
|
||||
margin:0;
|
||||
background-color:#003;
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
|
||||
iframe {
|
||||
width:100%;
|
||||
height:100%;
|
||||
border:0;
|
||||
margin:0;
|
||||
padding:0;
|
||||
position:absolute;
|
||||
display:block;
|
||||
margin:0px;
|
||||
min-height: 100px;
|
||||
min-width: 100px;
|
||||
max-height: 95%;
|
||||
max-width: 99%%;
|
||||
float: left;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
#viewlink {
|
||||
width:400px;
|
||||
}
|
||||
|
||||
|
||||
input{
|
||||
padding:5px;
|
||||
margin:5px;
|
||||
}
|
||||
button{
|
||||
padding:5px;
|
||||
margin:5px;
|
||||
position:relative;
|
||||
|
||||
}
|
||||
|
||||
.menu {
|
||||
z-index: 10;
|
||||
float:right;
|
||||
right: 20px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.close {
|
||||
background-color: #d33;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.reload {
|
||||
background-color: #0a0;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.popup {
|
||||
z-index: 9;
|
||||
background-color: #f1f1f1;
|
||||
border: 1px solid #d3d3d3;
|
||||
text-align: center;
|
||||
min-height: 100px;
|
||||
min-width: 100px;
|
||||
max-height: 95%;
|
||||
max-width: 99%;
|
||||
scale: 0.5;
|
||||
}
|
||||
|
||||
.popup {
|
||||
position: absolute;
|
||||
/*resize: both; !*enable this to css resize*! */
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.popup-header {
|
||||
cursor: move;
|
||||
background-color: #2196f3;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.popup .resizer-right {
|
||||
width: 5px;
|
||||
height: 100%;
|
||||
background: transparent;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
cursor: e-resize;
|
||||
}
|
||||
|
||||
.popup .resizer-bottom {
|
||||
width: 100%;
|
||||
height: 5px;
|
||||
background: transparent;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
cursor: n-resize;
|
||||
}
|
||||
|
||||
.popup .resizer-both {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
background: transparent;
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
cursor: nw-resize;
|
||||
}
|
||||
|
||||
|
||||
/*NOSELECT*/
|
||||
|
||||
.popup * {
|
||||
-webkit-touch-callout: none; /* iOS Safari */
|
||||
-webkit-user-select: none; /* Safari */
|
||||
-khtml-user-select: none; /* Konqueror HTML */
|
||||
-moz-user-select: none; /* Firefox */
|
||||
-ms-user-select: none; /* Internet Explorer/Edge */
|
||||
user-select: none; /* Non-prefixed version, currently
|
||||
supported by Chrome and Opera */
|
||||
padding:10px;
|
||||
width:80%;
|
||||
font-size:1.2em;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<input placeholder="Enter an OBS.Ninja Room Link" id="viewlink" />
|
||||
|
||||
<button onclick="loadIframe();">Load URL</button>You can drag and resize the generated windows; multiple can be created.
|
||||
|
||||
<div id="container"></div>
|
||||
|
||||
<div id="container1" style="width:100%;height:100%;display:none;"></div>
|
||||
<div id="container2" style="width: calc(25vh*1.777);height: calc(25vh); display:none; float:left; position: fixed; top: 2%; left: 0%;"></div>
|
||||
<input placeholder="Enter a Room name" id="viewlink" type="text" onchange="loadIframes()"/>
|
||||
<script>
|
||||
var currentZIndex = 100;
|
||||
function initDragElement(popup){
|
||||
|
||||
var pos1 = 0,
|
||||
pos2 = 0,
|
||||
pos3 = 0,
|
||||
pos4 = 0;
|
||||
function loadIframes(url=false){
|
||||
|
||||
var elmnt = null;
|
||||
|
||||
var header = getHeader(popup);
|
||||
var iframe = getIFrame(popup);
|
||||
|
||||
popup.onmousedown = function() {
|
||||
this.style.zIndex = "" + ++currentZIndex;
|
||||
};
|
||||
|
||||
if (header) {
|
||||
header.parentPopup = popup;
|
||||
header.onmousedown = dragMouseDown;
|
||||
}
|
||||
|
||||
|
||||
function dragMouseDown(e) {
|
||||
elmnt = this.parentPopup;
|
||||
elmnt.style.zIndex = "" + ++currentZIndex;
|
||||
|
||||
e = e || window.event;
|
||||
// get the mouse cursor position at startup:
|
||||
pos3 = e.clientX;
|
||||
pos4 = e.clientY;
|
||||
document.onmouseup = closeDragElement;
|
||||
// call a function whenever the cursor moves:
|
||||
document.onmousemove = elementDrag;
|
||||
}
|
||||
|
||||
function elementDrag(e) {
|
||||
if (!elmnt) {
|
||||
return;
|
||||
}
|
||||
|
||||
e = e || window.event;
|
||||
// calculate the new cursor position:
|
||||
pos1 = pos3 - e.clientX;
|
||||
pos2 = pos4 - e.clientY;
|
||||
pos3 = e.clientX;
|
||||
pos4 = e.clientY;
|
||||
// set the element's new position:
|
||||
elmnt.style.top = elmnt.offsetTop - pos2 + "px";
|
||||
elmnt.style.left = elmnt.offsetLeft - pos1 + "px";
|
||||
var roomname = document.getElementById("viewlink").value;
|
||||
|
||||
iframe.style.top = elmnt.offsetTop - pos2 + "px";
|
||||
iframe.style.left = elmnt.offsetLeft - pos1 + "px";
|
||||
}
|
||||
|
||||
function closeDragElement() {
|
||||
/* stop moving when mouse button is released:*/
|
||||
document.onmouseup = null;
|
||||
document.onmousemove = null;
|
||||
}
|
||||
|
||||
function getHeader(element) {
|
||||
var headerItems = element.getElementsByClassName("popup-header");
|
||||
|
||||
if (headerItems.length === 1) {
|
||||
return headerItems[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getIFrame(element) {
|
||||
var headerItems = element.getElementsByTagName("iframe");
|
||||
|
||||
if (headerItems.length === 1) {
|
||||
return headerItems[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function initResizeElement(p) {
|
||||
|
||||
var iframe = getIFrame(p);
|
||||
var element = null;
|
||||
var startX, startY, startWidth, startHeight;
|
||||
|
||||
var right = document.createElement("div");
|
||||
right.className = "resizer-right";
|
||||
p.appendChild(right);
|
||||
right.addEventListener("mousedown", initDrag, false);
|
||||
right.parentPopup = p;
|
||||
|
||||
var bottom = document.createElement("div");
|
||||
bottom.className = "resizer-bottom";
|
||||
p.appendChild(bottom);
|
||||
bottom.addEventListener("mousedown", initDrag, false);
|
||||
bottom.parentPopup = p;
|
||||
|
||||
var both = document.createElement("div");
|
||||
both.className = "resizer-both";
|
||||
p.appendChild(both);
|
||||
both.addEventListener("mousedown", initDrag, false);
|
||||
both.parentPopup = p;
|
||||
|
||||
|
||||
function initDrag(e) {
|
||||
element = this.parentPopup;
|
||||
|
||||
startX = e.clientX;
|
||||
startY = e.clientY;
|
||||
startWidth = parseInt(
|
||||
document.defaultView.getComputedStyle(element).width,
|
||||
10
|
||||
);
|
||||
startHeight = parseInt(
|
||||
document.defaultView.getComputedStyle(element).height,
|
||||
10
|
||||
);
|
||||
document.documentElement.addEventListener("mousemove", doDrag, false);
|
||||
document.documentElement.addEventListener("mouseup", stopDrag, false);
|
||||
document.documentElement.addEventListener("click", stopDrag, false)
|
||||
}
|
||||
|
||||
function doDrag(e) {
|
||||
if (e.buttons==0){
|
||||
stopDrag(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
element.style.width = startWidth + e.clientX - startX + "px";
|
||||
element.style.height = startHeight + e.clientY - startY + "px";
|
||||
document.getElementById("viewlink").parentNode.removeChild(document.getElementById("viewlink"));
|
||||
document.getElementById("container1").style.display="inline-block";
|
||||
document.getElementById("container2").style.display="inline-block";
|
||||
|
||||
iframe.style.width = startWidth + e.clientX - startX + "px";
|
||||
iframe.style.height = startHeight + e.clientY - startY + "px";
|
||||
}
|
||||
|
||||
function stopDrag(e) {
|
||||
document.documentElement.removeEventListener("mousemove", doDrag, false);
|
||||
document.documentElement.removeEventListener("mouseup", stopDrag, false);
|
||||
}
|
||||
|
||||
function getIFrame(element) {
|
||||
var headerItems = element.getElementsByTagName("iframe");
|
||||
|
||||
if (headerItems.length === 1) {
|
||||
return headerItems[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function loadIframe(){
|
||||
|
||||
var iframeContainer = document.createElement("div");
|
||||
iframeContainer.className="popup";
|
||||
iframeContainer.style.zIndex = "" + ++currentZIndex;
|
||||
iframeContainer.style.width="325px";
|
||||
iframeContainer.style.height="420px";
|
||||
var path = window.location.host+window.location.pathname.split("/").slice(0,-1).join("/");
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Move";
|
||||
button.className = "popup-header menu";
|
||||
iframeContainer.appendChild(button);
|
||||
var room1 = "https://"+path+"/?room="+roomname+"&push="+roomname+"_front&webcam&autostart&vd=front&ad=1&exclude="+roomname+"_rear";
|
||||
var room2 = "https://"+path+"/?room="+roomname+"&push="+roomname+"_rear&webcam&autostart&vd=back&ad=0&view&cleanoutput&nosettings&transparent";
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Close";
|
||||
button.className = "menu close";
|
||||
button.onclick = function(){iframe.contentWindow.postMessage({"close":true}, '*');iframe.parentNode.parentNode.removeChild(iframeContainer);}
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Reload";
|
||||
button.className = "menu reload";
|
||||
button.onclick = function(){iframe.contentWindow.postMessage({"reload":true}, '*');}
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.allow="autoplay";
|
||||
iframe.src = document.getElementById("viewlink").value || "https://obs.ninja";
|
||||
iframe.style.width="325px";
|
||||
iframe.style.height="420px";
|
||||
|
||||
iframe.allow = "autoplay;camera;microphone;fullscreen;picture-in-picture;";
|
||||
iframe.src = room1;
|
||||
var iframeContainer = document.createElement("div");
|
||||
iframeContainer.appendChild(iframe);
|
||||
document.getElementById("container1").appendChild(iframeContainer);
|
||||
|
||||
document.getElementById("container").appendChild(iframeContainer);
|
||||
|
||||
initDragElement(iframeContainer);
|
||||
initResizeElement(iframeContainer);
|
||||
setTimeout(function(){
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.allow = "autoplay;camera;microphone;fullscreen;picture-in-picture;";
|
||||
iframe.src = room2;
|
||||
var iframeContainer = document.createElement("div");
|
||||
iframeContainer.appendChild(iframe);
|
||||
document.getElementById("container2").appendChild(iframeContainer);
|
||||
},3000);
|
||||
|
||||
}
|
||||
|
||||
|
||||
3086
examples/main.css
Normal file
3086
examples/main.css
Normal file
File diff suppressed because it is too large
Load Diff
555
examples/midi.html
Normal file
555
examples/midi.html
Normal file
@ -0,0 +1,555 @@
|
||||
<html>
|
||||
<head>
|
||||
<script src="https://cdn.jsdelivr.net/npm/webmidi"></script>
|
||||
<link rel="stylesheet" href="./main.css" />
|
||||
<style>
|
||||
.container {
|
||||
max-width: 80%;
|
||||
width: fit-content;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: 10px;
|
||||
box-shadow: 0 4px 8px 0 rgb(0 0 0 / 10%);
|
||||
background-color: #ddd;
|
||||
color: black;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.card>div {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
font-size: 1.5em;
|
||||
padding: 10px;
|
||||
background-color: #457b9d;
|
||||
color: white;
|
||||
border-bottom: 2px solid #3b6a87;
|
||||
}
|
||||
|
||||
small {
|
||||
font-style: italic;
|
||||
display: block;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
span.warning {
|
||||
color: rgb(212, 191, 0);
|
||||
}
|
||||
|
||||
input {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
video {
|
||||
max-width: 640px;
|
||||
max-height: 360px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
audio {
|
||||
max-width: 640px;
|
||||
max-height: 360px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
div#processing {
|
||||
display: none;
|
||||
justify-content: center;
|
||||
place-items: center;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
background: #141926;
|
||||
flex-direction: column;
|
||||
}
|
||||
button {
|
||||
margin:5px;
|
||||
border:solid black 2px;
|
||||
}
|
||||
|
||||
body {
|
||||
color:white;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #225273!important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
<title>VDO.Ninja MIDI Controller</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">
|
||||
<a id="logoname" href="./" style="text-decoration: none; color: white; margin: 2px">
|
||||
<span data-translate="logo-header">
|
||||
<font id="qos">V</font>DO.Ninja
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div id="info">
|
||||
<h1>VDO.Ninja MIDI test app</h1>
|
||||
|
||||
<div class="card">
|
||||
<h2>About</h2>
|
||||
<div>
|
||||
You can check the console debug logs for added details.
|
||||
<br /><br />You can download a virtual MIDI I/O controller for windwos here:<br />
|
||||
http://www.tobias-erichsen.de/software/loopmidi.html
|
||||
<br /><br />This code uses the WebMIDI.js library, referenced here:<br />
|
||||
https://github.com/djipco/webmidi
|
||||
<br /><br />
|
||||
Below you can test the <a href="https://docs.vdo.ninja/general-settings/midi#midi-pass-through-mode">MIDI hotkey commands</a> for VDO.Ninja below:<br />
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>Select the MIDI Output device:</h2>
|
||||
<div>
|
||||
<label for="outputdevice">MIDI Output device:</label>
|
||||
<select name="outputdevice" id="outputdevice">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>&midi=1</h2>
|
||||
<div id="container1">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>&midi=3</h2>
|
||||
<div id="container2">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>&midi=4 ; director</h2>
|
||||
<div id="container3">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>&midi=4 ; guest 1</h2>
|
||||
<div id="container4">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>&midi=4 ; guest 2</h2>
|
||||
<div id="container5">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>Sample Remote Director Control links</h2>
|
||||
<div id="container6">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div id='commands'>
|
||||
|
||||
</div>
|
||||
<script>
|
||||
// Enable WebMidi.js
|
||||
WebMidi.enable(function (err) {
|
||||
|
||||
if (err) {
|
||||
console.log("WebMidi could not be enabled.", err);
|
||||
}
|
||||
|
||||
// Viewing available inputs and outputs
|
||||
console.log(WebMidi.inputs);
|
||||
console.log(WebMidi.outputs);
|
||||
|
||||
var output = WebMidi.outputs[0];
|
||||
|
||||
|
||||
var midiout = 0;
|
||||
var outputdevice = document.getElementById("outputdevice");
|
||||
for (var i=0;i<WebMidi.outputs.length;i++){
|
||||
var opt = document.createElement('option');
|
||||
opt.value = WebMidi.outputs[i].id;
|
||||
opt.innerHTML = WebMidi.outputs[i].name + " (id:"+(1+i)+")";
|
||||
if (i==0){
|
||||
midiout = opt.value;
|
||||
opt.selected = true;
|
||||
}
|
||||
outputdevice.appendChild(opt);
|
||||
}
|
||||
|
||||
var path = window.location.host+window.location.pathname.split("/").slice(0,-1).join("/");
|
||||
|
||||
outputdevice.onchange = function(e){
|
||||
midiout = outputdevice.value;
|
||||
output = WebMidi.getOutputById(midiout);
|
||||
console.log("MIDI DEVICE CHANGED: "+midiout);
|
||||
|
||||
var container = document.getElementById("container6");
|
||||
container.innerHTML = "<br />https://"+path+"/?midiremote=4&director=ROOMNAMEHERE";
|
||||
container.innerHTML += "<br /><br />";
|
||||
container.innerHTML += "https://"+path+"/?room=ROOMNAMEHERE&midiout="+(outputdevice.selectedIndex+1)+"&vd=0&ad=0&push&autostart&label=MIDI_CONTROLLER";
|
||||
}
|
||||
|
||||
var container = document.getElementById("container6");
|
||||
container.innerHTML = "<br />https://"+path+"/?midiremote=4&director=ROOMNAMEHERE";
|
||||
container.innerHTML += "<br /><br />";
|
||||
container.innerHTML += "https://"+path+"/?room=ROOMNAMEHERE&midiout="+(outputdevice.selectedIndex+1)+"&vd=0&ad=0&push&autostart&label=MIDI_CONTROLLER";
|
||||
|
||||
// Reacting when a new device becomes available
|
||||
WebMidi.addListener("connected", function(e) {
|
||||
console.log(e);
|
||||
});
|
||||
|
||||
// Reacting when a device becomes unavailable
|
||||
WebMidi.addListener("disconnected", function(e) {
|
||||
console.log(e);
|
||||
});
|
||||
|
||||
// Display the current time
|
||||
console.log(WebMidi.time);
|
||||
|
||||
|
||||
// Retrieve an input by name, id or index
|
||||
// var input = WebMidi.getInputByName("StreamDeck2Daw");
|
||||
// input = WebMidi.getInputById("1809568182");
|
||||
var input = WebMidi.inputs[1];
|
||||
|
||||
// Listen for a 'note on' message on all channels
|
||||
input.addListener('noteon', "all",
|
||||
function (e) {
|
||||
console.log("Received 'noteon' message (" + e.note.name + e.note.octave + ").");
|
||||
console.log(e);
|
||||
}
|
||||
);
|
||||
|
||||
// Listen to pitch bend message on channel 3
|
||||
input.addListener('pitchbend', 3,
|
||||
function (e) {
|
||||
console.log("Received 'pitchbend' message.", e);
|
||||
}
|
||||
);
|
||||
|
||||
// Listen to control change message on all channels
|
||||
input.addListener('controlchange', "all",
|
||||
function (e) {
|
||||
console.log("Received 'controlchange' message.", e);
|
||||
}
|
||||
);
|
||||
|
||||
// Listen to NRPN message on all channels
|
||||
input.addListener('nrpn', "all",
|
||||
function (e) {
|
||||
if(e.controller.type === 'entry') {
|
||||
console.log("Received 'nrpn' 'entry' message.", e);
|
||||
}
|
||||
if(e.controller.type === 'decrement') {
|
||||
console.log("Received 'nrpn' 'decrement' message.", e);
|
||||
}
|
||||
if(e.controller.type === 'increment') {
|
||||
console.log("Received 'nrpn' 'increment' message.", e);
|
||||
}
|
||||
console.log("message value: " + e.controller.value + ".", e);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
||||
var container = document.getElementById("container1");
|
||||
|
||||
|
||||
///
|
||||
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Note G3; Chat";
|
||||
button.onclick = function(){output.playNote("G3");}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Note A3; Mute";
|
||||
button.onclick = function(){output.playNote("A3");}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Note B3; Mute Video";
|
||||
button.onclick = function(){output.playNote("B3");}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Note C4; ScreenShare";
|
||||
button.onclick = function(){output.playNote("C4");}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Note D4; Hangup";
|
||||
button.onclick = function(){output.playNote("D4");}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Note E4; Hands";
|
||||
button.onclick = function(){output.playNote("E4");}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Note F4; Record";
|
||||
button.onclick = function(){output.playNote("F4");}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Note G4; Turn on Dir's Audio";
|
||||
button.onclick = function(){output.playNote("G4");}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Note A4; Stop Dir's Audio";
|
||||
button.onclick = function(){output.playNote("A4");}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
///
|
||||
|
||||
var container = document.getElementById("container2");
|
||||
|
||||
///
|
||||
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Note C1; velocity 0";
|
||||
button.onclick = function(){output.playNote("C1", 1, {velocity: 0});}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Note C1; velocity 1";
|
||||
button.onclick = function(){output.playNote("C1", 1, {velocity: 1});}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Note C1; velocity 2";
|
||||
button.onclick = function(){output.playNote("C1", 1, {velocity: 2});}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Note C1; velocity 3";
|
||||
button.onclick = function(){output.playNote("C1", 1, {velocity: 3});}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Note C1; velocity 4";
|
||||
button.onclick = function(){output.playNote("C1", 1, {velocity: 4});}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Note C1; velocity 5";
|
||||
button.onclick = function(){output.playNote("C1", 1, {velocity: 5});}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Note C1; velocity 6";
|
||||
button.onclick = function(){output.playNote("C1", 1, {velocity: 6});}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Note C1; velocity 7";
|
||||
button.onclick = function(){output.playNote("C1", 1, {velocity: 7});}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Note C1; velocity 8";
|
||||
button.onclick = function(){output.playNote("C1", 1, {velocity: 8});}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
///
|
||||
|
||||
var container = document.getElementById("container3");
|
||||
|
||||
|
||||
///
|
||||
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "channel 110; value 0";
|
||||
button.onclick = function(){output.sendControlChange(110, 0, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "channel 110; value 1";
|
||||
button.onclick = function(){output.sendControlChange(110, 1, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "channel 110; value 2";
|
||||
button.onclick = function(){output.sendControlChange(110, 2, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "channel 110; value 3";
|
||||
button.onclick = function(){output.sendControlChange(110, 3, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "channel 110; value 4";
|
||||
button.onclick = function(){output.sendControlChange(110, 4, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "channel 110; value 5";
|
||||
button.onclick = function(){output.sendControlChange(110, 5, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "channel 110; value 6";
|
||||
button.onclick = function(){output.sendControlChange(110, 6, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "channel 110; value 7";
|
||||
button.onclick = function(){output.sendControlChange(110, 7, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "channel 110; value 8";
|
||||
button.onclick = function(){output.sendControlChange(110, 8, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
///
|
||||
|
||||
var container = document.getElementById("container4");
|
||||
|
||||
|
||||
///
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "channel 111; value 0";
|
||||
button.onclick = function(){output.sendControlChange(111, 0, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "channel 111; value 1";
|
||||
button.onclick = function(){output.sendControlChange(111, 1, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "channel 111; value 2";
|
||||
button.onclick = function(){output.sendControlChange(111, 2, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "channel 111; value 3";
|
||||
button.onclick = function(){output.sendControlChange(111, 3, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "channel 111; value 4";
|
||||
button.onclick = function(){output.sendControlChange(111, 4, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "channel 111; value 5";
|
||||
button.onclick = function(){output.sendControlChange(111, 5, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
|
||||
///
|
||||
|
||||
var container = document.getElementById("container5");
|
||||
|
||||
|
||||
///
|
||||
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "channel 112; transfer popup";
|
||||
button.onclick = function(){output.sendControlChange(112, 0, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "channel 112; scene 1";
|
||||
button.onclick = function(){output.sendControlChange(112, 1, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "channel 112; mute in scene";
|
||||
button.onclick = function(){output.sendControlChange(112, 2, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "channel 112; mute everywhere";
|
||||
button.onclick = function(){output.sendControlChange(112, 3, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "channel 112; hang up";
|
||||
button.onclick = function(){output.sendControlChange(112, 4, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "channel 112; solo chat";
|
||||
button.onclick = function(){output.sendControlChange(112, 5, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "remote speaker";
|
||||
button.onclick = function(){output.sendControlChange(112, 6, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "remote display";
|
||||
button.onclick = function(){output.sendControlChange(112, 7, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "scene 2";
|
||||
button.onclick = function(){output.sendControlChange(112, 12, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "scene 3";
|
||||
button.onclick = function(){output.sendControlChange(112, 13, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "scene 4";
|
||||
button.onclick = function(){output.sendControlChange(112, 14, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "scene 5";
|
||||
button.onclick = function(){output.sendControlChange(112, 15, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "scene 6";
|
||||
button.onclick = function(){output.sendControlChange(112, 16, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = " scene 7";
|
||||
button.onclick = function(){output.sendControlChange(112, 17, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "scene 8";
|
||||
button.onclick = function(){output.sendControlChange(112, 18, 1);}; // "speaker" also works in the same way.
|
||||
container.appendChild(button);
|
||||
|
||||
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
97
examples/minidirector.css
Normal file
97
examples/minidirector.css
Normal file
@ -0,0 +1,97 @@
|
||||
body{
|
||||
zoom: 75%;
|
||||
}
|
||||
.hidden{
|
||||
display:unset!important;
|
||||
visibility: visible;
|
||||
width:unset;
|
||||
height:unset;
|
||||
opacity: 1;
|
||||
}
|
||||
button[data-action-type='solo-chat'] {
|
||||
display:none! important;
|
||||
}
|
||||
|
||||
button[data-action-type='recorder-local'] {
|
||||
display:none! important;
|
||||
}
|
||||
span[data-action-type='ordering'] {
|
||||
display:none! important;
|
||||
}
|
||||
button[data-action-type='open-file-share'] {
|
||||
display:none! important;
|
||||
}
|
||||
|
||||
button[data-action-type='add-channel']{
|
||||
display:none! important;
|
||||
}
|
||||
button[data-action-type='toggle-remote-speaker']{
|
||||
display:none! important;
|
||||
}
|
||||
button[data-action-type='toggle-remote-display']{
|
||||
display:none! important;
|
||||
}
|
||||
button[data-action-type='hide-guest']{
|
||||
display:none! important;
|
||||
}
|
||||
button[data-action-type='create-timer']{
|
||||
display:none! important;
|
||||
}
|
||||
button[data-action-type='change-url']{
|
||||
display:none! important;
|
||||
}
|
||||
button[data-action-type='change-params']{
|
||||
display:none! important;
|
||||
}
|
||||
span[data-action-type='change-quality']{
|
||||
display:none! important;
|
||||
}
|
||||
|
||||
span[data-action-type='sceneCluster2']{
|
||||
display:none! important;
|
||||
}
|
||||
span[data-action-type='sceneCluster1']{
|
||||
display:none! important;
|
||||
}
|
||||
|
||||
.orderspan{
|
||||
display:none! important;
|
||||
}
|
||||
#roomHeader{
|
||||
display:none! important;
|
||||
}
|
||||
.directorContainer {
|
||||
display:none!important;
|
||||
}
|
||||
|
||||
.hideDropMenu{
|
||||
display:none!important;
|
||||
}
|
||||
|
||||
#header{
|
||||
display:none!important;
|
||||
}
|
||||
body {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
button[class="pull-right"]{
|
||||
display:none! important;
|
||||
}
|
||||
|
||||
div#guestFeeds {
|
||||
padding: 1px!important;
|
||||
margin: 1px!important;
|
||||
}
|
||||
div[class="vidcon directorMargins"] {
|
||||
padding: 1px!important;
|
||||
margin: 1px!important;
|
||||
width: 260px;
|
||||
}
|
||||
button[data-action-type]{
|
||||
margin: 1px!important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
486
examples/obs_client.html
Normal file
486
examples/obs_client.html
Normal file
@ -0,0 +1,486 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript" src="./thirdparty/obs-websocket.min.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="./main.css" />
|
||||
<style>
|
||||
|
||||
.container {
|
||||
max-width: 80%;
|
||||
width: fit-content;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: 10px;
|
||||
box-shadow: 0 4px 8px 0 rgb(0 0 0 / 10%);
|
||||
background-color: #ddd;
|
||||
color: black;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.card>div {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
font-size: 1.5em;
|
||||
padding: 10px;
|
||||
background-color: #457b9d;
|
||||
color: white;
|
||||
border-bottom: 2px solid #3b6a87;
|
||||
}
|
||||
|
||||
small {
|
||||
font-style: italic;
|
||||
display: block;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
span.warning {
|
||||
color: rgb(212, 191, 0);
|
||||
}
|
||||
|
||||
input {
|
||||
padding: 10px;
|
||||
display: inline-block;
|
||||
flex-flow: unset;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
video {
|
||||
max-width: 640px;
|
||||
max-height: 360px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
audio {
|
||||
max-width: 640px;
|
||||
max-height: 360px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
div#processing {
|
||||
display: none;
|
||||
justify-content: center;
|
||||
place-items: center;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
background: #141926;
|
||||
flex-direction: column;
|
||||
}
|
||||
button {
|
||||
margin:5px;
|
||||
border:solid black 2px;
|
||||
}
|
||||
|
||||
body {
|
||||
color:white;
|
||||
display: inline-block;
|
||||
flex-flow: unset;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #225273!important;
|
||||
}
|
||||
|
||||
.hidden{
|
||||
display:none !important;
|
||||
}
|
||||
|
||||
.stat {
|
||||
background-color: black;
|
||||
margin: 7px;
|
||||
padding: 5px;
|
||||
}
|
||||
.stat:nth-child(2n) {
|
||||
background-color: #333;
|
||||
}
|
||||
.stat:empty {
|
||||
display:none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
<title>OBS Controller Demo using VDO.NInja</title>
|
||||
</head>
|
||||
|
||||
<div class="container">
|
||||
<h1>OBS remote (client)</h1>
|
||||
<div id="info">
|
||||
<div class="card">
|
||||
<h2>Scenes</h2>
|
||||
<div id="scene_list">
|
||||
</div>
|
||||
</div>
|
||||
<div class="card hidden">
|
||||
<h2>General</h2>
|
||||
<div>
|
||||
<button onclick="basicCommand(this);" data-command="GetVersion">GetVersion</button>
|
||||
<button onclick="basicCommand(this);" data-command="GetStats">GetStats</button>
|
||||
<button onclick="basicCommand(this);" data-command="GetVideoInfo">GetVideoInfo</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>Output</h2>
|
||||
<div id="outputs">
|
||||
<button onclick="basicCommand(this);" data-command="ListOutputs">ListOutputs</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>Active Sources</h2>
|
||||
<div id="active_source_list">
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>All Sources</h2>
|
||||
<div id="source_list">
|
||||
</div>
|
||||
</div>
|
||||
<div class="card hidden">
|
||||
<h2>Source debug</h2>
|
||||
<div>
|
||||
<button onclick="basicCommand(this);" data-command="GetMediaSourcesList">GetMediaSourcesList</button>
|
||||
<button onclick="basicCommand(this);" data-command="GetSourcesList">GetSourcesList</button>
|
||||
<button onclick="basicCommand(this);" data-command="GetSourceActive">GetSourceActive</button>
|
||||
<button onclick="basicCommand(this);" data-command="GetAudioActive">GetAudioActive</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="audio" class="card hidden">
|
||||
<h2>Audio</h2>
|
||||
<div>
|
||||
<button class="hidden" onclick="basicCommand(this, {source:selectedSource});" data-command="GetVolume">GetVolume</button>
|
||||
<input type='range' min="0" max="100" value="100" onchange="basicCommand(this, {source:selectedSource, volume:parseInt(this.value)/100});" data-command="SetVolume" />
|
||||
<button class="hidden" onclick="basicCommand(this, {source:selectedSource});" data-command="ToggleMute">ToggleMute</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card" id='commands'>
|
||||
<h2>Custom Commands</h2>
|
||||
<input id="newCommand" placeholder="enter a custom command" type='text' /><button id="goCreate" onclick="createCommand()">Create</button>
|
||||
<br />
|
||||
A list of possible commands <a href="https://github.com/Palakis/obs-websocket/blob/4.x-current/docs/generated/protocol.md#requests">available here:</a><br />
|
||||
</div>
|
||||
</div>
|
||||
<div style="width:100%;display:block;margin:0;padding:0;">
|
||||
<div id='OBSstats' style="width:49%;display:inline-block;vertical-align: top;">
|
||||
<div id="stat-current-profile" class='stat'></div>
|
||||
<div id="stat-current-scene" class='stat'></div>
|
||||
<div id="stat-streaming" class='stat'></div>
|
||||
<div id="stat-memory-usage" class='stat'></div>
|
||||
<div id="stat-recording" class='stat'></div>
|
||||
<div id="stat-recording-paused" class='stat'></div>
|
||||
<div id="stat-average-frame-time" class='stat'></div>
|
||||
<div id="stat-cpu-usage" class='stat'></div>
|
||||
<div id="stat-fps" class='stat'></div>
|
||||
<div id="stat-free-disk-space" class='stat'></div>
|
||||
</div>
|
||||
<div id='OBSsettings' style="width:49%;display:inline-block;vertical-align: top;">
|
||||
<div id="setting-baseHeight" class='stat'></div>
|
||||
<div id="setting-baseWidth" class='stat'></div>
|
||||
<div id="setting-outputHeight" class='stat'></div>
|
||||
<div id="setting-outputWidth" class='stat'></div>
|
||||
<div id="setting-scaleType" class='stat'></div>
|
||||
<div id="setting-fps" class='stat'></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script>
|
||||
|
||||
function basicCommand(ele, data={}){
|
||||
sendToOBS(ele.dataset.command, data);
|
||||
}
|
||||
|
||||
function createCommand(){
|
||||
var command = document.getElementById("newCommand").value;
|
||||
document.getElementById("newCommand").value = "";
|
||||
var button = document.createElement("button");
|
||||
button.innerText = command;
|
||||
button.dataset.command = command;
|
||||
button.onclick = function(){basicCommand(this);};
|
||||
document.getElementById("commands").appendChild(button);
|
||||
}
|
||||
|
||||
(function(w) {
|
||||
w.URLSearchParams = w.URLSearchParams || function(searchString) {
|
||||
var self = this;
|
||||
searchString = searchString.replace("??", "?");
|
||||
self.searchString = searchString;
|
||||
self.get = function(name) {
|
||||
var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(self.searchString);
|
||||
if (results == null) {
|
||||
return null;
|
||||
} else {
|
||||
return decodeURI(results[1]) || 0;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
})(window);
|
||||
|
||||
var urlEdited = window.location.search.replace(/\?\?/g, "?");
|
||||
urlEdited = urlEdited.replace(/\?/g, "&");
|
||||
urlEdited = urlEdited.replace(/\&/, "?");
|
||||
|
||||
if (urlEdited !== window.location.search){
|
||||
warnlog(window.location.search + " changed to " + urlEdited);
|
||||
window.history.pushState({path: urlEdited.toString()}, '', urlEdited.toString());
|
||||
}
|
||||
var urlParams = new URLSearchParams(urlEdited);
|
||||
|
||||
if (urlParams.get("password")){
|
||||
var password = urlParams.get("password");
|
||||
localStorage.setItem('password',password)
|
||||
} else if (localStorage.getItem('password')){
|
||||
password = localStorage.getItem('password');
|
||||
}
|
||||
if (urlParams.get("room")){
|
||||
var roomname = urlParams.get("room")
|
||||
localStorage.setItem('roomname',roomname)
|
||||
} else if (localStorage.getItem('roomname')){
|
||||
roomname = localStorage.getItem('roomname');
|
||||
}
|
||||
|
||||
const obs = new OBSWebSocket();
|
||||
var scenesData = {};
|
||||
var selectedSource = null;
|
||||
scenesData.scenes = [];
|
||||
|
||||
function sendToOBS(action, data){
|
||||
var msg = {};
|
||||
msg.sendToOBS = {};
|
||||
msg.sendToOBS.action = action;
|
||||
msg.sendToOBS.data = data;
|
||||
iframe.contentWindow.postMessage({"sendData":msg}, '*');
|
||||
}
|
||||
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.src = "./?room="+roomname+"&password="+password+"&push&novideo=mainOBSOutput&noaudio=mainOBSOutput&autostart&vd=0&ad=0&transparent&cleanoutput&label=CLIENT_"+Math.floor(Math.random() * 1000000);
|
||||
// iframe.style.opacity = 0;
|
||||
iframe.style.width = "160px";
|
||||
iframe.style.height = "90px";
|
||||
iframe.style.position = "fixed";
|
||||
iframe.style.top = "10px";
|
||||
iframe.style.right = "170px";
|
||||
document.body.appendChild(iframe)
|
||||
|
||||
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
|
||||
var eventer = window[eventMethod];
|
||||
var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";
|
||||
eventer(messageEvent, function (e) {
|
||||
if (e.source != iframe.contentWindow){return} // reject messages send from other iframes
|
||||
if ("dataReceived" in e.data){
|
||||
if ("sentFromOBS" in e.data.dataReceived){
|
||||
processIncoming(e.data.dataReceived.sentFromOBS);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function changeScene(scene){
|
||||
sendToOBS('SetCurrentScene', {
|
||||
'scene-name': scene
|
||||
});
|
||||
}
|
||||
|
||||
function processIncoming(data){
|
||||
if ("scenes" in data){
|
||||
scenesData = data.scenes;
|
||||
updateSceneList();
|
||||
}
|
||||
if ("callbackData" in data){
|
||||
console.log(data.callbackData);
|
||||
} else if ("callbackError" in data){
|
||||
console.log(data.callbackError);
|
||||
}
|
||||
if ("rawData" in data){
|
||||
var data = JSON.parse(data.rawData);
|
||||
console.log(data);
|
||||
if (("update-type" in data) && (data["update-type"]="Heartbeat")){
|
||||
for (var i in data){
|
||||
if (i === "stats"){
|
||||
for (var j in data[i]){
|
||||
if (document.getElementById("stat-"+j)){
|
||||
|
||||
if (typeof data[i][j] == "number"){
|
||||
data[i][j] = parseInt(data[i][j]*100)/100.0;
|
||||
}
|
||||
if (data[i][j]===true){
|
||||
document.getElementById("stat-"+j).innerHTML = j+ " : <font color='#CFC'>" + data[i][j]+"</font>";
|
||||
} else if (data[i][j] === false){
|
||||
document.getElementById("stat-"+j).innerHTML = j+ " : <font color='#FCC'>" + data[i][j]+"</font>";
|
||||
} else {
|
||||
document.getElementById("stat-"+j).innerHTML = j+ " : <font color='#DDD'>" + data[i][j]+"</font>";
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (document.getElementById("stat-"+i)){
|
||||
if (data[i]===true){
|
||||
document.getElementById("stat-"+i).innerHTML = i+ " : <font color='#CFC'>" + data[i]+"</font>";
|
||||
} else if (data[i] === false){
|
||||
document.getElementById("stat-"+i).innerHTML = i+ " : <font color='#FCC'>" + data[i]+"</font>";
|
||||
} else {
|
||||
document.getElementById("stat-"+i).innerHTML = i+ " : <font color='#DDD'>" + data[i]+"</font>";
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ("baseHeight" in data){
|
||||
for (var i in data){
|
||||
if (document.getElementById("setting-"+i)){
|
||||
if (data[i]===true){
|
||||
document.getElementById("setting-"+i).innerHTML = i+ " : <font color='#CFC'>" + data[i]+"</font>";
|
||||
} else if (data[i] === false){
|
||||
document.getElementById("setting-"+i).innerHTML = i+ " : <font color='#FCC'>" + data[i]+"</font>";
|
||||
} else {
|
||||
document.getElementById("setting-"+i).innerHTML = i+ " : <font color='#DDD'>" + data[i]+"</font>";
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ("sources" in data){
|
||||
if ("name" in data){
|
||||
document.getElementById("active_source_list").innerHTML = "";
|
||||
for (var i =0;i<data.sources.length;i++){
|
||||
var button = document.createElement("button");
|
||||
button.innerText = data.sources[i].name;
|
||||
button.dataset.name = data.sources[i].name;
|
||||
button.dataset.type = "source"
|
||||
button.onclick = function(){
|
||||
console.log("CLICKED: " + this.innerText);
|
||||
selectedSource = this.dataset.name;
|
||||
document.getElementById("audio").classList.add("hidden");
|
||||
var sources = document.querySelectorAll("[data-name");
|
||||
for (var k = 0 ; k<sources.length; k++){
|
||||
sources[k].classList.remove("pressed");
|
||||
}
|
||||
var sources = document.querySelectorAll("[data-name='"+selectedSource+"']");
|
||||
console.log(sources);
|
||||
for (var k = 0 ; k<sources.length; k++){
|
||||
document.getElementById("audio").classList.remove("hidden");
|
||||
sources[k].classList.add("pressed");
|
||||
}
|
||||
};
|
||||
document.getElementById("active_source_list").appendChild(button);
|
||||
}
|
||||
if (selectedSource){
|
||||
var sources = document.querySelectorAll("[data-name");
|
||||
document.getElementById("audio").classList.add("hidden");
|
||||
for (var k = 0 ; k<sources.length; k++){
|
||||
sources[k].classList.remove("pressed");
|
||||
}
|
||||
var sources = document.querySelectorAll("[data-name='"+selectedSource+"']");
|
||||
console.log(sources);
|
||||
for (var k = 0 ; k<sources.length; k++){
|
||||
sources[k].classList.add("pressed");
|
||||
document.getElementById("audio").classList.remove("hidden");
|
||||
}
|
||||
} else {
|
||||
document.getElementById("audio").classList.add("hidden");
|
||||
}
|
||||
} else {
|
||||
document.getElementById("source_list").innerHTML = "";
|
||||
for (var i =0;i<data.sources.length;i++){
|
||||
var button = document.createElement("button");
|
||||
button.innerText = data.sources[i].name;
|
||||
button.dataset.name = data.sources[i].name;
|
||||
button.dataset.type = "source"
|
||||
button.onclick = function(){
|
||||
console.log("CLICKED: " + this.innerText);
|
||||
selectedSource = this.dataset.name;
|
||||
document.getElementById("audio").classList.add("hidden");
|
||||
var sources = document.querySelectorAll("[data-name");
|
||||
for (var k = 0 ; k<sources.length; k++){
|
||||
sources[k].classList.remove("pressed");
|
||||
}
|
||||
var sources = document.querySelectorAll("[data-name='"+selectedSource+"']");
|
||||
console.log(sources);
|
||||
for (var k = 0 ; k<sources.length; k++){
|
||||
sources[k].classList.add("pressed");
|
||||
document.getElementById("audio").classList.remove("hidden");
|
||||
}
|
||||
};
|
||||
document.getElementById("source_list").appendChild(button);
|
||||
}
|
||||
if (selectedSource){
|
||||
var sources = document.querySelectorAll("[data-name");
|
||||
document.getElementById("audio").classList.add("hidden");
|
||||
for (var k = 0 ; k<sources.length; k++){
|
||||
sources[k].classList.remove("pressed");
|
||||
}
|
||||
var sources = document.querySelectorAll("[data-name='"+selectedSource+"']");
|
||||
console.log(sources);
|
||||
for (var k = 0 ; k<sources.length; k++){
|
||||
sources[k].classList.add("pressed");
|
||||
document.getElementById("audio").classList.remove("hidden");
|
||||
}
|
||||
} else {
|
||||
document.getElementById("audio").classList.add("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
<!-- congestion: 0 -->
|
||||
<!-- droppedFrames: 0 -->
|
||||
<!-- flags: {audio: true, encoded: true, multiTrack: true, rawValue: 31, service: true, …} -->
|
||||
<!-- height: 1080 -->
|
||||
<!-- name: "simple_stream" -->
|
||||
<!-- reconnecting: false -->
|
||||
<!-- settings: {bind_ip: 'default', dyn_bitrate: false, low_latency_mode_enabled: false, new_socket_loop_enabled: false} -->
|
||||
<!-- totalBytes: 351121 -->
|
||||
<!-- totalFrames: 30 -->
|
||||
<!-- type: "rtmp_output" -->
|
||||
<!-- width: 1920 -->
|
||||
|
||||
} else if ("outputs" in data){
|
||||
document.getElementById("outputs").innerHTML = "";
|
||||
for (var i =0;i<data.outputs.length;i++){
|
||||
var button = document.createElement("button");
|
||||
button.innerText = data.outputs[i].name;
|
||||
button.dataset.output = data.outputs[i].name;
|
||||
button.onclick = function(){
|
||||
console.log("CLICKED: " + this.innerText);
|
||||
var outputName = this.dataset.output;
|
||||
if (this.classList.contains("pressed")){
|
||||
this.classList.remove("pressed");
|
||||
sendToOBS("StopOutput",{outputName:outputName});
|
||||
} else {
|
||||
this.classList.add("pressed");
|
||||
sendToOBS("StartOutput",{outputName:outputName});
|
||||
}
|
||||
};
|
||||
document.getElementById("outputs").appendChild(button);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function updateSceneList(){
|
||||
var scenes = scenesData.scenes;
|
||||
document.getElementById("scene_list").innerHTML = "";
|
||||
scenes.forEach(scene => {
|
||||
var button = document.createElement("button");
|
||||
button.innerText = scene.name;
|
||||
button.onclick = function(){
|
||||
console.log("CLICKED");
|
||||
changeScene(this.innerText);
|
||||
}; // "speaker" also works in the same way.
|
||||
document.getElementById("scene_list").appendChild(button);
|
||||
|
||||
if (scene.name === scenesData.currentScene) {
|
||||
button.classList.add("pressed");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
388
examples/obs_ws_dock.html
Normal file
388
examples/obs_ws_dock.html
Normal file
@ -0,0 +1,388 @@
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript" src="https://vdo.ninja/beta/thirdparty/obs-websocket.min.js"></script>
|
||||
<link rel="stylesheet" href="https://vdo.ninja/beta/main.css" />
|
||||
<title>OBS Controller Demo using VDO.Ninja</title>
|
||||
<style>
|
||||
|
||||
.container {
|
||||
max-width: 80%;
|
||||
width: fit-content;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: 10px;
|
||||
box-shadow: 0 4px 8px 0 rgb(0 0 0 / 10%);
|
||||
background-color: #ddd;
|
||||
color: black;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.card>div {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
font-size: 1.5em;
|
||||
padding: 10px;
|
||||
background-color: #457b9d;
|
||||
color: white;
|
||||
border-bottom: 2px solid #3b6a87;
|
||||
}
|
||||
|
||||
small {
|
||||
font-style: italic;
|
||||
display: block;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
span.warning {
|
||||
color: rgb(212, 191, 0);
|
||||
}
|
||||
|
||||
input {
|
||||
padding: 10px;
|
||||
display: inline-block;
|
||||
flex-flow: unset;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
video {
|
||||
max-width: 640px;
|
||||
max-height: 360px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
audio {
|
||||
max-width: 640px;
|
||||
max-height: 360px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
div#processing {
|
||||
display: none;
|
||||
justify-content: center;
|
||||
place-items: center;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
background: #141926;
|
||||
flex-direction: column;
|
||||
}
|
||||
button {
|
||||
margin:5px;
|
||||
border:solid black 2px;
|
||||
}
|
||||
|
||||
body {
|
||||
color:white;
|
||||
display: inline-block;
|
||||
flex-flow: unset;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #CEF!important;
|
||||
}
|
||||
|
||||
#info{
|
||||
margin: 20px;
|
||||
max-height: 50%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#client {
|
||||
margin:10px;
|
||||
display:block;
|
||||
}
|
||||
label {
|
||||
color:white;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>OBS remote (server)</h1>
|
||||
<span id='setup'>
|
||||
<label for="address">Websocket Address</label>
|
||||
<input name="address" id="address" placeholder="address (optional)" value="localhost:4444" />
|
||||
<label for="address">Websocket Password</label>
|
||||
<input name="password" id="password" placeholder="password here (optional)" />
|
||||
<br />
|
||||
<label for="vdoroomname">Room name to use</label>
|
||||
<input name="vdoroomname" id="vdoroomname" placeholder="vdo room name to use (optional)" />
|
||||
<label for="vdopassword">Room password to use</label>
|
||||
<input name="vdopassword" id="vdopassword" placeholder="vdo password to use (optional)" />
|
||||
<br />
|
||||
<button id="address_button">Connect</button>
|
||||
<button id="address_button_2">Connect and share OBS Output</button>
|
||||
</span>
|
||||
<a id="client" target="_blank"></a>
|
||||
<div id="info"></div>
|
||||
</div>
|
||||
<script>
|
||||
|
||||
var hostname = "vdo.ninja/beta"; // all that's supported as of this moment.
|
||||
console.error("TODO: Change hostname");
|
||||
|
||||
const obs = new OBSWebSocket();
|
||||
var scenesData = {};
|
||||
scenesData.scenes = [];
|
||||
|
||||
function sendToOBS(action, data={}){
|
||||
document.getElementById("info").innerHTML = action + "<br />"+document.getElementById("info").innerHTML;
|
||||
obs.sendCallback(action, data, sendCallback)
|
||||
}
|
||||
|
||||
(function(w) {
|
||||
w.URLSearchParams = w.URLSearchParams || function(searchString) {
|
||||
var self = this;
|
||||
searchString = searchString.replace("??", "?");
|
||||
self.searchString = searchString;
|
||||
self.get = function(name) {
|
||||
var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(self.searchString);
|
||||
if (results == null) {
|
||||
return null;
|
||||
} else {
|
||||
return decodeURI(results[1]) || 0;
|
||||
}
|
||||
};
|
||||
};
|
||||
})(window);
|
||||
|
||||
var urlEdited = window.location.search.replace(/\?\?/g, "?");
|
||||
urlEdited = urlEdited.replace(/\?/g, "&");
|
||||
urlEdited = urlEdited.replace(/\&/, "?");
|
||||
|
||||
if (urlEdited !== window.location.search){
|
||||
warnlog(window.location.search + " changed to " + urlEdited);
|
||||
window.history.pushState({path: urlEdited.toString()}, '', urlEdited.toString());
|
||||
}
|
||||
var urlParams = new URLSearchParams(urlEdited);
|
||||
|
||||
var roomname = Math.floor(Math.random() * 1000000);
|
||||
var pwurl = Math.floor(Math.random() * 1000000);
|
||||
|
||||
if (urlParams.get("password")){
|
||||
pwurl = urlParams.get("password");
|
||||
localStorage.setItem('password',pwurl)
|
||||
} else if (localStorage.getItem('password')){
|
||||
pwurl = localStorage.getItem('password');
|
||||
} else {
|
||||
localStorage.setItem('password',pwurl)
|
||||
}
|
||||
|
||||
if (urlParams.get("room")){
|
||||
roomname = urlParams.get("room")
|
||||
localStorage.setItem('roomname',roomname)
|
||||
} else if (localStorage.getItem('roomname')){
|
||||
roomname = localStorage.getItem('roomname');
|
||||
} else {
|
||||
localStorage.setItem('roomname',roomname)
|
||||
}
|
||||
|
||||
document.getElementById('vdoroomname').value = roomname;
|
||||
document.getElementById('vdopassword').value = pwurl;
|
||||
|
||||
|
||||
if (localStorage.getItem('address')){
|
||||
document.getElementById('address').value = localStorage.getItem('address');
|
||||
}
|
||||
|
||||
if (localStorage.getItem('wspass')){
|
||||
document.getElementById('password').value = localStorage.getItem('wspass');
|
||||
}
|
||||
|
||||
var iframe = null;
|
||||
function createIFrame(visible=true){
|
||||
iframe = document.createElement("iframe");
|
||||
|
||||
if (visible){
|
||||
iframe.src = "https://"+hostname+"/?room="+roomname+"&push=mainOBSOutput&od=0&transparent&webcam&vd=obs&view&password="+pwurl+"&label=OBS_"+Math.floor(Math.random() * 1000000);
|
||||
iframe.style.minWidth = "720px";
|
||||
iframe.style.minHeight = "480px";
|
||||
iframe.style.maxWidth = "50%";
|
||||
iframe.style.maxHeight = "50%";
|
||||
iframe.style.display = "block";
|
||||
iframe.style.margin = "auto";
|
||||
iframe.allow = "autoplay;camera;microphone;fullscreen;picture-in-picture;";
|
||||
} else {
|
||||
iframe.src = "https://"+hostname+"/?room="+roomname+"&push&autostart&vd=0&view&ad=0&transparent&cleanoutput&password="+pwurl+"&label=OBS_"+Math.floor(Math.random() * 1000000);
|
||||
iframe.style.opacity = 0;
|
||||
iframe.style.width = 0;
|
||||
iframe.style.height = 0;
|
||||
iframe.style.position = "absolulte";
|
||||
iframe.style.top = "-100px";
|
||||
iframe.style.left = "-100px";
|
||||
}
|
||||
document.getElementById("client").parentNode.insertBefore(iframe, document.getElementById("client").nextSibling);
|
||||
|
||||
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
|
||||
var eventer = window[eventMethod];
|
||||
var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";
|
||||
eventer(messageEvent, function (e) {
|
||||
if (e.source != iframe.contentWindow){return} // reject messages send from other iframes
|
||||
console.log(e);
|
||||
if ("dataReceived" in e.data){
|
||||
if ("sendToOBS" in e.data.dataReceived){
|
||||
if ("action" in e.data.dataReceived.sendToOBS){
|
||||
if ("data" in e.data.dataReceived.sendToOBS){
|
||||
sendToOBS(e.data.dataReceived.sendToOBS.action, e.data.dataReceived.sendToOBS.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ("action" in e.data){
|
||||
if (e.data.action === "new-push-connection"){
|
||||
console.log(e.data);
|
||||
updateSceneList();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sendCallback(err, data){
|
||||
console.log("CALLBACK TRIGGERED");
|
||||
var msg = {};
|
||||
msg.sentFromOBS = {};
|
||||
msg.sentFromOBS.callbackData = data;
|
||||
msg.sentFromOBS.callbackError = err;
|
||||
try {
|
||||
iframe.contentWindow.postMessage({"sendData":msg}, '*');
|
||||
} catch(e){}
|
||||
}
|
||||
|
||||
function sendRawData(data){
|
||||
var msg = {};
|
||||
msg.sentFromOBS = {};
|
||||
msg.sentFromOBS.rawData = data;
|
||||
try {
|
||||
iframe.contentWindow.postMessage({"sendData":msg}, '*');
|
||||
} catch(e){}
|
||||
}
|
||||
|
||||
function updateSceneList(){
|
||||
var msg = {};
|
||||
msg.sentFromOBS = {};
|
||||
msg.sentFromOBS.scenes = scenesData;
|
||||
try {
|
||||
iframe.contentWindow.postMessage({"sendData":msg}, '*');
|
||||
} catch(e){}
|
||||
console.log(msg);
|
||||
obs.send("GetSourcesList");
|
||||
obs.send('GetCurrentScene');
|
||||
obs.send("GetVideoInfo");
|
||||
obs.send("ListOutputs");
|
||||
}
|
||||
|
||||
document.getElementById('address_button').addEventListener('click', e => {
|
||||
connect(e, false);
|
||||
});
|
||||
|
||||
document.getElementById('address_button_2').addEventListener('click', e => {
|
||||
connect(e, true);
|
||||
});
|
||||
|
||||
function connect(e, camera){
|
||||
const address = document.getElementById('address').value || "localhost:4444";
|
||||
const password = document.getElementById('password').value;
|
||||
|
||||
|
||||
roomname = document.getElementById('vdoroomname').value || Math.floor(Math.random() * 1000000);
|
||||
pwurl = document.getElementById('vdopassword').value || Math.floor(Math.random() * 1000000);
|
||||
localStorage.setItem('roomname',roomname)
|
||||
localStorage.setItem('password',pwurl)
|
||||
|
||||
createIFrame(camera); // connects to VDO.Ninja's IFRAME API
|
||||
|
||||
localStorage.setItem('address',address);
|
||||
if (password){
|
||||
localStorage.setItem('wspass',password);
|
||||
var ret = obs.connect({
|
||||
address: address,
|
||||
password: password
|
||||
});
|
||||
} else {
|
||||
var ret = obs.connect({
|
||||
address: address
|
||||
});
|
||||
}
|
||||
|
||||
ret.then(() => {
|
||||
console.log(`Success!`);
|
||||
return obs.send('GetSceneList');
|
||||
}).then(data => {
|
||||
document.getElementById("setup").style.display = "none";
|
||||
scenesData = data;
|
||||
updateSceneList();
|
||||
var clientLink = "https://"+hostname+"/obs_client.html?room="+roomname+"&password="+pwurl;
|
||||
document.getElementById("client").href = clientLink;
|
||||
document.getElementById("client").innerHTML = "<b><font style='color:#70c4ff;'>client link:</font></b> "+clientLink;
|
||||
document.getElementById("info").innerHTML = "<br /><p style='color:#bdffbd;'>Connection to OBS websockets opened.</p>" + document.getElementById("info").innerHTML;
|
||||
try {
|
||||
obs._socket.onmessage2 = obs._socket.onmessage;
|
||||
obs._socket.onmessage = function(data){
|
||||
obs._socket.onmessage2(data);
|
||||
if (data.type && data.data){
|
||||
if (data.type == "message"){
|
||||
sendRawData(data.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(e){console.error(e);}
|
||||
|
||||
}).catch(err => { // Promise convention dicates you have a catch on every chain.
|
||||
console.log(err);
|
||||
document.getElementById("info").innerHTML = "<br />Error trying to connect." + document.getElementById("info").innerHTML;
|
||||
if ("error" in err){
|
||||
document.getElementById("info").innerHTML = "<br />"+err.error + document.getElementById("info").innerHTML;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// We use the source visibility one and filter visibility web socket commands quite often in shows.
|
||||
|
||||
obs.on('SwitchScenes', data => {
|
||||
console.log(`New Active Scene: ${data.sceneName}`);
|
||||
scenesData.currentScene = data.sceneName
|
||||
updateSceneList();
|
||||
});
|
||||
obs.on('ConnectionOpened', (data) => function(){
|
||||
document.getElementById("setup").style.display = "none";
|
||||
document.getElementById("info").innerHTML = "<br /><p style='color:#bdffbd;'>Connection to OBS websockets opened.</p>" + document.getElementById("info").innerHTML;
|
||||
});
|
||||
obs.on('ConnectionClosed', (data) => function(){
|
||||
document.getElementById("setup").style.display = "unset";
|
||||
document.getElementById("info").innerHTML = "<br />Connection to OBS websockets closed" + document.getElementById("info").innerHTML;
|
||||
});
|
||||
obs.on('AuthenticationSuccess', (data) => function(){
|
||||
document.getElementById("setup").style.display = "none";
|
||||
document.getElementById("info").innerHTML = "<br />OBS websockets authenticated" + document.getElementById("info").innerHTML;
|
||||
});
|
||||
obs.on('AuthenticationFailure', (data) => function(){
|
||||
document.getElementById("setup").style.display = "unset";
|
||||
document.getElementById("info").innerHTML = "<br />Authentication to OBS websockets failed" + document.getElementById("info").innerHTML;
|
||||
});
|
||||
obs.on('ScenesChanged', (data) => function(){
|
||||
scenesData = data;
|
||||
updateSceneList()
|
||||
});
|
||||
// You must add this handler to avoid uncaught exceptions.
|
||||
obs.on('error', err => {
|
||||
document.getElementById("info").innerHTML = "<br />OBS websockets error" + document.getElementById("info").innerHTML;
|
||||
console.error('socket error:', err);
|
||||
if ("error" in err){
|
||||
document.getElementById("info").innerHTML = "<br />"+err.error + document.getElementById("info").innerHTML;
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
69
examples/p2p.html
Normal file
69
examples/p2p.html
Normal file
@ -0,0 +1,69 @@
|
||||
<html>
|
||||
<body>
|
||||
<div id="results" style="overflow:scroll;max-height:300px;">
|
||||
starting...
|
||||
</div>
|
||||
<script> // https://jsfiddle.net/steveseguin/0t3ayvk8/31/
|
||||
var connectionID = Math.random()*100000001;
|
||||
function RecvDataWindow(){
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.src = "https://vdo.ninja/beta/?view="+connectionID+"&cleanoutput";
|
||||
iframe.style.width = "0px";
|
||||
iframe.style.height = "0px";
|
||||
iframe.style.position = "fixed";
|
||||
iframe.style.left = "-100px";
|
||||
iframe.style.top = "-100px";
|
||||
iframe.id = "frame1"
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
|
||||
var eventer = window[eventMethod];
|
||||
var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";
|
||||
|
||||
eventer(messageEvent, function (e) {
|
||||
if (e.source != iframe.contentWindow){return} // reject messages send from other iframes
|
||||
if ("dataReceived" in e.data){ // raw data
|
||||
document.getElementById("results").innerHTML += e.data.dataReceived+"<br />";
|
||||
console.log(e.data);
|
||||
try {
|
||||
iframe.contentWindow.postMessage({"sendData":"pong!!", "UUID":e.data.UUID}, '*');
|
||||
} catch(E){}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function SendDataWindow(){
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.src = "https://vdo.ninja/beta/?push="+connectionID+"&vd=0&ad=0&autostart&cleanoutput";
|
||||
iframe.style.width = "0px";
|
||||
iframe.style.height = "0px";
|
||||
iframe.style.position = "fixed";
|
||||
iframe.style.left = "-100px";
|
||||
iframe.style.top = "-100px";
|
||||
iframe.id = "frame2";
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
setInterval(function(){
|
||||
try {
|
||||
console.log(".");
|
||||
document.getElementById("frame2").contentWindow.postMessage({"sendData":"ping!!"}, '*');
|
||||
} catch(E){}
|
||||
}, 1000);
|
||||
|
||||
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
|
||||
var eventer = window[eventMethod];
|
||||
var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";
|
||||
|
||||
eventer(messageEvent, function (e) {
|
||||
if (e.source != iframe.contentWindow){return} // reject messages send from other iframes
|
||||
if ("dataReceived" in e.data){ // raw data
|
||||
console.log(e.data);
|
||||
document.getElementById("results").innerHTML += e.data.dataReceived+"<br />";
|
||||
}
|
||||
});
|
||||
}
|
||||
SendDataWindow();
|
||||
RecvDataWindow();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
280
examples/sensors.html
Normal file
280
examples/sensors.html
Normal file
@ -0,0 +1,280 @@
|
||||
<html>
|
||||
<head><title>Sensor and video stream access example</title>
|
||||
<style>
|
||||
body{
|
||||
padding:0;
|
||||
margin:0;
|
||||
background-color: rgb(222,242,253);
|
||||
}
|
||||
iframe {
|
||||
border:0;
|
||||
margin:0;
|
||||
padding:0;
|
||||
display:block;
|
||||
margin:10px;
|
||||
width:640px;
|
||||
height:320px;
|
||||
}
|
||||
#viewlink {
|
||||
width:400px;
|
||||
}
|
||||
#container {
|
||||
display:block;
|
||||
padding:0px;
|
||||
}
|
||||
input{
|
||||
padding:5px;
|
||||
margin:5px;
|
||||
}
|
||||
button{
|
||||
padding:5px;
|
||||
margin:5px;
|
||||
}
|
||||
canvas{
|
||||
width:100%;
|
||||
display:block;
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
<canvas id="canvas" style="display:none;max-height:70vh;max-width:calc(70vh*1.777);width:100%;height:100%;" width="1920" height="1080" ></canvas>
|
||||
<input placeholder="Enter a VDO.Ninja View URL here" id="viewlink" style="display:block;" onchange="loadIframe();"/>
|
||||
<label for="hori">FOA-Horizontal</label>
|
||||
<input type="range" id="hori" name="hori" value="63" title="63" min="40" max="80" title="67" onchange="updateHor(this);">
|
||||
<label for="vert">FOA-Vertical</label>
|
||||
<input type="range" id="vert" name="vert" value="50" title="50" min="30" max="70" onchange="updateVer(this);">
|
||||
<label for="draw">Draw Delay</label>
|
||||
<input type="range" id="draw" name="draw" value="110" title="110" min="0" max="500" style="width:500px" onchange="updateDelay(this);"><br /><br />
|
||||
Add &sensor to the push link to send data; see: <a target="_blank" href="https://docs.vdo.ninja/source-settings/sensor">https://docs.vdo.ninja/source-settings/sensor</a>
|
||||
<div id="container">
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// https://www.camerafv5.com/devices/manufacturers/google/pixel_4a_sunfish_1/ ; pixel 4a specs
|
||||
var horFOA = 49.6;
|
||||
var verFOA = 63.3;
|
||||
var drawDelay = 110;
|
||||
function updateHor(hor){
|
||||
horFOA = parseInt(hor.value);
|
||||
hor.title = horFOA;
|
||||
}
|
||||
function updateVer(ver){
|
||||
verFOA = parseInt(ver.value);
|
||||
ver.title = verFOA;
|
||||
}
|
||||
function updateDelay(time){
|
||||
drawDelay = parseInt(time.value);
|
||||
time.title = drawDelay;
|
||||
}
|
||||
function loadIframe(url=false){ // this is pretty important if you want to avoid camera permission popup problems. You can also call it automatically via: <body onload=>loadIframe();"> , but don't call it before the page loads.
|
||||
|
||||
var canvas = document.getElementById("canvas");
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.imageSmoothingEnabled= false;
|
||||
var iframe = document.createElement("iframe");
|
||||
var iframeContainer = document.createElement("div");
|
||||
|
||||
if (url){
|
||||
var iframesrc = url;
|
||||
} else {
|
||||
var iframesrc = document.getElementById("viewlink").value;
|
||||
}
|
||||
console.log(iframesrc);
|
||||
document.getElementById("viewlink").parentNode.removeChild(document.getElementById("viewlink"));
|
||||
document.getElementById("canvas").style.display="block";
|
||||
iframe.allow = "autoplay;camera;microphone;fullscreen;picture-in-picture;";
|
||||
|
||||
if (iframesrc==""){
|
||||
iframesrc="./";
|
||||
}
|
||||
|
||||
iframe.src = iframesrc;
|
||||
|
||||
iframeContainer.appendChild(iframe);
|
||||
|
||||
document.getElementById("container").appendChild(iframeContainer);
|
||||
|
||||
var videos = iframe.contentWindow.document.querySelectorAll("video");
|
||||
var sensors = {};
|
||||
|
||||
function drawFrame(vid){
|
||||
try {
|
||||
if (sensors.mag){ // androids may not support this.
|
||||
var angle = 1.5 * Math.PI - Math.atan2(sensors.mag.y,sensors.mag.x);
|
||||
var startPixel = (angle / ( 2 * Math.PI)) * 1920;
|
||||
var endPixel = (verFOA/360) * 1920 + startPixel;
|
||||
} else if (sensors.ori){
|
||||
var angle = sensors.ori.a;
|
||||
var frontToBack = sensors.ori.b;
|
||||
var leftToRight = sensors.ori.g;
|
||||
|
||||
var startPixel = Math.floor((angle / 360) * 1920);
|
||||
var width = Math.floor((verFOA/360) * 1920);
|
||||
var height = vid.videoHeight*(width/vid.videoWidth);
|
||||
|
||||
var h_offset = Math.floor(((frontToBack+(verFOA/2))/180 * 1080)-540);
|
||||
var w_offset = Math.floor((leftToRight+horFOA)/180 * 1920);
|
||||
}
|
||||
|
||||
setTimeout(function(a1,a2,a3,a4,a5){
|
||||
|
||||
ctx.filter = 'blur(4px)';
|
||||
ctx.drawImage(a1,a2,a3,a4,a5);
|
||||
|
||||
ctx.filter = "none";
|
||||
ctx.drawImage(a1,a2,a3,a4,a5);
|
||||
|
||||
}, drawDelay, vid, startPixel-w_offset, h_offset, width, height);
|
||||
} catch(e){console.error(e);}
|
||||
};
|
||||
|
||||
setInterval(function(){
|
||||
if (videos.length){
|
||||
if ("UUID" in sensors){
|
||||
if (videos[0].id !== "videosource_"+sensors.UUID){
|
||||
videos = iframe.contentWindow.document.querySelectorAll("video#videosource_"+sensors.UUID);
|
||||
}
|
||||
if (videos.length){
|
||||
drawFrame(videos[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
},100);
|
||||
|
||||
|
||||
//////////// LISTEN FOR EVENTS
|
||||
|
||||
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
|
||||
var eventer = window[eventMethod];
|
||||
var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";
|
||||
|
||||
|
||||
/// If you have a routing system setup, you could have just one global listener for all iframes instead.
|
||||
|
||||
eventer(messageEvent, function (e) {
|
||||
if (e.source != iframe.contentWindow){return} // reject messages send from other iframes
|
||||
|
||||
if ("stats" in e.data){
|
||||
var outputWindow = document.createElement("div");
|
||||
//console.log(e.data.stats);
|
||||
|
||||
|
||||
var out = "<br />total_inbound_connections:"+e.data.stats.total_inbound_connections;
|
||||
out += "<br />total_outbound_connections:"+e.data.stats.total_outbound_connections;
|
||||
|
||||
for (var streamID in e.data.stats.inbound_stats){
|
||||
out += "<br /><br /><b>streamID:</b> "+streamID+"<br />";
|
||||
out += printValues(e.data.stats.inbound_stats[streamID]);
|
||||
}
|
||||
|
||||
outputWindow.innerHTML = out;
|
||||
iframeContainer.appendChild(outputWindow);
|
||||
}
|
||||
|
||||
if ("gotChat" in e.data){
|
||||
var outputWindow = document.createElement("div");
|
||||
outputWindow.innerHTML = e.data.gotChat.msg;
|
||||
outputWindow.style.border="1px dotted black";
|
||||
iframeContainer.appendChild(outputWindow);
|
||||
}
|
||||
|
||||
if ("action" in e.data){
|
||||
var outputWindow = document.createElement("div");
|
||||
outputWindow.innerHTML = "child-page-action: "+e.data.action+"<br />";
|
||||
outputWindow.style.border="1px dotted black";
|
||||
iframeContainer.appendChild(outputWindow);
|
||||
console.log(e.data.action);
|
||||
|
||||
if (e.data.action == "new-view-connection"){
|
||||
setTimeout(function(){
|
||||
videos = iframe.contentWindow.document.querySelectorAll("video");
|
||||
console.log(videos);
|
||||
},500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ("streamIDs" in e.data){
|
||||
var outputWindow = document.createElement("div");
|
||||
outputWindow.innerHTML = "child-page-action: streamIDs<br />";
|
||||
for (var key in e.data.streamIDs) {
|
||||
outputWindow.innerHTML += "streamID: " + key + ", label:"+e.data.streamIDs[key] + "\n";
|
||||
}
|
||||
outputWindow.style.border="1px dotted black";
|
||||
iframeContainer.appendChild(outputWindow);
|
||||
}
|
||||
|
||||
if ("loudness" in e.data){
|
||||
//console.log(e.data);
|
||||
if (document.getElementById("loudness")){
|
||||
outputWindow = document.getElementById("loudness");
|
||||
} else {
|
||||
var outputWindow = document.createElement("div");
|
||||
outputWindow.style.border="1px dotted black";
|
||||
iframeContainer.appendChild(outputWindow);
|
||||
outputWindow.id = "loudness";
|
||||
}
|
||||
outputWindow.innerHTML = "child-page-action: loudness<br />";
|
||||
for (var key in e.data.loudness) {
|
||||
outputWindow.innerHTML += key + " Loudness: " + e.data.loudness[key] + "\n";
|
||||
}
|
||||
outputWindow.style.border="1px black";
|
||||
|
||||
}
|
||||
|
||||
if ("sensors" in e.data){
|
||||
sensors = e.data.sensors;
|
||||
if (document.getElementById("sensors")){
|
||||
outputWindow = document.getElementById("sensors");
|
||||
} else {
|
||||
var outputWindow = document.createElement("div");
|
||||
outputWindow.style.border="1px dotted black";
|
||||
iframeContainer.appendChild(outputWindow);
|
||||
outputWindow.id = "sensors";
|
||||
console.log(sensors);
|
||||
}
|
||||
outputWindow.innerHTML = "child-page-action: sensors<br /><br />";
|
||||
|
||||
for (var key in e.data.sensors.lin) {
|
||||
outputWindow.innerHTML += key + " linear: " + e.data.sensors.lin[key] + "<br />";
|
||||
}
|
||||
for (var key in e.data.sensors.acc) {
|
||||
outputWindow.innerHTML += key + " acceleration: " + e.data.sensors.acc[key] + "<br />";
|
||||
}
|
||||
for (var key in e.data.sensors.gyro) {
|
||||
outputWindow.innerHTML += key + " gyro: " + e.data.sensors.gyro[key] + "<br />";
|
||||
}
|
||||
for (var key in e.data.sensors.mag) {
|
||||
outputWindow.innerHTML += key + " magnet: " + e.data.sensors.mag[key] + "<br />";
|
||||
}
|
||||
for (var key in e.data.sensors.ori) {
|
||||
outputWindow.innerHTML += key + " orientation: " + e.data.sensors.ori[key] + "<br />";
|
||||
}
|
||||
outputWindow.style.border="1px black";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function printValues( obj) {
|
||||
var out = "";
|
||||
for (var key in obj) {
|
||||
if (typeof obj[key] === "object") {
|
||||
out +="<br />";
|
||||
out += printValues(obj[key]);
|
||||
} else {
|
||||
out +="<b>"+key+"</b>: "+obj[key]+"<br />";
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
111
examples/twitch.html
Normal file
111
examples/twitch.html
Normal file
@ -0,0 +1,111 @@
|
||||
<html>
|
||||
<head><title>Twitch + Video</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=0.7, maximum-scale=1.0, user-scalable=yes" />
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
|
||||
<style>
|
||||
body{
|
||||
padding:0;
|
||||
margin:0;
|
||||
background-color:#003;
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
|
||||
iframe {
|
||||
width:100%;
|
||||
height:100%;
|
||||
border:0;
|
||||
margin:0;
|
||||
padding:0;
|
||||
position:absolute;
|
||||
display:block;
|
||||
}
|
||||
|
||||
|
||||
input{
|
||||
padding:10px;
|
||||
width:80%;
|
||||
font-size:1.2em;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
|
||||
@media screen and (orientation:portrait) {
|
||||
#container2{
|
||||
width:100%;height:100%;display:none;
|
||||
}
|
||||
#container1{
|
||||
width: 50vw;height: 50vh; display:none; float:left; position: fixed; top: 0; right: 0%;
|
||||
}
|
||||
iframe{
|
||||
width:100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (orientation:landscape) {
|
||||
#container2{
|
||||
width:60vw;height:100%;display:none;
|
||||
z-index:5;
|
||||
}
|
||||
#container1{
|
||||
width: 50vw;height: 80vh; display:none; float:left; position: fixed; top: 0; right: -10vw;
|
||||
}
|
||||
iframe{
|
||||
max-width:60vw;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
|
||||
<div id="container2"></div>
|
||||
<div id="container1" ></div>
|
||||
<div id="clean">
|
||||
<input placeholder="Enter a VDON stream ID" id="viewlink" type="text" />
|
||||
<input placeholder="Enter the Twitch channel name" id="twitch" type="text" />
|
||||
<button onclick="loadIframes()" style="display:block;padding:10px;margin:10px;">START</button>
|
||||
</div>
|
||||
<script>
|
||||
|
||||
window.addEventListener("orientationchange", function() {
|
||||
// Announce the new orientation number
|
||||
// alert(window.orientation);
|
||||
}, false);
|
||||
|
||||
function loadIframes(url=false){
|
||||
|
||||
var roomname = document.getElementById("viewlink").value;
|
||||
var twitch = document.getElementById("twitch").value;
|
||||
|
||||
document.getElementById("clean").parentNode.removeChild(document.getElementById("clean"));
|
||||
document.getElementById("container1").style.display="inline-block";
|
||||
document.getElementById("container2").style.display="inline-block";
|
||||
|
||||
var path = window.location.host+window.location.pathname.split("/").slice(0,-1).join("/");
|
||||
|
||||
var room1 = "https://"+path+"/?push="+roomname+"&webcam&autostart&vd=front&ad=1&transparent&noheader";
|
||||
var room2 = "https://www.twitch.tv/embed/"+twitch+"/chat?parent="+location.hostname;
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.allow = "autoplay;camera;microphone;fullscreen;picture-in-picture;";
|
||||
iframe.src = room1;
|
||||
var iframeContainer = document.createElement("div");
|
||||
iframeContainer.appendChild(iframe);
|
||||
document.getElementById("container1").appendChild(iframeContainer);
|
||||
|
||||
setTimeout(function(){
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.allow = "autoplay;camera;microphone;fullscreen;picture-in-picture;";
|
||||
iframe.src = room2;
|
||||
var iframeContainer = document.createElement("div");
|
||||
iframeContainer.appendChild(iframe);
|
||||
document.getElementById("container2").appendChild(iframeContainer);
|
||||
},3000);
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
23
iframe.html
23
iframe.html
@ -38,9 +38,7 @@ function loadIframe(){ // this is pretty important if you want to avoid camera
|
||||
var iframe = document.createElement("iframe");
|
||||
var iframeContainer = document.createElement("div");
|
||||
var iframesrc = document.getElementById("viewlink").value;
|
||||
iframe.allow="autoplay;camera;microphone";
|
||||
iframe.allowtransparency="true";
|
||||
iframe.allowfullscreen ="true";
|
||||
iframe.allow = "autoplay;camera;microphone;fullscreen;picture-in-picture;";
|
||||
|
||||
if (iframesrc==""){
|
||||
iframesrc="./";
|
||||
@ -163,8 +161,21 @@ function loadIframe(){ // this is pretty important if you want to avoid camera
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Request Stats";
|
||||
button.onclick = function(){iframe.contentWindow.postMessage({"getStats":true}, '*');};
|
||||
button.innerHTML = "Pan Left";
|
||||
button.title = "Requires &panning to be added to the view link";
|
||||
button.onclick = function(){iframe.contentWindow.postMessage({"panning":0}, '*');};
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Pan right";
|
||||
button.title = "Requires &panning to be added to the view link";
|
||||
button.onclick = function(){iframe.contentWindow.postMessage({"panning":180}, '*');};
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Pan Center";
|
||||
button.title = "Requires &panning to be added to the view link";
|
||||
button.onclick = function(){iframe.contentWindow.postMessage({"panning":90}, '*');};
|
||||
iframeContainer.appendChild(button);
|
||||
|
||||
var button = document.createElement("button");
|
||||
@ -394,7 +405,7 @@ function printValues( obj) {
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<input placeholder="Enter an OBS.Ninja View URL here" id="viewlink" />
|
||||
<input placeholder="Enter an VDO.Ninja View URL here" id="viewlink" />
|
||||
<button onclick="loadIframe();">ADD</button>
|
||||
<input type="checkbox" id="clean" checked>Clean Output
|
||||
<input type="checkbox" id="transparent" checked>Transparent
|
||||
|
||||
148
index.html
148
index.html
@ -55,7 +55,7 @@
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="./lineawesome/css/line-awesome.min.css" />
|
||||
<link rel="stylesheet" href="./main.css?ver=70" />
|
||||
<link rel="stylesheet" href="./main.css?ver=72" />
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/adapter.min.js"></script>
|
||||
<style id="lightbox-animations" type="text/css"></style>
|
||||
</head>
|
||||
@ -67,8 +67,8 @@
|
||||
<span itemprop="thumbnail" itemscope itemtype="http://schema.org/ImageObject">
|
||||
<link itemprop="url" href="./media/obsNinja_logo_full.png" />
|
||||
</span>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/CodecsHandler.js?ver=33"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=215"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/CodecsHandler.js?ver=34"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=291"></script>
|
||||
<input id="zoomSlider" type="range" style="display: none;" />
|
||||
<div id="header">
|
||||
|
||||
@ -89,12 +89,11 @@
|
||||
<a
|
||||
id="reshare"
|
||||
data-drag="1"
|
||||
onclick="popupMessage(event);copyFunction(this)"
|
||||
onclick="copyFunction(this, event)"
|
||||
class="task grabLinks"
|
||||
onmousedown="copyFunction(this)"
|
||||
style="font-weight: bold; color: #afa !important; cursor: grab; background-color: #0000; font-size: 115%; min-width: 335px; max-width: 800px;"
|
||||
></a>
|
||||
<i class="las la-paperclip" style="color: #DDD;" onclick="popupMessage(event);copyFunction(document.getElementById('reshare'));" onmouseover="this.style.cursor='pointer'"></i>
|
||||
<i class="las la-paperclip" style="color: #DDD;" onclick="copyFunction(document.getElementById('reshare'), event);" onmouseover="this.style.cursor='pointer'"></i>
|
||||
</div>
|
||||
<div id="head4" style="display: inline-block;" class="advanced">
|
||||
<font style="font-size: 68%; color: white;">
|
||||
@ -143,7 +142,7 @@
|
||||
<div id="screenshare2button" onmousedown="event.preventDefault(); event.stopPropagation();" title="Create a Secondary Stream" alt="Create a Secondary Stream" onclick="createIframePopup()" tabindex="20" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="float advanced" style="cursor: pointer;">
|
||||
<i id="screenshare2toggle" onmousedown="event.preventDefault(); event.stopPropagation();" class="toggleSize las la-tv my-float"></i>
|
||||
</div>
|
||||
<div id="websitesharebutton" onmousedown="event.preventDefault(); event.stopPropagation();" title="Share a website as an embedded iFRAME" alt="Share a website as an embedded iFRAME" onclick="shareWebsite()" tabindex="21" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="float advanced" style="cursor: pointer;">
|
||||
<div id="websitesharebutton" onmousedown="event.preventDefault(); event.stopPropagation();" title="Share a website as an embedded iFRAME" alt="Share a website as an embedded iFRAME" onclick="shareWebsite(false, event)" tabindex="21" role="button" aria-pressed="false" onkeyup="enterPressedClick(event,this);" class="float advanced" style="cursor: pointer;">
|
||||
<i id="websitesharetoggle" onmousedown="event.preventDefault(); event.stopPropagation();" class="toggleSize las la-window-maximize my-float"></i>
|
||||
</div>
|
||||
|
||||
@ -317,10 +316,15 @@
|
||||
<button onclick="this.disabled=true;setTimeout(function(){requestBasicPermissions();},20);" id="getPermissions" style="display:none;" data-ready="false" >
|
||||
<span data-translate="ask-for-permissions">Allow Access to Camera/Microphone</span>
|
||||
</button>
|
||||
<button onclick="publishWebcam(this)" title="start streaming" tabindex="15" id="gowebcam" class="gowebcam" alt="Start Streaming" disabled data-audioready="false" data-ready="false" >
|
||||
<span data-translate="waiting-for-camera">Waiting for Camera to Load</span>
|
||||
</button>
|
||||
<br />
|
||||
<span style="display:block;">
|
||||
<button onclick="publishWebcam(this)" title="start streaming" tabindex="15" id="gowebcam" class="gowebcam" alt="Start Streaming" disabled data-audioready="false" data-ready="false" >
|
||||
<span data-translate="waiting-for-camera">Waiting for Camera to Load</span>
|
||||
</button>
|
||||
</span>
|
||||
<div id="consentWarning" class="startupWarning advanced">
|
||||
<i class="las la-exclamation-circle"></i>
|
||||
<p><span data-translate="privacy-disabled">Privacy warning: The director will be able to remotely change your camera and microphone.</span></p>
|
||||
</div>
|
||||
<span id="guestTips" style="display:none">
|
||||
<p>For the best possible experience, make sure</p>
|
||||
<span><i class="las la-plug"></i><span>Your device is powered</span></span>
|
||||
@ -392,7 +396,7 @@
|
||||
<option value="4" data-translate="digital-greenscreen">Digital greenscreen</option>
|
||||
<option value="5" data-translate="virtual-background">Virtual background</option>
|
||||
</select>
|
||||
<span data-warnSimdNotice="true" style='display:none; font-size: 140%; margin-left:10px; vertical-align: middle; cursor:pointer' title="Improve performance and quality with this tip" onclick="warnUser(`For improved performance, use Chrome v87 or newer with SIMD support enabled.<br />Enable SIMD here: <a href='chrome://flags/#enable-webassembly-simd' target='_blank' onclick='popupMessage(event);copyFunction(this)' >chrome://flags/#enable-webassembly-simd</a>`);">
|
||||
<span data-warnSimdNotice="true" style='display:none; font-size: 140%; margin-left:10px; vertical-align: middle; cursor:pointer' title="Improve performance and quality with this tip" onclick="warnUser(`For improved performance, use Chrome v87 or newer with SIMD support enabled.<br />Enable SIMD here: <a href='chrome://flags/#enable-webassembly-simd' target='_blank' onclick='copyFunction(this,event)' >chrome://flags/#enable-webassembly-simd</a>`);">
|
||||
<i class="las la-info-circle"></i>
|
||||
</span>
|
||||
<span data-effectsNotice="true" style='display:none; font-size: 140%; margin-left:10px; vertical-align: middle; cursor:pointer' title="Improve performance and quality with this tip" onclick="warnUser('Use a Chromium Based Browser');">
|
||||
@ -429,12 +433,14 @@
|
||||
margin: 0 6px;"/>
|
||||
</span>
|
||||
|
||||
<div id="SafariWarning">
|
||||
<div id="SafariWarning" class="startupWarning advanced">
|
||||
<i class="las la-exclamation-circle"></i>
|
||||
<p><span data-translate="use-chrome-instead">Consider using a Chromium-based browser instead.<br />
|
||||
Safari is more prone to having audio issues</span></p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<div class="outer close">
|
||||
<div class="inner">
|
||||
@ -461,7 +467,7 @@
|
||||
<i class="las la-cog" style="font-size: 170%; vertical-align: middle;" aria-hidden="true"></i>
|
||||
</span>
|
||||
<center>
|
||||
<span id="videoSettings2" style="margin: auto auto; display: none; background-color: white; vertical-aligh: middle; border: 3px solid #ccc; max-width: 500px; padding: 10px 10px 5px 10px; margin: 10px 0 5px 0;">
|
||||
<span id="videoSettings2" style="margin: auto auto; display: none; background-color: white; vertical-aligh: middle; border: 3px solid #ccc; max-width: 500px; padding: 10px 10px 5px 10px; margin: 0px 0px 10px;">
|
||||
<form id="webcamquality2">
|
||||
<input type="radio" id="fullhd2" name="resolution2" value="0" />
|
||||
<label for="fullhd">
|
||||
@ -480,8 +486,11 @@
|
||||
<div id="webcamstats2" style="padding: 5px 0 0 0;"></div>
|
||||
</form>
|
||||
</span>
|
||||
<br />
|
||||
</center>
|
||||
<div id="consentWarning2" class="startupWarning advanced">
|
||||
<i class="las la-exclamation-circle"></i>
|
||||
<p><span data-translate="privacy-disabled">Privacy warning: The director will be able to remotely access your camera and microphone if you continue.</span></p>
|
||||
</div>
|
||||
<p id="audioScreenShare1">
|
||||
<i class="las la-microphone-alt"></i>
|
||||
<span data-translate="audio-sources">Audio Sources</span>
|
||||
@ -495,12 +504,10 @@
|
||||
</select>
|
||||
</p>
|
||||
<br />
|
||||
<span id="headphonesDiv2" style="background-color: #f3f3f3; min-width: 270px; display: none; padding: 5px 10px; border: 1px solid #ccc; vertical-align: middle;">
|
||||
<span id="headphonesDiv2">
|
||||
<i class="las la-headphones"></i>
|
||||
|
||||
<span data-translate="select-output-source"> Audio Output Destination: <button onclick="playtone(true)" class="white" style="padding:3px 5px 2px 5px; margin:0; margin-left:15px; position: relative; " type="button">Test</button></span>
|
||||
<br />
|
||||
<select id="outputSourceScreenshare" style="background-color: #FFF; padding:10px 5px; min-width: 268px; display:inline-block; vertical-align: middle;" onclick="requestOutputAudioStream();">
|
||||
<select id="outputSourceScreenshare" style="background-color: #FFF; margin-top:5px; padding:10px 5px; width:100%; display:inline-block; vertical-align: middle;" onclick="requestOutputAudioStream();">
|
||||
<option value="default">
|
||||
Default Device
|
||||
</option>
|
||||
@ -740,7 +747,7 @@
|
||||
👋 👀 Welcome to VDO Ninja! We've rebranded! 📼 Nothing else is changing and we're staying 100% free.
|
||||
</h4>
|
||||
<br />
|
||||
🌻 Site Updated on July XXth. The <a href="https://docs.vdo.ninja/release-notes/v18_3">v18.3 release notes are here</a>. If new issues occur, the previous version can also be <a href="https://vdo.ninja/v18/">found here</a>.
|
||||
🌻 Site Updated on August 29th. The <a href="https://docs.vdo.ninja/release-notes/v19">v19.0 release notes are coming soon</a>. If new issues occur, the previous version can also be <a href="https://vdo.ninja/v183/">found here</a>.
|
||||
|
||||
<br />
|
||||
<br />
|
||||
@ -811,7 +818,7 @@
|
||||
<div class='directorBlock'>
|
||||
<h2 title="Invite a guest or camera source to publish into the group room" style="margin-top: 5px;"><i class="las la-video director-link-icons" ></i> INVITE A GUEST</h2>
|
||||
<span style="margin:5px; line-height: 1.6;" data-translate='invite-users-to-join'>Guests can use the link to join the group room</span>
|
||||
<a onclick='popupMessage(event);copyFunction(this)' id="director_block_1" onmousedown='copyFunction(this)' class='task grabLinks' style='cursor:copy;background-color: #0003;'></a>
|
||||
<a onclick='copyFunction(this,event)' id="director_block_1" class='task grabLinks' style='cursor:copy;background-color: #0003;'></a>
|
||||
<span style="display:block;">
|
||||
<span style="bottom: 0; margin: 0 0 0 10px; top: 22px; position: relative;">
|
||||
<label class="switch" title="If disabled, the invited guest will not be able to see or hear anyone in the room.">
|
||||
@ -820,7 +827,7 @@
|
||||
</label>
|
||||
<span data-translate="guests-hear-others">Guests hear others</span>
|
||||
</span>
|
||||
<button class='pull-right grey' style='font-size:1.15em' onclick='popupMessage(event);copyFunction(getById("director_block_1"))'><i class='las la-copy'></i>Copy link</button>
|
||||
<button class='pull-right grey' style='font-size:1.15em' onclick='copyFunction(getById("director_block_1"),event)'><i class='las la-copy'></i>Copy link</button>
|
||||
<button class='pull-right grey' style='font-size:1.15em' id="showCustomizerButton1" onclick='showCustomizer(1,this)'><i class='las la-tools'></i>Customize</button>
|
||||
<span>
|
||||
</div>
|
||||
@ -830,7 +837,7 @@
|
||||
<div class='directorBlock' style="background-color: var(--green-accent);" >
|
||||
<h2 title="Use this link in the OBS Browser Source to capture the video or audio" style="margin-left: 1px;margin-top: 5px;"><i class="las la-th-large director-link-icons" style="margin-right: 6px;" ></i> <span data-translate="capture-a-group-scene">CAPTURE A GROUP SCENE</span></h2>
|
||||
<span style="margin:5px; line-height: 1.6;" data-translate='this-is-obs-browser-source-link'>Use in OBS or other studio software to capture the group video mix</span>
|
||||
<a onclick='popupMessage(event);copyFunction(this)' id="director_block_3" onmousedown='copyFunction(this)' class='task grabLinks' style='cursor:copy;background-color: #0003;'></a>
|
||||
<a onclick='copyFunction(this,event)' id="director_block_3" class='task grabLinks' style='cursor:copy;background-color: #0003;'></a>
|
||||
<span style="display:block;">
|
||||
<span style="bottom: 0; margin: 0 0 0 10px; top: 22px; position: relative;">
|
||||
<label class="switch" title="If disabled, you must manually add a video to a scene for it to appear.">
|
||||
@ -839,7 +846,7 @@
|
||||
</label>
|
||||
<span data-translate="auto-add-guests">Auto-add guests</span>
|
||||
</span>
|
||||
<button class='pull-right grey' style='font-size:1.15em' onclick='popupMessage(event);copyFunction(getById("director_block_3"))'><i class='las la-copy'></i>Copy link</button>
|
||||
<button class='pull-right grey' style='font-size:1.15em' onclick='copyFunction(getById("director_block_3"),event)'><i class='las la-copy'></i>Copy link</button>
|
||||
<button class='pull-right grey' style='font-size:1.15em' id="showCustomizerButton3" onclick='showCustomizer(3,this)'><i class='las la-tools'></i>Customize</button>
|
||||
<span>
|
||||
</div>
|
||||
@ -914,19 +921,17 @@
|
||||
</label>
|
||||
<span data-translate="auto-select-camera">Auto-select default camera</span>
|
||||
<Br />
|
||||
<label class="switch" title="The camera will load in a default safe-mode that may work if other modes fail.">
|
||||
<input type="checkbox" data-param="&safemode" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
<span data-translate="compatibility-mode">Compatibility Mode</span>
|
||||
<Br />
|
||||
<label class="switch" title="The guest won't have access to changing camera settings or screenshare">
|
||||
<input type="checkbox" data-param="&ns" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
<span data-translate="hide-setting-buttons">Hide settings button</span>
|
||||
|
||||
<Br />
|
||||
<label class="switch" title="The guest's self-video preview will appear tiny in the top right">
|
||||
<input type="checkbox" data-param="&mini" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
<span data-translate="mini-self-preview">Mini self-preview</span>
|
||||
|
||||
<Br />
|
||||
<label class="switch" title="Allow the guests to pick a virtual backscreen effect">
|
||||
<input type="checkbox" data-param="&effects" onchange="updateLink(1,this);">
|
||||
@ -935,7 +940,6 @@
|
||||
<font class="tooltip" style='cursor: help;position:relative;bottom:2px;font-family:"Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji", Times, Symbola, Aegyptus, Code2000, Code2001, Code2002, Musica, serif, LastResort;'>⚠<span class="tooltiptext">Uses more CPU and freezes the video if the guest doesn't keep the tab visible.</span></font> <span data-translate="virtual-backgrounds">Virtual backgrounds</span>
|
||||
|
||||
<br />
|
||||
|
||||
<label class="switch" title="Videos use an animated transition when being remixed">
|
||||
<input type="checkbox" data-param="&animate" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
@ -991,8 +995,16 @@
|
||||
<input type="checkbox" data-param="&webp" onchange="updateLinkWebP(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
<font class="tooltip" style='cursor: help;position:relative;bottom:2px;font-family:"Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji", Times, Symbola, Aegyptus, Code2000, Code2001, Code2002, Musica, serif, LastResort;'>⚠<span class="tooltiptext">You must keep the director's tab open and visible for this to work, or use the electron capture app.</span></font>
|
||||
<font class="tooltip" style='cursor: help;position:relative;bottom:2px;font-family:"Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji", Times, Symbola, Aegyptus, Code2000, Code2001, Code2002, Musica, serif, LastResort;'>⚠<span class="tooltiptext">Pretty experimental and has Lo-Fi quality, though relatively low CPU usage.</span></font>
|
||||
<span data-translate="low-cpu=broadcast-codec">Low-CPU broadcast codec</span>
|
||||
|
||||
<Br />
|
||||
<label class="switch" title="The guest's self-video preview will appear tiny in the top right">
|
||||
<input type="checkbox" data-param="&mini" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
<span data-translate="mini-self-preview">Mini self-preview</span>
|
||||
|
||||
<Br />
|
||||
<label class="switch" title="The guest can only see the Director's video, if provided">
|
||||
<input type="checkbox" data-param="&broadcast" id="broadcastSlider" onchange="updateLink(1,this);">
|
||||
@ -1143,6 +1155,7 @@
|
||||
<h4 style='color:#CCC;margin:20px 20px 0 20px;' data-translate='more-than-four-can-join' >These four guest slots are just for demonstration. More than four guests can actually join a room.</h4>
|
||||
</div></div>
|
||||
</div>
|
||||
<div id="hiddenElements"></div>
|
||||
<div id="overlayClockContainer" data-initial="600" class="advanced"><span id="overlayClock"></span></div>
|
||||
<div id="overlayMsgs" onclick="function(e){e.target.innerHTML = '';}" style="display:none"></div>
|
||||
<div id="bigPlayButton" onclick="function(e){e.target.innerHTML = '';}" style="display:none"></div>
|
||||
@ -1178,9 +1191,10 @@
|
||||
</button>
|
||||
|
||||
<!---- /////// BREAK //////// -->
|
||||
<span style="user-select: none;grid-column: 1;width:100%;margin:5px 0 ;font-size:80%; cursor: pointer;" onclick="toggleByDataset('1');getById('chevarrow3').classList.toggle('bottom');getById('chevarrow3').classList.toggle('right');"><i id="chevarrow3" style="padding:0px 7px 0 3px;" class="chevron right" aria-hidden="true"></i><span data-translate="More-scene-options">More scene options</span></span>
|
||||
<span class="hideDropMenu" onclick="toggleByDataset('1');getById('chevarrow3').classList.toggle('bottom');getById('chevarrow3').classList.toggle('right');"><i id="chevarrow3" style="padding:0px 7px 0 3px;" class="chevron right" aria-hidden="true"></i><span data-translate="More-scene-options">More scene options</span></span>
|
||||
<span class="hideDropMenu" style="grid-column: 2;"></span>
|
||||
|
||||
<button data-action-type="addToScene" class="hidden" data-cluster="1" style="grid-column: 1;" data-scene="2" title="Add this Video to any remote '&scene=2'" onclick="directEnable(this, event, 2);">
|
||||
<button data-action-type="addToScene" class="hidden" data-cluster="1" data-scene="2" title="Add this Video to any remote '&scene=2'" onclick="directEnable(this, event, 2);">
|
||||
<i class="las la-plus-square" style="color:#060"></i>
|
||||
<span data-translate="add-to-scene2">add to scene 2</span>
|
||||
</button>
|
||||
@ -1190,7 +1204,7 @@
|
||||
<span data-translate="mute-scene" >mute in scene</span>
|
||||
</button>
|
||||
|
||||
<span class="hidden" data-cluster="1" >
|
||||
<span class="hidden" data-cluster="1" data-action-type="sceneCluster1">
|
||||
<button style="width: 35.2px" data-action-type="addToScene" data-scene="3" data-action-type="add-scene-3" title="Add to Scene 3" onclick="directEnable(this, event, 3);">
|
||||
<span >S3</span>
|
||||
</button>
|
||||
@ -1202,7 +1216,7 @@
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<span class="hidden" data-cluster="1">
|
||||
<span class="hidden" data-cluster="1" data-action-type="sceneCluster2">
|
||||
<button style="width: 35.2px" data-action-type="addToScene" data-scene="6" data-action-type="add-scene-6" title="Add to Scene 6" onclick="directEnable(this, event, 6);">
|
||||
<span >S6</span>
|
||||
</button>
|
||||
@ -1214,7 +1228,7 @@
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<button class="hidden" data-cluster="1" data-action-type="force-keyframe" style="grid-column: 1; background-image: linear-gradient(90deg, #C9F0FF 0%, #FFDFB9 39%, #FFDFDF 70%, #D9FFEC 100%);" data-value="0" title="Force the remote sender to issue a keyframe to all scenes, fixing Pixel Smearing issues." onclick="requestKeyframeScene(this, event);">
|
||||
<button class="hidden" data-cluster="1" data-action-type="force-keyframe" style=" background-image: linear-gradient(90deg, #C9F0FF 0%, #FFDFB9 39%, #FFDFDF 70%, #D9FFEC 100%);" data-value="0" title="Force the remote sender to issue a keyframe to all scenes, fixing Pixel Smearing issues." onclick="requestKeyframeScene(this);">
|
||||
<span data-translate="force-keyframe">Rainbow Puke Fix</span>
|
||||
</button>
|
||||
|
||||
@ -1224,10 +1238,11 @@
|
||||
</button>
|
||||
|
||||
<!---- /////// BREAK //////// -->
|
||||
<span style="user-select: none;grid-column: 1;width:100%;margin:5px 0 ;font-size:80%;cursor: pointer;" onclick="toggleByDataset('2');getById('chevarrow4').classList.toggle('bottom');getById('chevarrow4').classList.toggle('right');"><i id="chevarrow4" class="chevron right" aria-hidden="true" style="padding:0px 7px 0 3px;" ></i><span data-translate="additional-controls">Additional controls</span></span>
|
||||
<span class="hideDropMenu" onclick="toggleByDataset('2');getById('chevarrow4').classList.toggle('bottom');getById('chevarrow4').classList.toggle('right');"><i id="chevarrow4" class="chevron right" aria-hidden="true" style="padding:0px 7px 0 3px;" ></i><span data-translate="additional-controls">Additional controls</span></span>
|
||||
<span class="hideDropMenu" style="grid-column: 2;" ></span>
|
||||
|
||||
|
||||
<button class="hidden" data-cluster="2" data-action-type="solo-video" style="grid-column: 1; text-shadow: 0px 0px yellow;" data-value="0" title="Solo this video everywhere" onclick="requestInfocus(this);">
|
||||
<button class="hidden" data-cluster="2" data-action-type="solo-video" style="text-shadow: 0px 0px yellow;" data-value="0" title="Solo this video everywhere" onclick="requestInfocus(this);">
|
||||
<i class="las la-user"></i>
|
||||
<span data-translate="solo-video">Highlight guest</span>
|
||||
</button>
|
||||
@ -1245,7 +1260,7 @@
|
||||
<i class="las la-eye-slash"></i> <span data-translate="toggle-remote-display">Blind Guest</span>
|
||||
</button>
|
||||
|
||||
<span class="hidden" data-cluster="2">
|
||||
<span class="hidden" data-cluster="2" data-action-type="ordering">
|
||||
<button style="width:34px;" data-action-type="order-down" title="Shift this Video Down in Order" onclick="changeOrder(-1,this.dataset.UUID);">
|
||||
<span data-translate="order-down"><i class="las la-minus"></i></span>
|
||||
</button>
|
||||
@ -1294,7 +1309,7 @@
|
||||
<input data-action-type="volume" type="range" min="0" max="200" value="100" title="Remotely change the volume of this guest" oninput="remoteVolumeUI(this)" ondblclick="this.value=100;remoteVolume(this);remoteVolumeUI(this);" onchange="remoteVolume(this);" style="grid-column: 2; margin:5px; width: 93%; position: relative;top: 0.6em; background-color:#fff0;"/><span class="tooltiptext" style='float: right; overflow: auto; left: 40px; width: 2.5em; top: -13px; margin: 0; position:relative;font-family:"Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji", Times, Symbola, Aegyptus,Code2000, Code2001, Code2002, Musica, serif, LastResort;' >100</span>
|
||||
</font>
|
||||
|
||||
<span class="hidden" data-cluster="2">
|
||||
<span class="hidden" data-cluster="2" data-action-type="change-quality">
|
||||
<button style="width: 35.2px" data-action-type="change-quality1" title="Disable Video Preview" onclick="toggleQualityDirector(0, this.dataset.UUID, this);">
|
||||
<span data-translate="change-to-low-quality"> <i class="las la-video-slash"></i></span>
|
||||
</button>
|
||||
@ -1386,7 +1401,7 @@
|
||||
|
||||
<button data-action-type="solo-video" data-value="0" title="Solo this video everywhere" onclick="requestInfocus(this);">
|
||||
<i class="las la-user"></i>
|
||||
<span data-translate="solo-video">Highlight guest</span>
|
||||
<span data-translate="solo-video">Highlight</span>
|
||||
</button>
|
||||
|
||||
<button data-action-type="recorder-local" title="Start Recording this remote stream to this local drive. *experimental*'" onclick="recordLocalVideoToggle();">
|
||||
@ -1476,7 +1491,7 @@
|
||||
<option value="4" data-translate="digital-greenscreen">Digital greenscreen</option>
|
||||
<option value="5" data-translate="virtual-background">Virtual background</option>
|
||||
</select>
|
||||
<span data-warnSimdNotice="true" style='display:none; font-size: 140%; margin-left:10px; vertical-align: middle; cursor:pointer' title="Improve performance and quality with this tip" onclick="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='popupMessage(event);copyFunction(this)' target='_blank'>chrome://flags/#enable-webassembly-simd</a>`);">
|
||||
<span data-warnSimdNotice="true" style='display:none; font-size: 140%; margin-left:10px; vertical-align: middle; cursor:pointer' title="Improve performance and quality with this tip" onclick="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>`);">
|
||||
<i class="las la-info-circle"></i>
|
||||
</span>
|
||||
<div id="selectImageTFLITE3" style="display:none;margin-top:10px;">
|
||||
@ -1517,13 +1532,41 @@
|
||||
<li class="context-menu__item">
|
||||
<a href="#" class="context-menu__link" data-action="Open">
|
||||
<i class="las la-external-link"></i>
|
||||
<span data-translate="open-in-new-tab">Open in new Tab</span>
|
||||
<span data-translate="open-in-new-tab">Open in new tab</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="context-menu__item">
|
||||
<a href="#" class="context-menu__link" data-action="Copy">
|
||||
<i class="las la-paperclip"></i>
|
||||
<span data-translate="copy-to-clipboard" >Copy to Clipboard</span>
|
||||
<span data-translate="copy-to-clipboard" >Copy to clipboard</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<nav id="context-menu-video" class="context-menu">
|
||||
<ul class="context-menu__items">
|
||||
<li class="context-menu__item">
|
||||
<a href="#" class="context-menu__link" data-action="Mirror">
|
||||
<i class="las la-external-link"></i>
|
||||
<span data-translate="mirror-video">Mirror</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="context-menu__item">
|
||||
<a href="#" class="context-menu__link" data-action="Controls">
|
||||
<i class="las la-external-link"></i>
|
||||
<span data-translate="toggle-control-video">Toggle control bar</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="context-menu__item">
|
||||
<a href="#" class="context-menu__link" data-action="PiP">
|
||||
<i class="las la-external-link"></i>
|
||||
<span data-translate="picture-in-picture">Picture-in-picture</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="context-menu__item">
|
||||
<a href="#" class="context-menu__link" data-action="Cast">
|
||||
<i class="las la-external-link"></i>
|
||||
<span data-translate="chrome-cast">Cast..</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
@ -1549,7 +1592,10 @@
|
||||
<label title="Increase this at your peril. Changes the total inbound video bitrate per guest; mobile devices excluded. Webp-mode also excluded." for="trbSettingInput">Change room video quality:</label>
|
||||
<span style="margin-left: 6px;" id="trbSettingInputFeedback"></span>-kbps
|
||||
<input id="trbSettingInput" type="range" min="0" max="4000" value="500" onchange="changeTRB(this);" oninput="getById('trbSettingInputFeedback').innerHTML = this.value;" style="width:100%;display:block;" />
|
||||
|
||||
<span style="margin: 20px 0 0 0;display:block" id='highlightDirectorSpan'>
|
||||
<label for="highlightDirector">Highlight Director</label>
|
||||
<input id="highlightDirector" style="width: 15px; height: 15px; margin:10px;" name="highlightDirector" data-value="0" data-action-type="solo-video" type="checkbox" onchange="requestInfocus(this);" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1697,7 +1743,7 @@
|
||||
|
||||
|
||||
var session = WebRTC.Media; // session is a required global variable if configuring manually. Run before loading main.js but after webrtc.js.
|
||||
session.version = "18.4b";
|
||||
session.version = "19.0";
|
||||
session.streamID = session.generateStreamID(); // randomly generates a streamID for this session. You can set your own programmatically if needed
|
||||
|
||||
session.defaultPassword = "someEncryptionKey123"; // Change this password if self-deploying for added security/privacy
|
||||
@ -1774,11 +1820,11 @@
|
||||
// session.title // "zzzz"
|
||||
</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=14"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="lib-js" src="./lib.js?ver=58"></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=237"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=248"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
99
main.css
99
main.css
@ -11,6 +11,7 @@
|
||||
--fit-style: contain;
|
||||
--fadein-speed: 0;
|
||||
--video-margin: 0px;
|
||||
--video-rounded: 0px;
|
||||
}
|
||||
|
||||
* {
|
||||
@ -27,6 +28,15 @@ table {
|
||||
margin:10px;
|
||||
}
|
||||
|
||||
.hideDropMenu{
|
||||
user-select: none;
|
||||
grid-column: 1;
|
||||
width:100%;
|
||||
margin:5px 0;
|
||||
font-size:80%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#bigPlayButton {
|
||||
margin:0 auto;
|
||||
background-color: #0000;
|
||||
@ -214,7 +224,6 @@ button.white:active {
|
||||
color: white;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
#header {
|
||||
width: 100%;
|
||||
padding: 1px;
|
||||
@ -227,8 +236,9 @@ button.white:active {
|
||||
color: white;
|
||||
text-align: right;
|
||||
margin-right: 10px;
|
||||
pointer-events: none;
|
||||
cursor: help;
|
||||
float: right;
|
||||
font-size: 90%;
|
||||
}
|
||||
#head6 {
|
||||
display: inline-block;
|
||||
@ -425,9 +435,9 @@ hr {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
margin: var(--video-margin);
|
||||
padding: var(--video-margin);
|
||||
border-radius: var(--video-rounded);
|
||||
}
|
||||
|
||||
#gridlayout {
|
||||
@ -626,22 +636,16 @@ button.glyphicon-button.active.focus {
|
||||
@media only screen and (max-height: 400px){
|
||||
#obsState {
|
||||
transform: scale(0.5);
|
||||
display:none!important;
|
||||
opacity:0;
|
||||
}
|
||||
}
|
||||
@media only screen and (max-height: 300px){
|
||||
#obsState {
|
||||
transform: scale(0.4);
|
||||
display:none!important;
|
||||
opacity:0;
|
||||
}
|
||||
}
|
||||
@media only screen and (max-height: 200px){
|
||||
#obsState {
|
||||
transform: scale(0.3);
|
||||
display:none!important;
|
||||
opacity:0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -857,11 +861,6 @@ body {
|
||||
transition: opacity .1s linear;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.previewWebcam {
|
||||
max-width: 640px;
|
||||
max-width: 83vw;
|
||||
@ -943,6 +942,10 @@ body {
|
||||
background-color:#ddeeff;
|
||||
}
|
||||
|
||||
.green {
|
||||
background-color:#474!important;
|
||||
}
|
||||
|
||||
/*https://css-tricks.com/styling-cross-browser-compatible-range-inputs-css/*/
|
||||
input[type=range] {
|
||||
-webkit-appearance: none;
|
||||
@ -1219,7 +1222,7 @@ input[type=range]:focus::-ms-fill-upper {
|
||||
#audioSourceScreenshare {
|
||||
display:block;
|
||||
height: 60px;
|
||||
min-width: 290px;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
padding: 5px;
|
||||
resize: both;
|
||||
@ -1231,6 +1234,17 @@ p#audioScreenShare1 {
|
||||
background: #f3f3f3;
|
||||
padding: 4px 10px 10px 10px;
|
||||
text-align: left;
|
||||
min-width:350px;
|
||||
}
|
||||
#headphonesDiv2{
|
||||
background-color: #f3f3f3;
|
||||
min-width: 350px;
|
||||
display: none;
|
||||
padding: 4px 10px 10px 10px;
|
||||
border: 1px solid #ccc;
|
||||
vertical-align: middle;
|
||||
margin: 10px 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#audioScreenShare1 > i {
|
||||
@ -1990,10 +2004,11 @@ audio.fileshare::-webkit-media-controls-play-button, video.fileshare::-webkit-me
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display:none;
|
||||
display:none!important;
|
||||
visibility: hidden;
|
||||
width:0px;
|
||||
height:0px;
|
||||
opacity: 0;
|
||||
}
|
||||
/* visited link */
|
||||
.grabLinks a:visited {
|
||||
@ -2374,8 +2389,7 @@ input[type=checkbox] {
|
||||
.directorBlock button i {
|
||||
margin-right: 5px;
|
||||
}
|
||||
.task {
|
||||
color: #808080;
|
||||
a.task {
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
}
|
||||
@ -2385,6 +2399,18 @@ input[type=checkbox] {
|
||||
margin-left: 5px;
|
||||
font-size:1.2em;
|
||||
}
|
||||
.shift {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
margin: 7px 0 0 4px;
|
||||
padding: 0;
|
||||
width: 27px;
|
||||
font-size: 0.8em;
|
||||
top: -7px;
|
||||
}
|
||||
.shift>i {
|
||||
cursor:pointer;
|
||||
}
|
||||
#toggleroomnotes {
|
||||
grid-column: 4;
|
||||
grid-row: 1;
|
||||
@ -2436,10 +2462,14 @@ i.las.la-circle {
|
||||
}
|
||||
.streamID {
|
||||
text-align: right;
|
||||
margin: 5px;
|
||||
font-size: 0.7em;
|
||||
text-overflow: ellipsis;
|
||||
margin: 5px 5px 5px 0px;
|
||||
font-size: 0.7em;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
/* left: 22px; */
|
||||
position: relative;
|
||||
width: 230px;
|
||||
display: inline-block;
|
||||
}
|
||||
.streamID i {
|
||||
margin-left: 5px;
|
||||
@ -2471,7 +2501,14 @@ div#guestFeeds {
|
||||
div#guestFeeds:empty {
|
||||
display:none;
|
||||
}
|
||||
|
||||
#hiddenElements{
|
||||
visibility:hidden;
|
||||
position: absolute;
|
||||
left:-9999;
|
||||
top:-9999;
|
||||
width:0px;
|
||||
height:0px;
|
||||
}
|
||||
#press2talk[data-enabled="true"] {
|
||||
background: #1e0000;
|
||||
-webkit-box-shadow: inset 0px 0px 1px #b90000;
|
||||
@ -2882,9 +2919,9 @@ input:checked + .slider:before {
|
||||
border: 10px dashed rgb(64 65 62)
|
||||
}
|
||||
|
||||
#SafariWarning{
|
||||
.startupWarning{
|
||||
max-width:100%;
|
||||
display:none;
|
||||
display:block;
|
||||
width: 450px;
|
||||
border-left: 4px solid #eff150;
|
||||
background: #fffded;
|
||||
@ -2895,18 +2932,26 @@ input:checked + .slider:before {
|
||||
box-shadow: 0px 5px 10px -5px #a9a9a9;
|
||||
text-align: left;
|
||||
}
|
||||
#SafariWarning > p {
|
||||
.startupWarning > p {
|
||||
text-align: left;
|
||||
display:inline-block;
|
||||
padding-left: 38px;
|
||||
|
||||
}
|
||||
#SafariWarning > i {
|
||||
.startupWarning > i {
|
||||
position: absolute;
|
||||
font-size: 2em;
|
||||
padding: 2px 0 0 0;
|
||||
}
|
||||
|
||||
#consentWarning{
|
||||
margin: 0 auto 20px auto;
|
||||
}
|
||||
|
||||
#consentWarning2{
|
||||
margin: 0px auto 10px auto;
|
||||
}
|
||||
|
||||
#alertModal {
|
||||
position: absolute;
|
||||
background-color: rgb(221 221 221);
|
||||
|
||||
525
main.js
525
main.js
@ -129,6 +129,8 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
window.prompt = function(title, val){
|
||||
return ipcRenderer.sendSync('prompt', {title, val});
|
||||
};
|
||||
|
||||
ipcRenderer.sendSync('prompt', {title, val});
|
||||
} catch(e){}
|
||||
}
|
||||
|
||||
@ -156,7 +158,10 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
if (urlParams.has('nomicbutton') || urlParams.has('nmb')) {
|
||||
getById("mutebutton").style.setProperty("display", "none", "important");
|
||||
}
|
||||
|
||||
|
||||
if (urlParams.has('nomouseevents') || urlParams.has('nme')) {
|
||||
session.disableMouseEvents = true;
|
||||
}
|
||||
|
||||
if (urlParams.has('novideobutton') || urlParams.has('nvb')) {
|
||||
getById("mutevideobutton").style.setProperty("display", "none", "important");
|
||||
@ -205,7 +210,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
log("MAKE DRAGGABLE");
|
||||
delayedStartupFuncs.push([makeDraggableElement, document.getElementById("subControlButtons")]);
|
||||
if (safariVersion() && !getChromeVersion()){ // if desktop Safari, so macOS, give a note saying it sucks
|
||||
getById("SafariWarning").style.display = "block";
|
||||
getById("SafariWarning").classList.remove("advanced");
|
||||
}
|
||||
}
|
||||
|
||||
@ -222,7 +227,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
session.style = 1;
|
||||
//getById("header").style.display = "none";
|
||||
//getById("header").style.opacity = 0;
|
||||
session.showList=false;
|
||||
session.showList=true;
|
||||
}
|
||||
|
||||
if (urlParams.has('showlist')) {
|
||||
@ -310,6 +315,14 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
session.midiHotkeys = urlParams.get('midi') || urlParams.get ('hotkeys') || 1;
|
||||
session.midiHotkeys = parseInt(session.midiHotkeys);
|
||||
}
|
||||
|
||||
if (urlParams.has('midiremote') || urlParams.has('remotemidi')){
|
||||
if (session.director!==false){
|
||||
session.midiRemote = urlParams.get('midiremote') || urlParams.get ('remotemidi') || 4;
|
||||
} else {
|
||||
session.midiRemote = urlParams.get('midiremote') || urlParams.get ('remotemidi') || 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (urlParams.has('midipush') || urlParams.has('midiout') || urlParams.has('mo')){
|
||||
session.midiOut = urlParams.get('midipush') || urlParams.get('midiout') || urlParams.get('mo') || true;
|
||||
@ -341,7 +354,6 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
getById("container-6").classList.add("skip-animation");
|
||||
getById("container-6").classList.remove('pointer');
|
||||
session.website = urlParams.get('website') || urlParams.get('iframe') || false;
|
||||
|
||||
if (session.website){
|
||||
if (session.director){
|
||||
delayedStartupFuncs.push([shareWebsite, session.website]);
|
||||
@ -349,6 +361,23 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
delayedStartupFuncs.push([session.publishIFrame, session.website]);
|
||||
}
|
||||
}
|
||||
} else if (urlParams.has('webcam2') || urlParams.has('wc2')) {
|
||||
session.webcamonly = true;
|
||||
screensharebutton = false;
|
||||
session.introButton = true;
|
||||
} else if (urlParams.has('screenshare2') || urlParams.has('ss2')) {
|
||||
session.screenshare = true;
|
||||
session.introButton = true;
|
||||
if (urlParams.get('screenshare2') || urlParams.get('ss2')){
|
||||
session.screenshare = urlParams.get('screenshare2') || urlParams.get('ss2');
|
||||
}
|
||||
}
|
||||
if (urlParams.has('intro') || urlParams.has('ib')) {
|
||||
session.introButton = true;
|
||||
}
|
||||
|
||||
if (urlParams.has('hidesolo') || urlParams.has('hs')){
|
||||
session.hidesololinks=true;
|
||||
}
|
||||
|
||||
if (urlParams.has('ssb')) {
|
||||
@ -358,6 +387,10 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
if (urlParams.has('mute') || urlParams.has('muted') || urlParams.has('m')) {
|
||||
session.muted = true;
|
||||
}
|
||||
|
||||
if (urlParams.has('safemode')) {
|
||||
session.safemode = true;
|
||||
}
|
||||
|
||||
if (urlParams.has('videomute') || urlParams.has('videomuted') || urlParams.has('vm')) {
|
||||
session.videoMutedFlag = true;
|
||||
@ -410,9 +443,14 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
|
||||
if (session.screenshare !== false) {
|
||||
getById("container-3").className = 'column columnfade advanced'; // Hide screen share on mobile
|
||||
getById("container-2").classList.add("skip-animation");
|
||||
getById("container-2").classList.remove('pointer');
|
||||
if (session.introButton){
|
||||
getById("container-3").className = 'column columnfade advanced'; // Hide screen share
|
||||
getById("head1").className = 'advanced';
|
||||
} else {
|
||||
getById("container-3").className = 'column columnfade advanced'; // Hide webcam
|
||||
getById("container-2").classList.add("skip-animation");
|
||||
getById("container-2").classList.remove('pointer');
|
||||
}
|
||||
}
|
||||
|
||||
if (urlParams.has('manual')) {
|
||||
@ -470,7 +508,6 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
session.scene = session.scene.replace(/[\W]+/g, "_");
|
||||
} else {
|
||||
session.scene = (parseInt(session.scene) || 0) + "";
|
||||
|
||||
}
|
||||
session.disableWebAudio = true;
|
||||
session.audioEffects = false;
|
||||
@ -479,6 +516,10 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
if (session.scene!=="1"){ // scene =0 and 1 should load instantly.
|
||||
session.hiddenSceneViewBitrate = 0; // By default this is ~ 400kbps, but if you have 10 scenes, i don't want to kill things.
|
||||
}
|
||||
|
||||
if (urlParams.has('preloadbitrate')) {
|
||||
session.hiddenSceneViewBitrate = parseInt(urlParams.get('preloadbitrate')) || 500;
|
||||
}
|
||||
|
||||
if (urlParams.has('scenetype') || urlParams.has('type')) {
|
||||
session.sceneType = parseInt(urlParams.get('scenetype')) || parseInt(urlParams.get('type')) || false;
|
||||
@ -499,10 +540,15 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
|
||||
if (session.webcamonly == true) {
|
||||
getById("container-2").className = 'column columnfade advanced'; // Hide screen share on mobile
|
||||
getById("container-3").classList.add("skip-animation");
|
||||
getById("container-3").classList.remove('pointer');
|
||||
delayedStartupFuncs.push([previewWebcam]);
|
||||
if (session.introButton){
|
||||
getById("container-2").className = 'column columnfade advanced'; // Hide screen share
|
||||
getById("head3").className = 'advanced';
|
||||
} else {
|
||||
getById("container-2").className = 'column columnfade advanced'; // Hide screen share
|
||||
getById("container-3").classList.add("skip-animation");
|
||||
getById("container-3").classList.remove('pointer');
|
||||
delayedStartupFuncs.push([previewWebcam]);
|
||||
}
|
||||
}
|
||||
|
||||
if (urlParams.has('css')){
|
||||
@ -588,7 +634,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
session.taintedSession = false;
|
||||
session.hash = hash;
|
||||
}
|
||||
});
|
||||
}).catch(errorlog);
|
||||
}
|
||||
|
||||
if (session.defaultPassword !== false) {
|
||||
@ -697,6 +743,21 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
|
||||
if (urlParams.has('animated') || urlParams.has('animate')){
|
||||
session.animatedMoves = urlParams.get('animated') || urlParams.get('animate');
|
||||
if (session.animatedMoves === "false") {
|
||||
session.animatedMoves = false;
|
||||
} else if (session.animatedMoves === "0") {
|
||||
session.animatedMoves = false;
|
||||
} else if (session.animatedMoves === "no") {
|
||||
session.animatedMoves = false;
|
||||
} else if (session.animatedMoves === "off") {
|
||||
session.animatedMoves = false;
|
||||
} else {
|
||||
session.animatedMoves=true;
|
||||
}
|
||||
} else if (session.mobile){
|
||||
session.animatedMoves=false;
|
||||
} else {
|
||||
session.animatedMoves=true;
|
||||
}
|
||||
|
||||
@ -704,7 +765,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
if (urlParams.has('pie')){
|
||||
session.customWSS = urlParams.get('pie') || false; // If session.customWSS == true, then there is no need to set parameters via URL
|
||||
if (session.customWSS){
|
||||
session.wss = "wss://us-nyc-1.websocket.me/v3/1?api_key="+session.customWSS; // if URL param is set, it will use the API key.
|
||||
session.wss = "wss://free3.piesocket.com/v3/1?api_key="+session.customWSS; // if URL param is set, it will use the API key.
|
||||
}
|
||||
}
|
||||
|
||||
@ -877,6 +938,10 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
// session.view = true;
|
||||
// }
|
||||
//}
|
||||
|
||||
if (urlParams.has('ruler') || urlParams.has('grid') || urlParams.has('thirds')) {
|
||||
session.ruleOfThirds=true;
|
||||
}
|
||||
|
||||
if (urlParams.has('nopreview') || urlParams.has('np')) {
|
||||
log("preview OFF");
|
||||
@ -933,13 +998,14 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (urlParams.has('micdelay') || urlParams.has('delay') || urlParams.has('md')) {
|
||||
log("audio gain ENABLED");
|
||||
session.micDelay = urlParams.get('micdelay') || urlParams.get('delay') || urlParams.get('md');
|
||||
session.micDelay = parseInt(session.micDelay) || 0;
|
||||
session.disableWebAudio = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (urlParams.has('tips')){
|
||||
getById("guestTips").style.display="flex";
|
||||
@ -950,7 +1016,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
session.audioGain = urlParams.get('audiogain') || urlParams.get('gain') || urlParams.get('g');
|
||||
session.audioGain = parseInt(session.audioGain) || 0;
|
||||
session.disableWebAudio = false;
|
||||
}
|
||||
}
|
||||
if (urlParams.has('compressor') || urlParams.has('comp')) {
|
||||
log("audio gain ENABLED");
|
||||
session.compressor = 1;
|
||||
@ -1067,14 +1133,22 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
|
||||
if (urlParams.has('margin')) {
|
||||
if (urlParams.get('margin') || 10){
|
||||
try {
|
||||
var videoMargin = urlParams.get('margin') || 10;
|
||||
videoMargin = parseInt(videoMargin);
|
||||
videoMargin+="px";
|
||||
document.querySelector(':root').style.setProperty('--video-margin', videoMargin);
|
||||
} catch(e){errorlog("variable css failed");}
|
||||
}
|
||||
try {
|
||||
var videoMargin = urlParams.get('margin') || 10;
|
||||
videoMargin = parseInt(videoMargin);
|
||||
videoMargin+="px";
|
||||
document.querySelector(':root').style.setProperty('--video-margin', videoMargin);
|
||||
} catch(e){errorlog("variable css failed");}
|
||||
}
|
||||
|
||||
if (urlParams.has('rounded')) {
|
||||
try {
|
||||
var videoRounded = urlParams.get('rounded') || 50;
|
||||
videoRounded = parseInt(videoRounded);
|
||||
videoRounded+="px";
|
||||
document.querySelector(':root').style.setProperty('--video-rounded', videoRounded);
|
||||
} catch(e){errorlog("variable css failed");}
|
||||
|
||||
}
|
||||
|
||||
if (urlParams.has('fadein')) {
|
||||
@ -1205,14 +1279,24 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
getById("flipcamerabutton").classList.remove("advanced");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (urlParams.has('consent')){
|
||||
session.consent = true;
|
||||
getById("consentWarning").classList.remove("advanced");
|
||||
getById("consentWarning2").classList.remove("advanced");
|
||||
}
|
||||
|
||||
if (urlParams.has('autojoin') || urlParams.has('autostart') || urlParams.has('aj') || urlParams.has('as')) {
|
||||
session.autostart = true;
|
||||
if (session.screenshare!==false) {
|
||||
delayedStartupFuncs.push([publishScreen]);
|
||||
}
|
||||
}
|
||||
if (session.consent){
|
||||
setTimeout(function(){
|
||||
warnUser("⚠ Privacy warning: The director of this room can remotely switch your camera or microphone without permission.", 8000);
|
||||
}, 1500);
|
||||
}
|
||||
}
|
||||
|
||||
if (urlParams.has('noiframe') || urlParams.has('noiframes') || urlParams.has('nif') || urlParams.has('nowebsite') ) {
|
||||
|
||||
@ -1240,8 +1324,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
log("exclude video playback");
|
||||
log(session.exclude);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (urlParams.has('novideo') || urlParams.has('nv') || urlParams.has('hidevideo') || urlParams.has('showonly')) {
|
||||
|
||||
session.novideo = urlParams.get('novideo') || urlParams.get('nv') || urlParams.get('hidevideo') || urlParams.get('showonly');
|
||||
@ -1372,11 +1455,21 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
getById("helpbutton").style.opacity = 0;
|
||||
getById("reportbutton").style.display = "none";
|
||||
getById("reportbutton").style.opacity = 0;
|
||||
getById("calendarButton").style.display = "none";
|
||||
getById("calendarButton").style.opacity = 0;
|
||||
getById("chatBody").innerHTML = "";
|
||||
}
|
||||
|
||||
if (urlParams.has('beep') || urlParams.has('notify') || urlParams.has('tone')) {
|
||||
session.beepToNotify = true;
|
||||
var addtone = createAudioElement();
|
||||
addtone.id = "jointone";
|
||||
addtone.src = "./media/join.mp3";
|
||||
getById("testtone").parentNode.insertBefore(addtone, getById("testtone").nextSibling)
|
||||
var addtone = createAudioElement();
|
||||
addtone.id = "leavetone";
|
||||
addtone.src = "./media/leave.mp3";
|
||||
getById("testtone").parentNode.insertBefore(addtone, getById("testtone").nextSibling)
|
||||
}
|
||||
if (urlParams.has('r2d2')) {
|
||||
getById("testtone").innerHTML = "";
|
||||
@ -1512,6 +1605,12 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
getById("credits").style.display = "none";
|
||||
getById("header").style.display = "none";
|
||||
getById("controlButtons").style.display = "none";
|
||||
getById("helpbutton").style.display = "none";
|
||||
getById("helpbutton").style.opacity = 0;
|
||||
getById("reportbutton").style.display = "none";
|
||||
getById("reportbutton").style.opacity = 0;
|
||||
getById("calendarButton").style.display = "none";
|
||||
getById("calendarButton").style.opacity = 0;
|
||||
var styleTmp = document.createElement('style');
|
||||
styleTmp.innerHTML = `
|
||||
video {
|
||||
@ -1522,6 +1621,21 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
getById("credits").innerHTML = "Version: " + session.version + " - " + getById("credits").innerHTML;
|
||||
|
||||
if (urlParams.has('minidirector')) {
|
||||
try {
|
||||
var cssStylesheet = document.createElement('link');
|
||||
cssStylesheet.rel = 'stylesheet';
|
||||
cssStylesheet.type = 'text/css';
|
||||
cssStylesheet.media = 'screen';
|
||||
cssStylesheet.href = 'minidirector.css';
|
||||
document.getElementsByTagName('head')[0].appendChild(cssStylesheet);
|
||||
} catch (e) {
|
||||
errorlog(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (urlParams.has('cleanish')) {
|
||||
session.cleanish = true;
|
||||
}
|
||||
@ -1605,19 +1719,35 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
|
||||
if (urlParams.has('buffer')) { // needs to be before sync
|
||||
session.buffer = parseFloat(urlParams.get('buffer')) || 0;
|
||||
log("buffer Changed: " + session.buffer);
|
||||
session.sync = 0;
|
||||
if ((getChromeVersion() > 50) && (getChromeVersion()< 78)){
|
||||
|
||||
} else {
|
||||
session.buffer = parseFloat(urlParams.get('buffer')) || 0;
|
||||
log("buffer Changed: " + session.buffer);
|
||||
session.sync = 0;
|
||||
session.audioEffects = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (urlParams.has('panning') || urlParams.has('pan')) {
|
||||
session.panning=true;
|
||||
if (urlParams.get('panning') || urlParams.get('pan')){
|
||||
session.panning = urlParams.get('panning') || urlParams.get('pan');
|
||||
}
|
||||
session.audioEffects = true;
|
||||
}
|
||||
|
||||
if (urlParams.has('sync')) {
|
||||
session.sync = parseFloat(urlParams.get('sync'));
|
||||
log("sync Changed; in milliseconds. If not set, defaults to auto.");
|
||||
log(session.sync);
|
||||
session.audioEffects = true;
|
||||
if (session.buffer === false) {
|
||||
session.buffer = 0;
|
||||
if ((getChromeVersion() > 50) && (getChromeVersion()< 78)){
|
||||
|
||||
} else {
|
||||
session.sync = parseFloat(urlParams.get('sync'));
|
||||
log("sync Changed; in milliseconds. If not set, defaults to auto.");
|
||||
log(session.sync);
|
||||
session.audioEffects = true;
|
||||
if (session.buffer === false) {
|
||||
session.buffer = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1722,7 +1852,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
for (let i = 0; i < elementsTmp.length; i++) {
|
||||
elementsTmp[i].style.display = "inline-block";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (urlParams.has('viewereffect') || urlParams.has('viewereffects') || urlParams.has('ve')) {
|
||||
@ -1734,11 +1864,18 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
session.audioEffects = true;
|
||||
session.audioMeterGuest = true;
|
||||
setInterval(function(){activeSpeaker(false);},100);
|
||||
} else if (urlParams.has('noisegate')){
|
||||
session.quietOthers = true;
|
||||
session.audioEffects = true;
|
||||
session.audioMeterGuest = true;
|
||||
setInterval(function(){activeSpeaker(false);},100);
|
||||
}
|
||||
|
||||
if (urlParams.has('meter') || urlParams.has('meterstyle')){
|
||||
session.meterStyle = urlParams.get('meter') || urlParams.get('meterstyle') || 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (urlParams.has('directorchat') || urlParams.has('dc')){
|
||||
session.directorChat = true;
|
||||
@ -1950,6 +2087,13 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
session.wss = "wss://" + urlParams.get('wss');
|
||||
}
|
||||
}
|
||||
|
||||
if (urlParams.has('osc') || urlParams.has('api')) {
|
||||
if (urlParams.get('osc') || urlParams.get('api')) {
|
||||
session.api = urlParams.get('osc') || urlParams.get('api');
|
||||
setTimeout(function(){oscClient();},1000);
|
||||
}
|
||||
}
|
||||
|
||||
if (urlParams.has('queue')) {
|
||||
session.queue = true;
|
||||
@ -2012,6 +2156,15 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
}
|
||||
|
||||
if (urlParams.has('hidescreenshare') || urlParams.has('hidess') || urlParams.has('sshide') || urlParams.has('screensharehide')) { // this way I don't need to remember what it's called. I can just guess. :D
|
||||
session.screenShareElementHidden = true;
|
||||
}
|
||||
|
||||
if (urlParams.has('zoomedbitrate') || urlParams.has('zb')) { // this way I don't need to remember what it's called. I can just guess. :D
|
||||
session.zoomedBitrate = urlParams.get('zoomedbitrate') || urlParams.get('zb') || 2500;
|
||||
session.zoomedBitrate = parseInt(session.zoomedBitrate) ;
|
||||
}
|
||||
|
||||
if (urlParams.has('screenshareid') || urlParams.has('ssid')) {
|
||||
if (urlParams.get('screenshareid') || urlParams.get('ssid')) {
|
||||
session.screenshareid = urlParams.get('screenshareid') || urlParams.get('ssid');
|
||||
@ -2130,10 +2283,8 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
getById("mainmenu").style.display = "none";
|
||||
getById("translateButton").style.display = "none";
|
||||
log("Update Mixer Event on REsize SET");
|
||||
window.addEventListener("resize", updateMixer);
|
||||
window.addEventListener("orientationchange", function() {
|
||||
setTimeout(updateMixer, 200);
|
||||
});
|
||||
window.onresize = updateMixer;
|
||||
window.onorientationchange = function(){setTimeout(updateMixer, 200);};
|
||||
joinRoom(session.roomid); // this is a scene, so we want high resolutions
|
||||
getById("main").style.overflow = "hidden";
|
||||
|
||||
@ -2168,7 +2319,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
log("dir room hash is " + hash);
|
||||
session.directorHash = hash;
|
||||
return;
|
||||
});
|
||||
}).catch(errorlog);
|
||||
} else {
|
||||
session.directorPassword = false;
|
||||
}
|
||||
@ -2191,10 +2342,8 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
log("Update Mixer Event on REsize SET");
|
||||
getById("translateButton").style.display = "none";
|
||||
window.addEventListener("resize", updateMixer);
|
||||
window.addEventListener("orientationchange", function() {
|
||||
setTimeout(updateMixer, 200);
|
||||
});
|
||||
window.onresize = updateMixer;
|
||||
window.onorientationchange = function(){setTimeout(updateMixer, 200);};
|
||||
getById("main").style.overflow = "hidden";
|
||||
|
||||
if (session.chatbutton === true) {
|
||||
@ -2340,7 +2489,6 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
closeModal();
|
||||
async function loadModel(){
|
||||
model = await faceLandmarksDetection.load(faceLandmarksDetection.SupportedPackages.mediapipeFacemesh);
|
||||
|
||||
}
|
||||
loadModel();
|
||||
}
|
||||
@ -2352,7 +2500,31 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
|
||||
script.type = 'text/javascript';script2.type = 'text/javascript';script3.type = 'text/javascript';script4.type = 'text/javascript';
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
} else if (session.effects==9){
|
||||
var script = document.createElement('script');
|
||||
script.onload = function() {
|
||||
effectsEngine();
|
||||
}
|
||||
script.src = "./filters/sample.js";
|
||||
document.head.appendChild(script);
|
||||
warnUser("Loading custom effects model...",1000);
|
||||
} else if (session.effects==10){
|
||||
var script = document.createElement('script');
|
||||
script.onload = function() {
|
||||
effectsEngine();
|
||||
}
|
||||
script.src = "./filters/cube.js";
|
||||
document.head.appendChild(script);
|
||||
warnUser("Loading custom effects model...",1000);
|
||||
} else if (session.effects==11){
|
||||
var script = document.createElement('script');
|
||||
script.onload = function() {
|
||||
effectsEngine();
|
||||
}
|
||||
script.src = "./filters/anon.js";
|
||||
document.head.appendChild(script);
|
||||
warnUser("Loading custom effects model...",1000);
|
||||
}
|
||||
|
||||
if (location.protocol !== 'https:') {
|
||||
if (!(session.cleanOutput)) {
|
||||
@ -2370,7 +2542,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
errorlog(e);
|
||||
}
|
||||
|
||||
if (isIFrame) { // reduce CPU load if not needed.
|
||||
if (isIFrame) { // reduce CPU load if not needed. //iframe API
|
||||
window.onmessage = function(e) { // iFRAME support
|
||||
log(e);
|
||||
try {
|
||||
@ -2390,9 +2562,27 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
} catch (err) {
|
||||
errorlog(err);
|
||||
}
|
||||
|
||||
if ("sendData" in e.data) { // send generic data via p2p. Send whatever you want I guess; there is a max chunk size of course. Use filetransfer for large files?
|
||||
var UUID = false;
|
||||
var streamID = false;
|
||||
var type = false;
|
||||
if (e.data.UUID){
|
||||
UUID = e.data.UUID;
|
||||
} else if (e.data.streamID){
|
||||
streamID = e.data.streamID;
|
||||
}
|
||||
if (e.data.type){
|
||||
type = e.data.type;
|
||||
}
|
||||
var ret = session.sendGenericData(e.data.sendData, UUID, streamID, type); // comes out the other side as: ("dataReceived", data, UUID);
|
||||
if (!ret){warnlog("Not connected yet or no peers available");}
|
||||
return;
|
||||
}
|
||||
|
||||
if ("sendChat" in e.data) {
|
||||
sendChat(e.data.sendChat); // sends to all peers; more options down the road
|
||||
return;
|
||||
}
|
||||
// Chat out gets called via getChatMessage function
|
||||
// Related code: parent.postMessage({"chat": {"msg":-----,"type":----,"time":---} }, "*");
|
||||
@ -2475,6 +2665,25 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ("panning" in e.data){
|
||||
if ("UUID" in e.data){
|
||||
try {
|
||||
adjustPan(UUID, e.data.panning);
|
||||
} catch (e) {
|
||||
errorlog(e);
|
||||
}
|
||||
} else {
|
||||
for (var i in session.rpcs) {
|
||||
try {
|
||||
adjustPan(i, e.data.panning);
|
||||
} catch (e) {
|
||||
errorlog(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ("bitrate" in e.data) {
|
||||
for (var i in session.rpcs) {
|
||||
@ -2506,9 +2715,21 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
changeAudioDevice(e.data.changeAudioDevice);
|
||||
}
|
||||
|
||||
|
||||
if ("changeAudioOutputDevice" in e.data) {
|
||||
warnlog(e.data.changeAudioOutputDevice);
|
||||
changeAudioOutputDeviceById(e.data.changeAudioOutputDevice);
|
||||
}
|
||||
|
||||
if ("getDeviceList" in e.data) {
|
||||
warnlog(e.data.getDeviceList);
|
||||
enumerateDevices().then(function(deviceInfos) {
|
||||
parent.postMessage({
|
||||
"deviceList": deviceInfos
|
||||
}, "*");
|
||||
});
|
||||
}
|
||||
|
||||
if ("sceneState" in e.data) { // TRUE OR FALSE - tells the connected peers if they are live or not via a tally light change.
|
||||
|
||||
if (session.obsState.visibility !== e.data.sceneState) { // only move forward if there is a change; the event likes to double fire you see.
|
||||
session.obsStateSync();
|
||||
}
|
||||
@ -2548,6 +2769,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
if (stat.kind == "video") {
|
||||
|
||||
if ("qualityLimitationReason" in stat) {
|
||||
|
||||
session.pcs[UUID].stats.quality_limitation_reason = stat.qualityLimitationReason;
|
||||
}
|
||||
if ("framesPerSecond" in stat) {
|
||||
@ -2628,6 +2850,21 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
session.pushLoudness = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ("getEffectsData" in e.data) {
|
||||
log("GOT getEffects Data REQUESTed"); // face tracking info, etc.
|
||||
if (e.data.getEffectsData !== false) {
|
||||
session.pushEffectsData = e.data.getEffectsData; // which effect do you want the data from? it won't enable the effect necessarily; just the ML pipeline
|
||||
|
||||
//parent.postMessage({
|
||||
// "effectsData": loudness,
|
||||
// "effectsID": session.pushEffectsData
|
||||
//}, "*");
|
||||
|
||||
} else {
|
||||
session.pushEffectsData = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ("getStreamIDs" in e.data) {
|
||||
if (e.data.getStreamIDs == true) {
|
||||
@ -2775,76 +3012,9 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
var input = WebMidi.inputs[i];
|
||||
input.addListener('noteon', "all", function(e) {
|
||||
log(e);
|
||||
if (session.midiHotkeys==1){
|
||||
log(e);
|
||||
var note = e.note.name + e.note.octave;
|
||||
if (note == "G3") { // open and close the chat window
|
||||
toggleChat();
|
||||
} else if (note == "A3") { // mute your audio output
|
||||
toggleMute();
|
||||
} else if (note == "B3") { // mute your video output
|
||||
toggleVideoMute();
|
||||
} else if (note == "C4") { // enable / disable screenshare
|
||||
toggleScreenShare();
|
||||
} else if (note == "D4") { // completely kill your connection/session
|
||||
hangup();
|
||||
} else if (note == "E4") { // raise your hand; director sees this
|
||||
raisehand();
|
||||
} else if (note == "F4") { // start/stop local recording
|
||||
recordLocalVideoToggle();
|
||||
} else if (note == "G4") { // Director Enables their Audio output
|
||||
press2talk(true);
|
||||
} else if (note == "A4") { // Director cut's their audio/video output
|
||||
hangup2();
|
||||
}
|
||||
} else if (session.midiHotkeys==2){
|
||||
log(e);
|
||||
var note = e.note.name + e.note.octave;
|
||||
if (note == "G1") { // open and close the chat window
|
||||
toggleChat();
|
||||
} else if (note == "A1") { // mute your audio output
|
||||
toggleMute();
|
||||
} else if (note == "B1") { // mute your video output
|
||||
toggleVideoMute();
|
||||
} else if (note == "C2") { // enable / disable screenshare
|
||||
toggleScreenShare();
|
||||
} else if (note == "D2") { // completely kill your connection/session
|
||||
hangup();
|
||||
} else if (note == "E2") { // raise your hand; director sees this
|
||||
raisehand();
|
||||
} else if (note == "F2") { // start/stop local recording
|
||||
recordLocalVideoToggle();
|
||||
} else if (note == "G2") { // Director Enables their Audio output
|
||||
press2talk(true);
|
||||
} else if (note == "A2") { // Director cut's their audio/video output
|
||||
hangup2();
|
||||
}
|
||||
} else if (session.midiHotkeys==3){
|
||||
log(e);
|
||||
var note = e.note.name + e.note.octave;
|
||||
var velocity = e.velocity;
|
||||
if (note == "C1"){
|
||||
if (velocity == "0") { // open and close the chat window
|
||||
toggleChat();
|
||||
} else if (note == "1") { // mute your audio output
|
||||
toggleMute();
|
||||
} else if (note == "2") { // mute your video output
|
||||
toggleVideoMute();
|
||||
} else if (note == "3") { // enable / disable screenshare
|
||||
toggleScreenShare();
|
||||
} else if (note == "4") { // completely kill your connection/session
|
||||
hangup();
|
||||
} else if (note == "5") { // raise your hand; director sees this
|
||||
raisehand();
|
||||
} else if (note == "6") { // start/stop local recording
|
||||
recordLocalVideoToggle();
|
||||
} else if (note == "7") { // Director Enables their Audio output
|
||||
press2talk(true);
|
||||
} else if (note == "8") { // Director cut's their audio/video output
|
||||
hangup2();
|
||||
}
|
||||
}
|
||||
}
|
||||
var note = e.note.name + e.note.octave;
|
||||
var velocity = e.velocity || false;
|
||||
midiHotkeysNote(node,velocity);
|
||||
});
|
||||
input.addListener('controlchange', "all", function(e) {
|
||||
|
||||
@ -2865,76 +3035,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
var command = e.controller.number;
|
||||
var value = e.value;
|
||||
|
||||
if (command == 110){
|
||||
if (value == 0) { // open and close the chat window
|
||||
toggleChat();
|
||||
} else if (value == 1) { // mute your audio output
|
||||
toggleMute();
|
||||
} else if (value == 2) { // mute your video output
|
||||
toggleVideoMute();
|
||||
} else if (value == 3) { // enable / disable screenshare
|
||||
toggleScreenShare();
|
||||
} else if (value == 4) { // completely kill your connection/session
|
||||
hangup();
|
||||
} else if (value == 5) { // raise your hand; director sees this
|
||||
raisehand();
|
||||
} else if (value == 6) { // start/stop local recording
|
||||
recordLocalVideoToggle();
|
||||
} else if (value == 7) { // Director Enables their Audio output
|
||||
press2talk(true);
|
||||
} else if (value == 8) { // Director cut's their audio/video output
|
||||
hangup2();
|
||||
}
|
||||
} else if (command > 110){
|
||||
var guestslot = command-111;
|
||||
if (value == 0) {
|
||||
var elements = document.querySelectorAll('[data-action-type="forward"][data--u-u-i-d]');
|
||||
if (elements[guestslot]) {
|
||||
directMigrate(elements[guestslot], true);
|
||||
}
|
||||
} else if (value == 1) {
|
||||
var elements = document.querySelectorAll('[data-action-type="addToScene"][data--u-u-i-d]');
|
||||
if (elements[guestslot]) {
|
||||
directEnable(elements[guestslot], true);
|
||||
}
|
||||
} else if (value == 2) {
|
||||
var elements = document.querySelectorAll('[data-action-type="mute-scene"][data--u-u-i-d]');
|
||||
if (elements[guestslot]) {
|
||||
directMute(elements[guestslot], true);
|
||||
}
|
||||
} else if (value == 3) {
|
||||
var elements = document.querySelectorAll('[data-action-type="mute-guest"][data--u-u-i-d]');
|
||||
if (elements[guestslot]) {
|
||||
remoteMute(elements[guestslot], true);
|
||||
}
|
||||
} else if (value == 4) {
|
||||
var elements = document.querySelectorAll('[data-action-type="hangup"][data--u-u-i-d]');
|
||||
if (elements[guestslot]) {
|
||||
directHangup(elements[guestslot], true);
|
||||
}
|
||||
} else if (value == 5) {
|
||||
var elements = document.querySelectorAll('[data-action-type="solo-chat"][data--u-u-i-d]');
|
||||
if (elements[guestslot]) {
|
||||
session.toggleSoloChat(elements[guestslot].dataset.UUID);
|
||||
}
|
||||
} else if (value == 6) {
|
||||
var elements = document.querySelectorAll('[data-action-type="toggle-remote-speaker"][data--u-u-i-d]');
|
||||
if (elements[guestslot]) {
|
||||
remoteSpeakerMute(elements[guestslot]);
|
||||
}
|
||||
} else if (value == 7) {
|
||||
var elements = document.querySelectorAll('[data-action-type="toggle-remote-display"][data--u-u-i-d]');
|
||||
if (elements[guestslot]) {
|
||||
remoteDisplayMute(elements[guestslot]);
|
||||
}
|
||||
} else if ((value => 27)) {
|
||||
var elements = document.querySelectorAll('[data-action-type="volume"][data--u-u-i-d]');
|
||||
if (elements[guestslot]) {
|
||||
elements[guestslot].value = parseInt(value-27);
|
||||
remoteVolume(elements[guestslot]);
|
||||
}
|
||||
}
|
||||
}
|
||||
midiHotkeys(command, value)
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -2958,8 +3059,6 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
var languages = getById('languagesList').querySelectorAll('li a');
|
||||
var timezones = [];
|
||||
|
||||
@ -3022,9 +3121,11 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
try {
|
||||
var Connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
|
||||
session.stats.network_type = Connection.effectiveType + " / " + Connection.type;
|
||||
Connection.addEventListener('change', updateConnectionStatus);
|
||||
} catch (e) {warnlog(e);}
|
||||
if (Connection){
|
||||
session.stats.network_type = Connection.effectiveType + " / " + Connection.type;
|
||||
Connection.addEventListener('change', updateConnectionStatus);
|
||||
}
|
||||
} catch (e) {log(e);} // effectiveType is not yet supported by Firefox or Safari; 2021
|
||||
|
||||
|
||||
setInterval(function() {
|
||||
@ -3095,6 +3196,16 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
window.onload = function winonLoad() { // This just keeps people from killing the live stream accidentally. Also give me a headsup that the stream is ending
|
||||
window.addEventListener("beforeunload", function(e) {
|
||||
|
||||
if (!session.noExitPrompt && !session.cleanOutput && (session.permaid!==false || session.director)){
|
||||
(e || window.event).returnValue = "Are you sure you want to exit?"; //Gecko + IE
|
||||
return "Are you sure you want to exit?";
|
||||
} else {
|
||||
//setTimeout(function(){session.hangup();},0);
|
||||
return undefined; // ADDED OCT 29th; get rid of popup. Just close the socket connection if the user is refreshing the page. It's one or the other.
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("unload", function(e) {
|
||||
try {
|
||||
session.ws.close();
|
||||
if (session.videoElement.recording) {
|
||||
@ -3109,18 +3220,11 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
}
|
||||
}
|
||||
session.hangup();
|
||||
} catch (e) {}
|
||||
|
||||
if (!session.noExitPrompt && !session.cleanOutput && (session.permaid!==false || session.director)){
|
||||
(e || window.event).returnValue = "Are you sure you want to exit?"; //Gecko + IE
|
||||
return "Are you sure you want to exit?";
|
||||
} else {
|
||||
//setTimeout(function(){session.hangup();},0);
|
||||
return undefined; // ADDED OCT 29th; get rid of popup. Just close the socket connection if the user is refreshing the page. It's one or the other.
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
var lastTouchEnd = 0;
|
||||
document.addEventListener('touchend', function(event) {
|
||||
var now = (new Date()).getTime();
|
||||
@ -3169,8 +3273,6 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
toggleVideoMute();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
document.addEventListener("keyup", event => {
|
||||
@ -3188,6 +3290,11 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
if (!(event.altKey)) {
|
||||
AltPressed = false;
|
||||
}
|
||||
|
||||
if (event.altKey && event.shiftKey && event.keyCode === 67 /* C */) {
|
||||
toggleControlBar();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
BIN
media/join.mp3
Normal file
BIN
media/join.mp3
Normal file
Binary file not shown.
BIN
media/join.ogg
Normal file
BIN
media/join.ogg
Normal file
Binary file not shown.
BIN
media/join.wav
Normal file
BIN
media/join.wav
Normal file
Binary file not shown.
BIN
media/leave.mp3
Normal file
BIN
media/leave.mp3
Normal file
Binary file not shown.
BIN
media/leave.ogg
Normal file
BIN
media/leave.ogg
Normal file
Binary file not shown.
BIN
media/leave.wav
Normal file
BIN
media/leave.wav
Normal file
Binary file not shown.
11
media/thirds.svg
Normal file
11
media/thirds.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<svg width="800" height="600" xmlns="http://www.w3.org/2000/svg">
|
||||
|
||||
<g>
|
||||
<title>Layer 1</title>
|
||||
<line stroke-width="2" stroke-dasharray="5,5" stroke="#000" stroke-linecap="undefined" stroke-linejoin="undefined" id="svg_1" y2="200.2" x2="798.00001" y1="200.2" x1="2.99999" fill="none"/>
|
||||
<line stroke="#000" stroke-linecap="undefined" stroke-linejoin="undefined" id="svg_3" y2="616.2" x2="266" y1="2.2" x1="266" stroke-dasharray="5,5" stroke-width="2" fill="none"/>
|
||||
<line stroke-width="2" stroke-dasharray="5,5" stroke="#000" stroke-linecap="undefined" stroke-linejoin="undefined" id="svg_4" y2="200.2" x2="798.00001" y1="200.2" x1="2.99999" fill="none"/>
|
||||
<line stroke="#000" stroke-linecap="undefined" stroke-linejoin="undefined" id="svg_5" y2="616.2" x2="534" y1="2.2" x1="534" stroke-dasharray="5,5" stroke-width="2" fill="none"/>
|
||||
<ellipse ry="132" rx="135" id="svg_6" cy="200.43469" cx="400" stroke-dasharray="5,5" stroke-width="2" stroke="#000" fill="none"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 985 B |
26
monitor.html
26
monitor.html
@ -360,11 +360,29 @@
|
||||
updateData("retransmit", 0, UUID);
|
||||
}
|
||||
|
||||
if (e.data.remoteStats[UUID].info.label){
|
||||
if (!document.getElementById("label_"+UUID)){
|
||||
document.getElementById(UUID).innerHTML = "<h1 class='small' id='label_"+UUID+"'></h1>" + document.getElementById(UUID).innerHTML;
|
||||
var streamID = false;
|
||||
if ("streamID" in e.data) {
|
||||
streamID = e.data.streamID;
|
||||
}
|
||||
if (document.getElementById(UUID)){
|
||||
if ("label" in e.data.remoteStats[UUID].info){
|
||||
if (e.data.remoteStats[UUID].info.label){
|
||||
if (!document.getElementById("label_"+UUID)){
|
||||
document.getElementById(UUID).innerHTML = "<h1 class='small' id='label_"+UUID+"'></h1>" + document.getElementById(UUID).innerHTML;
|
||||
}
|
||||
document.getElementById("label_"+UUID).innerText = e.data.remoteStats[UUID].info.label + ", - a remote viewer of stream ID: "+streamID;
|
||||
} else if (streamID){
|
||||
if (!document.getElementById("label_"+UUID)){
|
||||
document.getElementById(UUID).innerHTML = "<h1 class='small' id='label_"+UUID+"'></h1>" + document.getElementById(UUID).innerHTML;
|
||||
}
|
||||
document.getElementById("label_"+UUID).innerText = "Stats for a remote viewer of stream ID: "+streamID;
|
||||
} else {
|
||||
if (!document.getElementById("label_"+UUID)){
|
||||
document.getElementById(UUID).innerHTML = "<h1 class='small' id='label_"+UUID+"'></h1>" + document.getElementById(UUID).innerHTML;
|
||||
}
|
||||
document.getElementById("label_"+UUID).innerText = "";
|
||||
}
|
||||
}
|
||||
document.getElementById("label_"+UUID).innerText = e.data.remoteStats[UUID].info.label;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -65,11 +65,14 @@
|
||||
Testing location: <select name="turnlist" id="turnlist" onchange="reloadTurn();" title="Select an exact location to test against">
|
||||
<option selected value="">Automatic</option>
|
||||
<option value="de1">Saarbruecken, Germany</option>
|
||||
<option value="de2">Frankfurt, Germany</option>
|
||||
<option value="fr1">Strasbourg, France</option>
|
||||
<option value="bra1">São Paulo, Brazil</option>
|
||||
<option value="cae1">Montreal, Canada</option>
|
||||
<option value="usc1">Chicago, USA</option>
|
||||
<option value="usw1">Los Angeles, USA</option>
|
||||
<option value="aus1">Sidney, Australia</option>
|
||||
<option value="usw1">Los Angeles 1, USA</option>
|
||||
<option value="usw2">Los Angeles 2, USA</option>
|
||||
<option value="aus1">Sydney, Australia</option>
|
||||
<option value="jap1">Tokyo, Japan</option>
|
||||
<option value="sing1">Singapore</option>
|
||||
</select>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user