Merge pull request #900 from steveseguin/v19.3

V19.3
This commit is contained in:
Steve Seguin 2021-10-06 01:47:50 -04:00 committed by GitHub
commit d098414037
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 2751 additions and 1344 deletions

View File

@ -1,5 +1,5 @@
#### ⚠ Notice! We've started our rebranding from OBS.Ninja to VDO.Ninja 🎈 -- nothing else will be changing.
#### ⚠ Notice! We've rebranded from OBS.Ninja to VDO.Ninja - still all else the same though
<img src="https://user-images.githubusercontent.com/2575698/124821455-bbfec580-df3c-11eb-9641-3d036cdd6c41.png" data-canonical-src="https://user-images.githubusercontent.com/2575698/124821455-bbfec580-df3c-11eb-9641-3d036cdd6c41.png" width="200" />

131
esports.html Normal file
View File

@ -0,0 +1,131 @@
<html>
<head>
<title>IFRAME Example</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: #0000;
}
iframe {
border:0;
margin:0;
padding:0;
display:block;
width:100%;
height:90%
}
#viewlink {
width:400px;
}
#container {
display:block;
padding:0px;
}
input{
padding:5px;
margin:5px;
}
button{
padding:5px;
margin:5px;
}
</style>
<script>
function loadIframe(){
document.getElementById("container").innerHTML = "";
var iframe = document.createElement("iframe");
var iframeContainer = document.createElement("div");
iframe.allow = "autoplay;camera;microphone;fullscreen;picture-in-picture;display-capture;";
var iframesrc = "https://vdo.ninja/?transparent&cleanoutput&bitrate=200&manual&noaudio&view=";
var listOfStreamIDs = [
"1234_pov",
"2345_pov",
"3456_pov",
"4567_pov",
"5678_pov"
];
var button = document.createElement("button");
button.innerHTML = "List connected StreamIDs";
button.onclick = function(){iframe.contentWindow.postMessage({"getStreamIDs":true}, '*');};
iframeContainer.appendChild(button);
var button = document.createElement("button");
button.innerHTML = "HIDE ALL";
button.dataset.sid = listOfStreamIDs[i];
button.onclick = function(){iframe.contentWindow.postMessage({"target":"*", "remove":true}, '*');};
iframeContainer.appendChild(button);
for (var i=0;i<listOfStreamIDs.length;i++){
if (i!==0){
iframesrc+=",";
}
iframesrc+=listOfStreamIDs[i];
var button = document.createElement("button");
button.innerHTML = "SHOW "+listOfStreamIDs[i];
button.dataset.sid = listOfStreamIDs[i];
button.title = "Publish using: https://vdo.ninja/?push="+listOfStreamIDs[i];
button.onclick = function(){
iframe.contentWindow.postMessage({"target":"*", "remove":true}, '*');
iframe.contentWindow.postMessage({"target":this.dataset.sid, "add":true, "settings":{"style":{"width":"100%", "height":"100%", "display":"block"}}}, '*');
}; // target can be a stream ID or * for all.
iframeContainer.appendChild(button);
}
iframe.src = iframesrc;
iframeContainer.appendChild(iframe);
document.getElementById("container").appendChild(iframeContainer);
//////////// 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 ("action" in e.data){
var outputWindow = document.createElement("div");
outputWindow.innerHTML = "event: "+e.data.action+"<br />";
outputWindow.style.border="1px dotted black";
iframeContainer.appendChild(outputWindow);
}
if ("streamIDs" in e.data){
var outputWindow = document.createElement("div");
outputWindow.innerHTML = "streamID list:<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);
}
});
}
</script>
</head>
<body>
<div id="container">
<button onclick="loadIframe();">CONNECT</button>
</div>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -54,7 +54,7 @@
transition: opacity .1s linear;
}
</style>
<link rel="stylesheet" href="./main.css?ver=125" />
<link rel="stylesheet" href="./main.css?ver=141" />
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/adapter.min.js"></script>
<style id="lightbox-animations" type="text/css"></style>
</head>
@ -67,7 +67,7 @@
<link itemprop="url" href="./media/vdoNinja_logo_full.png" />
</span>
<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>
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=301"></script>
<input id="zoomSlider" type="range" style="display: none;" />
<div id="header">
@ -101,6 +101,7 @@
<span data-translate="you-are-in-the-control-center">Control center for room:</span>
<div id="dirroomid" style="font-size: 140%; color: #99c; display: inline-block;"></div>
<span id="saveRoom" onclick="saveRoom(this)" style='cursor:pointer;margin-left:10px;' title="Will remember the room, prompting you the next time you visit if you wish to load this director's room again">💾</button>
</font>
</div>
<div id="head2" class="advanced" style="display: inline-block; text-decoration: none; font-size: 60%; color: white;">
@ -241,16 +242,16 @@
<input id="broadcastFlag" type="checkbox" title="For large group rooms, this option can reduce the load on remote guests substantially" />
</th><th style="text-align:left;; padding-top: 20px;">
<b>
<span data-translate="guests-only-see-director" title="For large group rooms, this option can reduce the load on remote guests substantially" >Guests can only see the Director's Video</span>
<span data-translate="guests-only-see-director" style="cursor: help;" title="For large group rooms, this option can reduce the load on remote guests substantially" >Guests can only see the Director's Video</span>
</b>
</th>
</tr><tr>
<th style="text-align:right; padding: 5px;; padding-bottom: 20px;">
<input id="showdirectorFlag" type="checkbox" title="The director will be visible in scenes, as if a performer themselves." />
<input id="showdirectorFlag" type="checkbox" title="The director will be visible in scenes as if a performer themselves." />
</th><th style="text-align:left;; padding-bottom: 20px;">
<b>
<span data-translate="scenes-can-see-director" title="Useful if you want to perform and direct at the same time" >Director will also be a performer</span>
<span data-translate="scenes-can-see-director" style="cursor: help;" title="If checked, the director can be added to scenes as if a guest. Otherwise, the director will never appear in a scene." >Director will be performing; appearing in scenes</span>
</b>
</th>
</tr><tr>
@ -383,7 +384,7 @@
<span id="headphonesDiv" class="audioMenu">
<div class="audioTitle2">
<i class="las la-headphones"></i><span data-translate="select-output-source"> Audio Output Destination:
</span><button onclick="playtone()" class="white" style="margin:0 0 0 15px;" type="button">Test</button></div>
</span><button onclick="playtone()" class="white" style="margin:0 0 0 15px;padding: 2px 10px 0px 10px;" type="button">Test</button></div>
<select id="outputSource" ></select>
</span>
@ -396,9 +397,9 @@
<option value="3" data-translate="blurred-background">Blurred background</option>
<option value="4" data-translate="digital-greenscreen">Digital greenscreen</option>
<option value="5" data-translate="virtual-background">Virtual background</option>
<option class="advanced" value="6" data-translate="face-mesh">Face mesh (slow load)</option>
<option class="advanced" value="anon" data-translate="anonymous-mask">Anonymous mask</option>
<option class="advanced" value="dog" data-translate="dog-face">Dog ears and nose</option>
<option value="6" data-translate="face-mesh" title="experimental">Face mesh (slow load) 👨‍🔬</option>
<option value="anon" data-translate="anonymous-mask" title="experimental">Anonymous mask 👨‍🔬</option>
<option value="dog" data-translate="dog-face" title="experimental">Dog ears and nose 👨‍🔬</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='copyFunction(this,event)' >chrome://flags/#enable-webassembly-simd</a>`);">
<i class="las la-info-circle"></i>
@ -683,11 +684,15 @@
<input type="text" autocorrect="off" id="iframeURL" autocapitalize="none" style="margin:10px; border:2px solid; padding:10px; width:400px;" title="Enter an HTTPS URL" multiple/><br />
<button onclick="previewIframe(getById('iframeURL').value);" >Preview</button>
<button onclick="this.innerHTML = 'Update'; session.publishIFrame(getById('iframeURL').value);" >Share</button><br />
<small class="iframeblob">
<div class="message-card info">
<h1>Usage information</h1>
<p></p>
<ul style="text-align: left;">
<li>Not all websites will work with this feature as some sites disallow embedding.</li>
<li>The site will try to auto-optimize standard Youtube or Twitch links.</li>
<li>Remote websites must be CORS/IFrame compatible with full SSL-encryption enabled.</li>
</small>
</ul>
</div>
<div id="iFramePreview" style=" width: 1280px; height: 720px; margin: auto; padding: 10px;"></div>
</div>
<div class="outer close">
@ -737,15 +742,12 @@
<li>
Video glitching and random audio-loss can occur when using the OBS browser source. The <a href='https://github.com/steveseguin/electroncapture/blob/master/README.md'>Electron Capture app</a> avoids these issues.
</li>
<li>
A list of less common issues can <a href="https://docs.vdo.ninja/common-errors-and-known-issues/known-issues-browser-bugs-and-more">be found here</a>.
</li>
<br />
<h4 style="color:#daad09;">
👋 👀 Welcome to VDO Ninja! We've rebranded! 📼 Nothing else is changing and we're staying 100% free.
</h4>
<br />
🎁 Site updated September 7th. The <a href="https://docs.vdo.ninja/release-notes/v19">v19.0 release notes are here</a>. If new issues occur, the previous version can be <a href="https://vdo.ninja/v183/">found here</a>.
🎁 Site updated October 6th. The <a href="https://docs.vdo.ninja/release-notes/v19">v19 release notes are here</a>. If new issues occur, the previous version can be <a href="https://vdo.ninja/v183/">found here</a>.
<br />
<br />
@ -828,7 +830,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='copyFunction(this,event)' id="director_block_3" class='task grabLinks' style='cursor:copy;background-color: #0003;'></a>
<a onclick='copyFunction(this,event)' data-drag="1" draggable="true" id="director_block_3" class='task grabLinks' style='cursor:grab;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.">
@ -1339,6 +1341,32 @@
</button>
</span>
<span id="mixGroup1" class="hidden" data-cluster="2">
<button style="width:35.2px;" data-action-type="toggle-group" data-value="1" title="Add/remove from group 1" onclick="changeGroup(this);">
<span >G1</span>
</button>
<button style="width: 35.2px" data-action-type="toggle-group" data-value="2" title="Add/remove from group 2" onclick="changeGroup(this);">
<span >G2</span>
</button>
<button style="width: 35.2px" data-action-type="toggle-group" data-value="3" title="Add/remove from group 3" onclick="changeGroup(this);">
<span >G3</span>
</button>
</span>
<span id="mixGroup2" class="hidden" data-cluster="2">
<button style="width:35.2px;" data-action-type="toggle-group" data-value="4" title="Add/remove from group 4" onclick="changeGroup(this);">
<span >G4</span>
</button>
<button style="width: 35.2px" data-action-type="toggle-group" data-value="5" title="Add/remove from group 5" onclick="changeGroup(this);">
<span >G5</span>
</button>
<button style="width: 35.2px" data-action-type="toggle-group" data-value="6" title="Add/remove from group 6" onclick="changeGroup(this);">
<span >G6</span>
</button>
</span>
<button class="hidden" data-cluster="2" data-action-type="advanced-audio-settings" data-active="false" title="Remote Audio Settings" onclick="requestAudioSettings(this);">
<span data-translate="advanced-audio-settings"><i class="las la-sliders-h"></i> Audio Settings</span>
@ -1417,39 +1445,36 @@
</div>
<div id="popupSelector" style="display:none;">
<span id="videoMenu3" class="videoMenu">
<span id="videoMenu3">
<i class="las la-video"></i><span data-translate="video-source"> Video Source </span>
<select id="videoSource3" ></select>
<span id="refreshVideoButton" title="Activate or Reload this video device."><i style="top: 3px; cursor: pointer; font-size: 120%; position: relative; left: 10px;" class="las la-sync-alt"></i></span>
<span id="gear_webcam3" style="display: none; cursor:pointer;" onclick="toggle(document.getElementById('videoSettings3'));">
<span id="gear_webcam3" style="display: none; cursor:pointer;" onclick="toggleQualityGear3();">
&nbsp;&nbsp;
<i class="las la-cog" style="font-size: 135%; top:1px; vertical-align: middle;" aria-hidden="true"></i>
</span>
<span id="videoSettings3" style="display: none;">
<center>
<form id="webcamquality3">
<input type="radio" id="fullhd3" name="resolution" value="0" />
<label for="fullhd3">
<span data-translate="max-resolution">Max Resolution</span>
</label> |
<input type="radio" checked id="halfhd3" name="resolution" value="1" />
<label for="halfhd3">
<span data-translate="balanced">Balanced</span>
</label> |
<input type="radio" id="nothd3" name="resolution" value="2" />
<label for="nothd3">
<span data-translate="smooth-cool">Smooth and Cool</span>
</label>
<div id="webcamstats3" style="padding: 5px 0 0 0;"></div>
</form>
</center>
</span>
</span>
<br />
<span id="videoSettings3" style="display: none;">
<center>
<form id="webcamquality3">
<input type="radio" id="fullhd3" name="resolution" value="0" />
<label for="fullhd3">
<span data-translate="max-resolution">Max Resolution</span>
</label> |
<input type="radio" checked id="halfhd3" name="resolution" value="1" />
<label for="halfhd3">
<span data-translate="balanced">Balanced</span>
</label> |
<input type="radio" id="nothd3" name="resolution" value="2" />
<label for="nothd3">
<span data-translate="smooth-cool">Smooth and Cool</span>
</label>
<div id="webcamstats3" style="padding: 5px 0 0 0;"></div>
</form>
</center>
</span>
<br />
<div class="form-group multiselect" alt="tip: Hold CTRL (command) to select Multiple" title="tip: Hold CTRL (command) to select Multiple" >
<a id="multiselect-trigger3" class="form-control multiselect-trigger" >
@ -1476,14 +1501,14 @@
<i class="las la-robot"></i>
<span data-translate="select-digital-effect"> Digital Video Effects: </span>
</div>
<select id="effectSelector3" onchange="effectsDynamicallyUpdate(event, this, false);">
<select id="effectSelector3" onchange="effectsDynamicallyUpdate(event, this);">
<option value="0" data-translate="no-effects-applied">No effects applied</option>
<option value="3" data-translate="blurred-background">Blurred background</option>
<option value="4" data-translate="digital-greenscreen">Digital greenscreen</option>
<option value="5" data-translate="virtual-background">Virtual background</option>
<option class="advanced" value="6" data-translate="face-mesh">Face mesh (slow load)</option>
<option class="advanced" value="anon" data-translate="anonymous-mask">Anonymous mask</option>
<option class="advanced" value="dog" data-translate="dog-face">Dog ears and nose</option>
<option value="6" data-translate="face-mesh" title="experimental">Face mesh (slow load) 👨‍🔬</option>
<option value="anon" data-translate="anonymous-mask" title="experimental">Anonymous mask 👨‍🔬</option>
<option value="dog" data-translate="dog-face" title="experimental">Dog ears and nose 👨‍🔬</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='copyFunction(this,event)' target='_blank'>chrome://flags/#enable-webassembly-simd</a>`);">
<i class="las la-info-circle"></i>
@ -1501,14 +1526,16 @@
<button id="shareScreenGear" style="width: 135px; padding:20px;text-align:center;" onclick="grabScreen()"><b>Share Screen</b><br /><i style="padding:5px; font-size:300%;" class="las la-desktop"></i></button>
<button id="pIpStartButton" style="width: 135px; background-color:#EFEFEF;padding:20px;text-align:center;display:none;"><b>Preview PiP VIdeo</b><br /><i style="padding:5px; font-size:300%;color:black;" class="las la-compress-arrows-alt"></i></button>
<br />
<div class="advanced" id="grabDirectorSoloLinkParent" title="The solo view link of the Director's video."><i class="las la-user"></i> Director's solo link:<a onclick="copyFunction(this,event)" data-drag="1" draggable="true" id="grabDirectorSoloLink" class="task" ></a></div>
<br />
<button onclick="toggleSettings()" style="width: 135px; background-color:#EFEFEF;padding:9px 12px 10px 2px;margin: 0px 0px 20px 0"><i class="chevron right" style="font-size:150%;top:3px;position:relative;"></i> <b><span data-translate="close-settings">Close Settings</span></b></button>
<button id='advancedOptionsCamera' onclick="this.classList.toggle('highlight');toggle(getById('popupSelector_constraints_video'),false,false); getById('popupSelector_constraints_loading').style.visibility='visible';" class="advancedToggle"><i class="las la-sliders-h" style="font-size:150%;top:3px;position:relative;"></i> <b><span class="mobileHide" data-translate="advanced">Advanced </span>Video</b></button>
<button id='advancedOptionsAudio' onclick="this.classList.toggle('highlight');toggle(getById('popupSelector_constraints_audio'),false,false); getById('popupSelector_constraints_loading').style.visibility='visible';" class="advancedToggle"><i class="las la-sliders-h" style="font-size:150%;top:3px;position:relative;"></i> <b><span class="mobileHide" data-translate="advanced">Advanced </span>Audio</b></button>
<button id='advancedOptionsCamera' onclick="this.classList.toggle('highlight');toggle(getById('popupSelector_constraints_video'),false,false); getById('popupSelector_constraints_loading').style.visibility='visible';" class="advancedToggle"><i class="las la-sliders-h" style="font-size:150%;top:3px;position:relative;"></i> <b><span class="mobileHide" data-translate="advanced">Advanced </span>Video</b></button>
<span id="popupSelector_constraints_audio" class="popupSelector_constraints" style="display: none;">
@ -1592,8 +1619,8 @@
<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>
<span style="margin: 20px 0 0 0;display:block" id='highlightDirectorSpan' title="Only the director's video will be visible to guests and within group scenes">
<label for="highlightDirector">Highlight Director (only video guests will see)</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>
@ -1712,6 +1739,7 @@
<li><a onclick="changeLg('cn');toggle(document.getElementById('languages'));" style="cursor: pointer;" data-tz="Asia/China">Chinese (中文)</a></li>
<li><a onclick="changeLg('cs');toggle(document.getElementById('languages'));" style="cursor: pointer;" data-tz="Europe/Prague">Czech</a></li>
<li><a onclick="changeLg('uk');toggle(document.getElementById('languages'));" style="cursor: pointer;" data-tz="Europe/Ukraine">Ukrainian</a></li>
<li><a onclick="changeLg('eu');toggle(document.getElementById('languages'));" style="cursor: pointer;" data-tz="Europe/Euskara">Basque</a></li>
<li><a onclick="changeLg('pig');toggle(document.getElementById('languages'));" style="cursor: pointer;">Pig Latin</a></li>
</ul>
<br />
@ -1744,7 +1772,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 = "19.1";
session.version = "19.3";
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
@ -1810,7 +1838,7 @@
// session.width // int
// session.quality // int -- if setting == 0, then than the default resolution will be 1080p, instead of 720p
// session.sink
// session.offsetChannel // int
// session.offsetChannel /2 int
// session.audioChannels // int
// session.security
// session.framerate // int
@ -1821,11 +1849,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=66"></script>
<script type="text/javascript" crossorigin="anonymous" id="lib-js" src="./lib.js?ver=199"></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=251"></script>
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=272"></script>
</body>
</html>

