dashcam 1.3.0-beta → 1.3.2-beta
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.
- package/bin/dashcam.js +3 -23
- package/lib/processManager.js +48 -97
- package/package.json +1 -1
package/bin/dashcam.js
CHANGED
|
@@ -99,16 +99,6 @@ async function recordingAction(options, command) {
|
|
|
99
99
|
process.exit(1);
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
// Check for piped input (description from stdin) if description option not set
|
|
103
|
-
let description = options.description;
|
|
104
|
-
if (!description && !process.stdin.isTTY) {
|
|
105
|
-
const chunks = [];
|
|
106
|
-
for await (const chunk of process.stdin) {
|
|
107
|
-
chunks.push(chunk);
|
|
108
|
-
}
|
|
109
|
-
description = Buffer.concat(chunks).toString('utf-8');
|
|
110
|
-
}
|
|
111
|
-
|
|
112
102
|
// Check screen recording permissions (macOS only)
|
|
113
103
|
const { ensurePermissions } = await import('../lib/permissions.js');
|
|
114
104
|
const hasPermissions = await ensurePermissions();
|
|
@@ -126,7 +116,7 @@ async function recordingAction(options, command) {
|
|
|
126
116
|
audio: options.audio,
|
|
127
117
|
output: options.output,
|
|
128
118
|
title: options.title,
|
|
129
|
-
description: description,
|
|
119
|
+
description: options.description,
|
|
130
120
|
project: options.project || options.k // Support both -p and -k for project
|
|
131
121
|
});
|
|
132
122
|
|
|
@@ -153,21 +143,11 @@ program
|
|
|
153
143
|
.command('create')
|
|
154
144
|
.description('Create a clip and output the resulting url or markdown. Will launch desktop app for local editing before publishing.')
|
|
155
145
|
.option('-t, --title <string>', 'Title of the replay. Automatically generated if not supplied.')
|
|
156
|
-
.option('-d, --description [text]', 'Replay markdown body
|
|
146
|
+
.option('-d, --description [text]', 'Replay markdown body')
|
|
157
147
|
.option('--md', 'Returns code for a rich markdown image link.')
|
|
158
148
|
.option('-k, --project <project>', 'Project ID to publish to')
|
|
159
149
|
.action(async (options) => {
|
|
160
150
|
try {
|
|
161
|
-
// Check for piped input (description from stdin)
|
|
162
|
-
let description = options.description;
|
|
163
|
-
if (!description && !process.stdin.isTTY) {
|
|
164
|
-
const chunks = [];
|
|
165
|
-
for await (const chunk of process.stdin) {
|
|
166
|
-
chunks.push(chunk);
|
|
167
|
-
}
|
|
168
|
-
description = Buffer.concat(chunks).toString('utf-8');
|
|
169
|
-
}
|
|
170
|
-
|
|
171
151
|
if (!processManager.isRecordingActive()) {
|
|
172
152
|
console.log('No active recording to create clip from');
|
|
173
153
|
console.log('Start a recording first with "dashcam record" or "dashcam start"');
|
|
@@ -192,7 +172,7 @@ program
|
|
|
192
172
|
try {
|
|
193
173
|
const uploadResult = await upload(result.outputPath, {
|
|
194
174
|
title: options.title || activeStatus?.options?.title || 'Dashcam Recording',
|
|
195
|
-
description: description || activeStatus?.options?.description,
|
|
175
|
+
description: options.description || activeStatus?.options?.description,
|
|
196
176
|
project: options.project || options.k || activeStatus?.options?.project,
|
|
197
177
|
duration: result.duration,
|
|
198
178
|
clientStartDate: result.clientStartDate,
|
package/lib/processManager.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { spawn } from 'child_process';
|
|
2
1
|
import fs from 'fs';
|
|
3
2
|
import path from 'path';
|
|
4
3
|
import os from 'os';
|
|
@@ -148,57 +147,36 @@ class ProcessManager {
|
|
|
148
147
|
this.isStopping = true;
|
|
149
148
|
|
|
150
149
|
try {
|
|
151
|
-
const pid = this.readPid();
|
|
152
150
|
const status = this.readStatus();
|
|
153
151
|
|
|
154
|
-
if (!
|
|
155
|
-
logger.warn('No active recording
|
|
152
|
+
if (!status || !status.isRecording) {
|
|
153
|
+
logger.warn('No active recording found');
|
|
156
154
|
return false;
|
|
157
155
|
}
|
|
158
156
|
|
|
159
|
-
//
|
|
160
|
-
|
|
161
|
-
process.kill(pid, 'SIGINT');
|
|
157
|
+
// Import recorder module
|
|
158
|
+
const { stopRecording } = await import('./recorder.js');
|
|
162
159
|
|
|
163
|
-
|
|
164
|
-
// Increase timeout to allow for upload to complete
|
|
165
|
-
const maxWaitTime = 120000; // 2 minutes max to allow for upload
|
|
166
|
-
const startWait = Date.now();
|
|
160
|
+
logger.info('Stopping recording directly');
|
|
167
161
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
}
|
|
162
|
+
// Stop the recording
|
|
163
|
+
const result = await stopRecording();
|
|
171
164
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
165
|
+
logger.info('Recording stopped successfully', {
|
|
166
|
+
outputPath: result.outputPath,
|
|
167
|
+
duration: result.duration
|
|
168
|
+
});
|
|
177
169
|
|
|
178
|
-
//
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
outputPath: status.outputPath,
|
|
189
|
-
gifPath: `${basePath}.gif`,
|
|
190
|
-
snapshotPath: `${basePath}.png`,
|
|
191
|
-
duration: Date.now() - status.startTime,
|
|
192
|
-
clientStartDate: status.startTime,
|
|
193
|
-
apps: [],
|
|
194
|
-
logs: []
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
this.cleanup({ preserveResult: true });
|
|
198
|
-
return result;
|
|
199
|
-
} else {
|
|
200
|
-
throw new Error('No status information available for active recording');
|
|
201
|
-
}
|
|
170
|
+
// Update status to indicate recording stopped
|
|
171
|
+
this.writeStatus({
|
|
172
|
+
isRecording: false,
|
|
173
|
+
completedTime: Date.now(),
|
|
174
|
+
pid: process.pid
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
this.cleanup({ preserveResult: true });
|
|
178
|
+
|
|
179
|
+
return result;
|
|
202
180
|
} catch (error) {
|
|
203
181
|
logger.error('Failed to stop recording', { error });
|
|
204
182
|
throw error;
|
|
@@ -213,69 +191,42 @@ class ProcessManager {
|
|
|
213
191
|
throw new Error('Recording already in progress');
|
|
214
192
|
}
|
|
215
193
|
|
|
216
|
-
//
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
// Get the path to the CLI binary
|
|
220
|
-
const binPath = path.join(__dirname, '..', 'bin', 'dashcam-background.js');
|
|
221
|
-
|
|
222
|
-
logger.debug('Background process path', { binPath, exists: fs.existsSync(binPath) });
|
|
223
|
-
|
|
224
|
-
// Create log files for background process
|
|
225
|
-
const logDir = PROCESS_DIR;
|
|
226
|
-
const stdoutLog = path.join(logDir, 'background-stdout.log');
|
|
227
|
-
const stderrLog = path.join(logDir, 'background-stderr.log');
|
|
228
|
-
|
|
229
|
-
// Always use 'ignore' for stdio to ensure complete detachment
|
|
230
|
-
// This is critical when parent process is invoked via exec() or other methods
|
|
231
|
-
// that might have open stdio pipes
|
|
232
|
-
const isWindows = process.platform === 'win32';
|
|
233
|
-
|
|
234
|
-
// Spawn a detached process that will handle the recording
|
|
235
|
-
const backgroundProcess = spawn(process.execPath, [
|
|
236
|
-
binPath,
|
|
237
|
-
JSON.stringify(options)
|
|
238
|
-
], {
|
|
239
|
-
detached: true,
|
|
240
|
-
stdio: 'ignore', // Always ignore to prevent hanging when parent has open pipes
|
|
241
|
-
windowsHide: true, // Hide the console window on Windows
|
|
242
|
-
env: {
|
|
243
|
-
...process.env,
|
|
244
|
-
DASHCAM_BACKGROUND: 'true'
|
|
245
|
-
}
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
// Get the background process PID before unreffing
|
|
249
|
-
const backgroundPid = backgroundProcess.pid;
|
|
194
|
+
// Import recorder module
|
|
195
|
+
const { startRecording } = await import('./recorder.js');
|
|
250
196
|
|
|
251
|
-
|
|
252
|
-
// Use the spawned process PID rather than waiting for status file
|
|
253
|
-
this.writePid(backgroundPid);
|
|
197
|
+
logger.info('Starting recording directly');
|
|
254
198
|
|
|
255
|
-
//
|
|
256
|
-
|
|
199
|
+
// Start recording with the provided options
|
|
200
|
+
const recordingOptions = {
|
|
201
|
+
fps: parseInt(options.fps) || 10,
|
|
202
|
+
includeAudio: options.audio || false,
|
|
203
|
+
customOutputPath: options.output || null
|
|
204
|
+
};
|
|
257
205
|
|
|
258
|
-
|
|
259
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
206
|
+
logger.info('Starting recording with options', { recordingOptions });
|
|
260
207
|
|
|
261
|
-
|
|
262
|
-
const status = this.readStatus();
|
|
208
|
+
const recordingResult = await startRecording(recordingOptions);
|
|
263
209
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
210
|
+
// Write PID and status files for status tracking
|
|
211
|
+
this.writePid(process.pid);
|
|
212
|
+
|
|
213
|
+
this.writeStatus({
|
|
214
|
+
isRecording: true,
|
|
215
|
+
startTime: recordingResult.startTime,
|
|
216
|
+
options,
|
|
217
|
+
pid: process.pid,
|
|
218
|
+
outputPath: recordingResult.outputPath
|
|
219
|
+
});
|
|
269
220
|
|
|
270
|
-
logger.info('
|
|
271
|
-
|
|
272
|
-
|
|
221
|
+
logger.info('Recording started successfully', {
|
|
222
|
+
outputPath: recordingResult.outputPath,
|
|
223
|
+
startTime: recordingResult.startTime
|
|
273
224
|
});
|
|
274
225
|
|
|
275
226
|
return {
|
|
276
|
-
pid:
|
|
277
|
-
outputPath:
|
|
278
|
-
startTime:
|
|
227
|
+
pid: process.pid,
|
|
228
|
+
outputPath: recordingResult.outputPath,
|
|
229
|
+
startTime: recordingResult.startTime
|
|
279
230
|
};
|
|
280
231
|
}
|
|
281
232
|
|