dashcam 1.3.28 → 1.3.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,7 +14,6 @@ import os from 'os';
14
14
  const PROCESS_DIR = path.join(os.homedir(), '.dashcam-cli');
15
15
  const STATUS_FILE = path.join(PROCESS_DIR, 'status.json');
16
16
  const RESULT_FILE = path.join(PROCESS_DIR, 'recording-result.json');
17
- const STOP_REQUEST_FILE = path.join(PROCESS_DIR, 'stop-request.txt');
18
17
 
19
18
  console.log('[Background INIT] Process directory:', PROCESS_DIR);
20
19
  console.log('[Background INIT] Status file:', STATUS_FILE);
@@ -218,26 +217,10 @@ async function runBackgroundRecording() {
218
217
  process.on('SIGINT', () => handleShutdown('SIGINT'));
219
218
  process.on('SIGTERM', () => handleShutdown('SIGTERM'));
220
219
 
221
- // Keep the process alive - wait indefinitely for signals
222
- // Also poll for stop request file (for Windows compatibility)
220
+ // Keep the process alive - wait indefinitely for SIGKILL from stop command
223
221
  logger.info('Background recording is now running. Waiting for stop signal...');
224
222
  console.log('[Background] Waiting for stop signal...');
225
223
 
226
- // Poll for stop request file every 500ms (Windows SIGTERM workaround)
227
- const pollInterval = setInterval(() => {
228
- if (fs.existsSync(STOP_REQUEST_FILE)) {
229
- console.log('[Background] Stop request file detected');
230
- clearInterval(pollInterval);
231
- // Delete the stop request file
232
- try {
233
- fs.unlinkSync(STOP_REQUEST_FILE);
234
- } catch (e) {
235
- // Ignore deletion errors
236
- }
237
- handleShutdown('STOP_FILE');
238
- }
239
- }, 500);
240
-
241
224
  } catch (error) {
242
225
  logger.error('Background recording setup failed:', error);
243
226
  console.error('[Background] Recording setup failed:', error.message);
@@ -252,7 +235,7 @@ async function runBackgroundRecording() {
252
235
  process.exit(1);
253
236
  }
254
237
 
255
- // Infinite loop - process will only exit via signal handlers
238
+ // Infinite loop - process will only exit via signal handlers or stop file
256
239
  await new Promise(() => {});
257
240
  }
258
241
 
package/bin/dashcam.js CHANGED
@@ -469,36 +469,63 @@ program
469
469
  console.log('Recording stopped successfully');
470
470
  logger.debug('Stop result:', result);
471
471
 
472
- // Wait for background process to write recording result
473
- logger.debug('Waiting for recording result from background process...');
474
- console.log('Waiting for recording result...');
472
+ // Reconstruct recording data from status and fix video with FFmpeg
473
+ console.log('Processing recording...');
474
+ logger.debug('Reconstructing recording data from status file');
475
475
 
476
- // Wait up to 30 seconds for recording result to appear
477
- const maxWaitForResult = 30000;
478
- const startWaitForResult = Date.now();
479
- let recordingResult = null;
480
- let checkCount = 0;
476
+ const { fixVideoContainer } = await import('../lib/recorder.js');
477
+ const { applicationTracker } = await import('../lib/applicationTracker.js');
478
+ const { logsTrackerManager } = await import('../lib/logs/index.js');
481
479
 
