buffer audio fix

This commit is contained in:
steveseguin 2022-11-14 17:24:40 -05:00
parent 99f174264f
commit a95cc4bc4e
4 changed files with 500 additions and 126 deletions

View File

@ -949,7 +949,7 @@
<span style="display:block;"> <span style="display:block;">
<span style="bottom: 0; margin: 0 0 0 10px; top: 22px; position: relative; display:inline-block; max-width: 45%;"> <span style="bottom: 0; margin: 0 0 0 10px; top: 22px; position: relative; display:inline-block; max-width: 45%;">
<label class="switch" title="If disabled, the invited guest will not be able to see or hear anyone in the room."> <label class="switch" title="If disabled, the invited guest will not be able to see or hear anyone in the room.">
<input type="checkbox" checked data-param="&view=" onchange="updateLinkInverse(1,this);saveDirectorSettings();"> <input type="checkbox" checked data-param="&do" onchange="updateLinkInverse(1,this);saveDirectorSettings();">
<span class="slider"></span> <span class="slider"></span>
</label> </label>
<span data-translate="guests-hear-others" style="line-height:0;position:relative;top:-3px;">Guests hear others</span> <span data-translate="guests-hear-others" style="line-height:0;position:relative;top:-3px;">Guests hear others</span>
@ -2296,11 +2296,11 @@
// session.darkmode = false; // enable or disable the dark style theme as the default // session.darkmode = false; // enable or disable the dark style theme as the default
// session.defaultBackgroundImages = ["./media/bg_sample1.webp", "./media/bg_sample2.webp"]; // for &effects=5 (virtual backgrounds) // session.defaultBackgroundImages = ["./media/bg_sample1.webp", "./media/bg_sample2.webp"]; // for &effects=5 (virtual backgrounds)
</script> </script>
<script type="text/javascript" crossorigin="anonymous" id="lib-js" src="./lib.js?ver=530"></script> <script type="text/javascript" crossorigin="anonymous" id="lib-js" src="./lib.js?ver=535"></script>
<!-- <!--
// If you wish to change branding, blank offers a good clean start. // 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" id="main-js" src="./main.js" data-translation="blank"></script>
--> -->
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=472"></script> <script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=476"></script>
</body> </body>
</html> </html>

101
lib.js
View File

