mirror of
https://github.com/eliasstepanik/vdo.ninja.git
synced 2026-01-11 05:38:31 +00:00
v14 release version
This commit is contained in:
parent
a0e765fa4d
commit
94e6380081
231
animations.js
231
animations.js
@ -1,178 +1,121 @@
|
||||
/* We need to create dynamic keyframes to show the animation from full-screen to normal. So we create a stylesheet in which we can insert CSS keyframe rules */
|
||||
$("body").append('<style id="lightbox-animations" type="text/css"></style>');
|
||||
$(".column").on('click', function() {
|
||||
if ( $(this).hasClass( "skip-animation" )){
|
||||
return;
|
||||
}
|
||||
var bounding_box = $(this).get(0).getBoundingClientRect();
|
||||
$(this).css({ top: bounding_box.top + 'px', left: bounding_box.left -20+ 'px' });
|
||||
$(this).addClass('in-animation').removeClass('pointer');
|
||||
$("#empty-container").remove();
|
||||
$('<div id="empty-container" class="column"></div>').insertAfter(this);
|
||||
|
||||
/* Click on the container */
|
||||
$(".column").on('click', function () {
|
||||
/* The position of the container will be set to fixed, so set the top & left properties of the container */
|
||||
var styles = '';
|
||||
styles = '@keyframes outlightbox {';
|
||||
styles += '0% {';
|
||||
styles += 'height: 100%;';
|
||||
styles += 'width: 100%;';
|
||||
styles += 'top: 0px;';
|
||||
styles += 'left: 0px;';
|
||||
styles += '}';
|
||||
styles += '50% {';
|
||||
styles += 'height: 220px;';
|
||||
styles += 'top: ' + bounding_box.y + 'px;';
|
||||
styles += '}';
|
||||
styles += '100% {';
|
||||
styles += 'height: 220px;';
|
||||
styles += 'width: '+bounding_box.width+'px;';
|
||||
styles += 'top: ' + bounding_box.y + 'px;';
|
||||
styles += 'left: ' + bounding_box.x + 'px;';
|
||||
styles += '}';
|
||||
styles += '}';
|
||||
|
||||
if ($(this).hasClass("skip-animation")) {
|
||||
return;
|
||||
}
|
||||
$("#lightbox-animations").empty();
|
||||
$("#lightbox-animations").get(0).sheet.insertRule(styles, 0);
|
||||
$("body").css('overflow', 'hidden');
|
||||
});
|
||||
|
||||
$(".close").on('click', function(e) {
|
||||
$(this).hide();
|
||||
$(".container-inner").hide();
|
||||
$("body").css('overflow', 'auto');
|
||||
var bounding_box = $(this).parent().get(0).getBoundingClientRect();
|
||||
$(this).parent().css({ top: bounding_box.top + 'px', left: bounding_box.left + 'px' });
|
||||
$(this).parent().addClass('out-animation');
|
||||
cleanupMediaTracks();
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
const bounding_box = $(this).get(0).getBoundingClientRect();
|
||||
$(this).css({
|
||||
top: bounding_box.top + 'px',
|
||||
left: bounding_box.left - 20 + 'px'
|
||||
});
|
||||
|
||||
/* Set container to fixed position. Add animation */
|
||||
$(this).addClass('in-animation').removeClass('pointer');
|
||||
|
||||
/* An empty container has to be added in place of the lightbox container so that the elements below don't come up
|
||||
Dimensions of this empty container is the same as the original container */
|
||||
$("#empty-container").remove();
|
||||
$('<div id="empty-container" class="column"></div>').insertAfter(this);
|
||||
|
||||
/* To animate the container from full-screen to normal, we need dynamic keyframes */
|
||||
let styles = '';
|
||||
styles = '@keyframes outlightbox {';
|
||||
styles += '0% {';
|
||||
styles += 'height: 100%;';
|
||||
styles += 'width: 100%;';
|
||||
styles += 'top: 0px;';
|
||||
styles += 'left: 0px;';
|
||||
styles += '}';
|
||||
styles += '50% {';
|
||||
styles += 'height: 220px;';
|
||||
styles += 'top: ' + bounding_box.y + 'px;';
|
||||
styles += '}';
|
||||
styles += '100% {';
|
||||
styles += 'height: 220px;';
|
||||
styles += 'width: ' + bounding_box.width + 'px;';
|
||||
styles += 'top: ' + bounding_box.y + 'px;';
|
||||
styles += 'left: ' + bounding_box.x + 'px;';
|
||||
styles += '}';
|
||||
styles += '}';
|
||||
|
||||
/* Add keyframe to CSS */
|
||||
$("#lightbox-animations").empty();
|
||||
$("#lightbox-animations").get(0).sheet.insertRule(styles, 0);
|
||||
|
||||
/* Hide the window scrollbar */
|
||||
$("body").css('overflow', 'hidden');
|
||||
$(".column").on('animationend', function(e){
|
||||
if (e.originalEvent.animationName == 'inlightbox') {
|
||||
$(this).children(".close").show();
|
||||
$(this).children(".container-inner").show();
|
||||
}
|
||||
else if (e.originalEvent.animationName == 'outlightbox') {
|
||||
$(this).removeClass('in-animation').removeClass('out-animation').removeClass('columnfade').addClass('pointer');
|
||||
$("#empty-container").remove();
|
||||
$("#lightbox-animations").get(0).sheet.deleteRule(0);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/* Click on close button when full-screen */
|
||||
$(".close").on('click', function (e) {
|
||||
$(this).hide();
|
||||
$(".container-inner").hide();
|
||||
|
||||
$("body").css('overflow', 'auto');
|
||||
|
||||
const bounding_box = $(this).parent().get(0).getBoundingClientRect();
|
||||
$(this).parent().css({top: `${
|
||||
bounding_box.top
|
||||
}px`, left: `${
|
||||
bounding_box.left
|
||||
}px`});
|
||||
|
||||
/* Show animation */
|
||||
$(this).parent().addClass('out-animation');
|
||||
|
||||
|
||||
try {
|
||||
|
||||
const oldstream = getById('previewWebcam').srcObject;
|
||||
|
||||
if (oldstream) {
|
||||
log("old stream found");
|
||||
oldstream.getTracks().forEach((track) => {
|
||||
track.stop();
|
||||
oldstream.removeTrack(track);
|
||||
log("stopping old track");
|
||||
});
|
||||
}
|
||||
activatedPreview = false;
|
||||
} catch (er) {
|
||||
errorlog(er);
|
||||
}
|
||||
log("Cleaned up Video");
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
/* On animationend : from normal to full screen & full screen to normal */
|
||||
$(".column").on('animationend', function (e) {
|
||||
/* On animation end from normal to full-screen */
|
||||
if (e.originalEvent.animationName == 'inlightbox') {
|
||||
$(this).children(".close").show();
|
||||
$(this).children(".container-inner").show();
|
||||
}
|
||||
/* On animation end from full-screen to normal */ else if (e.originalEvent.animationName == 'outlightbox') {
|
||||
/* Remove fixed positioning, remove animation rules */
|
||||
$(this).removeClass('in-animation').removeClass('out-animation').removeClass('columnfade').addClass('pointer');
|
||||
|
||||
/* Remove the empty container that was earlier added */
|
||||
$("#empty-container").remove();
|
||||
|
||||
/* Delete the dynamic keyframe rule that was earlier created */
|
||||
$("#lightbox-animations").get(0).sheet.deleteRule(0);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$('#audioSource').on('mousedown touchend focusin focusout', (_e) => {
|
||||
const state = $('#multiselect-trigger').data('state') || 0;
|
||||
if (state == 0) {
|
||||
// //open the dropdown
|
||||
$('#audioSource').on('mousedown touchend focusin focusout', function(e) {
|
||||
var state = $('#multiselect-trigger').data('state') || 0;
|
||||
if( state == 0 ) {
|
||||
$('#multiselect-trigger').data('state', '1').addClass('open').removeClass('closed');
|
||||
$('#multiselect-trigger').find('.chevron').removeClass('bottom');
|
||||
$('#multiselect-trigger').find('.chevron').removeClass('bottom');
|
||||
$('#multiselect-trigger').parent().find('.multiselect-contents').show();
|
||||
$('#multiselect-trigger').parent().find('.multiselect-contents').find('input[type="checkbox"]').parent().show();
|
||||
$('#multiselect-trigger').parent().find('.multiselect-contents').find('input[type="checkbox"]').show();
|
||||
}
|
||||
// e.preventDefault();
|
||||
$('#multiselect-trigger').parent().find('.multiselect-contents').find('input[type="checkbox"]').parent().show();;
|
||||
$('#multiselect-trigger').parent().find('.multiselect-contents').find('input[type="checkbox"]').show();;
|
||||
}
|
||||
});
|
||||
|
||||
$('#audioSource3').on('mousedown touchend focusin focusout', (_e) => {
|
||||
const state = $('#multiselect-trigger3').attr('data-state') || 0;
|
||||
if (state == 0) {
|
||||
// //open the dropdown
|
||||
$('#audioSource3').on('mousedown touchend focusin focusout', function(e) {
|
||||
var state = $('#multiselect-trigger3').attr('data-state') || 0;
|
||||
if( state == 0 ) {
|
||||
$('#multiselect-trigger3').attr('data-state', '1').addClass('open').removeClass('closed');
|
||||
$('#multiselect-trigger3').find('.chevron').removeClass('bottom');
|
||||
$('#multiselect-trigger3').find('.chevron').removeClass('bottom');
|
||||
$('#multiselect-trigger3').parent().find('.multiselect-contents').show();
|
||||
$('#multiselect-trigger3').parent().find('.multiselect-contents').find('input[type="checkbox"]').parent().show();
|
||||
$('#multiselect-trigger3').parent().find('.multiselect-contents').find('input[type="checkbox"]').show();
|
||||
}
|
||||
// e.preventDefault();
|
||||
$('#multiselect-trigger3').parent().find('.multiselect-contents').find('input[type="checkbox"]').parent().show();;
|
||||
$('#multiselect-trigger3').parent().find('.multiselect-contents').find('input[type="checkbox"]').show();;
|
||||
}
|
||||
});
|
||||
|
||||
// multiselect dropdowns
|
||||
$('#multiselect-trigger').on('mousedown touchend focusin focusout', function (e) {
|
||||
const state = $(this).data('state') || 0;
|
||||
if (state == 0) {
|
||||
|
||||
$('#multiselect-trigger').on('mousedown touchend focusin focusout', function(e) {
|
||||
var state = $(this).data('state') || 0;
|
||||
if( state == 0 ) {
|
||||
// open the dropdown
|
||||
$(this).data('state', '1').addClass('open').removeClass('closed');
|
||||
$(this).find('.chevron').removeClass('bottom');
|
||||
$(this).parent().find('.multiselect-contents').show();
|
||||
$(this).parent().find('.multiselect-contents').find('input[type="checkbox"]').parent().show();
|
||||
$(this).parent().find('.multiselect-contents').find('input[type="checkbox"]').show();
|
||||
$(this).parent().find('.multiselect-contents').find('input[type="checkbox"]').parent().show();;
|
||||
$(this).parent().find('.multiselect-contents').find('input[type="checkbox"]').show();;
|
||||
} else {
|
||||
// close the dropdown
|
||||
$(this).data('state', '0').addClass('closed').removeClass('open');
|
||||
$(this).find('.chevron').addClass('bottom');
|
||||
$(this).parent().find('.multiselect-contents').find('input[type="checkbox"]').not(":checked").parent().hide();
|
||||
$(this).parent().find('.multiselect-contents').find('input[type="checkbox"]').hide();
|
||||
} e.preventDefault();
|
||||
$(this).parent().find('.multiselect-contents').find('input[type="checkbox"]').not(":checked").parent().hide();;
|
||||
$(this).parent().find('.multiselect-contents').find('input[type="checkbox"]').hide();;
|
||||
}
|
||||
e.preventDefault();
|
||||
});
|
||||
// multiselect dropdowns
|
||||
$('#multiselect-trigger3').on('mousedown touchend focusin focusout', function (e) {
|
||||
const state = $(this).attr('data-state') || 0;
|
||||
|
||||
if (state == 0) {
|
||||
$('#multiselect-trigger3').on('mousedown touchend focusin focusout', function(e) {
|
||||
var state = $(this).attr('data-state') || 0;
|
||||
|
||||
if( state == 0 ) {
|
||||
// open the dropdown
|
||||
errorlog("STATE: " + state);
|
||||
errorlog("STATE: "+state);
|
||||
$(this).attr('data-state', '1').addClass('open').removeClass('closed');
|
||||
$(this).find('.chevron').removeClass('bottom');
|
||||
$(this).parent().find('.multiselect-contents').show();
|
||||
$(this).parent().find('.multiselect-contents').find('input[type="checkbox"]').parent().show();
|
||||
$(this).parent().find('.multiselect-contents').find('input[type="checkbox"]').show();
|
||||
$(this).parent().find('.multiselect-contents').find('input[type="checkbox"]').parent().show();;
|
||||
$(this).parent().find('.multiselect-contents').find('input[type="checkbox"]').show();;
|
||||
} else {
|
||||
// close the dropdown
|
||||
$(this).attr('data-state', '0').addClass('closed').removeClass('open');
|
||||
$(this).find('.chevron').addClass('bottom');
|
||||
$(this).parent().find('.multiselect-contents').find('input[type="checkbox"]').not(":checked").parent().hide();
|
||||
$(this).parent().find('.multiselect-contents').find('input[type="checkbox"]').hide();
|
||||
} e.preventDefault();
|
||||
$(this).parent().find('.multiselect-contents').find('input[type="checkbox"]').not(":checked").parent().hide();;
|
||||
$(this).parent().find('.multiselect-contents').find('input[type="checkbox"]').hide();;
|
||||
}
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
74
convert.html
Normal file
74
convert.html
Normal file
@ -0,0 +1,74 @@
|
||||
<body>
|
||||
<video id="player" controls style="display:none"></video>
|
||||
<div id="info">
|
||||
<h3>This tool can be used to convert WebM videos of dynamic resolution to MP4 files of a fixed 1280x720 resolution.</h3> Just select a video file and wait. It takes about 60-seconds to transcode 1-second of video. Very sloowww...<br />
|
||||
<p>You can use FFMpeg locally to achieve much faster results.</p>
|
||||
<p>This tool performs the following action in your browser: <i>fmpeg -i input.webm -vf scale=1280:720 output.mp4</i><p>
|
||||
<input type="file" id="uploader" title="Convert WebM to MP4">
|
||||
<hr>
|
||||
<h3>Bonus: This option converts MKV files to MP4 files without transcoding.</h3> </p><i>fmpeg -i INPUTFILE -vcodec copy -acodec copy output.mp4</i>
|
||||
<br /><br /><input type="file" id="uploader2" accept=".mkv" title="Convert MKV to MP4">
|
||||
<p>You can use FFMpeg locally to achieve much faster results with either option.</p>
|
||||
<h3>This option converts WebM files to MP4 files without transcoding, and attempting to force high resolutions.
|
||||
<br /><br /><input type="file" id="uploader3" accept=".webm" title="Convert WebM to MP4">
|
||||
|
||||
</div>
|
||||
<script src="https://unpkg.com/@ffmpeg/ffmpeg@0.9.6/dist/ffmpeg.min.js"></script>
|
||||
<script>
|
||||
const { createFFmpeg, fetchFile } = FFmpeg;
|
||||
const ffmpeg = createFFmpeg({ log: true });
|
||||
const transcode = async ({ target: { files } }) => {
|
||||
const { name } = files[0];
|
||||
document.getElementById('uploader').style.display="none";
|
||||
document.getElementById('uploader2').style.display="none";
|
||||
document.getElementById('uploader3').style.display="none";
|
||||
document.getElementById('info').innerText = "Transcoding file... this will take a while";
|
||||
await ffmpeg.load();
|
||||
ffmpeg.FS('writeFile', name, await fetchFile(files[0]));
|
||||
await ffmpeg.run('-i', name, '-vf', 'scale=1280:720', 'output.mp4');
|
||||
const data = ffmpeg.FS('readFile', 'output.mp4');
|
||||
const video = document.getElementById('player');
|
||||
video.src = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));
|
||||
video.style.display="block";
|
||||
document.getElementById('info').innerText = "Operation Done. Play video or download it.";
|
||||
}
|
||||
const transmux = async ({ target: { files } }) => {
|
||||
const { name } = files[0];
|
||||
document.getElementById('uploader').style.display="none";
|
||||
document.getElementById('uploader2').style.display="none";
|
||||
document.getElementById('uploader3').style.display="none";
|
||||
document.getElementById('info').innerText = "Transcoding file... this will take a while";
|
||||
await ffmpeg.load();
|
||||
ffmpeg.FS('writeFile', name, await fetchFile(files[0]));
|
||||
await ffmpeg.run('-i', name, '-vcodec', 'copy', '-acodec', 'copy', 'output.mp4');
|
||||
const data = ffmpeg.FS('readFile', 'output.mp4');
|
||||
const video = document.getElementById('player');
|
||||
video.src = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));
|
||||
video.style.display="block";
|
||||
document.getElementById('info').innerText = "Operation Done. Play video or download it.";
|
||||
}
|
||||
|
||||
const force1080 = async ({ target: { files } }) => {
|
||||
const { name } = files[0];
|
||||
const sourceBuffer = await fetch("cap.webm").then(r => r.arrayBuffer());
|
||||
document.getElementById('uploader').style.display="none";
|
||||
document.getElementById('uploader2').style.display="none";
|
||||
document.getElementById('uploader3').style.display="none";
|
||||
document.getElementById('info').innerText = "Tweaking file... this will take a moment";
|
||||
await ffmpeg.load();
|
||||
ffmpeg.FS('writeFile', name, await fetchFile(files[0]));
|
||||
ffmpeg.FS("writeFile","cap.webm", new Uint8Array(sourceBuffer, 0, sourceBuffer.byteLength));
|
||||
|
||||
await ffmpeg.run("-i", "concat:cap.webm|"+name, "-safe", "0", "-c", "copy", "-avoid_negative_ts", "1", "-strict", "experimental", "output.mp4");
|
||||
const data = ffmpeg.FS('readFile', 'output.mp4');
|
||||
const video = document.getElementById('player');
|
||||
video.src = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));
|
||||
video.style.display="block";
|
||||
document.getElementById('info').innerText = "Operation Done. Play video or download it.";
|
||||
}
|
||||
|
||||
document.getElementById('uploader').addEventListener('change', transcode);
|
||||
document.getElementById('uploader2').addEventListener('change', transmux);
|
||||
document.getElementById('uploader3').addEventListener('change', force1080);
|
||||
</script>
|
||||
</body>
|
||||
28
iframe.html
28
iframe.html
@ -314,7 +314,33 @@ function loadIframe(){ // this is pretty important if you want to avoid camera
|
||||
|
||||
}
|
||||
|
||||
|
||||
if ("sensors" in e.data){
|
||||
console.log(e.data);
|
||||
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";
|
||||
}
|
||||
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 />";
|
||||
}
|
||||
outputWindow.style.border="1px black";
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
BIN
images/mic-animate.gif
Normal file
BIN
images/mic-animate.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.3 KiB |
BIN
images/mic-slash.gif
Normal file
BIN
images/mic-slash.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 807 B |
BIN
images/mic.gif
Normal file
BIN
images/mic.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 489 B |
508
index.html
508
index.html
@ -14,7 +14,7 @@
|
||||
}
|
||||
|
||||
</script>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<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" />
|
||||
<meta content="utf-8" http-equiv="encoding" />
|
||||
<meta name="copyright" content="© 2020 Steve Seguin" />
|
||||
@ -47,12 +47,12 @@
|
||||
<meta property="twitter:image" content="./images/obsNinja_logo_full.png" />
|
||||
<meta name="msapplication-TileColor" content="#da532c" />
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
<!-- <script src="//console.re/connector.js" data-channel="obsninjadev" type="text/javascript" id="consolerescript"></script>-->
|
||||
<link rel="stylesheet" href="./lineawesome/css/line-awesome.min.css">
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/adapter-latest.js"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/qrcode.min.js"></script>
|
||||
<script type="text/javascript" src="./thirdparty/jquery.min.js"></script>
|
||||
<link rel="stylesheet" href="./main.css?ver=23" />
|
||||
<script type="text/javascript" src="./thirdparty/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="./thirdparty/aes.js"></script>
|
||||
<link rel="stylesheet" href="./main.css?ver=30" />
|
||||
</head>
|
||||
<body id="main" class="hidden">
|
||||
<span itemprop="image" itemscope itemtype="image/png">
|
||||
@ -62,8 +62,8 @@
|
||||
<span itemprop="thumbnail" itemscope itemtype="http://schema.org/ImageObject">
|
||||
<link itemprop="url" href="./images/obsNinja_logo_full.png" />
|
||||
</span>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/CodecsHandler.js?ver=23"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=125"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/CodecsHandler.js?ver=26"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=146"></script>
|
||||
<input id="zoomSlider" type="range" style="display: none;" />
|
||||
<div id="header">
|
||||
<a id="logoname" href="./" style="text-decoration: none; color: white; margin: 2px;">
|
||||
@ -98,7 +98,7 @@
|
||||
</font>
|
||||
</div>
|
||||
<div id="head2" class="advanced" style="display: inline-block; text-decoration: none; font-size: 60%; color: white;">
|
||||
<span data-translate="joining-room">You are joining room</span>:
|
||||
<span data-translate="joining-room">You are in room</span>:
|
||||
|
||||
<div id="roomid" style="display: inline-block;"></div>
|
||||
</div>
|
||||
@ -109,7 +109,7 @@
|
||||
<i id="chattoggle" class="toggleSize las la-comment-alt my-float"></i>
|
||||
<div id="chatNotification"></div>
|
||||
</div>
|
||||
<div id="mutespeakerbutton" title="Mute the Speaker" onclick="toggleSpeakerMute()" class="advanced float" style="cursor: pointer;" alt="Toggle the speaker output">
|
||||
<div id="mutespeakerbutton" title="Mute the Speaker" onclick="toggleSpeakerMute()" class="advanced float" style="cursor: pointer;" alt="Toggle the speaker output.">
|
||||
<i id="mutespeakertoggle" class="toggleSize las la-volume-up my-float" style="position: relative; top: 0.5px;"></i>
|
||||
</div>
|
||||
<div id="mutebutton" title="Mute the Mic" onclick="toggleMute()" class="advanced float" style="cursor: pointer;" alt="Toggle the mic">
|
||||
@ -137,7 +137,7 @@
|
||||
id="reportbutton"
|
||||
title="Submit any error logs"
|
||||
onclick="submitDebugLog();"
|
||||
style="cursor: pointer; visibility: hidden; display:none;"
|
||||
style="cursor: pointer; visibility: hidden; display:none;z-index:7;"
|
||||
>
|
||||
<i style="float: right; bottom: 0px; cursor: pointer; position: fixed; right: 46px; color: #d9e4eb; padding: 2px; margin: 2px 2px 0 0; font-size: 140%;" class="las la-bug" aria-hidden="true"></i>
|
||||
</span>
|
||||
@ -223,8 +223,10 @@
|
||||
<u>
|
||||
<i>Important Tips:</i><br /><br />
|
||||
</u>
|
||||
<li>Disabling video sharing between guests will improve performance</li>
|
||||
<li>Invite only guests to the room that you trust.</li>
|
||||
<li>The "Recording" option is considered experimental.</li>
|
||||
<li><a href="https://params.obs.ninja" style="color:black;"><u>Advanced URL parameters</u></a> are available to customize rooms.</li>
|
||||
</span>
|
||||
</ul>
|
||||
</div>
|
||||
@ -243,7 +245,7 @@
|
||||
<div class="container-inner">
|
||||
<br />
|
||||
<p>
|
||||
<video id="previewWebcam" class="previewWebcam" oncanplay="updateStats();" disablePictureInPicture controlsList="nodownload" muted autoplay playsinline ></video>
|
||||
<video id="previewWebcam" class="previewWebcam" oncanplay="updateStats();" controlsList="nodownload" muted autoplay playsinline ></video>
|
||||
</p>
|
||||
<div id="infof"></div>
|
||||
<button onclick="this.disabled=true;setTimeout(function(){requestBasicPermissions();},20);" id="getPermissions" style="display:none;" data-ready="false" >
|
||||
@ -262,7 +264,7 @@
|
||||
<span id="videoMenu" class="videoMenu">
|
||||
<i class="las la-video"></i><span data-translate="video-source"> Video Source </span>
|
||||
|
||||
<select id="videoSource" ></select>
|
||||
<select id="videoSourceSelect" ></select>
|
||||
<span id="gear_webcam" style="display: inline-block; cursor:pointer;" onclick="toggle(document.getElementById('videoSettings'));">
|
||||
|
||||
<i class="las la-cog" style="font-size: 140%; vertical-align: middle;" aria-hidden="true"></i>
|
||||
@ -403,7 +405,9 @@
|
||||
<h2>
|
||||
<span data-translate="create-reusable-invite">Create Reusable Invite</span>
|
||||
</h2>
|
||||
<div id="gencontent2" style="display:none;background-color: rgb(221, 221, 221); max-height: 100%;min-height: 90%;"></div>
|
||||
<div id="gencontent" class="container-inner">
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<span data-translate="here-you-can-pre-generate">Here you can pre-generate a reusable Browser Source link and a related guest invite link.</span>
|
||||
@ -471,6 +475,12 @@
|
||||
<span data-translate="allow-remote-control" title="Hold CTRL and the mouse wheel to zoom in and out remotely of compatible video streams">Remote Control Camera Zoom (android)</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="invite_setting_item">
|
||||
<input type="checkbox" id="invite_obfuscate" />
|
||||
<label for="invite_obfuscate">
|
||||
<span data-translate="obfuscate_url" title="Encode the URL so that it's harder for a guest to modify the settings.">Obfuscate the Invite URL</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="invite_setting_item">
|
||||
<span data-translate="add-a-password-to-stream" title="Add a password to make the stream inaccessible to those without the password"> Add a password:</span>
|
||||
<input id="invite_password" placeholder="Add an optional password" />
|
||||
@ -511,9 +521,11 @@
|
||||
<div class="container-inner">
|
||||
|
||||
<br /><br />
|
||||
SELECT THE VIDEO FILE TO SHARE<br /><br />
|
||||
SELECT THE VIDEO FILES TO SHARE<br /><br />
|
||||
<input id="fileselector" onchange="session.publishFile(this,event);" type="file" accept="video/*,audio/*" alt="Hold CTRL (or CMD) to select multiple files" title="Hold CTRL (or CMD) to select multiple files" multiple/>
|
||||
<br /><br />
|
||||
<p style="margin:10px">Keep this tab visible if using Chrome, else the video playback will stop</p>
|
||||
<p style="margin:10px">(Media file streaming is still quite experimental)</p>
|
||||
</div>
|
||||
|
||||
<div class="outer close">
|
||||
@ -529,11 +541,12 @@
|
||||
<h2><span data-translate="share-website-iframe">Share Website</span></h2>
|
||||
<i style="margin-top:30px;font-size:560%;overflow:hidden;" class="las la-broadcast-tower"></i>
|
||||
<div class="container-inner">
|
||||
|
||||
<br /><br />
|
||||
<br />
|
||||
<div id="previewIframe"></div>
|
||||
<br />
|
||||
Enter the URL website you wish to share.<br /><br />
|
||||
<input id="iframeURL" type="text" style="margin:10px; border:2px solid; padding:10px; width:400px;" title="Enter an HTTPS URL" multiple/><br />
|
||||
<button onclick="loadIframe(getById('iframeURL').value);" >Preview</button>
|
||||
<button onclick="previewIframe(getById('iframeURL').value);" >Preview</button>
|
||||
<button onclick="this.innerHTML = 'Update'; session.publishIFrame(getById('iframeURL').value);" >Share</button><br />
|
||||
<small>Remote website must be CORS/IFrame compatible with full SSL-encryption enabled.</small>
|
||||
<div id="iFramePreview" style=" width: 1280px; height: 720px; margin: auto; padding: 10px;"></div>
|
||||
@ -581,8 +594,9 @@
|
||||
</i>
|
||||
<br />
|
||||
<li>
|
||||
<a href="https://github.com/steveseguin/obsninja/wiki/FAQ#mac-os">MacOS <i class="lab la-apple"></i> users</a> will need to use OBS v23 or resort to
|
||||
<a href="https://github.com/steveseguin/electroncapture">Window Capturing</a> with the provided Electron-Capture app for the time being.
|
||||
<a href="https://github.com/steveseguin/obsninja/wiki/FAQ#mac-os">MacOS <i class="lab la-apple"></i> users</a> currently need to use a
|
||||
<a href="https://github.com/obsproject/obs-browser/issues/209#issuecomment-748683083">preview version of OBS Studio 26</a> or resort to
|
||||
window-capturing with the provided <a href="https://github.com/steveseguin/electroncapture">Electron-Capture app</a>.
|
||||
|
||||
</li>
|
||||
<li>If you have <a href="https://github.com/steveseguin/obsninja/wiki/FAQ#video-is-pixelated">"pixel smearing"</a> or corrupted video, try adding <b>&codec=vp9</b> or &codec=h264 to the OBS view link. Using Wi-Fi will make the issue worse.
|
||||
@ -595,8 +609,8 @@
|
||||
</li>
|
||||
<br />
|
||||
|
||||
🎈 Site Updated: <a href="https://www.reddit.com/r/OBSNinja/comments/k02enh/version_134_of_obsninja_released_change_log_here/">Dec 6th, 2020</a>. The previous version can be found at
|
||||
<a href="https://obs.ninja/v12/">https://obs.ninja/v12/</a> if you are having new issues.
|
||||
🎁 Site Updated: <a href="https://github.com/steveseguin/obsninja/wiki/v14-release-notes">Jan 2nd, 2021</a>. The previous version can be found at
|
||||
<a href="https://obs.ninja/v134/">https://obs.ninja/v134/</a> if you are having new issues.
|
||||
|
||||
<br />
|
||||
<br />
|
||||
@ -628,7 +642,359 @@
|
||||
</div>
|
||||
</div>
|
||||
<span id="electronDragZone" style="pointer-events: none; z-index:-10; position:absolute;top:0;left:0;width:100%;height:5%;-webkit-app-region: drag;min-height:33px;"></span>
|
||||
<div id="gridlayout" ></div>
|
||||
<div id="gridlayout" >
|
||||
<div id="roomHeader" style="display:none">
|
||||
<div class='directorContainer half' style="padding-top:10px;margin-bottom:0;margin-left:10px;padding-bottom:0">
|
||||
<span style='color:white' id="directorLinksButton" onclick="hideDirectorinvites(this);">
|
||||
<i class="las la-caret-down"></i><span data-translate="hide-the-links"> LINKS (GUEST INVITES & SCENES)</span>
|
||||
</span>
|
||||
<span id="help_directors_room" style='color:white;text-align: right;' data-translate="click-for-quick-room-overview" onclick="toggle(getById('roomnotes2'),this,false);"><i class="las la-question-circle"></i> Click Here for a quick overview and help</button>
|
||||
</div>
|
||||
<div id='roomnotes2' style='max-width:1190px;display:none;padding:0 0 0 10px;' >
|
||||
<font style='color:#CCC;' data-translate='welcome-to-control-room'>
|
||||
<b>Welcome. This is the director's control-room for the group-chat.</b><br /><br />
|
||||
You can host a group chat with friends using a room. Share the blue link to invite guests who will join the chat automatically.
|
||||
<br /><br />
|
||||
<font style='color:red'>Known Limitations with Group Rooms:</font><br />
|
||||
<li>A group room can handle up to around 30 guests, depending on numerous factors, including CPU and available bandwidth of all guests in the room. To achieve more than around 7-guests though, you will likely want to disable video sharing between guests. &roombitrate=0 or &novideo are options there.</li>
|
||||
|
||||
<li>Videos will appear of low quality on purpose for guests and director; this is to save bandwidth and CPU resources. It will be high-quality within OBS still though.</li>
|
||||
|
||||
<li>The state of the scenes, such as which videos are active in a scene, are lost when the director resets the control-room or the scene.</li>
|
||||
<br />
|
||||
Further Notes:<br /><br />
|
||||
<li>Links to Solo-views of each guest video are offered under videos as they load. These can be used within an OBS Browser Source.</li>
|
||||
<li>You can use the auto-mixing Group Scenes, the green links, to auto arrange multiple videos for you in OBS.</li>
|
||||
<li>You can use this control room to record isolated video or audio streams, but it is an experimental feature still.</li>
|
||||
<li>If you transfer a guest from one room to another, they won't know which room they have been transferred to.</li>
|
||||
<li>OBS will see a guest's video in high-quality; the default video bitrate is 2500kbps. Setting higher bitrates will improve motion.</li>
|
||||
<li>VP8 is typically the default video codec, but using &codec=vp9 or &codec=h264 as a URL in OBS can help to reduce corrupted video puke issues.</li>
|
||||
<li>&stereo=2 can be added to guests to turn off audio effects, such as echo cancellation and noise-reduction.</li>
|
||||
<li>https://invite.cam is a free service provided that can help obfuscuate the URL parameters of an invite link given to guests.</li>
|
||||
<li>Adding &showonly=SOME_OBS_VIRTUALCAM to the guest invite links allows for only a single video to be seen by the guests; this can be output of the OBS Virtual Camera for example</li>
|
||||
<br />
|
||||
|
||||
For advanced URL options and parameters, <a href="https://github.com/steveseguin/obsninja/wiki/Advanced-Settings">see the Wiki.</a>
|
||||
</font>
|
||||
</div>
|
||||
</div>
|
||||
<div class='directorContainer' id='directorLinks' style='display:none;margin-top:0;padding-top:0'>
|
||||
<div class='directorBlock'>
|
||||
<h2>GUEST INVITE</h2>
|
||||
<span data-translate='invite-users-to-join'>Invites users to join the group and broadcast their feed to it. They will see and hear other guests in the same room.
|
||||
These users will see every feed in the room.</span>
|
||||
<a onclick='popupMessage(event);copyFunction(this)' id="director_block_1" onmousedown='copyFunction(this)' class='task grabLinks' style='cursor:copy'></a>
|
||||
<button class='pull-left grey' style='font-size:1.15em' id="showCustomizerButton1" onclick='showCustomizer(1,this)'><i class='las la-tools'></i>Customize</button>
|
||||
<button class='pull-right grey' style='font-size:1.15em' onclick='popupMessage(event);copyFunction(getById("director_block_1"))'><i class='las la-video'></i>Copy link</button>
|
||||
</div>
|
||||
<div class='directorBlock'>
|
||||
<h2>BROADCAST INVITE</h2>
|
||||
<span data-translate='link-to-invite-camera'>Link to invite users to broadcast their feeds to the group. These users will not see or hear any feed from the group.</span>
|
||||
<a class='task grabLinks' id="director_block_2" style='cursor:copy' onclick='popupMessage(event);copyFunction(this)' onmousedown='copyFunction(this)'></a>
|
||||
<button class='pull-left grey' style='font-size:1.15em' id="showCustomizerButton2" onclick='showCustomizer(2,this)'><i class='las la-tools'></i>Customize</button>
|
||||
<button class='pull-right grey' style='font-size:1.15em;' onclick='popupMessage(event);copyFunction(getById("director_block_2"))'><i class='las la-video'></i>Copy link</button>
|
||||
</div>
|
||||
<div class='directorBlock'>
|
||||
<h2>SCENE LINK: MANUAL</h2>
|
||||
<span data-translate='this-is-obs-browser-source-link'>This is an OBS Browser Source link that is empty by default. Click 'add to scene' for each guest you want included in this scene</span>
|
||||
<a class='task grabLinks' id="director_block_3" onmousedown='copyFunction(this)' data-drag='1' draggable='true' onclick='popupMessage(event);copyFunction(this)' ></a>
|
||||
<button class='pull-left grey' style='font-size:1.15em' id="showCustomizerButton3" onclick='showCustomizer(3,this)'><i class='las la-tools'></i>Customize</button>
|
||||
<button class='pull-right grey' style='font-size:1.15em;' onclick='popupMessage(event);copyFunction(getById("director_block_3"))'><i class='las la-th-large' aria-hidden='true'></i></i>Copy link</button>
|
||||
</div>
|
||||
<div class='directorBlock'>
|
||||
<h2>SCENE LINK: AUTO</h2>
|
||||
<span data-translate='this-is-obs-browser-souce-link-auto'>Also an OBS Browser Source link. All guest videos in this group chat room will automatically be added into this scene.</span>
|
||||
<a class='task grabLinks' id="director_block_4" onmousedown='copyFunction(this)' draggable='true' data-drag='1' onclick='popupMessage(event);copyFunction(this)'></a>
|
||||
<button class='pull-left grey' style='font-size:1.15em' id="showCustomizerButton4" onclick='showCustomizer(4,this)'><i class='las la-tools'></i>Customize</button>
|
||||
<button class='pull-right grey' style='font-size:1.15em;' onclick='popupMessage(event);copyFunction(getById("director_block_4"))'><i class='las la-th-large'></i>Copy link</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class='directorContainer' id="customizeLinks" style='display:none;margin-top:0;padding-top:10px'>
|
||||
<div class='directorBlock' id="customizeLinks1" style='display:none;margin-top:0;padding-bottom:0;'>
|
||||
<div style="display:inline-block;top: 12px; position: relative;">
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&s" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Pro-audio mode
|
||||
<Br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&st" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Hide audio-only sources
|
||||
<Br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&l" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Ask for Display Name
|
||||
<Br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&sl" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Show Display Names
|
||||
</div>
|
||||
<div style="display:inline-block;top: 12px; position: relative; margin-left:10px;">
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&q" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
1080p60 Video if Available
|
||||
<Br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&ad" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Auto-select Default Microphone
|
||||
<Br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&vd" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Auto-select Default Camera
|
||||
<br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&m" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Mute Microphone by Default
|
||||
</div>
|
||||
<div style="display:inline-block;top: 12px; position: relative; margin-left:10px;">
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&np" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Disable Self-Preview
|
||||
<Br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&hand" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Display 'Raise-Hand' button
|
||||
<Br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&comp" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Enable Audio Compressor
|
||||
<Br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&eq" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Enable Equalizer as Option
|
||||
</div>
|
||||
<div style="display:inline-block;top: 12px; position: relative; margin-left:10px;">
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&broadcast" id="broadcastSlider" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Only see the Director's Feed
|
||||
<Br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&ns" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Hide Settings Button
|
||||
<Br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&mono" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Force Mono Audio
|
||||
<Br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="" id="obfuscate_director_1" onchange="updateLink(1,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Obfuscate Link and Parameters
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='directorBlock' id="customizeLinks2" style='display:none;margin-top:0;padding-bottom:0;'>
|
||||
<div style="display:inline-block;top: 12px; position: relative;">
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&s" onchange="updateLink(2,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Pro-audio mode
|
||||
<Br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&st" onchange="updateLink(2,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Hide audio-only sources
|
||||
<Br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&l" onchange="updateLink(2,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Ask for Display Name
|
||||
<Br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&sl" onchange="updateLink(2,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Show Display Names
|
||||
</div>
|
||||
<div style="display:inline-block;top: 12px; position: relative; margin-left:10px;">
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&q" onchange="updateLink(2,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
1080p60 Video if Available
|
||||
<Br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&ad" onchange="updateLink(2,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Auto-select Default Microphone
|
||||
<Br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&vd" onchange="updateLink(2,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Auto-select Default Camera
|
||||
<br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&m" onchange="updateLink(2,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Mute Microphone by Default
|
||||
</div>
|
||||
<div style="display:inline-block;top: 12px; position: relative; margin-left:10px;">
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&np" onchange="updateLink(2,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Disable Self-Preview
|
||||
<Br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&hand" onchange="updateLink(2,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Display 'Raise-Hand' button
|
||||
<Br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&comp" onchange="updateLink(2,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Enable Audio Compressor
|
||||
<Br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&eq" onchange="updateLink(2,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Enable Equalizer as Option
|
||||
</div>
|
||||
<div style="display:inline-block;top: 12px; position: relative; margin-left:10px;">
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&ns" onchange="updateLink(2,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Hide Settings Button
|
||||
<Br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&mono" onchange="updateLink(2,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Force Mono Audio
|
||||
<Br />
|
||||
<label class="switch">
|
||||
<input type="checkbox" id="obfuscate_director_2" data-param="" onchange="updateLink(2,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Obfuscate Link and Parameters
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='directorBlock' id="customizeLinks3" style='display:none;margin-top:0;padding-bottom:0;'>
|
||||
<div style="display:inline-block;top: 12px; position: relative;">
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&s" onchange="updateLink(3,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Pro-audio mode
|
||||
</div>
|
||||
<div style="display:inline-block;top: 12px; position: relative; margin-left:10px;">
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&st" onchange="updateLink(3,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Hide audio-only sources
|
||||
</div>
|
||||
<div style="display:inline-block;top: 12px; position: relative; margin-left:10px;">
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&sl" onchange="updateLink(3,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Show Display Names
|
||||
</div>
|
||||
<div style="display:inline-block;top: 12px; position: relative; margin-left:10px;">
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&vb=20000" onchange="updateLink(3,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Unlock Video Bitrate (20-mbps)
|
||||
</div>
|
||||
<div style="display:inline-block;top: 12px; position: relative; margin-left:10px;">
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&mono" onchange="updateLink(3,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Force Mono Audio
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='directorBlock' id="customizeLinks4" style='display:none;margin-top:0;padding-bottom:0;'>
|
||||
<div style="display:inline-block;top: 12px; position: relative;">
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&s" onchange="updateLink(4,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Pro-audio mode
|
||||
</div>
|
||||
<div style="display:inline-block;top: 12px; position: relative; margin-left:10px;">
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&st" onchange="updateLink(4,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Hide audio-only sources
|
||||
</div>
|
||||
<div style="display:inline-block;top: 12px; position: relative; margin-left:10px;">
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&sl" onchange="updateLink(4,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Show Display Names
|
||||
</div>
|
||||
<div style="display:inline-block;top: 12px; position: relative; margin-left:10px;">
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&vb=20000" onchange="updateLink(4,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Unlock Video Bitrate (20-mbps)
|
||||
</div>
|
||||
<div style="display:inline-block;top: 12px; position: relative; margin-left:10px;">
|
||||
<label class="switch">
|
||||
<input type="checkbox" data-param="&mono" onchange="updateLink(4,this);">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
Force Mono Audio
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id='guestFeeds' style="display:none"><div id='deleteme'>
|
||||
<div class='vidcon' style='margin: 15px 20px 0 0; min-height: 300px;text-align: center;'><h2>Guest 1</h2><i class='las la-user-circle' style='font-size:8em; margin: 20px 0px;' aria-hidden='true'></i></div>
|
||||
<div class='vidcon' style='margin: 15px 20px 0 0; min-height: 300px;text-align: center;'><h2>Guest 2</h2><i class='las la-user-circle' style='font-size:8em; margin: 20px 0px;' aria-hidden='true'></i></div>
|
||||
<div class='vidcon' style='margin: 15px 20px 0 0; min-height: 300px;text-align: center;'><h2>Guest 3</h2><i class='las la-user-circle' style='font-size:8em; margin: 20px 0px;' aria-hidden='true'></i></div>
|
||||
<div class='vidcon' style='margin: 15px 20px 0 0; min-height: 300px;text-align: center;'><h2>Guest 4</h2><i class='las la-user-circle' style='font-size:8em; margin: 20px 0px;' aria-hidden='true'></i></div>
|
||||
<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="overlayMsgs" onclick="function(e){e.target.innerHTML = '';}" style="display:none"></div>
|
||||
<div id="bigPlayButton" onclick="function(e){e.target.innerHTML = '';}" style="display:none"></div>
|
||||
<div id="controls_blank" style="display: none;">
|
||||
@ -636,12 +1002,12 @@
|
||||
|
||||
|
||||
|
||||
<button data-action-type="forward" data-value="0" title="Forward user to another room. They can always return." onclick="directMigrate(this, event);">
|
||||
<button data-action-type="forward" data-value="0" title="Move the user to another room, controlled by another director" onclick="directMigrate(this, event);">
|
||||
<i class="las la-paper-plane"></i>
|
||||
<span data-translate="forward-to-room">Transfer</span>
|
||||
</button>
|
||||
|
||||
<button data-action-type="direct-chat" title="Send Direct Message" onclick="directorSendMessage(this);">
|
||||
<button data-action-type="direct-chat" title="Send a Direct Message to this user." onclick="directorSendMessage(this);">
|
||||
<span data-translate="send-direct-chat"><i class="las la-envelope"></i> Message</span>
|
||||
</button>
|
||||
|
||||
@ -682,13 +1048,30 @@
|
||||
<i class="las la-circle"></i>
|
||||
<span data-translate="record"> Record</span>
|
||||
</button>
|
||||
|
||||
<button data-action-type="advanced-camera-settings" title="Advanced Settings and Remote Control" onclick="directorAdvanced(this);">
|
||||
<span data-translate="advanced-camera-settings"><i class="las la-cog"></i> Advanced</span>
|
||||
</button>
|
||||
<button data-action-type="voice-chat" title="Toggle Voice Chat with this Guest"">
|
||||
<button class="advanced" data-action-type="voice-chat" title="Toggle Voice Chat with this Guest"">
|
||||
<span data-translate="voice-chat"><i class="las la-microphone"></i> Voice Chat</span>
|
||||
</button>
|
||||
|
||||
<span>
|
||||
<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>
|
||||
<span class="orderspan">
|
||||
<div style="text-align: center;font-size: 150%;" data-action-type="order-value" title="Current Index Order of this Video" >0</div>
|
||||
Mix Order
|
||||
</span>
|
||||
<button style="width:34px;margin-left:0;" data-action-type="order-up" title="Shift this Video Up in Order" onclick="changeOrder(1,this.dataset.UUID);">
|
||||
<span data-translate="order-up"><i class="las la-plus"></i></span>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<button class="" data-action-type="advanced-audio-settings" data-active="false" style="grid-column: 1;" title="Remote Audio Settings" onclick="requestAudioSettings(this);">
|
||||
<span data-translate="advanced-audio-settings"><i class="las la-sliders-h"></i> Audio Settings</span>
|
||||
</button>
|
||||
<button class="" data-action-type="advanced-camera-settings" data-active="false" style="grid-column: 2;" title="Advanced Video Settings" onclick="requestVideoSettings(this);">
|
||||
<span data-translate="advanced-camera-settings"><i class="las la-sliders-h"></i> Video Settings</span>
|
||||
</button>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@ -720,12 +1103,15 @@
|
||||
</div>
|
||||
<select id="outputSource3" ></select>
|
||||
</span>
|
||||
<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><br />
|
||||
<button onclick="toggleSettings()" style="width: 135px; background-color:#EFEFEF;padding:10px 12px 12px 2px;margin: 10px 0px 20px 0"><i class="chevron right" style="font-size:150%;top:3px;position:relative;"></i> <b>Close Settings</b></button>
|
||||
<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 />
|
||||
|
||||
<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>Advanced Video</b></button>
|
||||
<button onclick="toggleSettings()" style="width: 135px; background-color:#EFEFEF;padding:9px 12px 10px 2px;margin: 10px 0px 20px 0"><i class="chevron right" style="font-size:150%;top:3px;position:relative;"></i> <b>Close Settings</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>Advanced 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">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">Advanced </span>Audio</b></button>
|
||||
|
||||
|
||||
<span id="popupSelector_constraints_audio" class="popupSelector_constraints" style="display: none;">
|
||||
@ -756,49 +1142,6 @@
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<div id="roomTemplate" style="display:none;">
|
||||
<div class='directorContainer half'>
|
||||
<button class="grey" data-translate="click-for-quick-room-overview" onclick="toggle(getById('roomnotes2'),this,false);"><i class="las la-question-circle"></i> Click Here for a quick overview and help</button>
|
||||
<span id="miniPerformer"><button id="press2talk" class="grey" onclick="press2talk();" title="You can also enable the director's Video Output from here"><i class="las la-headset"></i><span data-translate="push-to-talk-enable"> Enable Director's Push-to-Talk Mode</span></button></span>
|
||||
</div>
|
||||
|
||||
<div id='roomnotes2' style='max-width:1200px;display:none;padding:0 0 0 10px;' >
|
||||
<font style='color:#CCC;' data-translate='welcome-to-control-room'>
|
||||
<b>Welcome. This is the director's control-room for the group-chat.</b><br /><br />
|
||||
You can host a group chat with friends using a room. Share the blue link to invite guests who will join the chat automatically.
|
||||
<br /><br />
|
||||
<font style='color:red'>Known Limitations with Group Rooms:</font><br />
|
||||
<li>A group room can handle up to around 30 guests, depending on numerous factors, including CPU and available bandwidth of all guests in the room. To achieve more than around 7-guests though, you will likely want to disable video sharing between guests. &roombitrate=0 or &novideo are options there.</li>
|
||||
|
||||
<li>Videos will appear of low quality on purpose for guests and director; this is to save bandwidth and CPU resources. It will be high-quality within OBS still though.</li>
|
||||
|
||||
<li>The state of the scenes, such as which videos are active in a scene, are lost when the director resets the control-room or the scene.</li>
|
||||
<br />
|
||||
Further Notes:<br /><br />
|
||||
<li>Links to Solo-views of each guest video are offered under videos as they load. These can be used within an OBS Browser Source.</li>
|
||||
<li>You can use the auto-mixing Group Scenes, the green links, to auto arrange multiple videos for you in OBS.</li>
|
||||
<li>You can use this control room to record isolated video or audio streams, but it is an experimental feature still.</li>
|
||||
<li>If you transfer a guest from one room to another, they won't know which room they have been transferred to.</li>
|
||||
<li>OBS will see a guest's video in high-quality; the default video bitrate is 2500kbps. Setting higher bitrates will improve motion.</li>
|
||||
<li>VP8 is typically the default video codec, but using &codec=vp9 or &codec=h264 as a URL in OBS can help to reduce corrupted video puke issues.</li>
|
||||
<li>&stereo=2 can be added to guests to turn off audio effects, such as echo cancellation and noise-reduction.</li>
|
||||
<li>https://invite.cam is a free service provided that can help obfuscuate the URL parameters of an invite link given to guests.</li>
|
||||
<li>Adding &showonly=SOME_OBS_VIRTUALCAM to the guest invite links allows for only a single video to be seen by the guests; this can be output of the OBS Virtual Camera for example</li>
|
||||
<br />
|
||||
|
||||
For advanced URL options and parameters, <a href="https://github.com/steveseguin/obsninja/wiki/Advanced-Settings">see the Wiki.</a>
|
||||
</font>
|
||||
</div>
|
||||
|
||||
<div id='guestFeeds'><div id='deleteme'>
|
||||
<div class='vidcon' style='margin: 15px 20px 0 0; min-height: 300px;text-align: center;'><h2>Guest 1</h2><i class='las la-user-circle' style='font-size:8em; margin: 20px 0px;' aria-hidden='true'></i></div>
|
||||
<div class='vidcon' style='margin: 15px 20px 0 0; min-height: 300px;text-align: center;'><h2>Guest 2</h2><i class='las la-user-circle' style='font-size:8em; margin: 20px 0px;' aria-hidden='true'></i></div>
|
||||
<div class='vidcon' style='margin: 15px 20px 0 0; min-height: 300px;text-align: center;'><h2>Guest 3</h2><i class='las la-user-circle' style='font-size:8em; margin: 20px 0px;' aria-hidden='true'></i></div>
|
||||
<div class='vidcon' style='margin: 15px 20px 0 0; min-height: 300px;text-align: center;'><h2>Guest 4</h2><i class='las la-user-circle' style='font-size:8em; margin: 20px 0px;' aria-hidden='true'></i></div>
|
||||
<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="chatModule" style="display:none;text-align:right">
|
||||
<a target="popup" id="popOutChat" style="cursor:pointer;text-align:right;color:#B3C7F9;" onclick="createPopoutChat();"><i class="las la-external-link-alt"></i></a>
|
||||
<div id="chatBody">
|
||||
@ -813,6 +1156,9 @@
|
||||
<button style="width:60px;background-color:#EEE;" onclick="sendChatMessage()" data-translate='send-chat'>Send</button>
|
||||
</div>
|
||||
|
||||
<div id="voiceMeterTemplate" class="video-meter">
|
||||
</div>
|
||||
|
||||
<audio id="testtone" style="display:none;" preload="none">
|
||||
<source src="tone.mp3" type="audio/mpeg">
|
||||
<source src="tone.ogg" type="audio/ogg">
|
||||
@ -822,6 +1168,14 @@
|
||||
<img src="./images/favicon-32x32.png" id="dragImage" />
|
||||
</div>
|
||||
<div id="request_info_prompt" style="display:none">
|
||||
</div>
|
||||
<div id="screenPopup" class="popup-screen">
|
||||
<button onclick="getById('screenPopup').style.display='none';margin:0;padding:0;">Close Window</button>
|
||||
|
||||
<div>See the
|
||||
<a style="text-decoration: none; color: blue;" target="_blank" href="https://docs.obs.ninja/advanced">documentation</a> for more options and info.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div id="messagePopup" class="popup-message"></div>
|
||||
<div id="languages" class="popup-message" style="display: none; right: 0; bottom: 25px; position: absolute;">
|
||||
@ -865,7 +1219,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 = "14.0b";
|
||||
session.version = "14.3";
|
||||
session.streamID = session.generateStreamID(); // randomly generates a streamID for this session. You can set your own programmatically if needed
|
||||
|
||||
session.defaultPassword = "someEncryptionKey123"; // Disabling improves compatibility and is helpful for debugging.
|
||||
@ -930,7 +1284,7 @@
|
||||
<script type="text/javascript" id="main-js" src="./main.js" data-translation="blank"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="mixer-js" src="./mixer.js?ver=2"></script>
|
||||
-->
|
||||
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=93"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./animations.js?ver=13"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=131"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./animations.js?ver=16"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
148
main.css
148
main.css
@ -26,7 +26,7 @@ table {
|
||||
#bigPlayButton {
|
||||
margin:0 auto;
|
||||
background-color: #0000;
|
||||
color: white;
|
||||
color: #;
|
||||
font-family: Cousine, monospace;
|
||||
font-size: 4em;
|
||||
line-height: 1.5em;
|
||||
@ -46,10 +46,12 @@ table {
|
||||
|
||||
#playButton {
|
||||
font-size: 50vh;
|
||||
border-radius: 50vh;
|
||||
font-size: min(50vw, 50vh);
|
||||
cursor:pointer;
|
||||
opacity:30%;
|
||||
opacity:100%;
|
||||
margin-top: 20vh;
|
||||
background-color:#444;
|
||||
}
|
||||
|
||||
tr {
|
||||
@ -288,7 +290,17 @@ hr {
|
||||
background-color: gray;
|
||||
}
|
||||
|
||||
|
||||
.orderspan{
|
||||
font-size: 50%;
|
||||
display: inline-block;
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
width: 49px;
|
||||
height: 22px;
|
||||
top: 5px;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
}
|
||||
/* Clear floats after the columns */
|
||||
|
||||
.row:after {
|
||||
@ -299,7 +311,6 @@ hr {
|
||||
|
||||
.vidcon {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
@ -365,16 +376,15 @@ hr {
|
||||
max-width: 100%;
|
||||
padding: 5px;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
max-height: 160px;
|
||||
height: 157px;
|
||||
}
|
||||
|
||||
.directorsgrid .vidcon {
|
||||
display: inline-block !important;
|
||||
width: 275.3px !important;
|
||||
max-height: 530px !important;
|
||||
width: 269.2px !important;
|
||||
background: #7E7E7E;
|
||||
color: #FCFCFC;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.directorsgrid .vidcon>.las {
|
||||
@ -779,6 +789,9 @@ input[type=range]:focus::-ms-fill-upper {
|
||||
font-size: 92%;
|
||||
width: 385px !important
|
||||
}
|
||||
.mobileHide{
|
||||
display:none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.popupSelector_constraints{
|
||||
@ -955,7 +968,7 @@ img {
|
||||
/* Empty container that will replace the original container */
|
||||
#empty-container {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
/*float: left;*/
|
||||
width: 20%;
|
||||
min-width: 300px;
|
||||
padding: 28px;
|
||||
@ -1065,7 +1078,7 @@ img {
|
||||
#controlButtons {
|
||||
position: fixed;
|
||||
z-index: 5;
|
||||
bottom: 5px;
|
||||
bottom: 0px;
|
||||
width: 100%;
|
||||
display: none;
|
||||
justify-content: center;
|
||||
@ -1210,6 +1223,11 @@ img {
|
||||
color: red;
|
||||
top:0.5;
|
||||
}
|
||||
|
||||
.raisedHand{
|
||||
background-color: #DD1A;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animatetop {
|
||||
from {
|
||||
top: -300px;
|
||||
@ -1282,7 +1300,6 @@ video::-webkit-media-controls-timeline-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
audio::-webkit-media-controls-overlay-play-button, video::-webkit-media-controls-overlay-play-button {
|
||||
display: none;
|
||||
}
|
||||
@ -1311,14 +1328,27 @@ video.clean::-webkit-media-controls-timeline-container {
|
||||
display: inherit;
|
||||
}
|
||||
|
||||
|
||||
.mirrorControl::-webkit-media-controls-enclosure {
|
||||
padding: 0px;
|
||||
height: 30px;
|
||||
transform: scaleX(-1);
|
||||
-webkit-transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.popup-screen {
|
||||
align-text: center;
|
||||
position: absolute;
|
||||
display:none;
|
||||
top:0;
|
||||
left:0;
|
||||
z-index: 7 !important;
|
||||
padding: 20px;
|
||||
margin:15px 15px 80px 15px;
|
||||
width: 80vh !important;
|
||||
height: 80vh !important;
|
||||
background-color: #ccc !important;
|
||||
border: solid 1px #dfdfdf !important;
|
||||
box-shadow: 1px 1px 2px #cfcfcf !important;
|
||||
}
|
||||
.context-menu {
|
||||
display: none;
|
||||
position: absolute;
|
||||
@ -1417,11 +1447,18 @@ video.clean::-webkit-media-controls-timeline-container {
|
||||
#audioMenu {
|
||||
margin: 15px 0 0 0;
|
||||
}
|
||||
#videoSource {
|
||||
|
||||
#videosource {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
font-size: 100%;
|
||||
}
|
||||
#videoSourceSelect {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
font-size: 100%;
|
||||
max-width: 260px;
|
||||
}
|
||||
.gone {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
@ -1772,14 +1809,14 @@ input[type=checkbox] {
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
margin: 10px;
|
||||
padding: 5px 10px;
|
||||
max-width: 1200px
|
||||
max-width: 1190px
|
||||
}
|
||||
.directorContainer.half {
|
||||
background-color: var(--container-color);
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
padding: 5px 20px;
|
||||
max-width: 1200px
|
||||
max-width: 1190px
|
||||
}
|
||||
.directorBlock {
|
||||
cursor: grab;
|
||||
@ -1789,7 +1826,6 @@ input[type=checkbox] {
|
||||
position:relative;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
}
|
||||
.directorBlock:nth-child(1) {
|
||||
background-color: var(--blue-accent);
|
||||
@ -1805,7 +1841,6 @@ input[type=checkbox] {
|
||||
}
|
||||
.directorBlock button {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin: 10px;
|
||||
}
|
||||
@ -1862,6 +1897,11 @@ div#roomnotes2 {
|
||||
|
||||
.pull-right {
|
||||
float: right;
|
||||
right: 0;
|
||||
}
|
||||
.pull-left {
|
||||
float: left;
|
||||
left: 0;
|
||||
}
|
||||
i.las.la-circle {
|
||||
color: red;
|
||||
@ -2054,6 +2094,26 @@ span#guestTips {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.video-meter {
|
||||
padding:0.5vh;
|
||||
display:block;
|
||||
width:0.5vh;
|
||||
height:0.5vh;
|
||||
top: 2vh;
|
||||
right: 2vh;
|
||||
background-color:green;
|
||||
position:absolute;
|
||||
display:none;
|
||||
border-radius: 1vh;
|
||||
pointer-events:none;
|
||||
}
|
||||
#help_directors_room{
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
#shareScreenGear{
|
||||
display:none;
|
||||
}
|
||||
|
||||
@keyframes floating {
|
||||
0% { transform: translate(0, 0px); }
|
||||
@ -2080,3 +2140,55 @@ span#guestTips {
|
||||
}
|
||||
|
||||
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 40px;
|
||||
height: 24px;
|
||||
margin:5px 5px 10px 5px;
|
||||
bottom:20px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.switch input {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 17px;
|
||||
width: 17px;
|
||||
left: 3px;
|
||||
bottom: 3px;
|
||||
background-color: white;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
input:checked + .slider {
|
||||
background-color: #86b98f;
|
||||
}
|
||||
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px #86b98f;
|
||||
}
|
||||
|
||||
input:checked + .slider:before {
|
||||
-webkit-transform: translateX(16px);
|
||||
-ms-transform: translateX(16px);
|
||||
transform: translateX(16px);
|
||||
}
|
||||
@ -1,4 +1,15 @@
|
||||
body {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
font-family: "Lato", sans-serif;
|
||||
padding: 0 0px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
opacity: 1;
|
||||
transition: opacity .1s linear;
|
||||
background-color: #141926;
|
||||
}
|
||||
|
||||
@ -13,11 +24,6 @@ h1 small {
|
||||
font-size: 0.5em;
|
||||
}
|
||||
|
||||
#container, #graphs, #log {
|
||||
width: 80%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#explanation {
|
||||
color: white;
|
||||
font-family: sans-serif;
|
||||
@ -26,6 +32,12 @@ h1 small {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
#container, #graphs, #log {
|
||||
width: 80%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
|
||||
#explanation h2 {
|
||||
border-bottom: 1px solid #383838;
|
||||
margin-bottom: 10px;
|
||||
@ -33,16 +45,23 @@ h1 small {
|
||||
}
|
||||
|
||||
#feeds {
|
||||
display: flex;
|
||||
display: inline-block;
|
||||
width:100%;
|
||||
height:380px;
|
||||
|
||||
}
|
||||
|
||||
#feeds span {
|
||||
flex: 1;
|
||||
height: 30vh;
|
||||
display: flex;
|
||||
margin:auto;
|
||||
height: 100%;
|
||||
min-width:50%;
|
||||
display: inline-block;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#button_container{
|
||||
margin:auto;
|
||||
}
|
||||
#feeds h3 {
|
||||
color: whitesmoke;
|
||||
margin: 10px;
|
||||
@ -50,13 +69,13 @@ h1 small {
|
||||
}
|
||||
|
||||
iframe {
|
||||
height: auto;
|
||||
height: 85%;
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
#controls {
|
||||
margin-top: 20px;
|
||||
margin:auto;
|
||||
}
|
||||
|
||||
#controls button {
|
||||
@ -64,7 +83,7 @@ iframe {
|
||||
}
|
||||
|
||||
#controls button.active {
|
||||
background-color: green;
|
||||
background-color: #70ff70;
|
||||
}
|
||||
|
||||
canvas {
|
||||
@ -73,8 +92,8 @@ canvas {
|
||||
}
|
||||
|
||||
#log {
|
||||
margin-top: 20px;
|
||||
background: #2a2a2a;
|
||||
margin-top: 10px;
|
||||
background: #313131;
|
||||
padding: 20px 0px;
|
||||
border: 1px solid #383838;
|
||||
cursor: pointer;
|
||||
@ -90,15 +109,17 @@ canvas {
|
||||
}
|
||||
|
||||
#graphs {
|
||||
display: flex;
|
||||
display: block;
|
||||
margin-top: 20px;
|
||||
background: #2a2a2a;
|
||||
background: #313131;
|
||||
padding: 20px 0px;
|
||||
border: 1px solid #383838;
|
||||
text-align: center;
|
||||
|
||||
}
|
||||
|
||||
.graph {
|
||||
flex: 1;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@ -120,14 +141,13 @@ ol {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
@media only screen
|
||||
and (min-device-width: 375px)
|
||||
and (max-device-width: 812px)
|
||||
and (orientation: portrait) {
|
||||
|
||||
#container {
|
||||
width: 90%;
|
||||
}
|
||||
@media only screen and (max-width: 800px) {
|
||||
|
||||
#container, #graphs, #log {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#graphs {
|
||||
flex-direction: column;
|
||||
@ -142,8 +162,24 @@ ol {
|
||||
}
|
||||
|
||||
#feeds h3 {
|
||||
display: none;
|
||||
font-size:50%;
|
||||
}
|
||||
|
||||
h1{
|
||||
color: white;
|
||||
margin: 2px;
|
||||
font-size:70%
|
||||
}
|
||||
|
||||
#feeds span{
|
||||
height: 50%;
|
||||
width:100%;
|
||||
display: inline-block;
|
||||
}
|
||||
canvas {
|
||||
margin:auto;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#statsdiv {display: none;}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="./lineawesome/css/line-awesome.min.css" />
|
||||
<link rel="stylesheet" href="./main.css?ver=11" />
|
||||
<link rel="stylesheet" href="./speedtest.css?ver=1" />
|
||||
<meta charset="utf8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
@ -26,7 +25,9 @@
|
||||
};
|
||||
})(window);
|
||||
var urlParams = new URLSearchParams(window.location.search);
|
||||
|
||||
var quality_reason = "";
|
||||
var encoder = "";
|
||||
var Round_Trip_Time_ms = "";
|
||||
function copyFunction(copyText) {
|
||||
alert("Log copied to the clipboard.");
|
||||
try {
|
||||
@ -60,11 +61,15 @@
|
||||
var iframe = document.createElement("iframe");
|
||||
var iframeContainer = document.createElement("span");
|
||||
|
||||
iframe.allow = "autoplay";
|
||||
iframe.allow="autoplay;camera;microphone";
|
||||
iframe.allowtransparency="true";
|
||||
iframe.allowfullscreen ="true";
|
||||
|
||||
//iframe.allow = "autoplay";
|
||||
var srcString =
|
||||
"./?push=" +
|
||||
streamID +
|
||||
"&cleanoutput&privacy&webcam&audiodevice=0&fullscreen";
|
||||
"&cleanoutput&privacy&webcam&audiodevice=0&fullscreen&transparent";
|
||||
|
||||
if (urlParams.has("turn")) {
|
||||
srcString = srcString + "&turn=" + urlParams.get("turn");
|
||||
@ -95,6 +100,11 @@
|
||||
document.getElementById("container").appendChild(feeds);
|
||||
document.getElementById("feeds").appendChild(iframeContainer);
|
||||
|
||||
|
||||
setInterval(function (iframe1) {
|
||||
iframe1.contentWindow.postMessage({ getStats: true }, "*");
|
||||
}, 1000, iframe);
|
||||
|
||||
var iframe = document.createElement("iframe");
|
||||
var iframeContainer = document.createElement("span");
|
||||
|
||||
@ -208,9 +218,26 @@
|
||||
}
|
||||
if ("stats" in e.data) {
|
||||
var out = "";
|
||||
|
||||
for (var streamID in e.data.stats.inbound_stats) {
|
||||
out += printValues(e.data.stats.inbound_stats[streamID]);
|
||||
}
|
||||
|
||||
for (var streamID in e.data.stats.outbound_stats) {
|
||||
if (e.data.stats.outbound_stats[streamID].quality_Limitation_Reason){
|
||||
if (quality_reason != e.data.stats.outbound_stats[streamID].quality_Limitation_Reason) {
|
||||
quality_reason = e.data.stats.outbound_stats[streamID].quality_Limitation_Reason;
|
||||
logData("Quality Limitation Reason:", quality_reason);
|
||||
}
|
||||
}
|
||||
|
||||
if (e.data.stats.outbound_stats[streamID].encoder){
|
||||
if (encoder != e.data.stats.outbound_stats[streamID].encoder) {
|
||||
encoder = e.data.stats.outbound_stats[streamID].encoder;
|
||||
logData("Encoder used:", encoder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (out.split("Bitrate_in_kbps").length > 1) {
|
||||
for (var key in e.data.stats.inbound_stats[streamID]) {
|
||||
@ -246,8 +273,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById("statsdiv").innerHTML =
|
||||
"<b>Bitrate (Kbps)</b>" + out.split("Bitrate_in_kbps")[1];
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -279,21 +304,9 @@
|
||||
</script>
|
||||
</head>
|
||||
<body onload="loadIframe();">
|
||||
<div id="header">
|
||||
<a
|
||||
id="logoname"
|
||||
href="./"
|
||||
style="text-decoration: none; color: white; margin: 2px"
|
||||
>
|
||||
<span data-translate="logo-header">
|
||||
<font id="qos">O</font>BS.Ninja
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="container">
|
||||
<h1>
|
||||
OBS.Ninja Speed Test - prototype version
|
||||
<small>(Tests connection to TURN server and back)</small>
|
||||
OBS.Ninja Speed Test
|
||||
</h1>
|
||||
</div>
|
||||
<div id="graphs">
|
||||
@ -343,7 +356,6 @@
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div id="statsdiv"></div>
|
||||
|
||||
<script>
|
||||
var bitrate = {
|
||||
|
||||
35
thirdparty/aes.js
vendored
Normal file
35
thirdparty/aes.js
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
CryptoJS v3.1.2
|
||||
code.google.com/p/crypto-js
|
||||
(c) 2009-2013 by Jeff Mott. All rights reserved.
|
||||
code.google.com/p/crypto-js/wiki/License
|
||||
*/
|
||||
var CryptoJS=CryptoJS||function(u,p){var d={},l=d.lib={},s=function(){},t=l.Base={extend:function(a){s.prototype=this;var c=new s;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},
|
||||
r=l.WordArray=t.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=p?c:4*a.length},toString:function(a){return(a||v).stringify(this)},concat:function(a){var c=this.words,e=a.words,j=this.sigBytes;a=a.sigBytes;this.clamp();if(j%4)for(var k=0;k<a;k++)c[j+k>>>2]|=(e[k>>>2]>>>24-8*(k%4)&255)<<24-8*((j+k)%4);else if(65535<e.length)for(k=0;k<a;k+=4)c[j+k>>>2]=e[k>>>2];else c.push.apply(c,e);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<
|
||||
32-8*(c%4);a.length=u.ceil(c/4)},clone:function(){var a=t.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],e=0;e<a;e+=4)c.push(4294967296*u.random()|0);return new r.init(c,a)}}),w=d.enc={},v=w.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++){var k=c[j>>>2]>>>24-8*(j%4)&255;e.push((k>>>4).toString(16));e.push((k&15).toString(16))}return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j+=2)e[j>>>3]|=parseInt(a.substr(j,
|
||||
2),16)<<24-4*(j%8);return new r.init(e,c/2)}},b=w.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++)e.push(String.fromCharCode(c[j>>>2]>>>24-8*(j%4)&255));return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j++)e[j>>>2]|=(a.charCodeAt(j)&255)<<24-8*(j%4);return new r.init(e,c)}},x=w.Utf8={stringify:function(a){try{return decodeURIComponent(escape(b.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return b.parse(unescape(encodeURIComponent(a)))}},
|
||||
q=l.BufferedBlockAlgorithm=t.extend({reset:function(){this._data=new r.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=x.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,e=c.words,j=c.sigBytes,k=this.blockSize,b=j/(4*k),b=a?u.ceil(b):u.max((b|0)-this._minBufferSize,0);a=b*k;j=u.min(4*a,j);if(a){for(var q=0;q<a;q+=k)this._doProcessBlock(e,q);q=e.splice(0,a);c.sigBytes-=j}return new r.init(q,j)},clone:function(){var a=t.clone.call(this);
|
||||
a._data=this._data.clone();return a},_minBufferSize:0});l.Hasher=q.extend({cfg:t.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){q.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(b,e){return(new a.init(e)).finalize(b)}},_createHmacHelper:function(a){return function(b,e){return(new n.HMAC.init(a,
|
||||
e)).finalize(b)}}});var n=d.algo={};return d}(Math);
|
||||
(function(){var u=CryptoJS,p=u.lib.WordArray;u.enc.Base64={stringify:function(d){var l=d.words,p=d.sigBytes,t=this._map;d.clamp();d=[];for(var r=0;r<p;r+=3)for(var w=(l[r>>>2]>>>24-8*(r%4)&255)<<16|(l[r+1>>>2]>>>24-8*((r+1)%4)&255)<<8|l[r+2>>>2]>>>24-8*((r+2)%4)&255,v=0;4>v&&r+0.75*v<p;v++)d.push(t.charAt(w>>>6*(3-v)&63));if(l=t.charAt(64))for(;d.length%4;)d.push(l);return d.join("")},parse:function(d){var l=d.length,s=this._map,t=s.charAt(64);t&&(t=d.indexOf(t),-1!=t&&(l=t));for(var t=[],r=0,w=0;w<
|
||||
l;w++)if(w%4){var v=s.indexOf(d.charAt(w-1))<<2*(w%4),b=s.indexOf(d.charAt(w))>>>6-2*(w%4);t[r>>>2]|=(v|b)<<24-8*(r%4);r++}return p.create(t,r)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}})();
|
||||
(function(u){function p(b,n,a,c,e,j,k){b=b+(n&a|~n&c)+e+k;return(b<<j|b>>>32-j)+n}function d(b,n,a,c,e,j,k){b=b+(n&c|a&~c)+e+k;return(b<<j|b>>>32-j)+n}function l(b,n,a,c,e,j,k){b=b+(n^a^c)+e+k;return(b<<j|b>>>32-j)+n}function s(b,n,a,c,e,j,k){b=b+(a^(n|~c))+e+k;return(b<<j|b>>>32-j)+n}for(var t=CryptoJS,r=t.lib,w=r.WordArray,v=r.Hasher,r=t.algo,b=[],x=0;64>x;x++)b[x]=4294967296*u.abs(u.sin(x+1))|0;r=r.MD5=v.extend({_doReset:function(){this._hash=new w.init([1732584193,4023233417,2562383102,271733878])},
|
||||
_doProcessBlock:function(q,n){for(var a=0;16>a;a++){var c=n+a,e=q[c];q[c]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360}var a=this._hash.words,c=q[n+0],e=q[n+1],j=q[n+2],k=q[n+3],z=q[n+4],r=q[n+5],t=q[n+6],w=q[n+7],v=q[n+8],A=q[n+9],B=q[n+10],C=q[n+11],u=q[n+12],D=q[n+13],E=q[n+14],x=q[n+15],f=a[0],m=a[1],g=a[2],h=a[3],f=p(f,m,g,h,c,7,b[0]),h=p(h,f,m,g,e,12,b[1]),g=p(g,h,f,m,j,17,b[2]),m=p(m,g,h,f,k,22,b[3]),f=p(f,m,g,h,z,7,b[4]),h=p(h,f,m,g,r,12,b[5]),g=p(g,h,f,m,t,17,b[6]),m=p(m,g,h,f,w,22,b[7]),
|
||||
f=p(f,m,g,h,v,7,b[8]),h=p(h,f,m,g,A,12,b[9]),g=p(g,h,f,m,B,17,b[10]),m=p(m,g,h,f,C,22,b[11]),f=p(f,m,g,h,u,7,b[12]),h=p(h,f,m,g,D,12,b[13]),g=p(g,h,f,m,E,17,b[14]),m=p(m,g,h,f,x,22,b[15]),f=d(f,m,g,h,e,5,b[16]),h=d(h,f,m,g,t,9,b[17]),g=d(g,h,f,m,C,14,b[18]),m=d(m,g,h,f,c,20,b[19]),f=d(f,m,g,h,r,5,b[20]),h=d(h,f,m,g,B,9,b[21]),g=d(g,h,f,m,x,14,b[22]),m=d(m,g,h,f,z,20,b[23]),f=d(f,m,g,h,A,5,b[24]),h=d(h,f,m,g,E,9,b[25]),g=d(g,h,f,m,k,14,b[26]),m=d(m,g,h,f,v,20,b[27]),f=d(f,m,g,h,D,5,b[28]),h=d(h,f,
|
||||
m,g,j,9,b[29]),g=d(g,h,f,m,w,14,b[30]),m=d(m,g,h,f,u,20,b[31]),f=l(f,m,g,h,r,4,b[32]),h=l(h,f,m,g,v,11,b[33]),g=l(g,h,f,m,C,16,b[34]),m=l(m,g,h,f,E,23,b[35]),f=l(f,m,g,h,e,4,b[36]),h=l(h,f,m,g,z,11,b[37]),g=l(g,h,f,m,w,16,b[38]),m=l(m,g,h,f,B,23,b[39]),f=l(f,m,g,h,D,4,b[40]),h=l(h,f,m,g,c,11,b[41]),g=l(g,h,f,m,k,16,b[42]),m=l(m,g,h,f,t,23,b[43]),f=l(f,m,g,h,A,4,b[44]),h=l(h,f,m,g,u,11,b[45]),g=l(g,h,f,m,x,16,b[46]),m=l(m,g,h,f,j,23,b[47]),f=s(f,m,g,h,c,6,b[48]),h=s(h,f,m,g,w,10,b[49]),g=s(g,h,f,m,
|
||||
E,15,b[50]),m=s(m,g,h,f,r,21,b[51]),f=s(f,m,g,h,u,6,b[52]),h=s(h,f,m,g,k,10,b[53]),g=s(g,h,f,m,B,15,b[54]),m=s(m,g,h,f,e,21,b[55]),f=s(f,m,g,h,v,6,b[56]),h=s(h,f,m,g,x,10,b[57]),g=s(g,h,f,m,t,15,b[58]),m=s(m,g,h,f,D,21,b[59]),f=s(f,m,g,h,z,6,b[60]),h=s(h,f,m,g,C,10,b[61]),g=s(g,h,f,m,j,15,b[62]),m=s(m,g,h,f,A,21,b[63]);a[0]=a[0]+f|0;a[1]=a[1]+m|0;a[2]=a[2]+g|0;a[3]=a[3]+h|0},_doFinalize:function(){var b=this._data,n=b.words,a=8*this._nDataBytes,c=8*b.sigBytes;n[c>>>5]|=128<<24-c%32;var e=u.floor(a/
|
||||
4294967296);n[(c+64>>>9<<4)+15]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360;n[(c+64>>>9<<4)+14]=(a<<8|a>>>24)&16711935|(a<<24|a>>>8)&4278255360;b.sigBytes=4*(n.length+1);this._process();b=this._hash;n=b.words;for(a=0;4>a;a++)c=n[a],n[a]=(c<<8|c>>>24)&16711935|(c<<24|c>>>8)&4278255360;return b},clone:function(){var b=v.clone.call(this);b._hash=this._hash.clone();return b}});t.MD5=v._createHelper(r);t.HmacMD5=v._createHmacHelper(r)})(Math);
|
||||
(function(){var u=CryptoJS,p=u.lib,d=p.Base,l=p.WordArray,p=u.algo,s=p.EvpKDF=d.extend({cfg:d.extend({keySize:4,hasher:p.MD5,iterations:1}),init:function(d){this.cfg=this.cfg.extend(d)},compute:function(d,r){for(var p=this.cfg,s=p.hasher.create(),b=l.create(),u=b.words,q=p.keySize,p=p.iterations;u.length<q;){n&&s.update(n);var n=s.update(d).finalize(r);s.reset();for(var a=1;a<p;a++)n=s.finalize(n),s.reset();b.concat(n)}b.sigBytes=4*q;return b}});u.EvpKDF=function(d,l,p){return s.create(p).compute(d,
|
||||
l)}})();
|
||||
CryptoJS.lib.Cipher||function(u){var p=CryptoJS,d=p.lib,l=d.Base,s=d.WordArray,t=d.BufferedBlockAlgorithm,r=p.enc.Base64,w=p.algo.EvpKDF,v=d.Cipher=t.extend({cfg:l.extend(),createEncryptor:function(e,a){return this.create(this._ENC_XFORM_MODE,e,a)},createDecryptor:function(e,a){return this.create(this._DEC_XFORM_MODE,e,a)},init:function(e,a,b){this.cfg=this.cfg.extend(b);this._xformMode=e;this._key=a;this.reset()},reset:function(){t.reset.call(this);this._doReset()},process:function(e){this._append(e);return this._process()},
|
||||
finalize:function(e){e&&this._append(e);return this._doFinalize()},keySize:4,ivSize:4,_ENC_XFORM_MODE:1,_DEC_XFORM_MODE:2,_createHelper:function(e){return{encrypt:function(b,k,d){return("string"==typeof k?c:a).encrypt(e,b,k,d)},decrypt:function(b,k,d){return("string"==typeof k?c:a).decrypt(e,b,k,d)}}}});d.StreamCipher=v.extend({_doFinalize:function(){return this._process(!0)},blockSize:1});var b=p.mode={},x=function(e,a,b){var c=this._iv;c?this._iv=u:c=this._prevBlock;for(var d=0;d<b;d++)e[a+d]^=
|
||||
c[d]},q=(d.BlockCipherMode=l.extend({createEncryptor:function(e,a){return this.Encryptor.create(e,a)},createDecryptor:function(e,a){return this.Decryptor.create(e,a)},init:function(e,a){this._cipher=e;this._iv=a}})).extend();q.Encryptor=q.extend({processBlock:function(e,a){var b=this._cipher,c=b.blockSize;x.call(this,e,a,c);b.encryptBlock(e,a);this._prevBlock=e.slice(a,a+c)}});q.Decryptor=q.extend({processBlock:function(e,a){var b=this._cipher,c=b.blockSize,d=e.slice(a,a+c);b.decryptBlock(e,a);x.call(this,
|
||||
e,a,c);this._prevBlock=d}});b=b.CBC=q;q=(p.pad={}).Pkcs7={pad:function(a,b){for(var c=4*b,c=c-a.sigBytes%c,d=c<<24|c<<16|c<<8|c,l=[],n=0;n<c;n+=4)l.push(d);c=s.create(l,c);a.concat(c)},unpad:function(a){a.sigBytes-=a.words[a.sigBytes-1>>>2]&255}};d.BlockCipher=v.extend({cfg:v.cfg.extend({mode:b,padding:q}),reset:function(){v.reset.call(this);var a=this.cfg,b=a.iv,a=a.mode;if(this._xformMode==this._ENC_XFORM_MODE)var c=a.createEncryptor;else c=a.createDecryptor,this._minBufferSize=1;this._mode=c.call(a,
|
||||
this,b&&b.words)},_doProcessBlock:function(a,b){this._mode.processBlock(a,b)},_doFinalize:function(){var a=this.cfg.padding;if(this._xformMode==this._ENC_XFORM_MODE){a.pad(this._data,this.blockSize);var b=this._process(!0)}else b=this._process(!0),a.unpad(b);return b},blockSize:4});var n=d.CipherParams=l.extend({init:function(a){this.mixIn(a)},toString:function(a){return(a||this.formatter).stringify(this)}}),b=(p.format={}).OpenSSL={stringify:function(a){var b=a.ciphertext;a=a.salt;return(a?s.create([1398893684,
|
||||
1701076831]).concat(a).concat(b):b).toString(r)},parse:function(a){a=r.parse(a);var b=a.words;if(1398893684==b[0]&&1701076831==b[1]){var c=s.create(b.slice(2,4));b.splice(0,4);a.sigBytes-=16}return n.create({ciphertext:a,salt:c})}},a=d.SerializableCipher=l.extend({cfg:l.extend({format:b}),encrypt:function(a,b,c,d){d=this.cfg.extend(d);var l=a.createEncryptor(c,d);b=l.finalize(b);l=l.cfg;return n.create({ciphertext:b,key:c,iv:l.iv,algorithm:a,mode:l.mode,padding:l.padding,blockSize:a.blockSize,formatter:d.format})},
|
||||
decrypt:function(a,b,c,d){d=this.cfg.extend(d);b=this._parse(b,d.format);return a.createDecryptor(c,d).finalize(b.ciphertext)},_parse:function(a,b){return"string"==typeof a?b.parse(a,this):a}}),p=(p.kdf={}).OpenSSL={execute:function(a,b,c,d){d||(d=s.random(8));a=w.create({keySize:b+c}).compute(a,d);c=s.create(a.words.slice(b),4*c);a.sigBytes=4*b;return n.create({key:a,iv:c,salt:d})}},c=d.PasswordBasedCipher=a.extend({cfg:a.cfg.extend({kdf:p}),encrypt:function(b,c,d,l){l=this.cfg.extend(l);d=l.kdf.execute(d,
|
||||
b.keySize,b.ivSize);l.iv=d.iv;b=a.encrypt.call(this,b,c,d.key,l);b.mixIn(d);return b},decrypt:function(b,c,d,l){l=this.cfg.extend(l);c=this._parse(c,l.format);d=l.kdf.execute(d,b.keySize,b.ivSize,c.salt);l.iv=d.iv;return a.decrypt.call(this,b,c,d.key,l)}})}();
|
||||
(function(){for(var u=CryptoJS,p=u.lib.BlockCipher,d=u.algo,l=[],s=[],t=[],r=[],w=[],v=[],b=[],x=[],q=[],n=[],a=[],c=0;256>c;c++)a[c]=128>c?c<<1:c<<1^283;for(var e=0,j=0,c=0;256>c;c++){var k=j^j<<1^j<<2^j<<3^j<<4,k=k>>>8^k&255^99;l[e]=k;s[k]=e;var z=a[e],F=a[z],G=a[F],y=257*a[k]^16843008*k;t[e]=y<<24|y>>>8;r[e]=y<<16|y>>>16;w[e]=y<<8|y>>>24;v[e]=y;y=16843009*G^65537*F^257*z^16843008*e;b[k]=y<<24|y>>>8;x[k]=y<<16|y>>>16;q[k]=y<<8|y>>>24;n[k]=y;e?(e=z^a[a[a[G^z]]],j^=a[a[j]]):e=j=1}var H=[0,1,2,4,8,
|
||||
16,32,64,128,27,54],d=d.AES=p.extend({_doReset:function(){for(var a=this._key,c=a.words,d=a.sigBytes/4,a=4*((this._nRounds=d+6)+1),e=this._keySchedule=[],j=0;j<a;j++)if(j<d)e[j]=c[j];else{var k=e[j-1];j%d?6<d&&4==j%d&&(k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255]):(k=k<<8|k>>>24,k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255],k^=H[j/d|0]<<24);e[j]=e[j-d]^k}c=this._invKeySchedule=[];for(d=0;d<a;d++)j=a-d,k=d%4?e[j]:e[j-4],c[d]=4>d||4>=j?k:b[l[k>>>24]]^x[l[k>>>16&255]]^q[l[k>>>
|
||||
8&255]]^n[l[k&255]]},encryptBlock:function(a,b){this._doCryptBlock(a,b,this._keySchedule,t,r,w,v,l)},decryptBlock:function(a,c){var d=a[c+1];a[c+1]=a[c+3];a[c+3]=d;this._doCryptBlock(a,c,this._invKeySchedule,b,x,q,n,s);d=a[c+1];a[c+1]=a[c+3];a[c+3]=d},_doCryptBlock:function(a,b,c,d,e,j,l,f){for(var m=this._nRounds,g=a[b]^c[0],h=a[b+1]^c[1],k=a[b+2]^c[2],n=a[b+3]^c[3],p=4,r=1;r<m;r++)var q=d[g>>>24]^e[h>>>16&255]^j[k>>>8&255]^l[n&255]^c[p++],s=d[h>>>24]^e[k>>>16&255]^j[n>>>8&255]^l[g&255]^c[p++],t=
|
||||
d[k>>>24]^e[n>>>16&255]^j[g>>>8&255]^l[h&255]^c[p++],n=d[n>>>24]^e[g>>>16&255]^j[h>>>8&255]^l[k&255]^c[p++],g=q,h=s,k=t;q=(f[g>>>24]<<24|f[h>>>16&255]<<16|f[k>>>8&255]<<8|f[n&255])^c[p++];s=(f[h>>>24]<<24|f[k>>>16&255]<<16|f[n>>>8&255]<<8|f[g&255])^c[p++];t=(f[k>>>24]<<24|f[n>>>16&255]<<16|f[g>>>8&255]<<8|f[h&255])^c[p++];n=(f[n>>>24]<<24|f[g>>>16&255]<<16|f[h>>>8&255]<<8|f[k&255])^c[p++];a[b]=q;a[b+1]=s;a[b+2]=t;a[b+3]=n},keySize:8});u.AES=p._createHelper(d)})();
|
||||
50
translations/default.json
Normal file
50
translations/default.json
Normal file
@ -0,0 +1,50 @@
|
||||
{
|
||||
"logo-header": "<font id=\"qos\" style=\"color: white;\">O</font>BS.Ninja ",
|
||||
"GO": "GO",
|
||||
"copy-this-url": "Copy this URL into an OBS \"Browser Source\"",
|
||||
"you-are-in-the-control-center": "You are in the room's control center",
|
||||
"joining-room": "You are joining room",
|
||||
"add-group-chat": "Add Group Chat to OBS",
|
||||
"rooms-allow-for": "Rooms allow for simplified group-chat and the advanced management of multiple streams at once.",
|
||||
"room-name": "Room Name",
|
||||
"enter-the-rooms-control": "Enter the Room's Control Center",
|
||||
"show-tips": "Show me some tips..",
|
||||
"added-notes": "\n<u><i>Added Notes:</i></u>\n<li>Anyone can enter a room if they know the name, so keep it unique</li>\n<li>Invite only guests to the room you trust.</li>\n<li>iOS devices will share just their audio with other guests; this is mainly a hardware limitation</li>\n<li>The \"Recording\" option is considered experimental.</li>\n",
|
||||
"back": "Back",
|
||||
"add-your-camera": "Add your Camera to OBS",
|
||||
"waiting-for-camera": "Waiting for Camera to Load",
|
||||
"video-source": "Video source",
|
||||
"max-resolution": "1080p (hi-def)",
|
||||
"balanced": "720p (balanced)",
|
||||
"smooth-cool": "360p (smooth)",
|
||||
"select-audio-source": "Select Audio Source",
|
||||
"no-audio": "No Audio",
|
||||
"remote-screenshare-obs": "Remote Screenshare into OBS",
|
||||
"note-share-audio": "\n<b>note</b>: Do not forget to click \"Share audio\" in Chrome.<br>(Firefox does not support audio sharing.)",
|
||||
"select-screen-to-share": "SELECT SCREEN TO SHARE",
|
||||
"audio-sources": "Audio Sources",
|
||||
"create-reusable-invite": "Create Reusable Invite",
|
||||
"here-you-can-pre-generate": "Here you can pre-generate a reusable Browser Source link and a related guest invite link.",
|
||||
"generate-invite-link": "GENERATE THE INVITE LINK",
|
||||
"advanced-paramaters": "Advanced Options:",
|
||||
"unlock-video-bitrate": "Unlock Video Bitrate (20mbps)",
|
||||
"force-vp9-video-codec": "Force VP9 Video Codec (less artifacting)",
|
||||
"enable-stereo-and-pro": "Enable Stereo and Pro HD Audio",
|
||||
"video-resolution": "Video Resolution: ",
|
||||
"high-security-mode": "High Security Mode",
|
||||
"hide-screen-share": "Hide Screenshare Option",
|
||||
"allow-remote-control": "Remote Control Camera Zoom (android)",
|
||||
"add-the-guest-to-a-room": " Add the guest to a room:",
|
||||
"invite-group-chat-type": "This room guest can:",
|
||||
"can-see-and-hear": "Can see and hear the group chat",
|
||||
"can-hear-only": "Can only hear the group chat",
|
||||
"cant-see-or-hear": "Cannot hear or see the group chat",
|
||||
"info-blob": "\n<h2>What is OBS.Ninja</h2><br>\n<li>100% <b>free</b>; no downloads; no personal data collection; no sign-in</li>\n<li>Bring video from your smartphone, computer, or friends directly into your OBS video stream</li>\n<li>We use cutting edge Peer-to-Peer forwarding technology that offers privacy and ultra-low latency</li>\n<br>\n<li>Youtube video <i class=\"fa fa-youtube-play\" aria-hidden=\"true\"></i> <a href=\"https://www.youtube.com/watch?v=6R_sQKxFAhg\">Demoing it here</a> </li>\n<br>\n<i><font style=\"color:red\">Known issues:</font></i><br>\n<li><i class=\"fa fa-apple\" aria-hidden=\"true\"></i> <a href=\"https://github.com/steveseguin/obsninja/wiki/FAQ#mac-os\">MacOS users</a> need to use OBS v23 or resort to <a href=\"https://github.com/steveseguin/electroncapture\">Window Capturing</a> a browser with OBS v25</li>\n<li>Some users will have <a href=\"https://github.com/steveseguin/obsninja/wiki/FAQ#video-is-pixelated\">\"pixelation\" problems</a> with videos. Adding <b>&codec=vp9</b> to the OBS links will often correct it.</li>\n<br>\n",
|
||||
"remote-control-for-obs": "Remote Control for OBS",
|
||||
"add-to-group": "Add to Group Scene",
|
||||
"mute": "Mute",
|
||||
"record": "Record",
|
||||
"volume": "Volume",
|
||||
"open-in-new-tab": "Open in new Tab",
|
||||
"copy-to-clipboard": "Copy to Clipboard"
|
||||
}
|
||||
@ -36,27 +36,30 @@ function updateTranslation(filename) { // updates the website with a specific tr
|
||||
}
|
||||
|
||||
const oldTransItems = data.innerHTML;
|
||||
const allItems1 = document.querySelectorAll('[data-translate]');
|
||||
// const allItems1 = document.querySelectorAll('[data-translate]');
|
||||
|
||||
allItems1.forEach((ele) => {
|
||||
if (ele.dataset.translate in oldTransItems) {
|
||||
ele.innerHTML = oldTransItems[ele.dataset.translate];
|
||||
allItems.forEach((ele) => {
|
||||
const key = ele.dataset.translate;//.replace(/[\W]+/g, "-").toLowerCase();
|
||||
if (key in oldTransItems) {
|
||||
ele.innerHTML = oldTransItems[key];
|
||||
}
|
||||
});
|
||||
|
||||
const oldTransTitles = data.titles;
|
||||
const allTitles1 = document.querySelectorAll('[title]');
|
||||
allTitles1.forEach((ele) => {
|
||||
const key = ele.title.replace(/[\W]+/g, "-").toLowerCase();
|
||||
//const allTitles1 = document.querySelectorAll('[title]');
|
||||
allTitles.forEach((ele) => {
|
||||
const key = ele.dataset.key;
|
||||
//const key = ele.title.replace(/[\W]+/g, "-").toLowerCase();
|
||||
if (key in oldTransTitles) {
|
||||
ele.title = oldTransTitles[key];
|
||||
}
|
||||
});
|
||||
|
||||
const oldTransPlaceholders = data.placeholders;
|
||||
const allPlaceholders1 = document.querySelectorAll('[placeholder]');
|
||||
allPlaceholders1.forEach((ele) => {
|
||||
const key = ele.placeholder.replace(/[\W]+/g, "-").toLowerCase();
|
||||
//const allPlaceholders1 = document.querySelectorAll('[placeholder]');
|
||||
allPlaceholders.forEach((ele) => {
|
||||
const key = ele.dataset.key;
|
||||
//const key = ele.placeholder.replace(/[\W]+/g, "-").toLowerCase();
|
||||
if (key in oldTransPlaceholders) {
|
||||
ele.placeholder = oldTransPlaceholders[key];
|
||||
}
|
||||
@ -84,20 +87,24 @@ const updateList = [
|
||||
const allItems = document.querySelectorAll('[data-translate]');
|
||||
const defaultTrans = {};
|
||||
allItems.forEach((ele) => {
|
||||
const key = ele.dataset.translate.replace(/[\W]+/g, "-").toLowerCase();
|
||||
const key = ele.dataset.translate;//.replace(/[\W]+/g, "-").toLowerCase();
|
||||
defaultTrans[key] = ele.innerHTML;
|
||||
});
|
||||
|
||||
const defaultTransTitles = {};
|
||||
const allTitles = document.querySelectorAll('[title]');
|
||||
allTitles.forEach((ele) => {
|
||||
defaultTransTitles[ele.title] = ele.title;
|
||||
const key = ele.title.replace(/[\W]+/g, "-").toLowerCase();
|
||||
ele.dataset.key = key;
|
||||
defaultTransTitles[key] = ele.title;
|
||||
});
|
||||
|
||||
const defaultTransPlaceholders = {};
|
||||
const allPlaceholders = document.querySelectorAll('[placeholder]');
|
||||
allPlaceholders.forEach((ele) => {
|
||||
defaultTransPlaceholders[ele.placeholder] = ele.placeholder;
|
||||
const key = ele.placeholder.replace(/[\W]+/g, "-").toLowerCase();
|
||||
ele.dataset.key = key;
|
||||
defaultTransPlaceholders[key] = ele.placeholder;
|
||||
});
|
||||
|
||||
const combinedTrans = {};
|
||||
@ -112,23 +119,23 @@ for (const i in updateList) {
|
||||
var suceess = updateTranslation(ln); // we don't need to worry about DATA.
|
||||
if (suceess[0] == true) {
|
||||
const newTrans = suceess[1].innerHTML;
|
||||
const allItems = document.querySelectorAll('[data-translate]');
|
||||
//const allItems = document.querySelectorAll('[data-translate]');
|
||||
allItems.forEach((ele) => {
|
||||
const key = ele.dataset.translate;
|
||||
const key = ele.dataset.translate;//.replace(/[\W]+/g, "-").toLowerCase();
|
||||
newTrans[key] = ele.innerHTML;
|
||||
});
|
||||
|
||||
const newTransTitles = suceess[1].titles;
|
||||
const allTitles = document.querySelectorAll('[title]');
|
||||
//const allTitles = document.querySelectorAll('[title]');
|
||||
allTitles.forEach((ele) => {
|
||||
const key = ele.title.replace(/[\W]+/g, "-").toLowerCase();
|
||||
const key = ele.dataset.key;
|
||||
newTransTitles[key] = ele.title;
|
||||
});
|
||||
|
||||
const newPlaceholders = suceess[1].placeholders;
|
||||
const allPlaceholders = document.querySelectorAll('[placeholder]');
|
||||
// const allPlaceholders = document.querySelectorAll('[placeholder]');
|
||||
allPlaceholders.forEach((ele) => {
|
||||
const key = ele.placeholder.replace(/[\W]+/g, "-").toLowerCase();
|
||||
const key = ele.dataset.key;
|
||||
newPlaceholders[key] = ele.placeholder;
|
||||
});
|
||||
|
||||
@ -141,22 +148,23 @@ for (const i in updateList) {
|
||||
}
|
||||
// //////// RESET THING BACK
|
||||
allItems.forEach((ele) => {
|
||||
if (ele.dataset.translate in defaultTrans) {
|
||||
ele.innerHTML = defaultTrans[ele.dataset.translate];
|
||||
const key = ele.dataset.translate;//.replace(/[\W]+/g, "-").toLowerCase();
|
||||
if (key in defaultTrans) {
|
||||
ele.innerHTML = defaultTrans[key];
|
||||
}
|
||||
});
|
||||
allTitles.forEach((ele) => {
|
||||
const key = ele.title.replace(/[\W]+/g, "-").toLowerCase();
|
||||
const key = ele.dataset.key;
|
||||
if (key in defaultTransTitles) {
|
||||
ele.title = defaultTransTitles[key];
|
||||
}
|
||||
});
|
||||
allPlaceholders.forEach((ele) => {
|
||||
const key = ele.placeholder.replace(/[\W]+/g, "-").toLowerCase();
|
||||
const key = ele.dataset.key;
|
||||
if (key in defaultTransPlaceholders) {
|
||||
ele.placeholder = defaultTransPlaceholders[key];
|
||||
}
|
||||
});
|
||||
}, counter, lang);
|
||||
counter += 300;
|
||||
counter += 800;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user