@@ -132,6 +132,7 @@ $(document).ready(function () {
132132 if ( prios . length === 0 ) {
133133 $ ( '.sstbody' ) . append ( `<tr><td colspan="4" class="text-center text-muted">${ $ . i18n ( 'remote_input_no_sources' ) } </td></tr>` ) ;
134134 $ ( '#auto_btn' ) . empty ( ) ;
135+ appendStartupCheckbox ( ) ;
135136 return ;
136137 }
137138
@@ -243,6 +244,45 @@ $(document).ready(function () {
243244 if ( $ ( this ) . innerWidth ( ) > maxWidth ) maxWidth = $ ( this ) . innerWidth ( ) ;
244245 } ) ;
245246 $ ( '.btn_input_selection' ) . css ( "min-width" , maxWidth + "px" ) ;
247+
248+ appendStartupCheckbox ( ) ;
249+ }
250+
251+ function appendStartupCheckbox ( ) {
252+ if ( $ ( "#save_startup_source_btn" ) . length ) return ;
253+ $ ( '#auto_btn' ) . after (
254+ '<div id="save_startup_source_wrap" style="margin-top:12px; clear:both;">' +
255+ '<button id="save_startup_source_btn" type="button" class="btn btn-default btn-sm" style="width:100%;">' +
256+ '<span id="save_startup_source_icon" class="glyphicon glyphicon-unchecked" style="margin-right:6px;"></span>' +
257+ '<span id="save_startup_source_label">Use active source as startup source</span>' +
258+ '</button>' +
259+ '</div>'
260+ ) ;
261+ $ ( "#save_startup_source_btn" ) . on ( "click" , function ( ) {
262+ if ( $ ( this ) . hasClass ( "btn-success" ) ) {
263+ sendToHyperion ( "startupsource" , "set" , { data : { } } ) ;
264+ $ ( this ) . removeClass ( "btn-success" ) . addClass ( "btn-default" ) ;
265+ $ ( "#save_startup_source_icon" ) . removeClass ( "glyphicon-check" ) . addClass ( "glyphicon-unchecked" ) ;
266+ $ ( "#save_startup_source_label" ) . text ( "Use active source as startup source" ) ;
267+ } else {
268+ saveStartupSource ( ) ;
269+ }
270+ } ) ;
271+ applyStartupSource ( ) ;
272+ }
273+
274+ function setStartupSourceBtnActive ( active ) {
275+ if ( $ ( "#save_startup_source_btn" ) . length ) {
276+ if ( active ) {
277+ $ ( "#save_startup_source_btn" ) . removeClass ( "btn-default" ) . addClass ( "btn-success" ) ;
278+ $ ( "#save_startup_source_icon" ) . removeClass ( "glyphicon-unchecked" ) . addClass ( "glyphicon-check" ) ;
279+ $ ( "#save_startup_source_label" ) . text ( "Disable custom source as startup" ) ;
280+ } else {
281+ $ ( "#save_startup_source_btn" ) . removeClass ( "btn-success" ) . addClass ( "btn-default" ) ;
282+ $ ( "#save_startup_source_icon" ) . removeClass ( "glyphicon-check" ) . addClass ( "glyphicon-unchecked" ) ;
283+ $ ( "#save_startup_source_label" ) . text ( "Use active source as startup source" ) ;
284+ }
285+ }
246286 }
247287
248288
@@ -414,6 +454,44 @@ $(document).ready(function () {
414454 setupEventListeners ( ) ;
415455 }
416456
457+ // Save current source as startup source
458+ function saveStartupSource ( ) {
459+ const prios = window . serverInfo . priorities ;
460+ const active = prios . find ( p => p . active && [ "COLOR" , "EFFECT" , "IMAGE" ] . includes ( p . componentId ) ) ;
461+ if ( ! active ) {
462+ sendToHyperion ( "startupsource" , "set" , { data : { } } ) ;
463+ setStartupSourceBtnActive ( false ) ;
464+ return ;
465+ }
466+ const src = {
467+ componentId : active . componentId ,
468+ duration_ms : active . duration_ms || 0
469+ } ;
470+ if ( active . componentId === "COLOR" ) {
471+ src . color = active . value . RGB ;
472+ } else if ( active . componentId === "EFFECT" ) {
473+ src . effectName = active . owner ;
474+ } else if ( active . componentId === "IMAGE" ) {
475+ src . imageData = lastImgData ;
476+ src . imageName = lastFileName ;
477+ }
478+ sendToHyperion ( "startupsource" , "set" , { data : src } ) ;
479+ setStartupSourceBtnActive ( true ) ;
480+ }
481+
482+ // Query server for startup source state
483+ function applyStartupSource ( ) {
484+ sendToHyperion ( "startupsource" , "get" , { } ) ;
485+ $ ( window . hyperion ) . one ( "cmd-startupsource" , function ( event ) {
486+ const data = event . response . info ;
487+ if ( data && ! $ . isEmptyObject ( data ) ) {
488+ setStartupSourceBtnActive ( true ) ;
489+ } else {
490+ setStartupSourceBtnActive ( false ) ;
491+ }
492+ } ) ;
493+ }
494+
417495 // Setup Event Listeners for Controls
418496 function setupEventListeners ( ) {
419497 $ ( "#reset_color" ) . off ( ) . on ( "click" , resetColor ) ;
@@ -491,15 +569,32 @@ $(document).ready(function () {
491569 }
492570
493571 // Interval Updates and Event Handlers
572+ let startupApplied = false ;
573+
494574 function setupEventListenersForUpdates ( ) {
495575 $ ( window . hyperion ) . on ( 'components-updated' , ( e , comp ) => updateComponent ( comp ) ) ;
496576
577+ // Must register cmd-priorities-update BEFORE forceFirstUpdate() sends serverinfo
497578 $ ( window . hyperion ) . on ( "cmd-priorities-update" , ( event ) => {
498579 window . serverInfo . priorities = event . response . data . priorities ;
499580 window . serverInfo . priorities_autoselect = event . response . data . priorities_autoselect ;
500581 updateInputSelect ( ) ;
582+ if ( ! startupApplied && getStorage ( 'startupSource' ) ) {
583+ startupApplied = true ;
584+ applyStartupSource ( ) ;
585+ }
586+ } ) ;
587+
588+ // Reset flag on reconnect so apply re-runs
589+ $ ( window . hyperion ) . on ( "open" , function ( ) {
590+ startupApplied = false ;
501591 } ) ;
502592
593+ // If ws already open when listeners are set up, allow apply
594+ if ( globalThis . websocket && globalThis . websocket . readyState === WebSocket . OPEN ) {
595+ startupApplied = false ;
596+ }
597+
503598 $ ( window . hyperion ) . on ( "cmd-imageToLedMapping-update" , ( event ) => {
504599 window . serverInfo . imageToLedMappingType = event . response . data . imageToLedMappingType ;
505600 updateLedMapping ( ) ;
@@ -530,8 +625,11 @@ $(document).ready(function () {
530625 // Initialize everything
531626 function init ( ) {
532627 initColorPickerAndEffects ( ) ;
533- forceFirstUpdate ( ) ;
534628 setupEventListenersForUpdates ( ) ;
629+ forceFirstUpdate ( ) ;
630+
631+ // Query server for startup source state
632+ setTimeout ( function ( ) { applyStartupSource ( ) ; } , 500 ) ;
535633 }
536634
537635 init ( ) ;
0 commit comments