2373
lib.js

File diff suppressed because it is too large Load Diff

100
main.css
View File

@ -13,6 +13,7 @@
--video-margin: 0px;
--video-rounded: 0px;
--color-mode: light;
--button-radius: 2px;
}
* {
@ -244,6 +245,8 @@ button.white:active {
cursor: help;
float: right;
font-size: 90%;
line-height:100%;
margin-top:2px;
}
#head6 {
display: inline-block;
@ -857,7 +860,6 @@ body {
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
color: var(--gray90);
font-family: "Lato", sans-serif;
padding: 0 0px;
height: 100%;
width: 100%;
@ -1506,6 +1508,14 @@ img {
position: relative;
top: 1px;
}
#previewWebcam.rotate{
max-width: 30vh;
}
#previewWebcam.rotate{
max-width: 30vh;
}
.myVideo {
box-shadow: rgb(88, 88, 88) 0px 0px 5px 1px;
max-width: 800px !important;
@ -1905,7 +1915,7 @@ audio.fileshare::-webkit-media-controls-play-button, video.fileshare::-webkit-me
}
.audioTitle2 {
text-align: left;
padding: 0px 10px 10px 1px;
padding: 0px 10px 6px 1px;
}
.multiselect .multiselect-trigger:hover {
cursor: pointer;
@ -2031,20 +2041,42 @@ audio.fileshare::-webkit-media-controls-play-button, video.fileshare::-webkit-me
.grabLinks a:visited {
color: black !important;
}
#videoSettings3 {
margin: 0 auto 15px auto;
background-color: #f3f3f3;
#grabDirectorSoloLinkParent {
text-align: left;
margin: 17px 0 0 0;
width: 450px;
background-color: #f3f3f3;
padding: 10px 10px;
border: 1px solid #ccc;
vertical-align: middle;
}
#grabDirectorSoloLink{
max-width: 100%;
line-break: anywhere;
margin:0;
display:inline-flex;
padding:4px 5px 2px 7px;
cursor:grab;
background-color: #FFF;
color:darkblue;
}
#videoSettings3 {
background-color: #f3f3f3;
width: 100%;
padding: 7px 10px 1px 10px;
border: 1px solid #ccc;
font-size: 90%;
margin: 10px 0 0 0;
}
#videoSource3 {
display: inline-block;
vertical-align: middle;
padding: 3px;
font-size: 93%;
max-width: 370px;
max-width: 240px;
}
#outputSource {
display: inline-block;
@ -2085,6 +2117,17 @@ audio.fileshare::-webkit-media-controls-play-button, video.fileshare::-webkit-me
vertical-align: middle;
text-align: left;
}
#videoMenu3{
background-color: #f3f3f3;
width: 450px;
max-width:100%;
display: block;
padding: 10px 10px;
border: 1px solid #ccc;
vertical-align: middle;
text-align: left;
margin: 0 0 15px 0;
}
.audioMenu{
text-align: left;
@ -2384,7 +2427,7 @@ input[type=checkbox] {
background-color: var(--container-color);
width:1191px;
padding: 10px;
margin: 10px;
margin: 5px 10px 10px 10px;
}
.directorContainer {
background-color: var(--container-color);
@ -3263,6 +3306,10 @@ input:checked + .slider:before {
content: "\f544"; }
.la-info-circle:before {
content: "\f05a"; }
.la-play:before {
content: "\f04b"; }
.la-play-circle:before {
content: "\f144"; }
.la.la-hdd-o:before {
content: "\f0a0"; }
.la-key:before {
@ -3277,6 +3324,8 @@ input:checked + .slider:before {
content: "\f518"; }
.la-caret-down:before {
content: "\f0d7"; }
.la-comments:before {
content: "\f086"; }
.la-caret-right:before {
content: "\f0da"; }
.la-copy:before {
@ -3351,7 +3400,11 @@ input:checked + .slider:before {
content: "\f12a"; }
.la-chevron-down:before {
content: "\f078"; }
.la-music:before {
content: "\f001"; }
.la-hdd:before {
content: "\f0a0"; }
@media (prefers-color-scheme: dark) {
:root {
--color-mode: dark;
@ -3388,7 +3441,6 @@ body.darktheme button {
filter: brightness(0.70);
}
body.darktheme .las {
filter: brightness(0.85);
}
body.darktheme label {
filter: brightness(0.85);
@ -3455,40 +3507,43 @@ body.darktheme #webcamstats2{
background-color: #949494;
}
body.darktheme #audioSourceScreenshare{
background-color: #AAA;
background-color: #c1c1c1;
}
body.darktheme #headphonesDiv2{
background-color: #949494;
}
body.darktheme #outputSourceScreenshare{
background-color: #AAA;
background-color: #c1c1c1;
}
body.darktheme #audioSource{
background-color: #AAA;
background-color: #c1c1c1;
}
body.darktheme #outputSource{
background-color: #AAA;
background-color: #c1c1c1;
}
body.darktheme #videoSourceSelect{
background-color: #AAA;
background-color: #c1c1c1;
}
body.darktheme #videoSettings{
background-color: #949494;
}
body.darktheme #effectSelector{
background-color: #AAA;
background-color: #c1c1c1;
}
body.darktheme #effectSelector3{
background-color: #AAA;
background-color: #c1c1c1;
}
body.darktheme #audioSource3{
background-color: #AAA;
background-color: #c1c1c1;
}
body.darktheme #videoSource3{
background-color: #AAA;
background-color: #c1c1c1;
}
body.darktheme #videoMenu3{
background-color: #949494;
}
body.darktheme #outputSource3{
background-color: #AAA;
background-color: #c1c1c1;
}
body.darktheme #videoSettings3{
background-color: #949494;
@ -3503,3 +3558,10 @@ body.darktheme .alertModal{
body.darktheme .directorContainer{
filter: brightness(0.85);
}
body.darktheme #grabDirectorSoloLinkParent{
background-color: #949494;
}
body.darktheme #grabDirectorSoloLink{
background-color: #c1c1c1;
}

