mirror of
https://github.com/eliasstepanik/vdo.ninja.git
synced 2026-01-11 05:38:31 +00:00
fixed bug with pie / socket server
This commit is contained in:
parent
2bbda7fa19
commit
f57df65c4b
25
examples/changepass.html
Normal file
25
examples/changepass.html
Normal file
@ -0,0 +1,25 @@
|
||||
<html><body><script>
|
||||
var generateHash = function (str, length=false){
|
||||
var buffer = new TextEncoder("utf-8").encode(str);
|
||||
return crypto.subtle.digest("SHA-256", buffer).then(
|
||||
function (hash) {
|
||||
hash = new Uint8Array(hash);
|
||||
if (length){
|
||||
hash = hash.slice(0, parseInt(parseInt(length)/2));
|
||||
}
|
||||
hash = toHexString(hash);
|
||||
return hash;
|
||||
}
|
||||
);
|
||||
};
|
||||
function toHexString(byteArray){
|
||||
return Array.prototype.map.call(byteArray, function(byte){
|
||||
return ('0' + (byte & 0xFF).toString(16)).slice(-2);
|
||||
}).join('');
|
||||
}
|
||||
var password = prompt("Please enter the password");
|
||||
|
||||
generateHash(password + location.hostname, 4).then(function(hash) { // million to one error.
|
||||
alert("hash value: "+hash)
|
||||
});
|
||||
</script></body></html>
|
||||
331
examples/dual.html
Normal file
331
examples/dual.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>
|
||||
3
examples/mini.css
Normal file
3
examples/mini.css
Normal file
@ -0,0 +1,3 @@
|
||||
.tile {
|
||||
max-width:200px !important;
|
||||
}
|
||||
172
examples/status.html
Normal file
172
examples/status.html
Normal file
@ -0,0 +1,172 @@
|
||||
<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%;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin:0;
|
||||
background-color: #0000;
|
||||
color: white;
|
||||
font-family: Cousine, monospace;
|
||||
font-size: 3.2em;
|
||||
line-height: 1.1em;
|
||||
letter-spacing: 0.0em;
|
||||
text-transform: uppercase;
|
||||
padding: 0em;
|
||||
text-shadow: 0.05em 0.05em 0px rgba(0,0,0,1);
|
||||
max-width:100%;
|
||||
}
|
||||
|
||||
ul li {
|
||||
background-color: black;
|
||||
padding: 8px 8px 0px 8px;
|
||||
margin:0;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
hyphens: auto;
|
||||
max-width:100%;
|
||||
}
|
||||
|
||||
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 log = document.body.getElementsByTagName("ul")[0];
|
||||
var entry = document.createElement('li');
|
||||
if (type){
|
||||
type = "<i>"+type+"</i>";
|
||||
}
|
||||
entry.innerHTML = type + data;
|
||||
|
||||
//setTimeout(function(entry){ // hide message after 60 seconds
|
||||
// entry.innerHTML="";
|
||||
// entry.remove();
|
||||
// },60000,entry);
|
||||
|
||||
log.appendChild(entry);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="loadIframe();">
|
||||
<ul></ul>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
133
examples/webhid.html
Normal file
133
examples/webhid.html
Normal file
@ -0,0 +1,133 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>WebHID Demo</title>
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: black;
|
||||
border: none;
|
||||
color: #00FF00;
|
||||
padding: 15px 32px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
margin: 4px 2px;
|
||||
cursor: pointer;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
#connected {
|
||||
font-size: 24px;
|
||||
max-height:700px;
|
||||
overflow-y:scroll
|
||||
}
|
||||
#disconnectButton {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>STREAMDECK DEMO</h1>
|
||||
<img src="./media/streamdeck.png" /><br />
|
||||
<input class="button" type="button" id="connectButton" value="Connect" />
|
||||
<input class="button" type="button" id="disconnectButton" style="display:none" value="Disconnect" />
|
||||
<div id="connected" style>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const connectButton = document.getElementById("connectButton");
|
||||
const disconnectButton = document.getElementById("disconnectButton");
|
||||
const connect = document.getElementById("connect");
|
||||
const deviceButtonPressed = document.getElementById("deviceButtonPressed");
|
||||
var lastState = false;
|
||||
//productId: 0x0060,
|
||||
//class: models_1.StreamDeckOriginal,
|
||||
|
||||
//productId: 0x0063,
|
||||
//class: models_1.StreamDeckMini,
|
||||
|
||||
//productId: 0x006c,
|
||||
//class: models_1.StreamDeckXL,
|
||||
|
||||
//productId: 0x006d,
|
||||
//class: models_1.StreamDeckOriginalV2,
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
let devices = await navigator.hid.getDevices();
|
||||
devices.forEach(device => {
|
||||
console.log(`HID: ${device.productName}`);
|
||||
});
|
||||
});
|
||||
|
||||
function handleInputReport(e) {
|
||||
console.log(e.device.productName + ": got input report " + e.reportId);
|
||||
console.log(new Uint8Array(e.data.buffer));
|
||||
var data = new Uint8Array(e.data.buffer);
|
||||
if (lastState!==false){
|
||||
for (var i=0;i<data.length;i++){
|
||||
|
||||
if (parseInt(data[i])!=data[i]){continue;}
|
||||
if (lastState[i]!==data[i]){
|
||||
if (data[i]){
|
||||
document.getElementById("connected").innerHTML = "<br />Button "+(i+1)+" Pressed"+document.getElementById("connected").innerHTML;
|
||||
} else {
|
||||
document.getElementById("connected").innerHTML = "<br />Button "+(i+1)+" Released"+document.getElementById("connected").innerHTML;
|
||||
}
|
||||
} else {
|
||||
if (data[i]){
|
||||
document.getElementById("connected").innerHTML = "<br />Button "+(i+1)+" Pressed"+document.getElementById("connected").innerHTML;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lastState = data;
|
||||
}
|
||||
|
||||
let device;
|
||||
|
||||
connectButton.onclick = async () => {
|
||||
navigator.hid.requestDevice({
|
||||
filters: [{ vendorId: 0x0fd9}] // elgato?
|
||||
}).then((devices)=>{
|
||||
console.log(devices);
|
||||
|
||||
device = devices[0];
|
||||
|
||||
console.log(`HID connected: ${device.productName}`);
|
||||
document.getElementById("connected").innerHTML = "<br />Connected" +document.getElementById("connected").innerHTML;
|
||||
document.getElementById("disconnectButton").style.display = "inline-block";
|
||||
device.addEventListener("inputreport", handleInputReport);
|
||||
|
||||
//device.sendReport(outputReportId, outputReport).then(() => {
|
||||
// console.log("Sent output report " + outputReportId);
|
||||
//});
|
||||
|
||||
if (!device.opened){
|
||||
device.open().then(()=>{
|
||||
window.addEventListener("onbeforeunload", async () => {
|
||||
await device.close();
|
||||
});
|
||||
}).catch(function(err){console.error(err);});
|
||||
}
|
||||
}).catch(function(err){console.error(err);});
|
||||
|
||||
};
|
||||
|
||||
disconnectButton.onclick = async () => {
|
||||
await device.close();
|
||||
|
||||
//connected.style.display = "none";
|
||||
//connectButton.style.display = "initial";
|
||||
disconnectButton.style.display = "none";
|
||||
};
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
182
examples/zoom.html
Normal file
182
examples/zoom.html
Normal file
@ -0,0 +1,182 @@
|
||||
|
||||
<html>
|
||||
<head><style>
|
||||
span{margin:10px 0 0 0;display:block;}
|
||||
body {
|
||||
|
||||
background-color:#cdf;
|
||||
padding:0;
|
||||
width;100%;height:100%
|
||||
}
|
||||
|
||||
input{padding:5px;}
|
||||
|
||||
button {margin:10px 3px;}
|
||||
|
||||
#stream{
|
||||
display:block;
|
||||
}
|
||||
|
||||
</style></head>
|
||||
<body id="main" style="margin:5%;"
|
||||
<meta charset="utf-8"/>
|
||||
|
||||
<video id="video" autoplay="true" muted="true" playsinline style='height:420px;background-color:black;display:block;margin:0 0 10px 0;'></video>
|
||||
<div id="devices">
|
||||
<div class="select">
|
||||
<label for="videoSource">Video source: </label><select id="videoSource"></select>
|
||||
</div>
|
||||
<div class="select">
|
||||
<label for="audioSource">Audio source: </label><select id="audioSource"></select>
|
||||
</div>
|
||||
</div>
|
||||
<button onclick="fullwindow()">FULL WINDOW</button>
|
||||
<script>
|
||||
window.onerror = function backupErr(errorMsg, url=false, lineNumber=false) {
|
||||
console.error(errorMsg);
|
||||
console.error(lineNumber);
|
||||
console.error("Unhandeled Error occured"); //or any message
|
||||
return false;
|
||||
};
|
||||
|
||||
function fullwindow(){
|
||||
videoElement.style.width="100%";
|
||||
videoElement.style.padding= "0";
|
||||
videoElement.style.margin="0";
|
||||
videoElement.style.height="100%";
|
||||
videoElement.style.zIndex="5";
|
||||
videoElement.style.position = "absolute";
|
||||
videoElement.style.top="0px";
|
||||
videoElement.style.left="0px";
|
||||
document.getElementById("main").style.overflow = "hidden";
|
||||
videoElement.style.overflow = "hidden"
|
||||
document.getElementById("main").style.backgroundColor="#000";
|
||||
videoElement.style.cursor="none";
|
||||
document.getElementById("main").style.cursor="none";
|
||||
}
|
||||
|
||||
var videoElement = document.getElementById("video");
|
||||
var gotDev = false;
|
||||
async function gotDevices() {
|
||||
if (gotDev){return;}
|
||||
gotDev=true;
|
||||
await navigator.mediaDevices.getUserMedia({audio:true, video:true}); // is needed to ask for permissinos.
|
||||
navigator.mediaDevices.enumerateDevices().then((deviceInfos)=>{
|
||||
for (let i = 0; i !== deviceInfos.length; ++i) {
|
||||
var deviceInfo = deviceInfos[i];
|
||||
var option = document.createElement("option");
|
||||
option.value = deviceInfo.deviceId;
|
||||
|
||||
if (deviceInfo.kind === "audioinput") {
|
||||
option.text = deviceInfo.label || "microphone " + (audioSelect.length + 1);
|
||||
audioSelect.appendChild(option);
|
||||
if (option.text.startsWith("CABLE")){
|
||||
option.selected =true;
|
||||
}
|
||||
} else if (deviceInfo.kind === "videoinput") {
|
||||
option.text = deviceInfo.label || "camera " + (videoSelect.length + 1);
|
||||
if (option.text.startsWith("NewTek")){
|
||||
continue;
|
||||
}
|
||||
videoSelect.appendChild(option);
|
||||
if (option.text.startsWith("OBS")){
|
||||
option.selected =true;
|
||||
}
|
||||
}
|
||||
}
|
||||
getStream();
|
||||
});
|
||||
}
|
||||
|
||||
function getStream() {
|
||||
if (window.stream) {
|
||||
window.stream.getTracks().forEach(function (track) {
|
||||
track.stop();
|
||||
log("TRack stopping");
|
||||
});
|
||||
}
|
||||
|
||||
const constraints = {
|
||||
audio: {
|
||||
deviceId: { exact: audioSelect.value },
|
||||
echoCancellation : false,
|
||||
autoGainControl : false,
|
||||
noiseSuppression : false
|
||||
},
|
||||
video: {
|
||||
deviceId: { exact: videoSelect.value },
|
||||
width: { min: 1280, ideal: 1920, max: 1920 },
|
||||
height: { min: 720, ideal: 1080, max: 1080 }
|
||||
}
|
||||
};
|
||||
return navigator.mediaDevices.getUserMedia(constraints)
|
||||
.then(gotStream)
|
||||
.catch(console.error);
|
||||
}
|
||||
|
||||
|
||||
function gotStream(stream) {
|
||||
if (window.stream) {
|
||||
window.stream = stream; // make stream available to console
|
||||
videoElement.srcObject = stream;
|
||||
var senders = session.pc.getSenders();
|
||||
videoElement.srcObject.getVideoTracks().forEach((track)=>{
|
||||
var added = false;
|
||||
senders.forEach((sender) => { // I suppose there could be a race condition between negotiating and updating this. if joining at the same time as changnig streams?
|
||||
if (sender.track) {
|
||||
if (sender.track && sender.track.kind == "video") {
|
||||
sender.replaceTrack(track); // replace may not be supported by all browsers. eek.
|
||||
track.enabled = notCensored;
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (added==false){
|
||||
session.pc.addTrack(track);
|
||||
log("ADDED NOT REPLACED?");
|
||||
}
|
||||
});
|
||||
|
||||
videoElement.srcObject.getAudioTracks().forEach((track)=>{
|
||||
var added = false;
|
||||
senders.forEach((sender) => { // I suppose there could be a race condition between negotiating and updating this. if joining at the same time as changnig streams?
|
||||
if (sender.track) {
|
||||
if (sender.track && sender.track.kind == "audio") {
|
||||
sender.replaceTrack(track); // replace may not be supported by all browsers. eek.
|
||||
track.enabled = notCensored;
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (added==false){
|
||||
session.pc.addTrack(track);
|
||||
log("ADDED NOT REPLACED?");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
window.stream = stream; // make stream available to console
|
||||
videoElement.srcObject = stream;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var audioSelect = document.querySelector("select#audioSource");
|
||||
var videoSelect = document.querySelector("select#videoSource");
|
||||
audioSelect.onchange = getStream;
|
||||
videoSelect.onchange = getStream;
|
||||
gotDevices();
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -68,7 +68,7 @@
|
||||
<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=207"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=208"></script>
|
||||
<input id="zoomSlider" type="range" style="display: none;" />
|
||||
<div id="header">
|
||||
|
||||
@ -495,6 +495,8 @@
|
||||
</option>
|
||||
</select>
|
||||
</span>
|
||||
<br />
|
||||
<span data-translate="application-audio-capture">For application-specific audio capture, <a href='https://docs.vdo.ninja/audio' style='color: #007AC8;'>see here</a></span>
|
||||
</div>
|
||||
<div class="outer close">
|
||||
<div class="inner">
|
||||
@ -1338,7 +1340,7 @@
|
||||
<button data-action-type="recorder-local" title="Start Recording this remote stream to this local drive. *experimental*'" onclick="recordLocalVideoToggle();">
|
||||
<i class="las la-circle"></i>
|
||||
<span data-translate="record-local"> Record</span>
|
||||
</button>
|
||||
</button>
|
||||
|
||||
<span>
|
||||
<button style="width:34px;" data-action-type="order-down" title="Shift this Video Down in Order" onclick="changeOrderDirector(-1);">
|
||||
|
||||
134
lib.js
134
lib.js
@ -397,7 +397,11 @@ function warnUser(message, timeout=false){
|
||||
}
|
||||
|
||||
zindex = 31 + document.querySelectorAll('.alertModal').length;
|
||||
message = message.replace(/\n/g,"<br />");
|
||||
try{
|
||||
message = message.replace(/\n/g,"<br />");
|
||||
} catch(e){
|
||||
errorlog(message);
|
||||
}
|
||||
modalTemplate =
|
||||
`<div class="alertModal" id="alertModal" style="z-index:${zindex + 2}">
|
||||
<div class="alertModalInner">
|
||||
@ -2437,6 +2441,14 @@ function updateUserList(){
|
||||
},200);
|
||||
}
|
||||
|
||||
|
||||
function resetCanvas(){
|
||||
session.streamSrc.getVideoTracks().forEach((track) => {
|
||||
session.canvasSource.width = track.getSettings().width || 1280;
|
||||
session.canvasSource.height = track.getSettings().height || 720;
|
||||
});
|
||||
}
|
||||
|
||||
var LaunchTFWorkerCallback = false;
|
||||
function TFLiteWorker(){
|
||||
if (session.tfliteModule==false){
|
||||
@ -2471,6 +2483,8 @@ function TFLiteWorker(){
|
||||
function process(){
|
||||
if (session.tfliteModule.activelyProcessing){return;}
|
||||
session.tfliteModule.activelyProcessing=true;
|
||||
|
||||
|
||||
try{
|
||||
segmentationMaskCtx.drawImage(
|
||||
session.canvasSource,
|
||||
@ -3441,7 +3455,7 @@ function directorSendMessage(ele) {
|
||||
inputField.style.margin = "5px 10px 5px 10px";
|
||||
inputField.style.padding = "5px";
|
||||
|
||||
target.appendChild(inputField);
|
||||
|
||||
|
||||
var sendButton = document.createElement("button");
|
||||
sendButton.innerHTML = "<i class='las la-reply'></i> send message ";
|
||||
@ -3501,6 +3515,7 @@ function directorSendMessage(ele) {
|
||||
target.appendChild(closeButton);
|
||||
target.appendChild(sendButton);
|
||||
target.appendChild(overlayMsg);
|
||||
target.appendChild(inputField);
|
||||
ele.parentNode.appendChild(target);
|
||||
inputField.focus();
|
||||
inputField.select();
|
||||
@ -4661,7 +4676,7 @@ session.publishIFrame = function(iframeURL){
|
||||
container.id = "container";
|
||||
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.allow = "autoplay;camera;microphone;fullscreen;picture-in-picture;transparency;";
|
||||
iframe.allow = "autoplay;camera;microphone;fullscreen;picture-in-picture;";
|
||||
iframe.src = session.iframeSrc;
|
||||
iframe.id = "iframe_source"
|
||||
session.iframeEle = iframe;
|
||||
@ -7706,17 +7721,17 @@ function resetupAudioOut() {
|
||||
|
||||
function obfuscateURL(input) {
|
||||
if (input.startsWith("https://obs.ninja/")) {
|
||||
input = input.replace('https://obs.ninja/', '');
|
||||
input = input.replace('https://obs.ninja/', 'obs.ninja/');
|
||||
} else if (input.startsWith("http://obs.ninja/")) {
|
||||
input = input.replace('http://obs.ninja/', '');
|
||||
input = input.replace('http://obs.ninja/', 'obs.ninja/');
|
||||
} else if (input.startsWith("obs.ninja/")) {
|
||||
input = input.replace('obs.ninja/', '');
|
||||
input = input.replace('obs.ninja/', 'obs.ninja/');
|
||||
} else if (input.startsWith("https://vdo.ninja/")) {
|
||||
input = input.replace('https://vdo.ninja/', '');
|
||||
input = input.replace('https://vdo.ninja/', 'vdo.ninja/');
|
||||
} else if (input.startsWith("http://vdo.ninja/")) {
|
||||
input = input.replace('http://vdo.ninja/', '');
|
||||
input = input.replace('http://vdo.ninja/', 'vdo.ninja/');
|
||||
} else if (input.startsWith("vdo.ninja/")) {
|
||||
input = input.replace('vdo.ninja/', '');
|
||||
input = input.replace('vdo.ninja/', 'vdo.ninja/');
|
||||
}
|
||||
|
||||
input = input.replace('&view=', '&v=');
|
||||
@ -7902,25 +7917,66 @@ if (navigator.userAgent.toLowerCase().indexOf(' electron/') > -1) { // this ena
|
||||
window.navigator.mediaDevices.getDisplayMedia = () => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
|
||||
if (session.autostart){
|
||||
var sscid = 0
|
||||
if (typeof session.screenshare === "number"){
|
||||
sscid = session.screenshare-1;
|
||||
if (sscid<0){sscid=0;}
|
||||
if (parseInt(session.screenshare)+"" === session.screenshare){
|
||||
var sscid = parseInt(session.screenshare)-1;
|
||||
if (sscid<0){sscid=0;}
|
||||
const sources = await desktopCapturer.getSources({ types: ['screen'] });
|
||||
const stream = await window.navigator.mediaDevices.getUserMedia({
|
||||
audio: false,
|
||||
video: {
|
||||
mandatory: {
|
||||
chromeMediaSource: 'desktop',
|
||||
chromeMediaSourceId: sources[sscid].id,
|
||||
maxFrameRate: 60
|
||||
}
|
||||
}
|
||||
});
|
||||
resolve(stream);
|
||||
} else if (session.screenshare!==true){
|
||||
var sscid=null;
|
||||
const sources = await desktopCapturer.getSources({ types: ['window'] });
|
||||
for (var i=0; i<sources.length;i++){
|
||||
if (sources[i].name.startsWith(session.screenshare)){ // check if anythign starts with
|
||||
sscid=i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sscid===null){
|
||||
sscid = 0; // grab first window if nothing.
|
||||
for (var i=0; i<sources.length;i++){
|
||||
if (sources[i].name.includes(session.screenshare)){ // check if something includes the string; fallback
|
||||
sscid=i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
const stream = await window.navigator.mediaDevices.getUserMedia({
|
||||
audio: false,
|
||||
video: {
|
||||
mandatory: {
|
||||
chromeMediaSource: 'desktop',
|
||||
chromeMediaSourceId: sources[sscid].id,
|
||||
maxFrameRate: 60
|
||||
}
|
||||
}
|
||||
});
|
||||
resolve(stream);
|
||||
} else {
|
||||
var sscid = 0;
|
||||
const sources = await desktopCapturer.getSources({ types: ['screen'] });
|
||||
const stream = await window.navigator.mediaDevices.getUserMedia({
|
||||
audio: false,
|
||||
video: {
|
||||
mandatory: {
|
||||
chromeMediaSource: 'desktop',
|
||||
chromeMediaSourceId: sources[sscid].id,
|
||||
maxFrameRate: 60
|
||||
}
|
||||
}
|
||||
});
|
||||
resolve(stream);
|
||||
}
|
||||
const sources = await desktopCapturer.getSources({ types: ['screen'] });
|
||||
const stream = await window.navigator.mediaDevices.getUserMedia({
|
||||
audio: false,
|
||||
video: {
|
||||
mandatory: {
|
||||
chromeMediaSource: 'desktop',
|
||||
chromeMediaSourceId: sources[sscid].id,
|
||||
maxFrameRate: 60
|
||||
}
|
||||
}
|
||||
});
|
||||
resolve(stream)
|
||||
} else {
|
||||
const sources = await desktopCapturer.getSources({ types: ['screen', 'window'] });
|
||||
const selectionElem = document.createElement('div');
|
||||
@ -7984,7 +8040,7 @@ if (navigator.userAgent.toLowerCase().indexOf(' electron/') > -1) { // this ena
|
||||
}
|
||||
ElectronDesktopCapture = true;
|
||||
} catch(e){
|
||||
warnlog("couldn't load electron's screen capture; you might need to decrease security permissions a bit.");
|
||||
warnlog("Couldn't load electron's screen capture. Elevate the app's permission to allow it (right-click?)");
|
||||
}
|
||||
}
|
||||
|
||||
@ -10387,7 +10443,7 @@ function dragElement(elmnt) {
|
||||
function previewIframe(iframesrc) { // 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 iframe = document.createElement("iframe");
|
||||
iframe.allow = "autoplay;camera;microphone;fullscreen;transparency;picture-in-picture;";
|
||||
iframe.allow = "autoplay;camera;microphone;fullscreen;picture-in-picture;";
|
||||
iframe.style.width = "100%";
|
||||
iframe.style.height = "100%";
|
||||
iframe.style.border = "10px dashed rgb(64 65 62)";
|
||||
@ -10437,7 +10493,7 @@ function previewIframe(iframesrc) { // this is pretty important if you want to a
|
||||
function loadIframe(iframesrc) { // 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 iframe = document.createElement("iframe");
|
||||
iframe.allow = "autoplay;camera;microphone;fullscreen;transparency;picture-in-picture;";
|
||||
iframe.allow = "autoplay;camera;microphone;fullscreen;picture-in-picture;";
|
||||
iframe.style.width = "100%";
|
||||
iframe.style.height = "100%";
|
||||
iframe.style.border = "10px dashed rgb(64 65 62)";
|
||||
@ -12268,8 +12324,7 @@ function createIframePopup() {
|
||||
}
|
||||
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.allow = "autoplay;camera;microphone;fullscreen;picture-in-picture;transparency;";
|
||||
iframe.allowtransparency = "true";
|
||||
iframe.allow = "autoplay;camera;microphone;fullscreen;picture-in-picture;";
|
||||
|
||||
var extras = "";
|
||||
if (session.password){
|
||||
@ -13391,11 +13446,18 @@ function getChatMessage(msg, label = false, director = false, overlay = false) {
|
||||
|
||||
function updateClosedCaptions(msg, label, UUID) {
|
||||
msg.counter = parseInt(msg.counter);
|
||||
var transcript = sanitizeChat(msg.transcript); // keep it clean.
|
||||
var temp = document.createElement('div');
|
||||
temp.innerText = msg.transcript;
|
||||
temp.innerText = temp.innerHTML;
|
||||
var transcript = temp.textContent || temp.innerText || "";
|
||||
|
||||
if (transcript == "") {
|
||||
return;
|
||||
}
|
||||
transcript = transcript.toUpperCase();
|
||||
|
||||
transcript = transcript.charAt(0).toUpperCase() + transcript.slice(1);
|
||||
//transcript = transcript.substr(-1, 5000); // keep it from being too long
|
||||
|
||||
|
||||
if (label) {
|
||||
label = sanitizeLabel(label);
|
||||
@ -14653,6 +14715,7 @@ function attemptTFLiteJsFileLoad(){
|
||||
if (session.tfliteModule!==false){
|
||||
return true;
|
||||
}
|
||||
warnUser("Loading effects model...");
|
||||
TFLITELOADING=true;
|
||||
session.tfliteModule={};
|
||||
|
||||
@ -14685,7 +14748,8 @@ async function changeTFLiteImage(ev, ele){
|
||||
|
||||
|
||||
async function loadTFLiteModel(){
|
||||
try{
|
||||
try {
|
||||
|
||||
if (session.tfliteModule && (session.tfliteModule.img)){
|
||||
var img = session.tfliteModule.img;
|
||||
session.tfliteModule = await createTFLiteSIMDModule();
|
||||
@ -14702,6 +14766,7 @@ async function loadTFLiteModel(){
|
||||
}
|
||||
} catch(e){
|
||||
warnlog("TF-LITE FAILED TO LOAD");
|
||||
closeModal();
|
||||
return;
|
||||
}
|
||||
const modelResponse = await fetch("./thirdparty/tflite/segm_full_v679.tflite");
|
||||
@ -14711,6 +14776,7 @@ async function loadTFLiteModel(){
|
||||
session.tfliteModule._loadModel(session.tfliteModule.model.byteLength);
|
||||
session.tfliteModule.activelyProcessing = false;
|
||||
TFLITELOADING = false;
|
||||
closeModal();
|
||||
if ((session.effects>=3) && (session.effects<=5)){
|
||||
if (document.getElementById("videosource")){
|
||||
activatedPreview=false;
|
||||
|
||||
3
main.css
3
main.css
@ -368,9 +368,6 @@ hr {
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
margin: var(--video-margin);
|
||||
transition-property: all;
|
||||
transition-duration: 1s;
|
||||
transition-timing-function: ease-in;
|
||||
}
|
||||
|
||||
#gridlayout {
|
||||
|
||||
12
main.js
12
main.js
@ -286,7 +286,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
} else if (urlParams.has('screenshare') || urlParams.has('ss')) {
|
||||
session.screenshare = true;
|
||||
if (urlParams.get('screenshare') || urlParams.get('ss')){
|
||||
session.screenshare = parseInt(urlParams.get('screenshare'));
|
||||
session.screenshare = urlParams.get('screenshare') || urlParams.get('ss');
|
||||
}
|
||||
} else if (urlParams.has('fileshare') || urlParams.has('fs')) {
|
||||
getById("container-5").classList.remove('advanced');
|
||||
@ -2362,16 +2362,18 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
document.head.appendChild(script4);
|
||||
}
|
||||
script4.onload = function() {
|
||||
closeModal();
|
||||
async function loadModel(){
|
||||
model = await faceLandmarksDetection.load(faceLandmarksDetection.SupportedPackages.mediapipeFacemesh);
|
||||
|
||||
}
|
||||
loadModel();
|
||||
}
|
||||
script.src = "https://unpkg.com/@tensorflow/tfjs-core@2.4.0/dist/tf-core.js";
|
||||
script2.src = "https://unpkg.com/@tensorflow/tfjs-converter@2.4.0/dist/tf-converter.js";
|
||||
script3.src = "https://unpkg.com/@tensorflow/tfjs-backend-webgl@2.4.0/dist/tf-backend-webgl.js";
|
||||
script4.src = "https://unpkg.com/@tensorflow-models/face-landmarks-detection@0.0.1/dist/face-landmarks-detection.js";
|
||||
script.src = "./thirdparty/tfjs/tf-core.js";
|
||||
script2.src = "./thirdparty/tfjs/tf-converter.js";
|
||||
script3.src = "./thirdparty/tfjs/tf-backend-webgl.js";
|
||||
script4.src = "./thirdparty/tfjs/face-landmarks-detection.js";
|
||||
warnUser("Loading effects model...");
|
||||
|
||||
script.type = 'text/javascript';script2.type = 'text/javascript';script3.type = 'text/javascript';script4.type = 'text/javascript';
|
||||
document.head.appendChild(script);
|
||||
|
||||
5
thirdparty/ffmpeg.min.js
vendored
Normal file
5
thirdparty/ffmpeg.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1497
thirdparty/tfjs/face-landmarks-detection.js
vendored
Normal file
1497
thirdparty/tfjs/face-landmarks-detection.js
vendored
Normal file
File diff suppressed because one or more lines are too long
16300
thirdparty/tfjs/tf-backend-webgl.js
vendored
Normal file
16300
thirdparty/tfjs/tf-backend-webgl.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
thirdparty/tfjs/tf-backend-webgl.js.map
vendored
Normal file
1
thirdparty/tfjs/tf-backend-webgl.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
8058
thirdparty/tfjs/tf-converter.js
vendored
Normal file
8058
thirdparty/tfjs/tf-converter.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
thirdparty/tfjs/tf-converter.js.map
vendored
Normal file
1
thirdparty/tfjs/tf-converter.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
27681
thirdparty/tfjs/tf-core.js
vendored
Normal file
27681
thirdparty/tfjs/tf-core.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
thirdparty/tfjs/tf-core.js.map
vendored
Normal file
1
thirdparty/tfjs/tf-core.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user