@ -1571,7 +1571,7 @@ function manageSceneState(data, UUID){ // incoming obs details
} else { } else {
controlButton.onclick = async function(){ controlButton.onclick = async function(){
var msg = {}; var msg = {};
msg.obsCommand = {} msg.obsCommand = {};
msg.obsCommand.action = this.dataset.obsAction; msg.obsCommand.action = this.dataset.obsAction;
msg.UUID = this.dataset.UUID; msg.UUID = this.dataset.UUID;
if (document.querySelector("#obsRemotePassword>input").value){ if (document.querySelector("#obsRemotePassword>input").value){
@ -2122,6 +2122,17 @@ function getStorage(cname) {
function play(streamid=null, UUID=false){ // play whatever is in the URL params; or filter by a streamID option function play(streamid=null, UUID=false){ // play whatever is in the URL params; or filter by a streamID option
log("play stream: "+session.view+ " " +streamid); log("play stream: "+session.view+ " " +streamid);
if (session.viewDirectorOnly){
if (!(UUID || streamid)){
warnlog("No UUID and StreamID");
return;
} else if (session.directorList.indexOf(UUID)==-1){
warnlog("Not a director");
return;
}
}
if (session.view_set){ if (session.view_set){
var played = false; var played = false;
for (var j in session.view_set){ for (var j in session.view_set){
@ -4298,11 +4309,11 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
// ANIMATED - CONTAINER ; width/height/z-index/cover/////////////// // ANIMATED - CONTAINER ; width/height/z-index/cover///////////////
if (layout){ if (layout){
var left = (w/100*layout[vid.dataset.sid].x) || 0; var left = (w/100*layout[vid.dataset.sid].x) || layout[vid.dataset.sid].xp || 0;
var top = (h/100*layout[vid.dataset.sid].y) || 0; var top = (h/100*layout[vid.dataset.sid].y) || layout[vid.dataset.sid].yp || 0;
top+=hi; top+=hi;
var width = (w/100*layout[vid.dataset.sid].w) || 0; var width = (w/100*layout[vid.dataset.sid].w) || layout[vid.dataset.sid].wp || 0;
var height = (h/100*layout[vid.dataset.sid].h) || 0; var height = (h/100*layout[vid.dataset.sid].h) || layout[vid.dataset.sid].hp || 0;
if (layout[vid.dataset.sid].cover || layout[vid.dataset.sid].c){ // this should be true/false if (layout[vid.dataset.sid].cover || layout[vid.dataset.sid].c){ // this should be true/false
vid.style.objectFit = "cover"; vid.style.objectFit = "cover";
cover = true; cover = true;
@ -8060,11 +8071,13 @@ function playoutdelay(UUID){ // applies a delay to all videos
receiver.playoutDelayHint = parseFloat(sync_offset/1000); receiver.playoutDelayHint = parseFloat(sync_offset/1000);
var audio_delay = session.sync || 0; // video is typically showing greater delay than video var audio_delay = session.sync || 0; // video is typically showing greater delay than video
if (receiver.track.id in session.rpcs[UUID].delayNode){ audio_delay += target_buffer - session.rpcs[UUID].stats[tid].Buffer_Delay_in_ms
log("session.sync audio delay"); if (receiver.track.id in session.rpcs[UUID].inboundAudioPipeline){
if (audio_delay<0){audio_delay=0;} if (session.rpcs[UUID].inboundAudioPipeline[receiver.track.id] && session.rpcs[UUID].inboundAudioPipeline[receiver.track.id].delayNode){
session.rpcs[UUID].delayNode[receiver.track.id].delayTime.setValueAtTime(parseFloat(audio_delay/1000.0), session.audioCtx.currentTime+1); if (audio_delay<0){audio_delay=0;}
session.rpcs[UUID].stats[tid].Audio_Sync_Delay_ms = audio_delay; session.rpcs[UUID].inboundAudioPipeline[receiver.track.id].delayNode.delayTime.setValueAtTime(parseFloat(audio_delay/1000.0), session.audioCtx.currentTime+1);
session.rpcs[UUID].stats[tid].Audio_Sync_Delay_ms = audio_delay;
}
} }
} else if (session.rpcs[UUID].stats[tid]._type=="video"){ } else if (session.rpcs[UUID].stats[tid]._type=="video"){
if(sync_offset<0){sync_offset=0;} if(sync_offset<0){sync_offset=0;}
@ -10607,6 +10620,60 @@ function issueLayout(layout=false, scene=false, UUID=false) { // A directing roo
} }
} }
async function issueLayoutOBS(data) { // A directing room only is controlled by the Director, with the exception of MUTE.
var layout = data.layout || false;
var scene = data.scene || false;
var UUID = data.UUID || false;
var obsCommand = data.obsCommand || false;
log("issueLayoutOBS() called");
var msg = {};
msg.layout = layout;
msg.obsCommand = obsCommand;
if (data.remote){
msg.remote = data.remote;
} else {
msg.remote = session.remote || true;
}
msg = await session.encodeRemote(msg);
if (UUID){
try {
log("CONTROL STATE" + session.pcs[UUID].obsState.details.controlLevel);
} catch(e){
}
if (session.pcs[UUID] && (scene!==false) && (session.pcs[UUID].scene===(scene+""))){
if (!session.pcs[UUID].solo){
session.sendMessage(msg, UUID);
}
} else if (session.pcs[UUID] && session.pcs[UUID].layout){
session.sendMessage(msg, UUID);
log("broadcast");
}
} else {
for (var uuid in session.pcs){
try {
log("CONTROL STATE" + session.pcs[UUID].obsState.details.controlLevel);
} catch(e){
}
if ((scene!==false) && (session.pcs[uuid].scene===(scene+""))){
if (!session.pcs[uuid].solo){
session.sendMessage(msg, uuid);
}
} else if (session.pcs[uuid].layout){
session.sendMessage(msg, uuid);
log("broadcast");
}
}
}
}
var previousURL = ""; var previousURL = "";
var stillNeedURL = true; var stillNeedURL = true;
var reloadCancelled = false; var reloadCancelled = false;
@ -11238,7 +11305,10 @@ function loadDirectorSettings(){
directorLinks1.querySelector('[data-param="'+key+'"]').checked = settings.directorLinks1[key]; directorLinks1.querySelector('[data-param="'+key+'"]').checked = settings.directorLinks1[key];
directorLinks1.querySelector('[data-param="'+key+'"]').onchange(); directorLinks1.querySelector('[data-param="'+key+'"]').onchange();
} }
} catch(e){errorlog(e);} } catch(e){
errorlog("key :"+key);
errorlog(e);
}
}); });
} }
@ -11250,7 +11320,10 @@ function loadDirectorSettings(){
directorLinks2.querySelector('[data-param="'+key+'"]').checked = settings.directorLinks2[key]; directorLinks2.querySelector('[data-param="'+key+'"]').checked = settings.directorLinks2[key];
directorLinks2.querySelector('[data-param="'+key+'"]').onchange(); directorLinks2.querySelector('[data-param="'+key+'"]').onchange();
} }
} catch(e){errorlog(e);} } catch(e){
errorlog("key :"+key);
errorlog(e);
}
}); });
} }
} }
@ -27578,12 +27651,13 @@ function addAudioPipeline(UUID, track){ // INBOUND AUDIO EFFECTS
delete session.rpcs[UUID].inboundAudioPipeline[tid]; // get rid of old nodes. delete session.rpcs[UUID].inboundAudioPipeline[tid]; // get rid of old nodes.
} }
var trackid = track.id; var trackid = track.id;
session.rpcs[UUID].inboundAudioPipeline[trackid] = {}; session.rpcs[UUID].inboundAudioPipeline[trackid] = {};
session.rpcs[UUID].inboundAudioPipeline[trackid].mediaStream = createMediaStream(); session.rpcs[UUID].inboundAudioPipeline[trackid].mediaStream = createMediaStream();
session.rpcs[UUID].inboundAudioPipeline[trackid].mediaStream.addTrack(track); session.rpcs[UUID].inboundAudioPipeline[trackid].mediaStream.addTrack(track);
if (ChromeVersion && (ChromeVersion<106)){ // I'm going to deprecate this. if (ChromeVersion){ // I'm going to deprecate this. -> re investigate this
session.rpcs[UUID].inboundAudioPipeline[trackid].mutedAudio = createAudioElement(); // TODO: I don't know if this mutedAudio thing matters any more, in recent versions of Chrome, since it won't play even if muted. session.rpcs[UUID].inboundAudioPipeline[trackid].mutedAudio = createAudioElement(); // TODO: I don't know if this mutedAudio thing matters any more, in recent versions of Chrome, since it won't play even if muted.
session.rpcs[UUID].inboundAudioPipeline[trackid].mutedAudio.muted = true; session.rpcs[UUID].inboundAudioPipeline[trackid].mutedAudio.muted = true;
session.rpcs[UUID].inboundAudioPipeline[trackid].mutedAudio.playsinline = true; // ## Added Oct 9th 2022. Not sure it's does anything, but might help with iPhones? session.rpcs[UUID].inboundAudioPipeline[trackid].mutedAudio.playsinline = true; // ## Added Oct 9th 2022. Not sure it's does anything, but might help with iPhones?
@ -27659,6 +27733,7 @@ function addAudioPipeline(UUID, track){ // INBOUND AUDIO EFFECTS
} }
if (screwedUp){ if (screwedUp){
if (session.rpcs[UUID].inboundAudioPipeline[trackid].destination===false){ if (session.rpcs[UUID].inboundAudioPipeline[trackid].destination===false){
session.rpcs[UUID].inboundAudioPipeline[trackid].destination = session.audioCtx.createMediaStreamDestination(); session.rpcs[UUID].inboundAudioPipeline[trackid].destination = session.audioCtx.createMediaStreamDestination();
} }

33
main.js
View File

@ -1177,6 +1177,9 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
} else { } else {
session.password = decodeURIComponent(session.password); // will be re-encoded in a moment. session.password = decodeURIComponent(session.password); // will be re-encoded in a moment.
} }
} else if (urlParams.has('nopassword') || urlParams.has('nopass') || urlParams.has('nopw')) {
session.password = false;
session.defaultPassword = false;
} }
if (session.password) { if (session.password) {
@ -1646,6 +1649,11 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
} }
} }
if (urlParams.has('directoronly') || urlParams.has('do')){
session.viewDirectorOnly = true;
}
if (session.view!==false) { if (session.view!==false) {
session.view_set = session.view.split(","); session.view_set = session.view.split(",");
} }
@ -4653,6 +4661,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
} // don't use if the stream is in your room (as not needed) } // don't use if the stream is in your room (as not needed)
} // you can load a stream ID from inside a room that exists outside any room } // you can load a stream ID from inside a room that exists outside any room
if ("previewMode" in e.data){ if ("previewMode" in e.data){
if ("layout" in e.data){ if ("layout" in e.data){
session.layout = e.data.layout; session.layout = e.data.layout;
@ -4663,20 +4672,28 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
warnlog("changing layout request via IFRAME API"); warnlog("changing layout request via IFRAME API");
session.layout = e.data.layout; session.layout = e.data.layout;
pokeIframeAPI("layout-updated", session.layout); pokeIframeAPI("layout-updated", session.layout);
if (session.director){
if ("scene" in e.data){ if (e.data.obsCommand){
if ("UUID" in e.data){ issueLayoutOBS(e.data);
issueLayout(e.data.layout, e.data.scene, e.data.UUID); } else {
} else { if (session.director){
issueLayout(e.data.layout, e.data.scene); if ("scene" in e.data){
if ("UUID" in e.data){
issueLayout(e.data.layout, e.data.scene, e.data.UUID);
} else {
issueLayout(e.data.layout, e.data.scene);
}
} else if ("UUID" in e.data){
issueLayout(e.data.layout, false, e.data.UUID);
} }
} else if ("UUID" in e.data){
issueLayout(e.data.layout, false, e.data.UUID);
} }
} }
updateMixer(); updateMixer();
} else if (e.data.obsCommand){
errorlog("obsCommand via iframe API currently needs a layout..");
} }
if ("slotmode" in e.data){ if ("slotmode" in e.data){
if (session.slotmode){ if (session.slotmode){
session.slotmode = parseInt(e.data.slotmode); session.slotmode = parseInt(e.data.slotmode);

View File

@ -18,6 +18,8 @@
:root{ :root{
--aspect-ratio: 1.7777777777; --aspect-ratio: 1.7777777777;
--chat-width: 450px; --chat-width: 450px;
--iframe-width: 1280px;
--iframe-height: 720px;
} }
body { body {
@ -38,7 +40,7 @@
display: block; display: block;
height: 100%; height: 100%;
width: 1280px; width: var(--iframe-width);
max-height: calc(100vh - 80px); max-height: calc(100vh - 80px);
@ -51,10 +53,10 @@
} }
iframe.aspectRatio{ iframe.aspectRatio{
max-height: min(calc(100vh - 80px), calc(100vw - 160px - var(--chat-width)) / var(--aspect-ratio))) !important; max-height: min(calc(100vh - 80px), calc(100vw - 160px - var(--chat-width)) / var(--aspect-ratio)) !important;
max-width: min(calc((100vh - 80px) * var(--aspect-ratio)), calc(100vw - 160px - var(--chat-width))) !important; max-width: min(calc((100vh - 80px) * var(--aspect-ratio)), calc(100vw - 160px - var(--chat-width))) !important;
height: 720px; height: var(--iframe-height) !important;
width: 1280px; width: var(--iframe-width) !important;
} }
.gone { .gone {
position:absolute; position:absolute;
@ -121,6 +123,9 @@
font-family: Verdana; font-family: Verdana;
line-height: 14px; line-height: 14px;
} }
#sceneSettings{
font-size: 80%;
}
#chatModule { #chatModule {
bottom: 0; bottom: 0;
position: fixed; position: fixed;
@ -423,15 +428,17 @@
} }
#canvas{ #canvas{
background-color: #000; background-color: #000;
width: 1280px; width: var(--iframe-width);
height: 720px; height: var(--iframe-height);
margin:0; margin:0;
padding:0; padding:0;
border:0; border:0;
display: inline-block; display: inline-block;
} }
h3 {
margin-bottom: 6px;
}
.settings { .settings {
display: block; display: block;
@ -844,7 +851,8 @@
<button onclick="addElement();"> Add Element to Scene</button> <button onclick="addElement();"> Add Element to Scene</button>
<button onclick="saveScene(false, event);">💾 Save Scene</button> <button onclick="saveScene(false, event);">💾 Save Scene</button>
<button onclick="saveScene(true, event);">💾<span style="position:relative;right:12px;top:2px;width:12px;display: inline-block;">💾</span>Duplicate Scene</button> <button onclick="saveScene(true, event);">💾<span style="position:relative;right:12px;top:2px;width:12px;display: inline-block;">💾</span>Duplicate Scene</button>
<button onclick="copyJSON();" title="This can be used with &format directly in VDO.Ninja without the mixer app.">Show as JSON</button> <button onclick="setobsSceneName();" title="When this layout is triggered, OBS will change to the specified scene as well">Link OBS Scene</button>
<button onclick="copyJSON();" title="This can be used with &format directly in VDO.Ninja without the mixer app. Requires a guest being active.">Show as JSON</button>
<button onclick="removeScene();">🗑️ Remove Scene</button> <button onclick="removeScene();">🗑️ Remove Scene</button>
<button id="saveAndClose" onclick="saveScene(false, event);closeScene();">💾❌ Save and Close</button> <button id="saveAndClose" onclick="saveScene(false, event);closeScene();">💾❌ Save and Close</button>
<button onclick="closeScene();">❌ Close Scene Maker</button> <button onclick="closeScene();">❌ Close Scene Maker</button>
@ -913,27 +921,37 @@
<div class="modal-content"> <div class="modal-content">
<span class="close-btn">&times;</span> <span class="close-btn">&times;</span>
<h2>General Settings</h2> <h2>General Settings</h2>
<h4>Aspect Ratio</h4> <h3>Aspect Ratio</h3>
<input type="checkbox" checked class="aspectbutton" onchange="changeAspectRatio(16/9.0, this);">16:9 <input type="checkbox" checked class="aspectbutton" data-value="169" onchange="changeAspectRatio(16/9.0, this);">16:9
<input type="checkbox" class="aspectbutton" onchange="changeAspectRatio(9.0/16, this);">9:16 <input type="checkbox" class="aspectbutton" data-value="0.5625" onchange="changeAspectRatio(9.0/16, this);">9:16
<input type="checkbox" class="aspectbutton" onchange="changeAspectRatio(1.0, this);">1:1 <input type="checkbox" class="aspectbutton" data-value="1" onchange="changeAspectRatio(1.0, this);">1:1
<br /><small><i>This just impacts the aspect ratio of the local preview.</i></small><br /> <br /><small><i>This just impacts the aspect ratio of the local preview.</i></small><br />
<h4>Layout switching</h4> <h3 title="Does not impact the output; just increases pixel accuracy">Canvas Size</h3>
<input type="checkbox" title="When a user is assigned a slot or switches slots, the last active layout is re-applied automatically" id="updateOnSlotChange" checked onchange="submitChange(this)";>Update layout on a slot change <input type="checkbox" checked class="pixeldensity" data-value="720" onchange="changePixelDensity(720, this);">720p
<h4>Slot assignment</h4> <input type="checkbox" class="pixeldensity" data-value="1080" onchange="changePixelDensity(1080, this);">1080p
<input type="checkbox" title="A guest is assigned a slot when they join, automatically. If disabled, they must be assigned a slot manually." id="assignSlotToGuest" checked onchange="submitChange2(this)";>Assign a slot to new guests automatically
<h4>Show advanced controls</h4>
<input type="checkbox" title="Shows more director control options" onchange="toggleAdvanced(this)";>Show the advanced director control options
<h4>🗑 Remove all Layouts </h4> <h3>Unit type for saved scene edits 📏</h3>
<input type="checkbox" checked class="absolutePosition" data-value="false" onchange="changeAbsolutePosition(false, this);">Relative (Percentage)
<input type="checkbox" class="absolutePosition" data-value="true" onchange="changeAbsolutePosition(true, this);">Absolute (Pixels)
<h3>Layout switching</h3>
<input type="checkbox" title="When a user is assigned a slot or switches slots, the last active layout is re-applied automatically" id="updateOnSlotChange" checked onchange="submitChange(this)";>Update layout on a slot change
<h3>Linked OBS scenes</h3>
<input type="checkbox" title="When a user is assigned a slot or switches slots, the last active layout is re-applied automatically" id="syncOBS" onchange="submitChange3(this)";>Activate linked OBS scene on layout change
<h3>Slot assignment</h3>
<input type="checkbox" title="A guest is assigned a slot when they join, automatically. If disabled, they must be assigned a slot manually." id="assignSlotToGuest" checked onchange="submitChange2(this)";>Assign a slot to new guests automatically
<h3>Show advanced controls</h3>
<input type="checkbox" title="Shows more director control options" id="advancedMode" onchange="toggleAdvanced(this)";>Show the advanced director control options
<h3>🗑 Remove all Layouts</h3>
<button onclick="wipeLayouts();">This will remove all the scene layouts from the current session.</button><br /> <button onclick="wipeLayouts();">This will remove all the scene layouts from the current session.</button><br />
<h4>🚿 Load Default Layouts </h4> <h3>🚿 Load Default Layouts</h3>
<button onclick="resetLayouts();">This will replace all current scene layouts with the initial defaults.</button><br /> <button onclick="resetLayouts();">This will replace all current scene layouts with the initial defaults.</button><br />
<h4>📤 Export settings </h4> <h3>📤 Export settings </h3>
<button onclick="exportSession();">Export all scenes and settings to disk</button><br /> <button onclick="exportSession();">Export all scenes and settings to disk</button><br />
<h4>📥 Import settings </h4> <h3>📥 Import settings </h3>
Import scenes and settings from local file:<br /><input type="file" accept=".json" onchange="importSession(event);"/><br /><br /> Import scenes and settings from local file:<br /><input type="file" accept=".json" onchange="importSession(event);"/><br /><br />
<button class='close-btn'>Close Settings</button> <button class='close-btn'>Close Settings</button>
</div> </div>
@ -993,12 +1011,12 @@
})(window); })(window);
function errorlog(e,a=null,b=null){
console.error(e);
}
function warnlog(msg){ function warnlog(msg){
console.warn(msg); console.warn(msg);
} }
function errorlog(msg){
console.error(msg);
}
function log(msg){ function log(msg){
console.log(msg); console.log(msg);
} }
@ -1042,6 +1060,41 @@
return roomid; return roomid;
} }
var CtrlPressed = false;
document.addEventListener("keydown", event => {
if ((event.ctrlKey) || (event.metaKey)) { // detect if CTRL is pressed
if (!CtrlPressed){
CtrlPressed = true;
$(function(){
// $(".draggable").unbind();
$(".draggable").draggable({ snap: false , grid: [ 1,1 ] });
});
$(function(){
//$(".resizable").unbind();
$(".resizable").resizable({ snap: false , grid: [ 1,1 ] });
});
//errorlog("CtrlPressed :"+CtrlPressed);
}
}
});
document.addEventListener("keyup", event => {
if ((event.ctrlKey) || (event.metaKey)) { // detect if CTRL is pressed
//
} else if (CtrlPressed){
CtrlPressed = false;
$(function(){
// $(".draggable").unbind();
$(".draggable").draggable({ snap: true , grid: [ 10,10 ] });
});
$(function(){
//$(".resizable").unbind();
$(".resizable").resizable({ snap: true , grid: [ 10, 10] });
});
//errorlog("CtrlPressed :"+CtrlPressed);
}
});
var urlEdited = window.location.search.replace(/\?\?/g, "?"); var urlEdited = window.location.search.replace(/\?\?/g, "?");
urlEdited = urlEdited.replace(/\?/g, "&"); urlEdited = urlEdited.replace(/\?/g, "&");
@ -1070,13 +1123,24 @@
var toggleBroadcast = true; var toggleBroadcast = true;
var messageList = []; var messageList = [];
var password = false; var password = false;
var syncOBS = false;
if (urlParams.has('password') || urlParams.has('pass') || urlParams.has('pw') || urlParams.has('p')) { if (urlParams.has('password') || urlParams.has('pass') || urlParams.has('pw') || urlParams.has('p')) {
password = urlParams.get('password') || urlParams.get('pass') || urlParams.get('pw') || urlParams.get('p'); password = urlParams.get('password') || urlParams.get('pass') || urlParams.get('pw') || urlParams.get('p');
} }
var aspectRatio = 16/9.0; var aspectRatio = 16/9.0;
var pixelDensity = 720;
document.documentElement.style.setProperty('--aspect-ratio', aspectRatio); document.documentElement.style.setProperty('--aspect-ratio', aspectRatio);
var absolutePixel = false;
var advancedMode = false;
var hh = pixelDensity;
var ww = parseInt((pixelDensity*16/9) * (aspectRatio/(16/9)));
document.documentElement.style.setProperty('--iframe-width', ww);
document.documentElement.style.setProperty('--iframe-height',hh);
var roomname = false; var roomname = false;
if (urlParams.has("room") || urlParams.has("r") ||urlParams.has("dir") || urlParams.has("director")){ if (urlParams.has("room") || urlParams.has("r") ||urlParams.has("dir") || urlParams.has("director")){
roomname = urlParams.get("room") || urlParams.get("r") ||urlParams.get("dir") || urlParams.get("director"); roomname = urlParams.get("room") || urlParams.get("r") ||urlParams.get("dir") || urlParams.get("director");
@ -1154,7 +1218,6 @@
var msg = document.getElementById('chatInput').value; var msg = document.getElementById('chatInput').value;
msg = sanitize(msg); msg = sanitize(msg);
if (msg==""){return;} if (msg==""){return;}
console.log(msg);
iframe.contentWindow.postMessage({ sendChat: msg }, "*"); iframe.contentWindow.postMessage({ sendChat: msg }, "*");
document.getElementById('chatInput').value = ""; document.getElementById('chatInput').value = "";
@ -1263,9 +1326,7 @@
//chatUpdateTimeout = setTimeout(function(){updateMessages()},60000); //chatUpdateTimeout = setTimeout(function(){updateMessages()},60000);
} }
function errorlog(e,a=null,b=null){
console.error(e);
}
var currentLayout = {}; var currentLayout = {};
@ -1332,9 +1393,6 @@
ev.preventDefault(); ev.preventDefault();
var data = ev.dataTransfer.getData("text"); var data = ev.dataTransfer.getData("text");
var origThing = document.getElementById(data); var origThing = document.getElementById(data);
console.log(origThing);
console.log(data);
console.log(ev);
ev.target.style.border = ""; ev.target.style.border = "";
origThing.style.border = ""; origThing.style.border = "";
@ -1356,8 +1414,6 @@
ev.target.parentNode.insertBefore(origThing, ev.target.nextSibling); ev.target.parentNode.insertBefore(origThing, ev.target.nextSibling);
console.warn(origThing);
if (origThing.dataset.slot && (origThing.dataset.slot!=="undefined")){ if (origThing.dataset.slot && (origThing.dataset.slot!=="undefined")){
document.querySelectorAll("[data-slot='"+origThing.dataset.slot+"']").forEach(ele=>{ele.style.display = "block";}) document.querySelectorAll("[data-slot='"+origThing.dataset.slot+"']").forEach(ele=>{ele.style.display = "block";})
document.querySelectorAll("[data-slot='"+origThing.dataset.slot+"']").forEach(ele=>{ele.classList.remove("hidden");}) document.querySelectorAll("[data-slot='"+origThing.dataset.slot+"']").forEach(ele=>{ele.classList.remove("hidden");})
@ -1455,12 +1511,9 @@
thing.classList.add("thing"); thing.classList.add("thing");
thing.ondblclick = function(ev){ thing.ondblclick = function(ev){
var origThing = ev.target; var origThing = ev.target;
console.log(ev);
if (origThing.parentNode.id == "col1"){return;} if (origThing.parentNode.id == "col1"){return;}
ev.preventDefault(); ev.preventDefault();
var target = document.querySelector("[data-slot][class='empty']:not([class='hidden'])"); var target = document.querySelector("[data-slot][class='empty']:not([class='hidden'])");
console.log(origThing);
console.log(target);
origThing.style.border = ""; origThing.style.border = "";
var eles = document.querySelectorAll(".thing"); var eles = document.querySelectorAll(".thing");
@ -1489,8 +1542,6 @@
if (target.dataset.slot=="undefined"){return;} if (target.dataset.slot=="undefined"){return;}
target.parentNode.insertBefore(origThing, target.nextSibling); target.parentNode.insertBefore(origThing, target.nextSibling);
console.warn(origThing);
if (origThing.dataset.slot && (origThing.dataset.slot!=="undefined")){ if (origThing.dataset.slot && (origThing.dataset.slot!=="undefined")){
document.querySelector("[data-slot='"+origThing.dataset.slot+"']").style.display = "block"; document.querySelector("[data-slot='"+origThing.dataset.slot+"']").style.display = "block";
document.querySelector("[data-slot='"+origThing.dataset.slot+"']").classList.remove("hidden"); document.querySelector("[data-slot='"+origThing.dataset.slot+"']").classList.remove("hidden");
@ -1654,6 +1705,103 @@
getById("toggleBroadcast").checked = true; getById("toggleBroadcast").checked = true;
} }
} }
if (savedSession.settings && ("syncOBS" in savedSession.settings)){
syncOBS = savedSession.settings.syncOBS;
if (!syncOBS){
getById("syncOBS").value = "off";
getById("syncOBS").checked = false;
getById("syncOBS").removeAttribute('checked');
} else {
getById("syncOBS").value = "on";
getById("syncOBS").checked = true;
}
}
if (savedSession.settings && ("aspectRatio" in savedSession.settings)){
aspectRatio = savedSession.settings.aspectRatio;
document.documentElement.style.setProperty('--aspect-ratio', aspectRatio);
document.querySelectorAll(".aspectbutton").forEach(ele=>{
if ((ele.dataset.value == "169") && (aspectRatio == 16/9.0)){
ele.checked = true;
ele.value = true;
} else if (ele.dataset.value == aspectRatio){
ele.checked = true;
ele.value = true;
} else {
ele.checked = false;
ele.value = false;
}
});
}
if (savedSession.settings && ("advancedMode" in savedSession.settings)){
advancedMode = savedSession.settings.advancedMode;
if (!advancedMode){
getById("advancedMode").value = "off";
getById("advancedMode").checked = false;
getById("advancedMode").removeAttribute('checked');
} else {
getById("advancedMode").value = "on";
getById("advancedMode").checked = true;
}
if (iframe && iframe.contentWindow){
iframe.contentWindow.postMessage({"advancedMode":advancedMode}, '*');
}
}
if (savedSession.settings && ("absolutePixel" in savedSession.settings)){
absolutePixel = savedSession.settings.absolutePixel;
document.querySelectorAll(".absolutePosition").forEach(ele=>{
if (ele.dataset.value == "true"){
if (true == absolutePixel){
ele.checked = true;
ele.value = true;
} else {
ele.checked = false;
ele.value = false;
}
} else {
if (false == absolutePixel){
ele.checked = true;
ele.value = true;
} else {
ele.checked = false;
ele.value = false;
}
}
});
}
if (savedSession.settings && ("pixelDensity" in savedSession.settings)){
pixelDensity = savedSession.settings.pixelDensity;
if (pixelDensity==1080){
document.querySelectorAll(".pixeldensity").forEach(ele=>{
if (ele.dataset.value == pixelDensity){
ele.checked = true;
ele.value = true;
} else {
ele.checked = false;
ele.value = false;
}
});
var hh = pixelDensity;
var ww = parseInt((pixelDensity*16/9) * (aspectRatio/(16/9)));
document.documentElement.style.setProperty('--aspect-ratio', aspectRatio);
document.documentElement.style.setProperty('--iframe-width', ww+"px");
document.documentElement.style.setProperty('--iframe-height', hh+"px");
// getById("syncOBS").value = "off";
// getById("syncOBS").checked = false;
// getById("syncOBS").removeAttribute('checked');
}
}
} }
var savedSession = getStorage("savedSession"); var savedSession = getStorage("savedSession");
@ -1690,21 +1838,33 @@
assignSlotToGuest=false assignSlotToGuest=false
iframe.contentWindow.postMessage({"slotmode":2}, '*');; iframe.contentWindow.postMessage({"slotmode":2}, '*');;
} }
saveSession();
}
function submitChange3(element){
if (element.checked){
syncOBS=true;
} else { // do not assign guests to slots automatically
element.removeAttribute('checked');
syncOBS=false
}
saveSession(); saveSession();
} }
function toggleAdvanced(element){ function toggleAdvanced(element){
if (element.checked){ if (element.checked){
iframe.contentWindow.postMessage({"advancedMode":true}, '*'); iframe.contentWindow.postMessage({"advancedMode":true}, '*');
advancedMode = true;
} else { } else {
element.removeAttribute('checked'); element.removeAttribute('checked');
iframe.contentWindow.postMessage({"advancedMode":false}, '*'); iframe.contentWindow.postMessage({"advancedMode":false}, '*');
advancedMode = false;
} }
saveSession();
} }
function exportSession() { function exportSession() {
var content = JSON.stringify(savedSession); var content = JSON.stringify(savedSession,null,2);
var fileName = roomname + ".json"; var fileName = roomname + ".json";
var a = document.createElement("a"); var a = document.createElement("a");
var file = new Blob([content], {type: 'text/plain'}); var file = new Blob([content], {type: 'text/plain'});
@ -1714,10 +1874,9 @@
} }
function importSession(event){ function importSession(event){
var reader = new FileReader(); var reader = new FileReader();
reader.onload = function(event){ reader.onload = function(event){
console.log(event.target.result); log(event.target.result);
try { try {
var obj = JSON.parse(event.target.result); var obj = JSON.parse(event.target.result);
} catch(e){ } catch(e){
@ -1731,8 +1890,13 @@
document.getElementById("containermenu").innerHTML = ""; document.getElementById("containermenu").innerHTML = "";
drawAddNewLayout2(); drawAddNewLayout2();
drawAddNewLayout3(); drawAddNewLayout3();
for (var i in savedSession.layouts){ for (var i in savedSession.layouts){
drawLayout(savedSession.layouts[i]); if (savedSession.obsScenes && savedSession.obsScenes[i]){
drawLayout(savedSession.layouts[i], false, savedSession.obsScenes[i]);
} else {
drawLayout(savedSession.layouts[i]);
}
} }
alert("The saved session has been imported and loaded."); alert("The saved session has been imported and loaded.");
} else { } else {
@ -1752,6 +1916,7 @@
drawAddNewLayout2(); drawAddNewLayout2();
drawAddNewLayout3(); drawAddNewLayout3();
savedSession.obsScenes = [];
savedSession.layouts = initialLayouts.layouts; savedSession.layouts = initialLayouts.layouts;
for (var i in savedSession.layouts){ for (var i in savedSession.layouts){
@ -1760,6 +1925,29 @@
saveSession(); saveSession();
} }
function updateLayouts(){
document.getElementById("containermenu").innerHTML = "";
var slots = document.getElementById("col1").children;
for (var i=0;i<slots.length;i++){
slots[i].style.backgroundColor = colors[i];
slots[i].style.opacity = "0.9";
}
drawAddNewLayout2();
drawAddNewLayout3();
for (var i in savedSession.layouts){
if (savedSession.obsScenes && savedSession.obsScenes[i]){
drawLayout(savedSession.layouts[i], false, savedSession.obsScenes[i]);
} else {
drawLayout(savedSession.layouts[i]);
}
}
}
function wipeLayouts(){ function wipeLayouts(){
var yes = confirm("Are you sure? This will delete all the layouts."); var yes = confirm("Are you sure? This will delete all the layouts.");
@ -1769,7 +1957,7 @@
drawAddNewLayout2(); drawAddNewLayout2();
drawAddNewLayout3(); drawAddNewLayout3();
savedSession.obsScenes = [];
savedSession.layouts = []; savedSession.layouts = [];
for (var i in savedSession.layouts){ for (var i in savedSession.layouts){
drawLayout(savedSession.layouts[i]); drawLayout(savedSession.layouts[i]);
@ -1923,7 +2111,7 @@
if (event.target && (event.target.tagName == "INPUT")){warnlog("input in focus; return");return;} if (event.target && (event.target.tagName == "INPUT")){warnlog("input in focus; return");return;}
var value = parseInt(event.key); var value = parseInt(event.key);
if (value == event.key){ if (value == event.key){
console.log(value); log(value);
try { try {
if (document.querySelector("#containermenu").children[value]){ if (document.querySelector("#containermenu").children[value]){
document.querySelector("#containermenu").children[value].querySelector("canvas").click(); document.querySelector("#containermenu").children[value].querySelector("canvas").click();
@ -1957,6 +2145,10 @@
} }
roomname = sanitizeRoomName(roomname); roomname = sanitizeRoomName(roomname);
if (!advancedMode){
additional2+="&novice";
}
var iframeContainer = document.getElementById("iframeContainer"); var iframeContainer = document.getElementById("iframeContainer");
iframe.allow = "autoplay;camera;microphone;fullscreen;picture-in-picture;display-capture;"; iframe.allow = "autoplay;camera;microphone;fullscreen;picture-in-picture;display-capture;";
@ -1966,7 +2158,7 @@
roomname = generateString(10); roomname = generateString(10);
} }
var iframesrc = "./index.html?novice&showdirector&ltb=350&transparent&hideheader&hidetranslate&cleandirector&chatbutton=0&director="+roomname+additional+additional2+"&b64css="+injectCSS; var iframesrc = "./index.html?showdirector&ltb=350&transparent&hideheader&hidetranslate&cleandirector&chatbutton=0&director="+roomname+additional+additional2+"&b64css="+injectCSS;
if (roomname!==false){ if (roomname!==false){
setStorage("savedRoom", {roomname:roomname,password:password}, 9999); setStorage("savedRoom", {roomname:roomname,password:password}, 9999);
@ -2065,7 +2257,7 @@
var a = document.createElement("a"); var a = document.createElement("a");
a.innerHTML = "Scene View Link 📎"; a.innerHTML = "Scene View Link 📎";
a.href = "./?scene=0&layout&room="+roomname+additional; a.href = "./?scene=0&layout&remote&room="+roomname+additional;
a.target = "_blank"; a.target = "_blank";
a.onclick = function(evt){copyFunction(this, evt);}; a.onclick = function(evt){copyFunction(this, evt);};
document.getElementById("sources").appendChild(a); document.getElementById("sources").appendChild(a);
@ -2077,13 +2269,16 @@
slots[i].style.opacity = "0.9"; slots[i].style.opacity = "0.9";
} }
//drawAddNewLayout();
drawAddNewLayout2(); drawAddNewLayout2();
//drawAutoLayout();
drawAddNewLayout3(); drawAddNewLayout3();
for (var i in savedSession.layouts){
drawLayout(savedSession.layouts[i]); for (var i in savedSession.layouts){
if (savedSession.obsScenes && savedSession.obsScenes[i]){
drawLayout(savedSession.layouts[i], false, savedSession.obsScenes[i]);
} else {
drawLayout(savedSession.layouts[i]);
}
} }
document.getElementById("chatModule").classList.remove("hidden"); document.getElementById("chatModule").classList.remove("hidden");
@ -2110,8 +2305,6 @@
eventer(messageEvent, function (e) { eventer(messageEvent, function (e) {
if (e.source != iframe.contentWindow){return} // reject messages send from other iframes if (e.source != iframe.contentWindow){return} // reject messages send from other iframes
//console.log(e.data);
if ("gotChat" in e.data){ if ("gotChat" in e.data){
messageList.push(e.data.gotChat); messageList.push(e.data.gotChat);
messageList = messageList.slice(-100); messageList = messageList.slice(-100);
@ -2288,7 +2481,7 @@
function addLayout(){ function addLayout(){
var layout = prompt("Enter your new layout as a JSON string", '[{"x":0,"y":0,"w":100,"h":100}]'); var layout = prompt("Enter your new layout as a JSON string", '[{"x":0,"y":0,"w":100,"h":100}]');
layout = JSON.parse(layout); layout = JSON.parse(layout);
console.log(layout); log(layout);
drawLayout(layout); drawLayout(layout);
} }
@ -2306,6 +2499,15 @@
document.getElementById("canvas").classList.remove("hidden"); document.getElementById("canvas").classList.remove("hidden");
try {
var obsSceneName = item.parentNode.querySelector("canvas").obsSceneName;
document.getElementById("canvas").obsSceneName = obsSceneName;
} catch(e){
document.getElementById("canvas").obsSceneName = "";
errorlog(e);
}
try { try {
var tar = item.parentNode.querySelector("canvas").sceneName; var tar = item.parentNode.querySelector("canvas").sceneName;
document.getElementById("canvas").sceneName = tar; document.getElementById("canvas").sceneName = tar;
@ -2346,7 +2548,7 @@
return 0; return 0;
} }
function drawLayout(layoutOriginal, sceneName=false){ function drawLayout(layoutOriginal, sceneName=false, obsSceneName = ""){
var layout = []; var layout = [];
@ -2377,16 +2579,16 @@
ctx.fillStyle = colors[parseInt(layout[i].slot)]; ctx.fillStyle = colors[parseInt(layout[i].slot)];
ctx.lineWidth = 3; ctx.lineWidth = 3;
var x = layout[i].x*0.8 || 0;
var y = layout[i].y*0.45 || 0; var x = layout[i].x*0.8 || parseFloat(100*layout[i].xp/(pixelDensity*16/9)*0.8) || 0;
var w = layout[i].w*0.8 || 0; var y = layout[i].y*0.45 || parseFloat(100*layout[i].yp/(pixelDensity*16/9)*0.8) || 0;
var h = layout[i].h*0.45 || 0; var w = layout[i].w*0.8 || parseFloat(100*layout[i].wp/(pixelDensity*16/9)*0.8) || 0;
var h = layout[i].h*0.45 || parseFloat(100*layout[i].hp/(pixelDensity*16/9)*0.8) || 0;
ctx.beginPath(); ctx.beginPath();
ctx.rect(x, y, w, h); ctx.rect(x, y, w, h);
ctx.fill(); ctx.fill();
} }
canvas.layout = JSON.stringify(layout); canvas.layout = JSON.stringify(layout);
canvas.onclick = remoteActivate; canvas.onclick = remoteActivate;
@ -2438,6 +2640,9 @@
sceneName = parseInt(Math.random()*1000000); sceneName = parseInt(Math.random()*1000000);
} }
canvas.sceneName = sceneName; canvas.sceneName = sceneName;
canvas.obsSceneName = obsSceneName;
canvas.title = "Activate this layout; the view scene link will be updated"; canvas.title = "Activate this layout; the view scene link will be updated";
var canvasContainer = document.createElement("div"); var canvasContainer = document.createElement("div");
@ -2584,7 +2789,6 @@
this.parentNode.dimensions.innerHTML = parseInt(this.parentNode.style.width) +"x"+parseInt(this.parentNode.style.height); this.parentNode.dimensions.innerHTML = parseInt(this.parentNode.style.width) +"x"+parseInt(this.parentNode.style.height);
this.parentNode.dimensions.innerHTML += " : " + parseInt(this.parentNode.style.left) +"x"+parseInt(this.parentNode.style.top); this.parentNode.dimensions.innerHTML += " : " + parseInt(this.parentNode.style.left) +"x"+parseInt(this.parentNode.style.top);
this.parentNode.dimensions.innerHTML += " , layer: "+parseInt(this.parentNode.style.zIndex); this.parentNode.dimensions.innerHTML += " , layer: "+parseInt(this.parentNode.style.zIndex);
} }
function pushDown(event){ function pushDown(event){
@ -2604,11 +2808,11 @@
function addOldElement(object){ function addOldElement(object){
document.getElementById("canvas").innerHTML = ""; document.getElementById("canvas").innerHTML = "";
var hh = 720; var hh = pixelDensity;
var ww = parseInt(1280 * (aspectRatio/(16/9))); var ww = parseInt((pixelDensity*16/9) * (aspectRatio/(16/9)));
document.getElementById('canvas').style.width = ww+"px"; document.documentElement.style.setProperty('--iframe-width', ww+"px");
document.getElementById('canvas').style.height = hh+"px"; document.documentElement.style.setProperty('--iframe-height',hh+"px");
for (var i=0;i<object.length;i++){ for (var i=0;i<object.length;i++){
@ -2639,19 +2843,20 @@
container.muted = object[i].muted || false; container.muted = object[i].muted || false;
container.rounded = object[i].rounded || 0; container.rounded = object[i].rounded || 0;
var hh = 720; var hh = pixelDensity;
var ww = 1280 * (aspectRatio/(16/9)); var ww = (pixelDensity*16/9) * (aspectRatio/(16/9));
var yoffset = object[i].y*hh/100; var yoffset = object[i].y*hh/100 || object[i].yp || 0;
var xoffset =object[i].x*ww/100; var xoffset = object[i].x*ww/100 || object[i].xp || 0;
var w = object[i].w*ww/100; var w = object[i].w*ww/100 || object[i].wp || 0;
var h = object[i].h*hh/100; var h = object[i].h*hh/100 || object[i].hp || 0;
container.style = "z-index:"+container.zIndex+";left:"+xoffset+"px;top:"+yoffset+"px;width:"+w+"px;height:"+h+"px;background-color:"+color+";"; container.style = "z-index:"+container.zIndex+";left:"+xoffset+"px;top:"+yoffset+"px;width:"+w+"px;height:"+h+"px;background-color:"+color+";";
var h3 = document.createElement("h3"); var h3 = document.createElement("h3");
h3.className = "ui-widget-header"; h3.className = "ui-widget-header";
h3.innerHTML = "drag/resize me"; h3.innerHTML = "drag/resize me";
h3.title = "Drag with your mouse to move. Tip: Hold CTRL (cmd) to disable grid snapping";
container.appendChild(h3); container.appendChild(h3);
var button = document.createElement("button"); var button = document.createElement("button");
@ -2741,6 +2946,7 @@
var h3 = document.createElement("h3"); var h3 = document.createElement("h3");
h3.className = "ui-widget-header"; h3.className = "ui-widget-header";
h3.innerHTML = "drag/resize me"; h3.innerHTML = "drag/resize me";
h3.title = "Drag with your mouse to move. Tip: Hold CTRL (cmd) to disable grid snapping";
container.appendChild(h3); container.appendChild(h3);
var button = document.createElement("button"); var button = document.createElement("button");
@ -2803,10 +3009,8 @@
function combinedLayout(layout){ function combinedLayout(layout){
var combined = {}; var combined = {};
console.log(layout);
for (var i=0;i<layout.length;i++){ for (var i=0;i<layout.length;i++){
console.log(i);
if (!layout[i]){continue;} if (!layout[i]){continue;}
if (!("slot" in layout[i])){ if (!("slot" in layout[i])){
continue; continue;
@ -2817,7 +3021,6 @@
errorlog(e); errorlog(e);
continue; continue;
} }
console.log(stream);
if (!stream){ if (!stream){
if (layout[i].defaultStreamID){ if (layout[i].defaultStreamID){
combined[layout[i].defaultStreamID] = layout[i]; combined[layout[i].defaultStreamID] = layout[i];
@ -2826,15 +3029,13 @@
} }
combined[stream] = layout[i]; combined[stream] = layout[i];
} }
console.log(combined); log(combined);
return combined; return combined;
} }
function remoteActivate(event=null, layout=null){ function remoteActivate(event=null, layout=null){
console.log(this);
console.log(event); if (event.target && event.target.layout && layout===null){
console.log(layout);
if (event.target && layout===null){
layout = event.target.layout; layout = event.target.layout;
var layoutButtons = document.querySelectorAll(".pressed"); var layoutButtons = document.querySelectorAll(".pressed");
for (var i = 0;i<layoutButtons.length;i++){ for (var i = 0;i<layoutButtons.length;i++){
@ -2855,7 +3056,14 @@
currentLayout = combined; // global current state currentLayout = combined; // global current state
lastLayout = {"scene":"0", "layout":combined}; lastLayout = {"scene":"0", "layout":combined};
iframe.contentWindow.postMessage({"scene":"0", "layout":combined}, '*'); if (event.target && event.target.obsSceneName && syncOBS){
var obsCommand = {"action": "setCurrentScene", "value": event.target.obsSceneName};
log({"scene":"0", "layout":combined, "obsCommand": obsCommand});
iframe.contentWindow.postMessage({"scene":"0", "layout":combined, "obsCommand": obsCommand}, '*');
} else {
log({"scene":"0", "layout":combined});
iframe.contentWindow.postMessage({"scene":"0", "layout":combined}, '*');
}
} }
function deleteElement(event){ function deleteElement(event){
@ -3037,13 +3245,20 @@
var eles = document.querySelectorAll(".widget"); var eles = document.querySelectorAll(".widget");
for (var i=0;i<eles.length;i++){ for (var i=0;i<eles.length;i++){
console.log(eles);
var compute = window.getComputedStyle(eles[i]); var compute = window.getComputedStyle(eles[i]);
var ele = {}; var ele = {};
ele.w = parseFloat(compute.width)/ww*100;
ele.h = parseFloat(compute.height)/hh*100; if (absolutePixel){
ele.x = parseFloat(compute.left)/ww*100; ele.wp = parseFloat(compute.width);
ele.y = parseFloat(compute.top)/hh*100; ele.hp = parseFloat(compute.height);
ele.xp = parseFloat(compute.left);
ele.yp = parseFloat(compute.top);
} else {
ele.w = parseFloat(compute.width)/ww*100;
ele.h = parseFloat(compute.height)/hh*100;
ele.x = parseFloat(compute.left)/ww*100;
ele.y = parseFloat(compute.top)/hh*100;
}
try { try {
ele.z = parseInt(eles[i].zIndex) || 0; ele.z = parseInt(eles[i].zIndex) || 0;
@ -3075,21 +3290,42 @@
prompt("Layout as URL-encoded JSON. StreamIDs are based on current and default values.", encodeURIComponent(JSON.stringify(combined))); prompt("Layout as URL-encoded JSON. StreamIDs are based on current and default values.", encodeURIComponent(JSON.stringify(combined)));
} }
function setobsSceneName(){
var obsSceneName = document.getElementById("canvas").obsSceneName || "";
var input = prompt("Enter the OBS scene you want to trigger", obsSceneName);
if (input !==null){
document.getElementById("canvas").obsSceneName = input;
}
}
function saveScene(makenew=false, event=null){ function saveScene(makenew=false, event=null){
var scene = []; var scene = [];
var hh = parseInt(document.getElementById("canvas").style.height); var compute = window.getComputedStyle(document.getElementById("canvas"));
var ww = parseInt(document.getElementById("canvas").style.width);
var hh = parseInt(compute.height);
var ww = parseInt(compute.width);
var eles = document.querySelectorAll(".widget"); var eles = document.querySelectorAll(".widget");
for (var i=0;i<eles.length;i++){ for (var i=0;i<eles.length;i++){
console.log(eles);
var compute = window.getComputedStyle(eles[i]);
var ele = {}; var ele = {};
ele.w = parseFloat(eles[i].style.width)/ww*100;
ele.h = parseFloat(eles[i].style.height)/hh*100; if (absolutePixel){
ele.x = parseFloat(eles[i].style.left)/ww*100; ele.wp = parseFloat(eles[i].style.width) || 0;
ele.y = parseFloat(eles[i].style.top)/hh*100; ele.hp = parseFloat(eles[i].style.height) || 0;
ele.xp = parseFloat(eles[i].style.left) || 0;
ele.yp = parseFloat(eles[i].style.top) || 0;
} else {
ele.w = parseFloat(eles[i].style.width)/ww*100 || 0;
ele.h = parseFloat(eles[i].style.height)/hh*100 || 0;
ele.x = parseFloat(eles[i].style.left)/ww*100 || 0;
ele.y = parseFloat(eles[i].style.top)/hh*100 || 0;
}
//ele.w = parseFloat(eles[i].style.width)/ww*100;
//ele.h = parseFloat(eles[i].style.height)/hh*100;
//ele.x = parseFloat(eles[i].style.left)/ww*100;
//ele.y = parseFloat(eles[i].style.top)/hh*100;
try { try {
if ("slot" in eles[i]){ if ("slot" in eles[i]){
@ -3112,15 +3348,14 @@
ele.rounded = parseInt(eles[i].rounded) || 0; ele.rounded = parseInt(eles[i].rounded) || 0;
ele.muted = eles[i].muted || false; ele.muted = eles[i].muted || false;
} catch(e){errorlog(e);} } catch(e){errorlog(e);}
scene.push(ele); scene.push(ele);
//scene[sid] = ele; //scene[sid] = ele;
} }
console.log(scene); console.log(scene);
var sceneName = document.getElementById("canvas").sceneName || parseInt(Math.random()*1000000);
console.log("'sceneName: "+sceneName);
if (makenew){ if (makenew){
var canvasContainer = drawLayout(scene, false); var canvasContainer = drawLayout(scene);
popupMessage(event, "Saved as a new scene"); popupMessage(event, "Saved as a new scene");
document.querySelectorAll(".editButton").forEach(ele=>{ document.querySelectorAll(".editButton").forEach(ele=>{
@ -3134,7 +3369,10 @@
} catch(e){} } catch(e){}
} else { } else {
drawLayout(scene, sceneName); var sceneName = document.getElementById("canvas").sceneName || parseInt(Math.random()*1000000000);
var obsSceneName = document.getElementById("canvas").obsSceneName || "";
console.log("'sceneName: "+sceneName);
drawLayout(scene, sceneName, obsSceneName);
popupMessage(event, "Scene saved"); popupMessage(event, "Scene saved");
} }
@ -3166,12 +3404,22 @@
savedSession.settings.assignSlotToGuest = assignSlotToGuest; savedSession.settings.assignSlotToGuest = assignSlotToGuest;
savedSession.settings.toggleLabel = toggleLabel; savedSession.settings.toggleLabel = toggleLabel;
savedSession.settings.toggleBroadcast = toggleBroadcast; savedSession.settings.toggleBroadcast = toggleBroadcast;
savedSession.settings.syncOBS = syncOBS;
savedSession.settings.aspectRatio = aspectRatio;
savedSession.settings.pixelDensity = pixelDensity;
savedSession.settings.absolutePixel = absolutePixel;
savedSession.settings.advancedMode = advancedMode;
savedSession.version = 1; savedSession.version = 1;
savedSession.obsScenes = [];
for (var i=0;i<layouts.length;i++){ for (var i=0;i<layouts.length;i++){
if (!layouts[i].layout){continue;} if (!layouts[i].layout){continue;}
try { try {
savedSession.layouts.push(JSON.parse(layouts[i].layout)); savedSession.layouts.push(JSON.parse(layouts[i].layout));
var obs = layouts[i].obsSceneName || false;
savedSession.obsScenes.push(obs);
} catch(e){ } catch(e){
errorlog(e); errorlog(e);
} }
@ -3181,7 +3429,7 @@
if (iframe){ if (iframe){
iframe.contentWindow.postMessage({ layouts: savedSession.layouts }, "*"); iframe.contentWindow.postMessage({ layouts: savedSession.layouts }, "*");
} }
console.log(getStorage("savedSession")); log(getStorage("savedSession"));
} }
function changeAspectRatio(ar, button){ function changeAspectRatio(ar, button){
@ -3191,9 +3439,43 @@
ele.value = false; ele.value = false;
}); });
aspectRatio = ar; aspectRatio = ar;
saveSession();
document.documentElement.style.setProperty('--aspect-ratio', ar); document.documentElement.style.setProperty('--aspect-ratio', ar);
} }
function changeAbsolutePosition(value, button){
document.querySelectorAll(".absolutePosition").forEach(ele=>{
if (ele == button){return;}
ele.checked = false;
ele.value = false;
});
absolutePixel = value;
saveSession();
updateLayouts();
}
function changePixelDensity(pd, button){
document.querySelectorAll(".pixeldensity").forEach(ele=>{
if (ele == button){return;}
ele.checked = false;
ele.value = false;
});
pixelDensity = pd;
saveSession();
var hh = pixelDensity;
var ww = parseInt((pixelDensity*16/9) * (aspectRatio/(16/9)));
document.documentElement.style.setProperty('--aspect-ratio', aspectRatio);
document.documentElement.style.setProperty('--iframe-width', ww+"px");
document.documentElement.style.setProperty('--iframe-height', hh+"px");
updateLayouts();
//document.getElementById('canvas').style.width = ww+"px";
//document.getElementById('canvas').style.height = hh+"px";
}
//let modal = document.querySelector("#modal"); //let modal = document.querySelector("#modal");
document.querySelectorAll(".close-btn").forEach(ele2=>{ document.querySelectorAll(".close-btn").forEach(ele2=>{
ele2.onclick = function(){ ele2.onclick = function(){