169
main.js
View File

@ -116,6 +116,8 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
// session.sticky = confirm("Would you allow us to store a cookie to keep your session settings persistent?");
//} else {
session.sticky = true;
getById("saveRoom").style.display = "none";
//}
//if (session.sticky) {
setStorage("permission", "yes", 999);
@ -220,7 +222,6 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
}
}
if (urlParams.has('broadcast') || urlParams.has('bc')) {
log("Broadcast flag set");
session.broadcast = urlParams.get('broadcast') || urlParams.get('bc') || null;
@ -251,6 +252,10 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
}
}
if (urlParams.has('meshcast')) {
session.meshcast = urlParams.get('meshcast') || "both";
}
var filename = false;
try {
filename = window.location.pathname.substring(window.location.pathname.lastIndexOf('/') + 1);
@ -313,8 +318,14 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
getById("rooms").classList.remove('advanced');
}
if (urlParams.has('showdirector')) {
session.showDirector = true;
if (urlParams.has('showdirector') || urlParams.has('sd')) {
session.showDirector = urlParams.get('showdirector') || urlParams.get('sd') || true;
}
if (urlParams.has('rotate') ) {
session.rotate = urlParams.get('rotate') || 90;
session.rotate = parseInt(session.rotate);
}
if (urlParams.has('midi') || urlParams.has('hotkeys')) {
@ -339,9 +350,23 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
}
if (urlParams.has('webcam') || urlParams.has('wc')) {
if (urlParams.has('webcam') || urlParams.has('wc') || urlParams.has('miconly')) {
session.webcamonly = true;
screensharebutton = false;
if (urlParams.has('miconly')){
session.videoDevice=0;
getById("add_camera").innerHTML = "Share your Microphone";
miniTranslate(getById("add_camera"), "share-your-mic");
getById("videoMenu").style.display = "none";
//session.autostart = true;
getById("mutevideobutton").style.setProperty("display", "none", "important");
getById("videoMenu3").style.setProperty("display", "none", "important");
//if (session.consent){
// setTimeout(function(){
// warnUser("⚠ Privacy warning: The director of this room can remotely switch your camera or microphone without permission.", 8000);
// }, 1500);
//}
}
} else if (urlParams.has('screenshare') || urlParams.has('ss')) {
session.screenshare = true;
if (urlParams.get('screenshare') || urlParams.get('ss')){
@ -473,6 +498,10 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
session.aspectratio = 2; //1:1 ?
}
if (urlParams.has('forceaspectratio') || urlParams.has('far')) {
session.forceAspectRatio = true; // 9:16 (default of 0 is 16:9)
}
if (urlParams.has('cover')) {
session.cover = true;
document.documentElement.style.setProperty('--fit-style', 'cover');
@ -508,8 +537,8 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
}
if (urlParams.has('scene')) {
session.scene = urlParams.get('scene') || 0;
if (urlParams.has('scene') || urlParams.has('scn')) {
session.scene = urlParams.get('scene') || urlParams.get('scn') || 0;
if (typeof session.scene === "string"){
session.scene = session.scene.replace(/[\W]+/g, "_");
} else {
@ -582,6 +611,14 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
} else {
getById("main").classList.remove('hidden');
}
if (urlParams.has("base64css") || urlParams.has("b64css") || urlParams.has("cssbase64") || urlParams.has("cssb64")) {
var base64Css = urlParams.get("base64css") || urlParams.get("b64css") || urlParams.get("cssbase64") || urlParams.get("cssb64");
var css = decodeURIComponent(atob(base64Css)); // window.btoa(encodeURIComponent("#mainmenu{background-color: pink; ❤" ));
var cssStyleSheet = document.createElement("style");
cssStyleSheet.innerText = css;
document.querySelector("head").appendChild(cssStyleSheet);
};
if (urlParams.has("base64css") || urlParams.has("b64css")) {
var base64Css = urlParams.get("base64css") || urlParams.get("b64css");
@ -1084,10 +1121,9 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
if ((ver1.length == 3) && (parseInt(ver1[0]) == 2) && (cefVersion < 76) && (navigator.userAgent.indexOf('Mac OS X') != -1)) {
updateURL("streamlabs");
getById("main").innerHTML = "<div style='background-color:black;color:white;' data-translate='obs-macos-not-supported'><h1>Update OBS Studio to v26.1.2 or newer; older versions and StreamLabs OBS are not supported on macOS.\
<br /><i><small><small>download here: <a href='https://github.com/obsproject/obs-studio/releases/tag/26.1.2'>https://github.com/obsproject/obs-studio/releases/tag/26.1.2</a></small></small></i>\
<br /><i><small><small>download here: <a href='https://github.com/obsproject/obs-studio/releases'>https://github.com/obsproject/obs-studio/releases</a></small></small></i>\
</h1> <br /><br />\
<h2>Please use the <a href='https://github.com/steveseguin/electroncapture'>Electron Capture app</a> if there are further problems or if you wish to use StreamLabs on macOS still.</h2>\
<br />You can find more details <u><a href='https://github.com/steveseguin/obsninja/wiki/FAQ#mac-os'>within our wiki guide - https://github.com/steveseguin/obsninja/wiki/FAQ#mac-os</a></u></h2>\
<br /> You can bypass this error message by refreshing, <a href='" + window.location.href + "'> Clicking Here,</a> or by adding <i>&streamlabs</i> to the URL, but it may still not actually work.\
\
<br /> Please report this problem to steve@seguin.email if you feel it is an error.\
@ -1380,8 +1416,26 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
}
if (urlParams.has('order')) {
session.order = parseInt(urlParams.get('order')) || 0;
session.order = parseInt(urlParams.get('order')) || 1;
}
if (urlParams.has('slot')) {
session.slot = parseInt(urlParams.get('slot')) || 0;
}
if (urlParams.has('debug')){
debugStart();
}
if (urlParams.has('group')) {
session.group = urlParams.get('group') || "";
session.group = session.group.split(",");
}
if (urlParams.has('groupaudio') || urlParams.has('ga')) {
session.groupAudio = true;
}
if (urlParams.has('sensors') || urlParams.has('sensor') || urlParams.has('gyro') || urlParams.has('gyros') || urlParams.has('accelerometer')) {
session.sensorData = urlParams.get('sensors') || urlParams.get('sensor') || urlParams.get('gyro') || urlParams.get('gyros') || urlParams.get('accelerometer') || 30;
session.sensorData = parseInt(session.sensorData);
@ -1708,6 +1762,15 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
log("framerate Changed");
log(session.framerate);
}
if (urlParams.has('tz')){
session.tz = urlParams.get('tz');
if ((session.tz === null) || (session.tz === "")){
session.tz = false;
} else {
session.tz = parseInt(session.tz);
}
}
if (urlParams.has('maxframerate') || urlParams.has('mfr') || urlParams.has('mfps')) {
session.maxframerate = urlParams.get('maxframerate') || urlParams.get('mfr') || urlParams.get('mfps');
@ -1728,9 +1791,9 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
}
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.panning = urlParams.get('panning') || urlParams.get('pan');
if (session.panning===""){
session.panning=true
}
session.audioEffects = true;
}
@ -1839,16 +1902,16 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
// image = 5
}
if (!(getChromeVersion()>=57)){
getById("effectSelector").disabled=true;
getById("effectSelector3").disabled=true;
getById("effectSelector").title = "Effects are only support on Chromium-based browsers";
getById("effectSelector3").title = "Effects are only support on Chromium-based browsers";
var elementsTmp = document.querySelectorAll('[data-effectsNotice]');
for (let i = 0; i < elementsTmp.length; i++) {
elementsTmp[i].style.display = "inline-block";
}
}
//if (!(getChromeVersion()>=57)){
// getById("effectSelector").disabled=true;
// getById("effectSelector3").disabled=true;
// getById("effectSelector").title = "Effects are only support on Chromium-based browsers";
// getById("effectSelector3").title = "Effects are only support on Chromium-based browsers";
// var elementsTmp = document.querySelectorAll('[data-effectsNotice]');
// for (let i = 0; i < elementsTmp.length; i++) {
// elementsTmp[i].style.display = "inline-block";
// }
//}
if (urlParams.has('viewereffect') || urlParams.has('viewereffects') || urlParams.has('ve')) {
@ -1856,17 +1919,22 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
}
if (urlParams.has('activespeaker') || urlParams.has('speakerview') || urlParams.has('sas')){
session.activeSpeaker = true;
session.activeSpeaker = urlParams.get('activespeaker') || urlParams.get('speakerview') || urlParams.get('sas') || 1;
session.activeSpeaker = parseInt(session.activeSpeaker);
session.audioEffects = true;
session.audioMeterGuest = true;
//session.animatedMoves = false;
session.minipreview = 2;
if (session.activeSpeaker==1){
session.animatedMoves = false;
}
session.fadein=true;
document.querySelector(':root').style.setProperty('--fadein-speed', 0.5);
setInterval(function(){activeSpeaker(false);},100);
} else if (urlParams.has('noisegate')){
session.quietOthers = true;
session.quietOthers = urlParams.get('noisegate') || 1;
session.quietOthers = parseInt(session.quietOthers);
session.audioEffects = true;
session.audioMeterGuest = true;
setInterval(function(){activeSpeaker(false);},100);
@ -2320,7 +2388,16 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
getById("translateButton").style.display = "none";
log("Update Mixer Event on REsize SET");
window.onresize = updateMixer;
window.onorientationchange = function(){setTimeout(updateMixer, 200);};
window.onorientationchange = function(){
setTimeout(updateMixer, 200);
//if (session.effects){
// if (session.streamSrc){
// setTimeout(function(){
// updateRenderOutpipe(session.streamSrc, true);
// },500);
// }
//}
};
joinRoom(session.roomid); // this is a scene, so we want high resolutions
getById("main").style.overflow = "hidden";
@ -2917,6 +2994,44 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
errorlog(e);
}
}
if ("getDetailedState" in e.data) {
var detailedState = {};
for (var UUID in session.rpcs){
if (!session.rpcs[UUID].streamID){continue;}
detailedState[session.rpcs[UUID].streamID] = {};
var scenes = getById("container_" + UUID).querySelectorAll('[data-action-type="addToScene"][data-scene][data--u-u-i-d="'+UUID+'"]');
var sceneState = {};
for (var i=0;i<scenes.length;i++){
if (parseInt(scenes[i].dataset.value)){
sceneState[scenes[i].dataset.scene] = true;
} else {
sceneState[scenes[i].dataset.scene] = false;
}
}
detailedState[session.rpcs[UUID].streamID].scenes = sceneState;
}
if (session.showDirector){
if (document.getElementById("container_director")){
detailedState[session.streamID] = {};
var scenes = getById("container_director").querySelectorAll('[data-action-type="addToScene"][data-scene]');
var sceneState = {};
for (var i=0;i<scenes.length;i++){
if (parseInt(scenes[i].dataset.value)){
sceneState[scenes[i].dataset.scene] = true;
} else {
sceneState[scenes[i].dataset.scene] = false;
}
}
detailedState[session.streamID].scenes = sceneState;
}
}
parent.postMessage({
"detailedState": detailedState
}, "*");
}
if ("automixer" in e.data) {
if (e.data.automixer == true) {

View File

@ -218,9 +218,9 @@ ol {
margin:auto;
}
}
}
#statsdiv {display: none;}
#statsdiv {display: none;}

View File

@ -184,7 +184,7 @@
var iframe = document.createElement("iframe");
var iframeContainer = document.createElement("span");
iframe.allow="autoplay;camera;microphone";
iframe.allow="autoplay;camera;microphone;display-capture;";
iframe.allowtransparency="true";
iframe.allowfullscreen ="true";

File diff suppressed because one or more lines are too long