mirror of
https://github.com/eliasstepanik/vdo.ninja.git
synced 2026-01-11 05:38:31 +00:00
857 lines
45 KiB
HTML
857 lines
45 KiB
HTML
<html>
|
|
<head>
|
|
<script type="text/javascript">
|
|
// MS Internet Explorer must not be given a chance to fail before I can give the user an error message.
|
|
try {
|
|
var msie = window.navigator.userAgent.indexOf("MSIE ");
|
|
if (msie>0 || !!navigator.userAgent.match(/Trident.*rv\:11\./)){ // If MSIE or IE 11
|
|
alert("Internet Explorer is not supported.\n\nPlease consider using Microsoft Edge or Google Chrome instead\n\nYou will be forwarded to the download page for MS Edge now.");
|
|
console.error("INTERNET EXPLORER IS EVIL");
|
|
window.location = "https://www.microsoft.com/edge";
|
|
}
|
|
} catch(e){
|
|
console.error(e);
|
|
}
|
|
|
|
</script>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<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" />
|
|
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon" />
|
|
<link rel="icon" type="image/png" sizes="32x32" href="./images/favicon-32x32.png" />
|
|
<link rel="icon" type="image/png" sizes="16x16" href="./images/favicon-16x16.png" />
|
|
<link rel="icon" href="./images/favicon.ico" />
|
|
<link itemprop="thumbnailUrl" href="./images/obsNinja_logo_full.png" />
|
|
<!-- Primary Meta Tags -->
|
|
<title>OBS.Ninja</title>
|
|
<meta name="title" content="OBS.Ninja" />
|
|
<meta name="description" content="Bring live video from your smartphone, computer, or friends directly into OBS Studio. 100% free." />
|
|
<meta name="author" content="Steve Seguin" />
|
|
<!-- Open Graph / Facebook -->
|
|
<meta property="og:site_name" content="OBS.Ninja" />
|
|
<meta property="og:type" content="website" />
|
|
<meta property="og:url" content="https://obs.ninja/" />
|
|
<meta property="og:title" content="OBS.Ninja" />
|
|
<meta property="og:description" content="Bring live video from your smartphone, computer, or friends directly into OBS Studio. 100% free." />
|
|
<meta property="og:image" itemprop="image" content="https://obs.ninja/images/obsNinja_logo_full.png" />
|
|
<meta name="msapplication-TileImage" content="./images/obsNinja_logo_full.png" />
|
|
<meta property="og:image:type" content="image/png" />
|
|
<meta property="og:image:width" content="1200" />
|
|
<meta property="og:image:height" content="630" />
|
|
<!-- Twitter -->
|
|
<meta property="twitter:card" content="summary_large_image" />
|
|
<meta property="twitter:url" content="https://obs.ninja/" />
|
|
<meta property="twitter:title" content="OBS.Ninja" />
|
|
<meta property="twitter:description" content="Bring live video from your smartphone, computer, or friends directly into OBS Studio. 100% free." />
|
|
<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=22" />
|
|
</head>
|
|
<body id="main" class="hidden">
|
|
<span itemprop="image" itemscope itemtype="image/png">
|
|
<link itemprop="url" href="./images/obsNinja_logo_full.png" />
|
|
</span>
|
|
<link itemprop="thumbnailUrl" href="./images/obsNinja_logo_full.png" />
|
|
<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=22"></script>
|
|
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=118"></script>
|
|
<input id="zoomSlider" type="range" style="display: none;" />
|
|
<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 id="head1" style="display: inline-block; padding:1px; position: relative;">
|
|
<input id="joinroomID" name="joinroomID" size="22" placeholder="Join by Room Name here" />
|
|
<button onclick="jumptoroom();">GO</button>
|
|
</div>
|
|
<div id="head3" style="display: inline-block;" class="advanced">
|
|
<font style="color: #888;" id="copythisurl">
|
|
<span data-translate="copy-this-url">Copy this URL into an OBS "Browser Source"</span> <i style="color: #CCC;" class="las la-long-arrow-alt-right"></i>
|
|
</font>
|
|
<a
|
|
id="reshare"
|
|
data-drag="1"
|
|
onclick="popupMessage(event);copyFunction(this)"
|
|
class="task grabLinks"
|
|
onmousedown="copyFunction(this)"
|
|
style="font-weight: bold; color: #afa !important; cursor: grab; background-color: #0000; font-size: 115%; min-width: 335px; max-width: 800px;"
|
|
></a>
|
|
<i class="las la-paperclip" style="color: #DDD;" onclick="popupMessage(event);copyFunction(document.getElementById('reshare'));" onmouseover="this.style.cursor='pointer'"></i>
|
|
</div>
|
|
<div id="head4" style="display: inline-block;" class="advanced">
|
|
<font style="font-size: 68%; color: white;">
|
|
|
|
<span data-translate="you-are-in-the-control-center">Control center for room:</span>
|
|
|
|
<div id="dirroomid" style="font-size: 140%; color: #99c; display: inline-block;"></div>
|
|
</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>:
|
|
|
|
<div id="roomid" style="display: inline-block;"></div>
|
|
</div>
|
|
|
|
</div>
|
|
<div id="controlButtons" >
|
|
<div id="chatbutton" title="Toggle the Chat" onclick="toggleChat()" class="advanced float" style="cursor: pointer;" alt="Toggle the Chat">
|
|
<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">
|
|
<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">
|
|
<i id="mutetoggle" class="toggleSize las la-microphone my-float" style="position: relative; top: 0.5px;"></i>
|
|
</div>
|
|
<div id="mutevideobutton" title="Disable the Camera" onclick="toggleVideoMute()" class="advanced float" style="cursor: pointer;" alt="Toggle the camera">
|
|
<i id="mutevideotoggle" class="toggleSize las la-eye my-float"></i>
|
|
</div>
|
|
<div id="settingsbutton" title="Settings" onclick="toggleSettings()" class="advanced float" style="cursor: pointer;" alt="Toggle the Settings Menu">
|
|
<i id="settingstoggle" class="toggleSize las la-cog my-float"></i>
|
|
</div>
|
|
<div id="hangupbutton" title="Hangup the Call" onclick="hangup()" class="advanced float" style="cursor: pointer;" alt="Disconnect and End">
|
|
<i class="toggleSize my-float las la-phone rotate225" aria-hidden="true"></i>
|
|
</div>
|
|
|
|
</div>
|
|
<span
|
|
id="helpbutton"
|
|
title="Show Help Info"
|
|
onclick="alert('Email steve@seguin.email if the system breaks or check https://reddit.com/r/obsninja for support.\n\nThe Wiki contains many help guides and advanced settings.\n\nAccess the debug menu by pressing CTRL (command) and Left-Clicking on a video.\n\nMost issues can be fixed by using Wired Internet instead of Wi-Fi.')"
|
|
style="cursor: pointer; display:none;"
|
|
alt="How to Use This with OBS"
|
|
>
|
|
<i style="float: right; bottom: 0px; cursor: pointer; position: fixed; right: 24px; color: #d9e4eb; padding: 2px; margin: 2px 2px 0 0; font-size: 140%;" class="las la-question-circle" aria-hidden="true"></i>
|
|
</span>
|
|
<span title="Language Options" onclick="toggle(document.getElementById('languages'));" id="translateButton">
|
|
<i style="float: right; bottom: 0px; cursor: pointer; position: fixed; right: 2px; color: #d9e4eb; padding: 2px; margin: 2px 2px 0 0; font-size: 140%;" class="las la-language" aria-hidden="true"></i>
|
|
</span>
|
|
<div id="mainmenu" class="row" style="opacity: 0; align: center;">
|
|
<div id="container-1" class="column columnfade pointer" style=" overflow-y: auto;">
|
|
<h2>
|
|
<span data-translate="add-group-chat">Add Group Chat to OBS</span>
|
|
</h2>
|
|
<div class="container-inner">
|
|
<br />
|
|
<br />
|
|
<span data-translate="rooms-allow-for">Rooms allow for group-chat and the tools to manage multiple guests.</span>
|
|
<br />
|
|
<br />
|
|
<table>
|
|
<tr>
|
|
<th><b>
|
|
<span data-translate="room-name">Room Name</span>:
|
|
</b></th>
|
|
<th><input id="videoname1" placeholder="Enter a Room Name here" onkeyup="enterPressed(event, createRoom);" size="30" maxlength="30" style="font-size: 110%; padding: 5px;" /></th>
|
|
|
|
</tr><tr>
|
|
|
|
<th><b>
|
|
<span data-translate="password-input-field">Password</span>:
|
|
</b>
|
|
</th><th>
|
|
<input id="passwordRoom" placeholder="Optional room password here" onkeyup="enterPressed(event, createRoom);" size="30" maxlength="30" style="font-size: 110%; padding: 5px;" />
|
|
</th>
|
|
|
|
</tr><tr><th></th><th>
|
|
<br />
|
|
<button onclick="createRoom()" class="gobutton" style="float: left;">
|
|
<span data-translate="enter-the-rooms-control">Enter the Room's Control Center</span>
|
|
</button>
|
|
<br /><br />
|
|
<button class="white" style="display: block;" onclick="toggle(document.getElementById('roomnotes'),this);">
|
|
<span data-translate="show-tips">Show me some tips..</span>
|
|
</button>
|
|
</th></tr>
|
|
</table>
|
|
<br />
|
|
<ul style=" margin: auto auto; max-width: 500px; display: none; text-align: left;" id="roomnotes">
|
|
<br />
|
|
<span data-translate="added-notes">
|
|
<u>
|
|
<i>Important Tips:</i><br /><br />
|
|
</u>
|
|
<li>Invite only guests to the room that you trust.</li>
|
|
<li>iOS devices will share just their audio with other room guests; not video. This is intentional.</li>
|
|
<li>The "Recording" option is considered experimental.</li>
|
|
</span>
|
|
</ul>
|
|
</div>
|
|
<div class="outer close">
|
|
<div class="inner">
|
|
<label class="labelclass">
|
|
<span data-translate="back">Back</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="container-3" class="column columnfade pointer" onclick="previewWebcam()" style=" overflow-y: auto;">
|
|
<h2 id="add_camera">
|
|
<span data-translate="add-your-camera">Add your Camera to OBS</span>
|
|
</h2>
|
|
<div class="container-inner">
|
|
<br />
|
|
<p>
|
|
<video id="previewWebcam" class="previewWebcam" oncanplay="updateStats();" disablePictureInPicture 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" >
|
|
<span data-translate="ask-for-permissions">Allow Access to Camera/Microphone</span>
|
|
</button>
|
|
<button onclick="publishWebcam(this)" id="gowebcam" class="gowebcam" disabled data-ready="false" >
|
|
<span data-translate="waiting-for-camera">Waiting for Camera to Load</span>
|
|
</button>
|
|
<br />
|
|
<span id="videoMenu" class="videoMenu">
|
|
<i class="las la-video"></i><span data-translate="video-source"> Video Source </span>
|
|
|
|
<select id="videoSource" ></select>
|
|
<span id="gear_webcam" style="display: inline-block;" onclick="toggle(document.getElementById('videoSettings'));">
|
|
|
|
<i class="las la-cog" style="font-size: 140%; vertical-align: middle;" aria-hidden="true"></i>
|
|
</span>
|
|
</span>
|
|
<br />
|
|
<center>
|
|
<span id="videoSettings" style="display: none;">
|
|
<form id="webcamquality">
|
|
<input type="radio" id="fullhd" name="resolution" value="0" />
|
|
<label for="fullhd">
|
|
<span data-translate="max-resolution">Max Resolution</span>
|
|
</label> |
|
|
|
|
<input type="radio" checked id="halfhd" name="resolution" value="1" />
|
|
<label for="halfhd">
|
|
<span data-translate="balanced">Balanced</span>
|
|
</label> |
|
|
|
|
<input type="radio" id="nothd" name="resolution" value="2" />
|
|
<label for="nothd">
|
|
<span data-translate="smooth-cool">Smooth and Cool</span>
|
|
</label>
|
|
<div id="webcamstats" style="padding: 5px 0 0 0;"></div>
|
|
</form>
|
|
</span>
|
|
</center>
|
|
<div id="audioMenu" class="form-group multiselect" alt="tip: Hold CTRL (command) to select Multiple" title="tip: Hold CTRL (command) to select Multiple">
|
|
<a id="multiselect-trigger" class="form-control multiselect-trigger" tabindex="3">
|
|
<div class="audioTitle">
|
|
<i class="las la-microphone-alt"></i><span data-translate="select-audio-source"> Audio Source(s) </span>
|
|
<i id='chevarrow1' class="chevron bottom" aria-hidden="true"></i>
|
|
<div class="meter" id="meter1"></div>
|
|
</div>
|
|
</a>
|
|
<ul id="audioSource" class="multiselect-contents" >
|
|
<li>
|
|
<input type="checkbox" id="multiselect1" name="multiselect1" style="display: none;" checked value="ZZZ" />
|
|
<label for="multiselect1">
|
|
<span data-translate="no-audio">No Audio</span>
|
|
</label>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<br />
|
|
<span id="headphonesDiv" style="text-align:left; margin:17px 0; max-width: 550px; min-width: 420px; background-color: #f3f3f3; display: none; padding: 10px 10px; border: 1px solid #ccc; vertical-align: middle;">
|
|
<div class="audioTitle2">
|
|
<i class="las la-headphones"></i><span data-translate="select-output-source"> Audio Output Destination: <button onclick="playtone()" class="white" style="margin:0 0 0 15px;" type="button">Test</button>
|
|
</span></div>
|
|
<select id="outputSource" ></select>
|
|
|
|
</span>
|
|
|
|
</div>
|
|
<div class="outer close">
|
|
<div class="inner">
|
|
<label class="labelclass">
|
|
<span data-translate="back">Back</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="container-2" class="column columnfade pointer" style=" overflow-y: auto;">
|
|
<h2 id="add_screen">
|
|
<span data-translate="remote-screenshare-obs">Remote Screenshare into OBS</span>
|
|
</h2>
|
|
<div class="container-inner">
|
|
<span data-translate="note-share-audio">
|
|
<p>
|
|
<video id="screenshare" autoplay="true" muted="true" loop src="./images/screenshare.webm" />
|
|
</p>
|
|
</span>
|
|
<br />
|
|
<button class='gobutton' style="padding: 10px; font-size: 120%;" onclick="publishScreen()">
|
|
<span data-translate="select-screen-to-share">SELECT SCREEN TO SHARE</span>
|
|
</button>
|
|
<span id="gear_screen" style="display: inline-block; cursor: pointer;" onclick="toggle(document.getElementById('videoSettings2'));">
|
|
|
|
<i class="las la-cog" style="font-size: 170%; vertical-align: middle;" aria-hidden="true"></i>
|
|
</span>
|
|
<center>
|
|
<span id="videoSettings2" style="margin: auto auto; display: none; background-color: white; vertical-aligh: middle; border: 3px solid #ccc; max-width: 500px; padding: 10px 10px 5px 10px; margin: 10px 0 5px 0;">
|
|
<form id="webcamquality2">
|
|
<input type="radio" id="fullhd2" name="resolution2" value="0" />
|
|
<label for="fullhd">
|
|
<span data-translate="max-resolution">1080p (hi-def)</span>
|
|
</label> |
|
|
|
|
<input type="radio" checked id="halfhd2" name="resolution2" value="1" />
|
|
<label for="halfhd">
|
|
<span data-translate="balanced">720p (balanced)</span>
|
|
</label> |
|
|
|
|
<input type="radio" id="nothd2" name="resolution2" value="2" />
|
|
<label for="nothd">
|
|
<span data-translate="smooth-cool">360p (smooth)</span>
|
|
</label>
|
|
<div id="webcamstats2" style="padding: 5px 0 0 0;"></div>
|
|
</form>
|
|
</span>
|
|
<br />
|
|
</center>
|
|
<p id="audioScreenShare1">
|
|
<span data-translate="audio-sources">Audio Sources</span>
|
|
<br />
|
|
<select id="audioSourceScreenshare" multiple alt="tip: Hold CTRL (command) to select Multiple" title="tip: Hold CTRL (command) to select Multiple" style="height: 60px; min-width: 290px; resize: both; overflow: auto; padding: 5px;" onchange="requestAudioStream();">
|
|
<option value="screenshare" selected>
|
|
<span data-translate="screen-shrae-audio">Screen Share Audio (default)</span>
|
|
</option>
|
|
<option value="microphones">
|
|
<span data-translate="other-audio-sources">Other Audio Sources</span>
|
|
</option>
|
|
</select>
|
|
</p>
|
|
<br />
|
|
<span id="headphonesDiv2" style="background-color: #f3f3f3; min-width: 270px; display: none; padding: 5px 10px; border: 1px solid #ccc; vertical-align: middle;">
|
|
<i class="las la-headphones"></i>
|
|
|
|
<span data-translate="select-output-source"> Audio Output Destination: <button onclick="playtone(true)" class="white" style="padding:3px 5px 2px 5px; margin:0; margin-left:15px; position: relative; " type="button">Test</button></span>
|
|
<br />
|
|
<select id="outputSourceScreenshare" style="background-color: #FFF; padding:10px 5px; min-width: 268px; display:inline-block; vertical-align: middle;" onclick="requestOutputAudioStream();">
|
|
<option value="default">
|
|
<span data-translate="default">Default Device</span>
|
|
</option>
|
|
</select>
|
|
</span>
|
|
</div>
|
|
<div class="outer close">
|
|
<div class="inner">
|
|
<label class="labelclass">
|
|
<span data-translate="back">Back</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="container-4" class="column columnfade pointer" style=" overflow-y: auto;">
|
|
<h2>
|
|
<span data-translate="create-reusable-invite">Create Reusable Invite</span>
|
|
</h2>
|
|
<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>
|
|
<br />
|
|
<br />
|
|
<p>
|
|
<input style="padding: 5px; font-size: 120%;" id="videoname4" onkeyup="enterPressed(event, generateQRPage);" placeholder="Give this media source a name (optional)" size="35" maxlength="70" style="padding: 5px;" />
|
|
<br />
|
|
<br />
|
|
</p>
|
|
<button style="padding: 20px;" class='gobutton' onclick="generateQRPage()">
|
|
<span data-translate="generate-invite-link">GENERATE THE INVITE LINK</span>
|
|
</button>
|
|
<br />
|
|
<br />
|
|
<div style="margin: 20px; max-width: 400px; text-align: left; margin: auto auto;">
|
|
<div class="invite_setting_group">
|
|
<h4>
|
|
<span data-translate="advanced-paramaters">Advanced Options</span>
|
|
</h4>
|
|
<div class="invite_setting_item">
|
|
<input type="checkbox" id="invite_bitrate" />
|
|
<label for="invite_bitrate">
|
|
<span data-translate="unlock-video-bitrate" title="Ideal for 1080p60 gaming, if your computer and upload are up for it" >Unlock Video Bitrate (20mbps)</span>
|
|
</label>
|
|
</div>
|
|
<div class="invite_setting_item">
|
|
<input type="checkbox" id="invite_vp9" />
|
|
<label for="invite_vp9">
|
|
<span data-translate="force-vp9-video-codec" title="Better video compression and quality at the cost of increased CPU encoding load">Force VP9 Video Codec</span>
|
|
</label>
|
|
</div>
|
|
<div class="invite_setting_item">
|
|
<input type="checkbox" id="invite_stereo" />
|
|
<label for="invite_stereo">
|
|
<span data-translate="enable-stereo-and-pro" title="Disable digital audio-effects and increase audio bitrate">Enable Stereo and Pro HD Audio</span>
|
|
</label>
|
|
</div>
|
|
<div class="invite_setting_item">
|
|
<label for="invite_quality" data-translate="video-resolution">Video Resolution: </label>
|
|
<select id="invite_quality" name="invite_quality">
|
|
<option value="-1" selected>User Selectable</option>
|
|
<option value="0">Maximum Resolution</option>
|
|
<option value="1">Balanced</option>
|
|
<option value="2">Smooth and Cool</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="invite_setting_group">
|
|
<div class="invite_setting_item">
|
|
<input type="checkbox" id="invite_automic" />
|
|
<label for="invite_automic">
|
|
<span data-translate="hide-mic-selection" title="The guest will not have a choice over audio-options">Force Default Microphone</span>
|
|
</label>
|
|
</div>
|
|
<div class="invite_setting_item">
|
|
<input type="checkbox" id="invite_hidescreen" />
|
|
<label for="invite_hidescreen">
|
|
<span data-translate="hide-screen-share" title="The guest will only be able to select their webcam as an option">Hide Screenshare Option</span>
|
|
</label>
|
|
</div>
|
|
<div class="invite_setting_item">
|
|
<input type="checkbox" id="invite_remotecontrol" />
|
|
<label for="invite_remotecontrol">
|
|
<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">
|
|
<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" />
|
|
</div>
|
|
<div class="invite_setting_item">
|
|
<span data-translate="add-the-guest-to-a-room" title="Add the guest to a group-chat room; it will be created automatically if needed."> Add the guest to a room:</span>
|
|
<input id="invite_joinroom" placeholder="Enter Room name here" oninput="document.getElementById('invitegroupchat').style.display='block';" />
|
|
</div>
|
|
<div class="invite_setting_item">
|
|
<span id="invitegroupchat" style="display: none;" title="Customize the room settings for this guest">
|
|
<label for="invite_group_chat_type" data-translate="invite-group-chat-type">This room guest can:</label>
|
|
<select id="invite_group_chat_type" name="invite_group_chat_type">
|
|
<option value="0" selected data-translate="can-see-and-hear">Can see and hear the group chat</option>
|
|
<option value="1" data-translate="can-hear-only">Can only hear the group chat</option>
|
|
<option value="2" data-translate="cant-see-or-hear">Cannot hear or see the group chat</option>
|
|
</select>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<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>
|
|
<div class="outer close">
|
|
<div class="inner">
|
|
<label class="labelclass">
|
|
<span data-translate="back">Back</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="container-5" class="column columnfade pointer advanced" style=" overflow-y: auto;">
|
|
<h2><span data-translate="share-local-video-file">Stream Media File</span></h2>
|
|
<div class="container-inner">
|
|
|
|
<br /><br />
|
|
SELECT THE VIDEO FILE 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/>
|
|
</div>
|
|
<p>Keep this tab visible if using Chrome, else the video playback will stop</p>
|
|
<div class="outer close">
|
|
<div class="inner">
|
|
<label class="labelclass">
|
|
<span data-translate="back">Back</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
<div id="container-6" class="column columnfade pointer" style=" overflow-y: auto;">
|
|
<h2><span data-translate="share-website-iframe">Share Remote Website</span></h2>
|
|
<div class="container-inner">
|
|
|
|
<br /><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="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>
|
|
</div>
|
|
<div class="outer close">
|
|
<div class="inner">
|
|
<label class="labelclass">
|
|
<span data-translate="back">Back</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
<p></p>
|
|
<div id="info" class="fullcolumn columnfade">
|
|
<center>
|
|
<div class="infoblob" align="left">
|
|
<span data-translate="info-blob">
|
|
<h2>What is OBS.Ninja</h2>
|
|
<br />
|
|
<li>100%
|
|
<b>free</b>; no downloads; no personal data collection; no sign-in
|
|
</li>
|
|
<li>Bring video from your smartphone, computer, or friends directly into your OBS video stream</li>
|
|
<li>We use cutting edge Peer-to-Peer forwarding technology that offers privacy and ultra-low latency</li>
|
|
<br />
|
|
<li>Youtube video
|
|
<i class="lab la-youtube"></i>
|
|
<a href="https://www.youtube.com/watch?v=6R_sQKxFAhg">Demoing it here</a>
|
|
</li>
|
|
<br />
|
|
<i>
|
|
<font style="color: red;">Known issues:</font>
|
|
</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.
|
|
|
|
</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.
|
|
</li>
|
|
<li>
|
|
iOS devices may have occasional audio or camera issues, such as no sound. Fully close Safari and reopen it if nothing else seems to work.
|
|
</li>
|
|
<li>
|
|
The VP9 codec on Chromium-based browsers seems to lag when screen-sharing at the moment. Use the OBS Virtual Camera as a capture source instead.
|
|
</li>
|
|
<br />
|
|
|
|
🎈 Site Updated: <a href="https://www.reddit.com/r/OBSNinja/comments/k02enh/version_134_of_obsninja_released_change_log_here/">November 27th, 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.
|
|
|
|
<br />
|
|
<br />
|
|
<h3>
|
|
<i>
|
|
Check out the
|
|
<a href="https://www.reddit.com/r/OBSNinja/">sub-reddit
|
|
<i class="lab la-reddit-alien"></i> </a>for help and see the <a href="https://github.com/steveseguin/obsninja/wiki/">Wiki for advanced info</a>. I'm also on
|
|
<a href="https://discord.gg/T4xpQVv">Discord</a> and you can email me at steve@seguin.email
|
|
|
|
</i>
|
|
</h3>
|
|
</span>
|
|
</div>
|
|
</center>
|
|
</div>
|
|
<form method="post" onsubmit="setFormSubmitting()" style="display: none;">
|
|
<input type="submit" />
|
|
</form>
|
|
<div id="credits" class="credits">
|
|
Icons made by
|
|
<a href="https://www.flaticon.com/authors/lucy-g" title="Lucy G">Lucy G</a> from
|
|
<a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> is licensed by
|
|
|
|
<a href="https://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a> and by
|
|
|
|
<a href="https://www.flaticon.com/authors/gregor-cresnar" title="Gregor Cresnar">Gregor Cresnar</a> from
|
|
<a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a>
|
|
</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="overlayMsgs" onclick="function(e){e.target.innerHTML = '';}" style="display:none"></div>
|
|
<div id="controls_blank" style="display: none;">
|
|
<div class="controlsGrid">
|
|
|
|
<button data-action-type="addToScene" data-value="0" title="Add this Video to any remote '&scene=1'" onclick="directEnable(this, event);">
|
|
<i class="las la-plus-square"></i>
|
|
<span data-translate="add-to-scene">Add to Scene</span>
|
|
</button>
|
|
<button data-action-type="forward" data-value="0" title="Forward user to another room. They can always return." onclick="directMigrate(this, event);">
|
|
<i class="las la-paper-plane"></i>
|
|
<span data-translate="forward-to-room">Transfer</span>
|
|
</button>
|
|
|
|
<button data-action-type="recorder" title="Start Recording this stream. *experimental*' views" onclick="recordVideo(this, event)">
|
|
<i class="las la-circle"></i>
|
|
<span data-translate="record"> Record</span>
|
|
</button>
|
|
<button data-action-type="hangup" data-value="0" title="Force the user to Disconnect. They can always reconnect." onclick="directHangup(this, event);">
|
|
<i class="las la-sign-out-alt"></i>
|
|
<span data-translate="disconnect-guest" >Hangup</span>
|
|
</button>
|
|
|
|
<input data-action-type="volume" class="slider" type="range" min="1" max="100" value="100" title="Change this Audio's volume in all remote '&scene' views" onclick="directVolume(this);" style="grid-column: 1; margin:5px; width: 93%; position: relative; top: 0px; background-color:#fff0;"/>
|
|
|
|
<button data-action-type="mute" style="grid-column: 2;" title="Remotely Mute this Audio in all remote '&scene' views" onclick="directMute(this, event);">
|
|
<i class="las la-volume-off"></i>
|
|
<span data-translate="mute" >Mute in Scenes</span>
|
|
</button>
|
|
|
|
<span>
|
|
<button style="width: 36px" data-action-type="change-quality" title="Disable Video Preview" onclick="toggleQualityDirector(0, this.dataset.UUID, this);">
|
|
<span data-translate="change-to-low-quality"> <i class="las la-video-slash"></i></span>
|
|
</button>
|
|
<button class="pressed" style="width:36px;" data-action-type="change-quality" title="Low-Quality Preview" onclick="toggleQualityDirector(50, this.dataset.UUID, this);">
|
|
<span data-translate="change-to-medium-quality"> <i class="las la-video"></i></span>
|
|
</button>
|
|
<button style="width: 36px" data-action-type="change-quality" title="High-Quality Preview" onclick="toggleQualityDirector(1200, this.dataset.UUID, this);">
|
|
<span data-translate="change-to-high-quality"> <i class="las la-binoculars"></i></span>
|
|
</button>
|
|
</span>
|
|
<button data-action-type="direct-chat" title="Send Direct Message" onclick="directorSendMessage(this);">
|
|
<span data-translate="send-direct-chat"><i class="las la-envelope"></i> Message</span>
|
|
</button>
|
|
|
|
<button data-action-type="advanced-camera-settings" title="Advanced Settings and Remote Control" onclick="directorSendMessage(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" onclick="directorSendMessage(this);">
|
|
<span data-translate="voice-chat"><i class="las la-microphone"></i> Voice Chat</span>
|
|
</button>
|
|
|
|
|
|
|
|
</div>
|
|
</div>
|
|
<div id="popupSelector" style="display:none;">
|
|
<span id="videoMenu3" class="videoMenu">
|
|
<i class="las la-video"></i><span data-translate="video-source"> Video Source </span>
|
|
<select id="videoSource3" ></select>
|
|
</span>
|
|
<br />
|
|
<br />
|
|
|
|
<div class="form-group multiselect" alt="tip: Hold CTRL (command) to select Multiple" title="tip: Hold CTRL (command) to select Multiple" style="padding: 10px; background-color:#f3f3f3;">
|
|
<a id="multiselect-trigger3" class="form-control multiselect-trigger" tabindex="3">
|
|
<div id="audioTitle2" class="title">
|
|
<i class="las la-microphone-alt"></i><span data-translate="select-audio-source"> Audio Source(s) </span>
|
|
<i id="chevarrow2" class="chevron bottom" aria-hidden="true"></i>
|
|
</div>
|
|
</a>
|
|
<ul id="audioSource3" style="background-color:white;" class="multiselect-contents">
|
|
<li>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<br />
|
|
<span id="headphonesDiv3" style="display: inline-block;">
|
|
<div class="title">
|
|
<i class="las la-headphones"></i><span data-translate="select-output-source"> Audio Output Destination:
|
|
</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='advancedOptionsCamera' onclick="this.style.display = 'none'; toggle(getById('popupSelector_constraints_camera'),false,false); " style="display:none; background-color:#EFEFEF;padding:10px 12px 12px 2px;margin: 10px 0px 0px 10px"><i class="chevron bottom" style="font-size:150%;top:3px;position:relative;"></i> <b>Advanced Video</b></button>
|
|
<button id='advancedOptionsAudio' onclick="this.style.display = 'none'; toggle(getById('popupSelector_constraints_audio'),false,false); " style="display:none; background-color:#EFEFEF;padding:10px 12px 12px 2px;margin: 10px 0px 0px 10px"><i class="chevron bottom" style="font-size:150%;top:3px;position:relative;"></i> <b>Advanced Audio</b></button>
|
|
|
|
<span id="popupSelector_constraints_audio" class="popupSelector_constraints" style="display: none;">
|
|
|
|
</span>
|
|
<span id="popupSelector_constraints_video" class="popupSelector_constraints" style="display: none;">
|
|
|
|
</span>
|
|
</p>
|
|
</div>
|
|
<nav id="context-menu" class="context-menu">
|
|
<ul class="context-menu__items">
|
|
<li class="context-menu__item">
|
|
<a href="#" class="context-menu__link" data-action="Open">
|
|
<i class="las la-external-link"></i>
|
|
<span data-translate="open-in-new-tab">Open in new Tab</span>
|
|
</a>
|
|
</li>
|
|
<li class="context-menu__item">
|
|
<a href="#" class="context-menu__link" data-action="Copy">
|
|
<i class="las la-paperclip"></i>
|
|
<span data-translate="copy-to-clipboard" >Copy to Clipboard</span>
|
|
</a>
|
|
</li>
|
|
</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();"><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;">
|
|
<a target="popup" style="cursor:pointer;" onclick="createPopoutChat();">💢</a>
|
|
<div id="chatBody">
|
|
<div class="inMessage" data-translate='welcome-to-obs-ninja-chat'>
|
|
Welcome to OBS.Ninja! You can send text messages directly to connected peers from here.
|
|
</div>
|
|
<div class="outMessage" data-translate='names-and-labels-coming-soon'>
|
|
Names identifying connected peers will be a feature in an upcoming release.
|
|
</div>
|
|
</div>
|
|
<input id="chatInput" placeholder="Enter chat message to send here" onkeypress="EnterButtonChat(event)" />
|
|
<button style="width:60px;background-color:#EEE;" onclick="sendChatMessage()" data-translate='send-chat'>Send</button>
|
|
</div>
|
|
|
|
<audio id="testtone" style="display:none;" preload="none">
|
|
<source src="tone.mp3" type="audio/mpeg">
|
|
<source src="tone.ogg" type="audio/ogg">
|
|
</audio>
|
|
<div class="gone" >
|
|
<!-- This image is used when dragging elements -->
|
|
<img src="./images/favicon-32x32.png" id="dragImage" />
|
|
</div>
|
|
<div id="request_info_prompt" style="display:none">
|
|
</div>
|
|
<div id="messagePopup" class="popup-message"></div>
|
|
<div id="languages" class="popup-message" style="display: none; right: 0; bottom: 25px; position: absolute;">
|
|
<b data-translate='available-languages'>Available Languages:</b>
|
|
<br />
|
|
<u>
|
|
<a onclick="changeLg('ru');toggle(document.getElementById('languages'));" style="cursor: pointer;">Russian</a>
|
|
<br />
|
|
<a onclick="changeLg('fr');toggle(document.getElementById('languages'));" style="cursor: pointer;">French</a>
|
|
<br />
|
|
<a onclick="changeLg('en');toggle(document.getElementById('languages'));" style="cursor: pointer;">English</a>
|
|
<br />
|
|
<a onclick="changeLg('pt');toggle(document.getElementById('languages'));" style="cursor: pointer;">Portuguese</a>
|
|
<br />
|
|
<a onclick="changeLg('it');toggle(document.getElementById('languages'));" style="cursor: pointer;">Italian</a>
|
|
<br />
|
|
<a onclick="changeLg('de');toggle(document.getElementById('languages'));" style="cursor: pointer;">German</a>
|
|
<br />
|
|
<a onclick="changeLg('es');toggle(document.getElementById('languages'));" style="cursor: pointer;">Spanish</a>
|
|
<br />
|
|
<a onclick="changeLg('nl');toggle(document.getElementById('languages'));" style="cursor: pointer;">Dutch</a>
|
|
<br />
|
|
<a onclick="changeLg('tr');toggle(document.getElementById('languages'));" style="cursor: pointer;">Turkish</a>
|
|
<br />
|
|
<a onclick="changeLg('ja');toggle(document.getElementById('languages'));" style="cursor: pointer;">Japanese</a>
|
|
<br />
|
|
<a onclick="changeLg('cs');toggle(document.getElementById('languages'));" style="cursor: pointer;">Czech </a>
|
|
<br />
|
|
<a onclick="changeLg('pig');toggle(document.getElementById('languages'));" style="cursor: pointer;">Pig Latin</a>
|
|
<br />
|
|
</u>
|
|
<br />
|
|
<a href="https://github.com/steveseguin/obsninja/tree/master/translations" data-translate='add-more-here'>Add More Here!</a>
|
|
<br />
|
|
</div>
|
|
|
|
<script>
|
|
|
|
var session = WebRTC.Media; // session is a required global variable if configuring manually. Run before loading main.js but after webrtc.js.
|
|
session.version = "13.5b";
|
|
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.
|
|
session.salt = location.hostname; // used only if password is not == False.
|
|
|
|
// session.configuration = {
|
|
// iceServers: [
|
|
// { urls: ["stun:stun.l.google.com:19302", "stun:stun4.l.google.com:19302"] }, // more than 4 stun+turn servers may cause issues
|
|
// ],
|
|
// sdpSemantics: 'unified-plan'
|
|
// };
|
|
|
|
// var turn = {};
|
|
// turn.username = "steve";
|
|
// turn.credential = "justtesting";
|
|
// turn.urls = ["turn:turn.obs.ninja:443"]; // US CENTRAL
|
|
// session.configuration.iceServers.push(turn);
|
|
|
|
// turn = {};
|
|
// turn.username = "steve";
|
|
// turn.credential = "justtesting";
|
|
// turn.urls = ["turn:turn2.obs.ninja:443"]; // US WEST
|
|
// session.configuration.iceServers.push(turn);
|
|
|
|
// session.configuration.iceTransportPolicy = "relay"; // uncomment to enable "&privacy" and force the TURN server
|
|
|
|
// session.wss = false; // uses default handshake wss
|
|
|
|
///// The following lets you set the defaults
|
|
|
|
// session.webcamonly // true,false
|
|
// session.stereo // 0,1,2,3
|
|
// session.audiobitrate // int in kbps
|
|
// session.view // "xxxx"
|
|
// session.remote
|
|
// session.optimize
|
|
// session.disableOBS
|
|
// session.audio
|
|
// session.video
|
|
// session.forceios
|
|
// session.nocursor
|
|
// session.codec
|
|
// session.scale
|
|
// session.bitrate // int in kbps
|
|
// session.totalRoomBitrate = 500; // int, kbps
|
|
// session.height // int
|
|
// session.width // int
|
|
// session.quality // int
|
|
// session.sink
|
|
// session.offsetChannel // int
|
|
// session.audioChannels // int
|
|
// session.security
|
|
// session.framerate // int
|
|
// session.sync
|
|
// session.buffer // int in milliseconds
|
|
// session.roomid // "yyyy"
|
|
// session.scene
|
|
// session.title // "zzzz"
|
|
</script>
|
|
<!--
|
|
// If you wish to change branding, blank offers a good clean start.
|
|
<script type="text/javascript" id="main-js" src="./main.js" data-translation="blank"></script>
|
|
-->
|
|
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=87"></script>
|
|
<script type="text/javascript" crossorigin="anonymous" src="./animations.js?ver=13"></script>
|
|
</body>
|
|
</html>
|