482
- while (!recordingResult && (Date.now() - startWaitForResult) < maxWaitForResult) {
483
- recordingResult = processManager.readRecordingResult();
484
- checkCount++;
485
-
486
- if (!recordingResult) {
487
- if (checkCount % 5 === 0) {
488
- const elapsed = Math.round((Date.now() - startWaitForResult) / 1000);
489
- console.log(`Waiting for recording result... (${elapsed}s)`);
490
- }
491
- await new Promise(resolve => setTimeout(resolve, 1000));
480
+ // Get temp file path
481
+ const tempFileInfoPath = path.join(os.tmpdir(), 'dashcam', 'temp-file.json');
482
+ let tempFileInfo = null;
483
+ try {
484
+ tempFileInfo = JSON.parse(fs.readFileSync(tempFileInfoPath, 'utf8'));
485
+ } catch (error) {
486
+ logger.error('Failed to read temp file info', { error });
487
+ }
488
+
489
+ const tempFile = tempFileInfo?.tempFile || result.outputPath.replace('.webm', '-temp.webm');
490
+ const outputPath = result.outputPath;
491
+
492
+ // Fix the video with FFmpeg (handle incomplete recordings)
493
+ logger.info('Fixing video with FFmpeg', { tempFile, outputPath });
494
+ if (fs.existsSync(tempFile)) {
495
+ try {
496
+ await fixVideoContainer(tempFile, outputPath);
497
+ logger.info('Video fixed successfully');
498
+ } catch (error) {
499
+ logger.warn('FFmpeg fix failed, using temp file as-is', { error: error.message });
500
+ // If fix fails, just copy the temp file
501
+ fs.copyFileSync(tempFile, outputPath);
492
502
  }
503
+ } else {
504
+ logger.warn('Temp file not found, using output path directly', { tempFile });
493
505
  }
494
506
 
507
+ // Collect application and log data
508
+ const apps = await applicationTracker.getApps(activeStatus.startTime);
509
+ const logs = await logsTrackerManager.getLogsForRecording();
510
+
511
+ const recordingResult = {
512
+ outputPath,
513
+ duration: result.duration,
514
+ clientStartDate: activeStatus.startTime,
515
+ apps,
516
+ logs,
517
+ title: activeStatus?.options?.title,
518
+ description: activeStatus?.options?.description,
519
+ project: activeStatus?.options?.project
520
+ };
521
+
495
522
  if (!recordingResult || !recordingResult.outputPath) {
496
- console.error('Failed to get recording result from background process');
497
- logger.error('No recording result received', { recordingResult });
523
+ console.error('Failed to process recording');
524
+ logger.error('No recording result', { recordingResult });
498
525
  process.exit(1);
499
526
  }
500
527
 
501
- console.log('Recording result received, uploading...');
528
+ console.log('Uploading recording...');
502
529
  logger.debug('Recording result:', recordingResult);
503
530
 
504
531
  try {
@@ -11,8 +11,7 @@ const __dirname = path.dirname(__filename);
11
11
  // Use user home directory for cross-session communication
12
12
  const PROCESS_DIR = path.join(os.homedir(), '.dashcam-cli');
13
13
  const STATUS_FILE = path.join(PROCESS_DIR, 'status.json');
14
- const RESULT_FILE = path.join(PROCESS_DIR, 'recording-result.json');
15
- const STOP_REQUEST_FILE = path.join(PROCESS_DIR, 'stop-request.txt');
14
+ const RECORDING_RESULT_FILE = path.join(PROCESS_DIR, 'recording-result.json');
16
15
 
17
16
  console.log('[INIT] Process Manager initialized');
18
17
  console.log('[INIT] Process directory:', PROCESS_DIR);
@@ -282,44 +281,33 @@ class ProcessManager {
282
281
  return false;
283
282
  }
284
283
 
285
- logger.info('Sending stop signal to background process', { pid });
284
+ logger.info('Killing background process', { pid });
286
285
 
287
- // Write stop request file (for Windows where SIGTERM doesn't work reliably with detached processes)
286
+ // Kill the process immediately - no graceful shutdown needed
287
+ // Video is already being streamed to disk, we'll fix it with FFmpeg
288
288
  try {
289
- fs.writeFileSync(STOP_REQUEST_FILE, Date.now().toString());
290
- logger.debug('Wrote stop request file', { path: STOP_REQUEST_FILE });
289
+ process.kill(pid, 'SIGKILL');
290
+ logger.info('Sent SIGKILL to background process');
291
291
  } catch (error) {
292
- logger.error('Failed to write stop request file', { error });
293
- }
294
-
295
- // Send SIGTERM to the background process to trigger graceful shutdown (Unix/Mac)
296
- try {
297
- process.kill(pid, 'SIGTERM');
298
- logger.info('Sent SIGTERM to background process');
299
- } catch (error) {
300
- logger.error('Failed to send signal to background process', { error });
292
+ logger.error('Failed to kill background process', { error });
301
293
  throw new Error('Failed to stop background recording process');
302
294
  }
303
295
 
304
- // Wait for the background process to finish and write results
305
- logger.debug('Waiting for background process to complete...');
306
- const maxWaitTime = 30000; // 30 seconds
296
+ // Wait briefly for process to die
297
+ logger.debug('Waiting for background process to exit...');
298
+ const maxWaitTime = 5000; // 5 seconds should be plenty for SIGKILL
307
299
  const startWait = Date.now();
308
300
 
309
301
  while (this.isProcessRunning(pid) && (Date.now() - startWait) < maxWaitTime) {
310
- await new Promise(resolve => setTimeout(resolve, 500));
302
+ await new Promise(resolve => setTimeout(resolve, 100));
311
303
  }
312
304
 
313
305
  if (this.isProcessRunning(pid)) {
314
- logger.error('Background process did not exit within timeout, forcing kill');
315
- try {
316
- process.kill(pid, 'SIGKILL');
317
- } catch (error) {
318
- logger.error('Failed to force kill background process', { error });
319
- }
306
+ logger.error('Background process did not exit after SIGKILL');
307
+ throw new Error('Failed to kill background process');
320
308
  }
321
309
 
322
- logger.info('Background process stopped');
310
+ logger.info('Background process killed');
323
311
 
324
312
  // Mark status as completed
325
313
  this.markStatusCompleted({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dashcam",
3
- "version": "1.3.28",
3
+ "version": "1.3.29",
4
4
  "description": "Minimal CLI version of Dashcam desktop app",
5
5
  "main": "bin/dashcam.js",
6
6
  "bin": {