mirror of
https://github.com/eliasstepanik/vdo.ninja.git
synced 2026-01-11 13:48:38 +00:00
I've fixed issues with innerHTML calls in this release that would normally totally break things if there were changes to index.html. Now, if there is an error, it is handled more gracefully and usually just a single UI element breaks. You should be able to customize the index.html file now without too many hassles. You will also notice that the index.html has the following line: <script type="text/javascript" id="main-js" data-translation="blank" src="./main.js"></script> you can specify different languages or different branding/wording translations by setting the data-translation value to that of the json filename located in the translations folder. You can also create your own json files and specify them that way. By default I am specifying the "blank" translation. I'm trying to steer the app code in the direction of being a bit like a library, for numerous reasons, but please reach out if you have issues with this new release. This release has numerous bug fixes and uses a new handshake server to improve the group-room experience, which I will continue to update. I will continue to work towards allowing greater accessibility in stylizing the application.
321 lines
8.6 KiB
HTML
321 lines
8.6 KiB
HTML
<html>
|
|
<head><style>
|
|
html {
|
|
border:0;
|
|
margin:0;
|
|
}
|
|
|
|
video {
|
|
|
|
margin: 0;
|
|
padding: 0;
|
|
overflow: hidden;
|
|
cursor: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=), none;
|
|
user-select: none;
|
|
|
|
}
|
|
body {
|
|
padding: 0 0px;
|
|
height: 100%;
|
|
width: 100%;
|
|
background-color: #141926;
|
|
background-color: -webkit-linear-gradient(to top, #181925, #141826, #0F2027); /* Chrome 10-25, Safari 5.1-6 */
|
|
background-color: linear-gradient(to top, #181825, #141926, #0F2027); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
|
|
|
|
font-size: 2em;
|
|
font-family: Helvetica, Arial, sans-serif;
|
|
display: flex;
|
|
flex-flow: column;
|
|
border:0;
|
|
margin:0;
|
|
|
|
}
|
|
button{
|
|
padding:10px;
|
|
font-size: 20px;
|
|
margin: auto auto;
|
|
}
|
|
#header{
|
|
height:80px;
|
|
width:100%;
|
|
background-color: #101520;
|
|
}
|
|
.inputfield{
|
|
font-size: 20px;
|
|
align-self:center;
|
|
height:30px;
|
|
width:780px;
|
|
margin: auto auto;
|
|
padding:20px
|
|
}
|
|
|
|
.formcss{
|
|
font-size: 20px;
|
|
align-self:center;
|
|
margin: auto auto;
|
|
}
|
|
label {
|
|
font: white;
|
|
font-size: 1em;
|
|
color: white;
|
|
}
|
|
input[type='checkbox'] {
|
|
-webkit-appearance:none;
|
|
width:30px;
|
|
height:30px;
|
|
background:white;
|
|
border-radius:5px;
|
|
border:2px solid #555;
|
|
cursor: pointer;
|
|
}
|
|
input[type='checkbox']:checked {
|
|
background: #1A1;
|
|
}
|
|
</style></head>
|
|
<body >
|
|
|
|
<div id="header" style="-webkit-app-region: drag;color:white;font-size:2em">OBS.Ninja</div>
|
|
<div class="formcss" >
|
|
|
|
<input type="checkbox" class="check" id="prefervp9" name="prefervp9" value="false" onclick="modURL(this);">
|
|
<label for="prefervp9">Force VP9 Codec</label>
|
|
|
|
<input type="checkbox" class="check" id="showcursor" name="showcursor" value="false" onclick="modURL(this);">
|
|
<label for="showcursor">Show Mouse Cursor</label>
|
|
|
|
<input type="checkbox" class="check" id="highbitrate" name="highbitrate" value="false" onclick="modURL(this);">
|
|
<label for="highbitrate">High Video Bitrate</label>
|
|
|
|
<input type="checkbox" class="check" id="stereo" name="stereo" value="false" onclick="modURL(this);">
|
|
<label for="stereo">Pro Audio Mode</label>
|
|
|
|
<input type="checkbox" class="check" id="buffer" name="buffer" value="false" onclick="modURL(this);">
|
|
<label for="buffer">Lip-sync Fix</label>
|
|
|
|
<br><br><br>
|
|
<div class="formcss"><center>
|
|
<input type="text" id="changeText" class="inputfield" value="http://obs.ninja/?view=" onchange="modURL" onkeyup="enterPressed(event, gohere);" />
|
|
<button onclick="gohere();" id="gobutton">GO</button>
|
|
<br><br>
|
|
<label for="audioOutput">Audio output destination: </label><select id="audioOutput" style="max-width:400px"></select>
|
|
|
|
</center></div>
|
|
</div>
|
|
|
|
|
|
<script>
|
|
/*
|
|
* Copyright (c) 2020 Steve Seguin. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by the APGLv3 open-source license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. Alternative licencing options can be made available on request.
|
|
*
|
|
*/
|
|
|
|
var audioOutputSelect = document.querySelector('select#audioOutput');
|
|
audioOutputSelect.disabled = !('sinkId' in HTMLMediaElement.prototype);
|
|
audioOutputSelect.onclick = getPermssions;
|
|
audioOutputSelect.onchange = updateOutputTarget;
|
|
var listed = false;
|
|
|
|
function updateOutputTarget(e){
|
|
console.log("change audio: "+audioOutputSelect.value);
|
|
var url = document.getElementById('changeText').value;
|
|
url=updateURLParameter(url, "sink", audioOutputSelect.value);
|
|
document.getElementById('changeText').value = url;
|
|
}
|
|
|
|
function getPermssions(e){
|
|
if (listed==true){
|
|
return;
|
|
}
|
|
e.currentTarget.blur();
|
|
navigator.mediaDevices.getUserMedia({audio: true,video: false}).then((stream)=>{
|
|
navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(console.error); // list all devices
|
|
stream.getTracks().forEach(track => {
|
|
track.stop();
|
|
});
|
|
listed=true;
|
|
audioOutputSelect.focus();
|
|
|
|
}).catch(function(){alert("Failed to list available output devices\n\nPlease ensure you allowed the microphone permissions.");});
|
|
}
|
|
|
|
function gotDevices(deviceInfos) {
|
|
for (let i = 0; i !== deviceInfos.length; ++i) {
|
|
const deviceInfo = deviceInfos[i];
|
|
const option = document.createElement('option');
|
|
option.value = deviceInfo.deviceId;
|
|
if (deviceInfo.kind === 'audiooutput'){
|
|
option.text = deviceInfo.label || `speaker ${audioOutputSelect.length + 1}`;
|
|
audioOutputSelect.appendChild(option);
|
|
} else {
|
|
console.log('Some other kind of source/device: ', deviceInfo);
|
|
}
|
|
}
|
|
listed=true;
|
|
}
|
|
|
|
function enterPressed(event, callback){
|
|
if (event.keyCode === 13){ // Number 13 is the "Enter" key on the keyboard
|
|
event.preventDefault(); // Cancel the default action, if needed
|
|
callback();
|
|
}
|
|
}
|
|
|
|
(function (w) {
|
|
w.URLSearchParams = w.URLSearchParams || function (searchString) {
|
|
var self = this;
|
|
self.searchString = searchString;
|
|
self.get = function (name) {
|
|
var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(self.searchString);
|
|
if (results == null) {
|
|
return null;
|
|
}
|
|
else {
|
|
return decodeURI(results[1]) || 0;
|
|
}
|
|
};
|
|
}
|
|
|
|
})(window)
|
|
|
|
var urlParams = new URLSearchParams(window.location.search);
|
|
var isMobile = false;
|
|
if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)){ // does not detect iPad Pros.
|
|
isMobile=true; // if iOS, default to H264? meh. let's not.
|
|
}
|
|
|
|
function updateURLParameter(url, param, paramVal){
|
|
var TheAnchor = null;
|
|
var newAdditionalURL = "";
|
|
var tempArray = url.split("?");
|
|
var baseURL = tempArray[0];
|
|
var additionalURL = tempArray[1];
|
|
var temp = "";
|
|
|
|
if (additionalURL){
|
|
var tmpAnchor = additionalURL.split("#");
|
|
var TheParams = tmpAnchor[0];
|
|
TheAnchor = tmpAnchor[1];
|
|
if (TheAnchor){additionalURL = TheParams;}
|
|
|
|
tempArray = additionalURL.split("&");
|
|
|
|
for (var i=0; i<tempArray.length; i++){
|
|
if(tempArray[i].split('=')[0] != param){
|
|
newAdditionalURL += temp + tempArray[i];
|
|
temp = "&";
|
|
}
|
|
}
|
|
} else {
|
|
var tmpAnchor = baseURL.split("#");
|
|
var TheParams = tmpAnchor[0];
|
|
TheAnchor = tmpAnchor[1];
|
|
|
|
if(TheParams){baseURL = TheParams;}
|
|
}
|
|
|
|
if (paramVal===false){
|
|
temp="";
|
|
if(TheAnchor){temp += "#" + TheAnchor;}
|
|
var rows_txt = temp
|
|
} else if (paramVal===""){
|
|
if(TheAnchor){paramVal += "#" + TheAnchor;}
|
|
var rows_txt = temp + "" + param;
|
|
} else {
|
|
if(TheAnchor){paramVal += "#" + TheAnchor;}
|
|
var rows_txt = temp + "" + param + "=" + paramVal;
|
|
}
|
|
return baseURL + "?" + newAdditionalURL + rows_txt;
|
|
}
|
|
|
|
if (urlParams.has('name')){
|
|
var name = urlParams.get('name');
|
|
if (name!="OBSNinja"){
|
|
document.getElementById('changeText').value = "https://obs.ninja/?view="+name;
|
|
}
|
|
}
|
|
|
|
function modURL(ele=false){
|
|
var url = document.getElementById('changeText').value;
|
|
console.log(url);
|
|
if ((url.split("view").length>0) || (url.split("room").length>0)){
|
|
if (!document.getElementById("showcursor").checked){
|
|
url=updateURLParameter(url, "nocursor", "");
|
|
} else {
|
|
url=updateURLParameter(url, "nocursor", false);
|
|
}
|
|
|
|
if (ele!=false){
|
|
if (ele.id =="prefervp9"){
|
|
if (document.getElementById("prefervp9").checked){
|
|
url=updateURLParameter(url, "codec", "vp9");
|
|
} else {
|
|
url=updateURLParameter(url, "codec", false);
|
|
}
|
|
}
|
|
|
|
if (ele.id =="highbitrate"){
|
|
if (document.getElementById("highbitrate").checked){
|
|
url=updateURLParameter(url, "bitrate", "10000");
|
|
} else {
|
|
url=updateURLParameter(url, "bitrate", false);
|
|
}
|
|
}
|
|
|
|
if (ele.id =="stereo"){
|
|
if (document.getElementById("stereo").checked){
|
|
url=updateURLParameter(url, "stereo", "");
|
|
alert('Audio bitrate increased to 256kbps.\n\nPlease note: the Video Publisher must also have the stereo flag enabled for stereo to work.');
|
|
} else {
|
|
url=updateURLParameter(url, "stereo", false);
|
|
}
|
|
}
|
|
|
|
if (ele.id =="buffer"){
|
|
if (document.getElementById("buffer").checked){
|
|
url=updateURLParameter(url, "buffer", "");
|
|
} else {
|
|
url=updateURLParameter(url, "buffer", false);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
document.getElementById('changeText').value = url;
|
|
console.log(url);
|
|
return url;
|
|
}
|
|
function gohere(){
|
|
var url = modURL(true);
|
|
window.location = url;
|
|
};
|
|
</script>
|
|
</body>
|
|
</html>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|