mirror of
https://github.com/eliasstepanik/vdo.ninja.git
synced 2026-01-11 13:48:38 +00:00
587 lines
16 KiB
HTML
587 lines
16 KiB
HTML
<html>
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
|
<link rel="stylesheet" href="./lineawesome/css/line-awesome.min.css" />
|
|
<style>
|
|
html {
|
|
border:0;
|
|
margin:0;
|
|
outline:0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
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: -webkit-linear-gradient(to top, #363644, 50%, #151b29); /* Chrome 10-25, Safari 5.1-6 */
|
|
background: linear-gradient(to top, #363644, 50%, #151b29); /* 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;
|
|
outline:0;
|
|
}
|
|
|
|
button.glyphicon-button:focus,
|
|
button.glyphicon-button:active:focus,
|
|
button.glyphicon-button.active:focus,
|
|
button.glyphicon-button.focus,
|
|
button.glyphicon-button:active.focus,
|
|
button.glyphicon-button.active.focus {
|
|
outline: none !important;
|
|
}
|
|
|
|
#gobutton {
|
|
font-size: 20px;
|
|
font-weight: bold;
|
|
border: none;
|
|
background: #6aab23;
|
|
display: flex;
|
|
border-radius: 0px;
|
|
border-top-right-radius: 10px;
|
|
border-bottom-right-radius: 10px;
|
|
box-shadow: 0 12px 15px -10px #5ca70b, 0 2px 0px #6aab23;
|
|
color: white;
|
|
cursor: pointer;
|
|
box-sizing: border-box;
|
|
align-items: center;
|
|
padding: 0 1em;
|
|
}
|
|
#header{
|
|
width:100%;
|
|
background-color: #101520;
|
|
}
|
|
input#changeText {
|
|
font-size: 1em;
|
|
align-self: center;
|
|
width: 100%;
|
|
padding: 1em;
|
|
font-weight: bold;
|
|
background: white;
|
|
border: 4px solid white;
|
|
box-shadow: 0px 30px 40px -32px #6aab23, 0 2px 0px #6aab23;
|
|
border-top-left-radius: 10px;
|
|
border-bottom-left-radius: 10px;
|
|
transition: all 0.2s linear;
|
|
box-sizing: border-box;
|
|
border-bottom-right-radius: 0;
|
|
border-top-right-radius: 0;
|
|
}
|
|
|
|
input#changeText:focus {
|
|
outline: none;
|
|
}
|
|
|
|
.container{
|
|
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;
|
|
}
|
|
#audioOutput, #lastUrls {
|
|
font-size: calc(16px + 0.3vw);
|
|
width: 730px;
|
|
height: 100%;
|
|
flex: 20;
|
|
border-radius: 10px;
|
|
padding: 1em;
|
|
background: #eaeaea;
|
|
cursor:pointer;
|
|
}
|
|
label[for="audioOutput"] {
|
|
font-size: 3em;
|
|
color: #FE53BB;
|
|
text-shadow: 0px 0px 30px #fe53bb;
|
|
padding-right: 10px;
|
|
}
|
|
label[for="changeText"] {
|
|
font-size: 3em;
|
|
color: #00F6FF;
|
|
text-shadow: 0px 0px 30px #00f6ff;
|
|
padding-top: 5px;
|
|
padding-right: 10px;
|
|
}
|
|
|
|
label[for="lastUrls"] {
|
|
font-size: 3em;
|
|
color: #1a1;
|
|
text-shadow: 0px 0px 30px #1a1;
|
|
padding-right: 10px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
div#audioOutputContainer, #history {
|
|
display: flex;
|
|
flex-direction: row;
|
|
flex-wrap: nowrap;
|
|
justify-content: center;
|
|
margin: 4em;
|
|
}
|
|
|
|
@media only screen and (max-width: 1030px) {
|
|
body{
|
|
zoom: 0.9;
|
|
-moz-transform: scale(0.9);
|
|
-moz-transform-origin: 0 0;
|
|
}
|
|
}
|
|
|
|
#messageDiv {
|
|
font-size: .7em;
|
|
color: #DDD;
|
|
transition: all 0.5s linear;
|
|
font-style: italic;
|
|
opacity: 0;
|
|
text-align: center;
|
|
margin: 10px 0;
|
|
}
|
|
|
|
div#urlInput {
|
|
margin: 4em;
|
|
display: flex;
|
|
flex-direction: row;
|
|
}
|
|
@media only screen and (max-width: 940px) {
|
|
body{
|
|
zoom: 0.74;
|
|
-moz-transform: scale(0.74);
|
|
-moz-transform-origin: 0 0;
|
|
|
|
}
|
|
.container{
|
|
max-width:99%;
|
|
}
|
|
div#urlInput {
|
|
margin: 2em;
|
|
}
|
|
div#audioOutputContainer, #history {
|
|
margin: 2em;
|
|
}
|
|
}
|
|
@media only screen and (max-width: 840px) {
|
|
body{
|
|
zoom: 0.64;
|
|
-moz-transform: scale(0.64);
|
|
-moz-transform-origin: 0 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@media only screen and (max-height: 639px) {
|
|
div#urlInput {
|
|
margin: 2em;
|
|
}
|
|
div#audioOutputContainer, #history {
|
|
margin: 2em;
|
|
}
|
|
}
|
|
|
|
@media only screen and (max-width: 767px) {
|
|
|
|
div#urlInput {
|
|
margin: 2em 1em;
|
|
}
|
|
div#audioOutputContainer, #history {
|
|
margin: 2em 1em;
|
|
}
|
|
}
|
|
|
|
|
|
@media only screen and (max-height: 380px) {
|
|
div#urlInput {
|
|
margin: 1em;
|
|
}
|
|
div#audioOutputContainer, #history {
|
|
margin: 1em;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
label[for="audioOutput"], label[for="lastUrls"] {
|
|
font-size: 3em;
|
|
}
|
|
|
|
#warning4mac, #electronVersion {
|
|
background: #8500f7;
|
|
box-shadow: 0px 0px 50px 10px #8500f7ab, inset 0px 0px 10px 2px #8d08ffba;
|
|
border: 2px solid #8500f7;
|
|
border-radius: 10px;
|
|
width: 90%;
|
|
padding:1em;
|
|
margin:0 auto;
|
|
color:white;
|
|
font-size:1.3em;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
#warning4mac a, #electronVersion a {
|
|
color:white;
|
|
}
|
|
|
|
ul#lastUrls {
|
|
list-style: none;
|
|
background: #101520;
|
|
color: white;
|
|
padding: 1em;
|
|
}
|
|
|
|
ul#lastUrls li {
|
|
padding: 5px 0px;
|
|
}
|
|
ul#lastUrls li:nth-child(even) {
|
|
background-color: #182031;
|
|
}
|
|
|
|
#inputCombo {
|
|
display: flex;
|
|
flex-direction: row;
|
|
flex-wrap: nowrap;
|
|
flex-grow: 1;
|
|
}
|
|
#version{
|
|
margin: 0 auto;
|
|
font-size: 30%;
|
|
display: inline-block;
|
|
color: #000A;
|
|
}
|
|
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="header" style="-webkit-app-region: drag; color:#6f6f6f;font-size:20px; line-height: 20px; padding: 5px 10px; letter-spacing: 3; font-weight: bold;">Electron Capture</div>
|
|
<div class="container" >
|
|
|
|
<div id='warning4mac' style="display:none;"> ✨ Great News! OBS v26.1.2 <a href="https://github.com/obsproject/obs-browser/issues/209#issuecomment-748683083">now supports</a> VDO.Ninja without needing the Electron Capture app! 🥳</div>
|
|
<div id="electronVersion" style="display:none;">✨ Great News! <a href="https://github.com/steveseguin/electroncapture/releases/latest">Electron Capture <span id="currentElectronVersion"></span></a> is now available!<br>Update yours today to stay up-to-date with security patches.</div>
|
|
|
|
<div id="messageDiv" style='display:block'><br /></div>
|
|
<div class="container">
|
|
<div id="urlInput" title="Put the link you want to load here">
|
|
<label for="changeText">
|
|
<i class="las la-play"></i>
|
|
</label>
|
|
<div id="inputCombo">
|
|
<input type="text" id="changeText" class="inputfield" value="http://vdo.ninja/" onchange="modURL" onkeyup="enterPressed(event, gohere);" />
|
|
<button onclick="gohere();" id="gobutton">GO</button>
|
|
</div>
|
|
</div>
|
|
<div id="audioOutputContainer" title="This option will only work with the official vdo.ninja domain">
|
|
<label for="audioOutput"><i class="las la-headphones"></i></label><select id="audioOutput"></select>
|
|
</div>
|
|
<div id="history" title="History of past links used. You can clear this history using the button to the left">
|
|
<label for="lastUrls" onclick="resetHistory()">
|
|
<i class="las la-history"></i>
|
|
</label>
|
|
<select id="lastUrls" onchange="setUrl()"></select>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
<div id="version"></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 lastUrls = JSON.parse(localStorage.getItem('lastUrls'));
|
|
if (lastUrls != undefined) {
|
|
document.querySelector("#changeText").value = lastUrls[0];
|
|
if (lastUrls.length>0){
|
|
lastUrls.forEach((url)=>{
|
|
var o = document.createElement('option');
|
|
o.value = url;
|
|
o.text = url;
|
|
document.querySelector("#lastUrls").appendChild(o);
|
|
})
|
|
} else {
|
|
document.querySelector("#history").style.display="none";
|
|
}
|
|
} else {
|
|
document.querySelector("#history").style.display="none";
|
|
}
|
|
|
|
function setUrl(){
|
|
document.querySelector("#changeText").value = document.querySelector("#lastUrls").value;
|
|
gohere();
|
|
}
|
|
|
|
function resetHistory(){
|
|
localStorage.clear();
|
|
document.querySelector('#lastUrls').innerHTML = '';
|
|
lastUrls = [];
|
|
}
|
|
|
|
(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);
|
|
|
|
if (location.hostname.toLowerCase() == "vdo.ninja"){
|
|
try {
|
|
if (navigator.userAgent.toLowerCase().indexOf(' electron/') > -1) {
|
|
function compareVersions(version){
|
|
document.getElementById("version").innerHTML = "Current version: "+version;
|
|
version = version.split(".");
|
|
fetch('https://api.github.com/repos/steveseguin/electroncapture/releases/latest')
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
console.log("recentVersion: "+data.tag_name);
|
|
var recentVersion = data.tag_name.split(".");
|
|
var ood = false;
|
|
if (parseInt(recentVersion[0])>parseInt(version[0])){
|
|
ood = true;
|
|
} else if (parseInt(recentVersion[0])==parseInt(version[0])) {
|
|
if (parseInt(recentVersion[1])>parseInt(version[1])){
|
|
ood = true;
|
|
} else if (parseInt(recentVersion[1])==parseInt(version[1])) {
|
|
if (parseInt(recentVersion[2])>parseInt(version[2])){
|
|
ood = true;
|
|
}
|
|
}
|
|
}
|
|
if (ood){
|
|
document.getElementById("electronVersion").style.display = "block";
|
|
document.getElementById("currentElectronVersion").innerText = data.tag_name;
|
|
}
|
|
}).catch(console.error);
|
|
}
|
|
if (urlParams.has('version') || urlParams.has('ver')){
|
|
var ver = urlParams.get('version') || urlParams.get('ver') || false;
|
|
console.log("version: "+ver);
|
|
if (ver){
|
|
compareVersions(ver);
|
|
}
|
|
} else{
|
|
document.getElementById("version").innerHTML = "Elevate app privilleges to see current version";
|
|
try{
|
|
const ipcRenderer = require('electron').ipcRenderer;
|
|
console.log("ELECTRON DETECTED");
|
|
ipcRenderer.on('appVersion', function(event, version) {
|
|
console.log("version: "+version);
|
|
compareVersions(version);
|
|
})
|
|
ipcRenderer.send('getAppVersion');
|
|
} catch(e){}
|
|
}
|
|
}
|
|
} catch(e){console.error(e);}
|
|
}
|
|
|
|
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=null){
|
|
if (listed==true){
|
|
return;
|
|
}
|
|
if (e!==null){
|
|
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(){
|
|
document.getElementById("messageDiv").innerHTML = "Failed to list available output devices\n\nPlease ensure you allowed the microphone permissions.";
|
|
document.getElementById("messageDiv").style.display="block";
|
|
setTimeout(function(){document.getElementById("messageDiv").style.opacity="1.0";},0);
|
|
|
|
});
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
|
|
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.
|
|
}
|
|
// Windows can show the cursor, since it captures in a different way.
|
|
//if (navigator.platform.indexOf("Win") != -1){
|
|
// document.getElementById("showcursor").checked=true;
|
|
//}
|
|
|
|
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" && name!="VDONinja"){
|
|
document.getElementById('changeText').value = "https://vdo.ninja/?view="+name;
|
|
}
|
|
}
|
|
|
|
function addUrlToHistory(url){
|
|
if (lastUrls == undefined){
|
|
lastUrls = [];
|
|
}
|
|
if ( lastUrls[0] != url ) {
|
|
lastUrls.unshift(url);
|
|
if (lastUrls.length == 6) {
|
|
lastUrls.pop();
|
|
}
|
|
}
|
|
}
|
|
|
|
function modURL(){
|
|
var url = document.getElementById('changeText').value;
|
|
url = url.trim();
|
|
if (url.startsWith("obs.ninja")){
|
|
url = "https://"+url;
|
|
} else if (url.startsWith("youtube.com")){
|
|
url = "https://"+url;
|
|
} else if (url.startsWith("twitch.tv")){
|
|
url = "https://"+url;
|
|
} else if (url.startsWith("vdo.ninja")){
|
|
url = "https://"+url;
|
|
} else if (url.startsWith("http://")){
|
|
// pass
|
|
} else if (url.startsWith("https://")){
|
|
// pass
|
|
} else if (url.startsWith("file:")){
|
|
alert("Warning:\n\nFor security purposes, local files need to be loaded via the command-line or via the right-click context menu -> Edit URL.\n\nThis is supported in Electron Capture 2.15.2 and newer.");
|
|
} else {
|
|
url = "https://"+url;
|
|
}
|
|
console.log(url);
|
|
return url;
|
|
}
|
|
function gohere(){
|
|
addUrlToHistory(document.getElementById('changeText').value);
|
|
localStorage.setItem('lastUrls', JSON.stringify(lastUrls));
|
|
var url = modURL();
|
|
if ((document.getElementById('changeText').value.includes("obs.ninja")) && (document.getElementById('changeText').value.includes("http")) && (document.getElementById('changeText').value.includes("&sink"))){
|
|
alert("Notice: OBS.Ninja has been renamed to VDO.Ninja.\n\nPlease update your links accordingly for audio output to work correctly.");
|
|
} else if (!(document.getElementById('changeText').value.includes(window.location.hostname)) && (document.getElementById('changeText').value.includes("http")) && (document.getElementById('changeText').value.includes("&sink"))){
|
|
alert("Notice: The &sink command is domain specific.\nVisit https://YOURDOMAIN.com/electron instead.");
|
|
}
|
|
window.location = url;
|
|
};
|
|
getPermssions();
|
|
</script>
|
|
</body>
|
|
</html> |