@@ -26,12 +26,14 @@ import { getMultiContextPrintStateMonitor } from './services/MultiContextPrintSt
2626import { getMultiContextSpoolmanTracker } from './services/MultiContextSpoolmanTracker' ;
2727import { getMultiContextTemperatureMonitor } from './services/MultiContextTemperatureMonitor' ;
2828import { getSavedPrinterService } from './services/SavedPrinterService' ;
29+ import { resolveAndEnsureCameraStream } from './services/CameraStreamCoordinator' ;
2930import { initializeSpoolmanIntegrationService } from './services/SpoolmanIntegrationService' ;
3031import type { PollingData } from './types/polling' ;
3132import type { PrinterClientType , PrinterDetails } from './types/printer' ;
32- import { getCameraUserConfig , resolveCameraConfig } from './utils/camera-utils' ;
33+ import { getCameraUserConfig } from './utils/camera-utils' ;
3334import type { HeadlessConfig , PrinterSpec } from './utils/HeadlessArguments' ;
3435import { parseHeadlessArguments , validateHeadlessConfig } from './utils/HeadlessArguments' ;
36+ import { applyPerPrinterDefaults } from './utils/printerSettingsDefaults' ;
3537import { createHardDeadline } from './utils/ShutdownTimeout' ;
3638import { initializeDataDirectory } from './utils/setup' ;
3739import { getWebUIManager } from './webui/server/WebUIManager' ;
@@ -104,7 +106,7 @@ async function connectLastUsed(): Promise<string[]> {
104106 ) ;
105107
106108 // Convert StoredPrinterDetails to PrinterDetails
107- const printerDetails : PrinterDetails = {
109+ const printerDetails : PrinterDetails = applyPerPrinterDefaults ( {
108110 Name : lastUsedPrinter . Name ,
109111 IPAddress : lastUsedPrinter . IPAddress ,
110112 SerialNumber : lastUsedPrinter . SerialNumber ,
@@ -116,7 +118,7 @@ async function connectLastUsed(): Promise<string[]> {
116118 customCameraUrl : lastUsedPrinter . customCameraUrl ,
117119 customLedsEnabled : lastUsedPrinter . customLedsEnabled ,
118120 forceLegacyMode : lastUsedPrinter . forceLegacyMode ,
119- } ;
121+ } ) ;
120122
121123 const results = await connectionManager . connectHeadlessFromSaved ( [ printerDetails ] ) ;
122124
@@ -137,7 +139,7 @@ async function connectAllSaved(): Promise<string[]> {
137139 console . log ( `[Connection] Connecting to ${ savedPrinters . length } saved printer(s)...` ) ;
138140
139141 // Convert StoredPrinterDetails to PrinterDetails
140- const printerDetailsList : PrinterDetails [ ] = savedPrinters . map ( ( saved ) => ( {
142+ const printerDetailsList : PrinterDetails [ ] = savedPrinters . map ( ( saved ) => applyPerPrinterDefaults ( {
141143 Name : saved . Name ,
142144 IPAddress : saved . IPAddress ,
143145 SerialNumber : saved . SerialNumber ,
@@ -261,45 +263,24 @@ async function reconcileCameraStream(contextId: string): Promise<void> {
261263 return ;
262264 }
263265
264- const features = backendManager . getFeatures ( contextId ) ;
265- if ( ! features ) {
266+ const backend = backendManager . getBackendForContext ( contextId ) ;
267+ if ( ! backend ) {
266268 await go2rtcService . removeStream ( contextId ) ;
267269 return ;
268270 }
269271
270- const cameraConfig = resolveCameraConfig ( {
272+ const ensuredStream = await resolveAndEnsureCameraStream ( {
273+ contextId,
271274 printerIpAddress : context . printerDetails . IPAddress ,
272- printerFeatures : features ,
275+ printerFeatures : backend . getBackendStatus ( ) . features ,
273276 userConfig : getCameraUserConfig ( contextId ) ,
277+ go2rtcService,
274278 } ) ;
275279
276- if (
277- ! cameraConfig . isAvailable ||
278- ! cameraConfig . streamUrl ||
279- ! cameraConfig . streamType ||
280- ( cameraConfig . sourceType !== 'builtin' && cameraConfig . sourceType !== 'custom' )
281- ) {
282- await go2rtcService . removeStream ( contextId ) ;
280+ if ( ! ensuredStream ) {
283281 return ;
284282 }
285283
286- if (
287- go2rtcService . hasMatchingStream (
288- contextId ,
289- cameraConfig . streamUrl ,
290- cameraConfig . sourceType ,
291- cameraConfig . streamType
292- )
293- ) {
294- return ;
295- }
296-
297- await go2rtcService . addStream (
298- contextId ,
299- cameraConfig . streamUrl ,
300- cameraConfig . sourceType ,
301- cameraConfig . streamType
302- ) ;
303284 console . log ( `[Camera] Stream ready for context: ${ contextId } ` ) ;
304285 } catch ( error ) {
305286 console . error ( `[Camera] Failed to reconcile stream for context ${ contextId } :` , error ) ;
@@ -581,6 +562,21 @@ async function main(): Promise<void> {
581562 } ) ;
582563 console . log ( '[Events] Context-updated hook configured' ) ;
583564
565+ connectionManager . on ( 'feature-updated' , ( event : { contextId ?: string ; changedKeys ?: readonly string [ ] } ) => {
566+ const contextId = event . contextId ;
567+ if ( ! contextId ) {
568+ return ;
569+ }
570+
571+ const changedKeys = event . changedKeys || [ ] ;
572+ if ( ! changedKeys . includes ( 'oemCameraStreamUrl' ) ) {
573+ return ;
574+ }
575+
576+ void reconcileCameraStream ( contextId ) ;
577+ } ) ;
578+ console . log ( '[Events] Feature-updated hook configured' ) ;
579+
584580 connectionManager . on ( 'pre-disconnect' , ( contextId : string ) => {
585581 void go2rtcService . removeStream ( contextId ) ;
586582 } ) ;
0 commit comments