v1.5.0 - client: server-controlled defaults, persistent ID, hello/welcome fix, sleep handling
This commit is contained in:
+30
-6
@@ -1,4 +1,4 @@
|
||||
// === Frambe v1.4.1 - Client with WebSocket Remote Control ===
|
||||
// === Frambe v1.5.0 - Client with WebSocket Remote Control + Server-Controlled Defaults ===
|
||||
(function () {
|
||||
'use strict';
|
||||
var config = {}, assets = [], currentIndex = -1, slideshowTimer = null;
|
||||
@@ -6,15 +6,39 @@
|
||||
var selectedPersonId = null, isRunning = false, refreshTimer = null, urlDriven = false;
|
||||
var currentVideoPlaying = false, pileCanvas, pileCtx;
|
||||
var FRAME_PAD_RATIO = 0.03, FRAME_BOTTOM_RATIO = 0.10, FRAME_COLOR = '#ede8df';
|
||||
var wsConn = null, clientId = null, isSleeping = false;
|
||||
var persistentId = (function(){ var k='frambe_pid'; var v=localStorage.getItem(k); if(vi docker-compose.yml ){ v='fp-'+Math.random().toString(36).substr(2,9)+'-'+Date.now().toString(36); localStorage.setItem(k,v); } return v; })();
|
||||
var persistentId = (function(){ var k='frambe_pid'; var v=localStorage.getItem(k); if(vi docker-compose.yml ){ v='fp-'+Math.random().toString(36).substr(2,9)+'-'+Date.now().toString(36); localStorage.setItem(k,v); } return v; })();
|
||||
var wsConn = null, clientId = null, isSleeping = false, serverControlled = true;
|
||||
var persistentId = (function(){ var k='frambe_pid'; var v=localStorage.getItem(k); if(!v){ v='fp-'+Math.random().toString(36).substr(2,9)+'-'+Date.now().toString(36); localStorage.setItem(k,v); } return v; })();
|
||||
var $setupScreen=document.getElementById('setup-screen'),$slideshowScreen=document.getElementById('slideshow-screen'),$connectionStatus=document.getElementById('connection-status'),$setupContent=document.getElementById('setup-content'),$setupError=document.getElementById('setup-error'),$errorDetail=document.getElementById('error-detail'),$albumsList=document.getElementById('albums-list'),$btnStart=document.getElementById('btn-start'),$bgBlur=document.getElementById('bg-blur'),$mainFrame=document.getElementById('main-frame'),$mainPhoto=document.getElementById('main-photo'),$mainVideo=document.getElementById('main-video'),$clock=document.getElementById('clock'),$dateDisplay=document.getElementById('date-display'),$exifInfo=document.getElementById('exif-info'),$progressFill=document.getElementById('progress-fill'),$overlay=document.getElementById('overlay'),$btnSettings=document.getElementById('btn-settings'),$progressBar=document.getElementById('progress-bar');
|
||||
|
||||
// === WEBSOCKET ===
|
||||
function connectWebSocket(){var proto=location.protocol==='https:'?'wss:':'ws:';wsConn=new WebSocket(proto+'//'+location.host+'/ws');wsConn.onopen=function(){console.log('[Frambe] WebSocket connected');wsConn.send(JSON.stringify({type:'register',role:'frame',persistentId:persistentId,status:isRunning?'playing':(isSleeping?'sleeping':'idle'),config:getCurrentConfig()}));};wsConn.onmessage=function(e){try{var msg=JSON.parse(e.data);if(msg.type==='welcome'){clientId=msg.clientId;console.log('[Frambe] Registered as '+clientId);}else if(msg.type==='command'){handleRemoteCommand(msg.action,msg.payload||{});}}catch(err){}};wsConn.onclose=function(){setTimeout(connectWebSocket,5000);};}
|
||||
function sendStatus(s){if(wsConn&&wsConn.readyState===WebSocket.OPEN)wsConn.send(JSON.stringify({type:'status',status:s,currentAlbum:selectedAlbumId,config:getCurrentConfig()}));}
|
||||
function connectWebSocket(){var proto=location.protocol==='https:'?'wss:':'ws:';wsConn=new WebSocket(proto+'//'+location.host+'/ws');wsConn.onopen=function(){console.log('[Frambe] WebSocket connected');wsConn.send(JSON.stringify({type:'register',role:'frame',persistentId:persistentId,status:isRunning?'playing':(isSleeping?'sleeping':'idle'),config:getCurrentConfig(),source:currentSourceDescriptor()}));};wsConn.onmessage=function(e){try{var msg=JSON.parse(e.data);if(msg.type==='hello'||msg.type==='welcome'){clientId=msg.clientId;console.log('[Frambe] Registered as '+clientId);}else if(msg.type==='command'){handleRemoteCommand(msg.action,msg.payload||{});}else if(msg.type==='serverConfig'){applyServerConfig(msg.config||{});}}catch(err){}};wsConn.onclose=function(){setTimeout(connectWebSocket,5000);};}
|
||||
function sendStatus(s){if(wsConn&&wsConn.readyState===WebSocket.OPEN)wsConn.send(JSON.stringify({type:'status',status:s,currentAlbum:selectedAlbumId,config:getCurrentConfig(),source:currentSourceDescriptor()}));}
|
||||
function getCurrentConfig(){return{slideshowInterval:config.slideshowInterval,showClock:config.showClock,showDate:config.showDate,showExif:config.showExif,showProgress:config.showProgress};}
|
||||
function currentSourceDescriptor(){if(!selectedSource)return null;return{source:selectedSource,albumId:selectedAlbumId||null,personId:selectedPersonId||null};}
|
||||
|
||||
// === SERVER-CONTROLLED DEFAULTS ===
|
||||
// The server pushes a resolved config (default source, timers, display toggles, sleep
|
||||
// schedule) for clients that haven't been manually overridden. Applying it here makes
|
||||
// a freshly opened frame inherit the global settings without any local setup.
|
||||
function applyServerConfig(sc){
|
||||
console.log('[Frambe] Server config received');
|
||||
// Display + timer defaults
|
||||
if('slideshowInterval'in sc)config.slideshowInterval=sc.slideshowInterval;
|
||||
if('showClock'in sc)config.showClock=sc.showClock;
|
||||
if('showDate'in sc)config.showDate=sc.showDate;
|
||||
if('showExif'in sc)config.showExif=sc.showExif;
|
||||
if('showProgress'in sc)config.showProgress=sc.showProgress;
|
||||
if(isRunning)applyConfigChange({slideshowInterval:config.slideshowInterval,showClock:config.showClock,showDate:config.showDate,showExif:config.showExif,showProgress:config.showProgress});
|
||||
// Sleep schedule state — if the server says we are inside the sleep window, honour it.
|
||||
if(sc.sleep){if(sc.sleep.sleeping&&!isSleeping)goToSleep();else if(sc.sleep.sleeping===false&&isSleeping)wakeUp();}
|
||||
// Default photo source — only auto-start if nothing is playing yet and no URL/local choice was made.
|
||||
if(sc.source&&sc.source.source&&!isRunning&&!urlDriven&&!selectedSource){
|
||||
selectedSource=sc.source.source;selectedAlbumId=sc.source.albumId||null;selectedPersonId=sc.source.personId||null;
|
||||
console.log('[Frambe] Auto-start from server default: '+selectedSource);
|
||||
if(!(sc.sleep&&sc.sleep.sleeping))doStartSlideshow();
|
||||
}
|
||||
}
|
||||
|
||||
function handleRemoteCommand(action,payload){console.log('[Frambe] Remote: '+action);switch(action){case'setSource':selectedSource=payload.source;selectedAlbumId=payload.albumId||null;selectedPersonId=payload.personId||null;if(isSleeping)wakeUp();if(isRunning){clearTimeout(slideshowTimer);stopVideo();}doStartSlideshow();break;case'start':if(isSleeping)wakeUp();if(!isRunning&&selectedSource)doStartSlideshow();break;case'stop':if(isRunning)exitSlideshowInternal();sendStatus('idle');break;case'next':if(isRunning)showNextAsset();break;case'prev':if(isRunning)showPrevAsset();break;case'sleep':goToSleep();break;case'wake':wakeUp();break;case'refresh':location.reload();break;case'setConfig':applyConfigChange(payload);break;}}
|
||||
function goToSleep(){isSleeping=true;document.body.style.background='#000';if($slideshowScreen)$slideshowScreen.style.display='none';if($setupScreen)$setupScreen.style.display='none';var s=document.getElementById('sleep-overlay');if(!s){s=document.createElement('div');s.id='sleep-overlay';s.style.cssText='position:fixed;top:0;left:0;width:100%;height:100%;background:#000;z-index:9999;';document.body.appendChild(s);}s.style.display='block';if(isRunning){clearTimeout(slideshowTimer);stopVideo();}sendStatus('sleeping');}
|
||||
function wakeUp(){isSleeping=false;document.body.style.background='';var s=document.getElementById('sleep-overlay');if(s)s.style.display='none';if(isRunning)$slideshowScreen.style.display='block';else $setupScreen.style.display='flex';sendStatus(isRunning?'playing':'idle');}
|
||||
|
||||
Reference in New Issue
Block a user