v1.4.3 - persistent device ID via localStorage so refresh reuses same client slot
This commit is contained in:
+9
-17
@@ -9,30 +9,22 @@ services:
|
||||
- "3030:3000"
|
||||
environment:
|
||||
# REQUIRED
|
||||
- IMMICH_URL=http://your-immich-server:2283
|
||||
- IMMICH_API_KEY=your-api-key-here
|
||||
- IMMICH_URL=http://10.0.0.40:2283
|
||||
- IMMICH_API_KEY=aQAm76nwCi5I68vFWz18irMmnyrzI5yzcb74rXvt4
|
||||
- ADMIN_USERNAME=jessikitty
|
||||
- ADMIN_PASSWORD=23Pinkpr!ncesses
|
||||
- FRAMBE_API_TOKEN=whosethatgirl-itsjess
|
||||
|
||||
# Slideshow
|
||||
- SLIDESHOW_INTERVAL=30
|
||||
- TRANSITION_DURATION=2
|
||||
- SLIDESHOW_INTERVAL=300
|
||||
- TRANSITION_DURATION=5
|
||||
- IMAGE_FIT=contain
|
||||
- SHUFFLE=true
|
||||
- BACKGROUND_BLUR=true
|
||||
- REFRESH_INTERVAL=300 # Seconds between album/person refresh checks
|
||||
- REFRESH_INTERVAL=300 # Seconds between album/person refresh checks
|
||||
|
||||
# Overlays
|
||||
- SHOW_CLOCK=true
|
||||
- SHOW_DATE=true
|
||||
- SHOW_EXIF=true
|
||||
- SHOW_EXIF=false
|
||||
- SHOW_PROGRESS=true
|
||||
|
||||
# Admin Authentication (leave ADMIN_PASSWORD blank to disable login)
|
||||
- ADMIN_USERNAME=admin
|
||||
# - ADMIN_PASSWORD=changeme
|
||||
|
||||
# API Token for external access (Home Assistant, scripts, etc.)
|
||||
# - FRAMBE_API_TOKEN=your-secret-token-here
|
||||
|
||||
# Auto-start (optional — or use URL params instead)
|
||||
# - ALBUM_ID=
|
||||
# - SHOW_FAVORITES_ONLY=false
|
||||
|
||||
+2
-1
@@ -7,10 +7,11 @@
|
||||
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 $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',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 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 getCurrentConfig(){return{slideshowInterval:config.slideshowInterval,showClock:config.showClock,showDate:config.showDate,showExif:config.showExif,showProgress:config.showProgress};}
|
||||
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;}}
|
||||
|
||||
@@ -90,8 +90,14 @@ wss.on('connection', (ws, req) => {
|
||||
log('WS admin: ' + ip);
|
||||
ws.send(JSON.stringify({ type: 'clientList', clients: getClientList() }));
|
||||
} else {
|
||||
clients.set(id, { id, ws, name:'', ip, userAgent:ua, connectedAt:now, firstSeen:now, lastSeen:Date.now(), status:msg.status||'idle', config:msg.config||{}, source:msg.source||null });
|
||||
log('WS frame: ' + id + ' (' + ip + ')');
|
||||
const pid = msg.persistentId || null;
|
||||
const existing = pid ? Array.from(clients.values()).find(c => c.persistentId === pid) : null;
|
||||
const effectiveId = existing ? existing.id : id;
|
||||
const firstName = existing ? existing.name : '';
|
||||
const firstSeen = existing ? existing.firstSeen : now;
|
||||
if (existing) { clients.delete(Array.from(clients.entries()).find(([,c]) => c.persistentId === pid)?.[0]); }
|
||||
clients.set(effectiveId, { id:effectiveId, persistentId:pid, ws, name:firstName, ip, userAgent:ua, connectedAt:now, firstSeen, lastSeen:Date.now(), status:msg.status||'idle', config:msg.config||{}, source:msg.source||null });
|
||||
log('WS frame: ' + effectiveId + (pid?' [persistent]':'') + ' (' + ip + ')');
|
||||
broadcastAdminClients();
|
||||
}
|
||||
} else if (msg.type === 'ping') {
|
||||
|
||||
Reference in New Issue
Block a user