dashcam 1.0.1-beta.2 → 1.0.1-beta.4
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 +46 -23
- package/lib/processManager.js +25 -0
- package/package.json +1 -1
package/bin/dashcam.js
CHANGED
|
@@ -84,22 +84,27 @@ program
|
|
|
84
84
|
.option('-t, --title <title>', 'Title for the recording')
|
|
85
85
|
.option('-d, --description <description>', 'Description for the recording (supports markdown)')
|
|
86
86
|
.option('-p, --project <project>', 'Project ID to upload the recording to')
|
|
87
|
+
.option('-s, --silent', 'Silent mode - suppress all output')
|
|
87
88
|
.action(async (options, command) => {
|
|
88
89
|
try {
|
|
90
|
+
const silent = options.silent;
|
|
91
|
+
const log = (...args) => { if (!silent) console.log(...args); };
|
|
92
|
+
const logError = (...args) => { if (!silent) console.error(...args); };
|
|
93
|
+
|
|
89
94
|
// Check if recording is already active
|
|
90
95
|
if (processManager.isRecordingActive()) {
|
|
91
96
|
const status = processManager.getActiveStatus();
|
|
92
97
|
const duration = ((Date.now() - status.startTime) / 1000).toFixed(1);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
98
|
+
log('Recording already in progress');
|
|
99
|
+
log(`Duration: ${duration} seconds`);
|
|
100
|
+
log(`PID: ${status.pid}`);
|
|
101
|
+
log('Use "dashcam stop" to stop the recording');
|
|
97
102
|
process.exit(0);
|
|
98
103
|
}
|
|
99
104
|
|
|
100
105
|
// Check authentication
|
|
101
106
|
if (!await auth.isAuthenticated()) {
|
|
102
|
-
|
|
107
|
+
log('You need to login first. Run: dashcam auth <api-key>');
|
|
103
108
|
process.exit(1);
|
|
104
109
|
}
|
|
105
110
|
|
|
@@ -107,12 +112,12 @@ program
|
|
|
107
112
|
const { ensurePermissions } = await import('../lib/permissions.js');
|
|
108
113
|
const hasPermissions = await ensurePermissions();
|
|
109
114
|
if (!hasPermissions) {
|
|
110
|
-
|
|
115
|
+
log('\n⚠️ Cannot start recording without screen recording permission.');
|
|
111
116
|
process.exit(1);
|
|
112
117
|
}
|
|
113
118
|
|
|
114
119
|
// Always use background mode
|
|
115
|
-
|
|
120
|
+
log('Starting recording...');
|
|
116
121
|
|
|
117
122
|
try {
|
|
118
123
|
const result = await processManager.startRecording({
|
|
@@ -124,37 +129,37 @@ program
|
|
|
124
129
|
project: options.project
|
|
125
130
|
});
|
|
126
131
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
132
|
+
log(`Recording started successfully (PID: ${result.pid})`);
|
|
133
|
+
log(`Output: ${result.outputPath}`);
|
|
134
|
+
log('Use "dashcam status" to check progress');
|
|
135
|
+
log('Use "dashcam stop" to stop recording and upload');
|
|
131
136
|
|
|
132
137
|
// Keep this process alive for background recording
|
|
133
|
-
|
|
138
|
+
log('Recording is running in background...');
|
|
134
139
|
|
|
135
140
|
// Set up signal handlers for graceful shutdown
|
|
136
141
|
let isShuttingDown = false;
|
|
137
142
|
const handleShutdown = async (signal) => {
|
|
138
143
|
if (isShuttingDown) {
|
|
139
|
-
|
|
144
|
+
log('Shutdown already in progress...');
|
|
140
145
|
return;
|
|
141
146
|
}
|
|
142
147
|
isShuttingDown = true;
|
|
143
148
|
|
|
144
|
-
|
|
149
|
+
log(`\nReceived ${signal}, stopping background recording...`);
|
|
145
150
|
try {
|
|
146
151
|
// Stop the recording using the recorder directly (not processManager)
|
|
147
152
|
const { stopRecording } = await import('../lib/recorder.js');
|
|
148
153
|
const stopResult = await stopRecording();
|
|
149
154
|
|
|
150
155
|
if (stopResult) {
|
|
151
|
-
|
|
156
|
+
log('Recording stopped:', stopResult.outputPath);
|
|
152
157
|
|
|
153
158
|
// Import and call upload function with the correct format
|
|
154
159
|
const { upload } = await import('../lib/uploader.js');
|
|
155
160
|
|
|
156
|
-
|
|
157
|
-
await upload(stopResult.outputPath, {
|
|
161
|
+
log('Starting upload...');
|
|
162
|
+
const uploadResult = await upload(stopResult.outputPath, {
|
|
158
163
|
title: options.title || 'Dashcam Recording',
|
|
159
164
|
description: options.description || 'Recorded with Dashcam CLI',
|
|
160
165
|
project: options.project,
|
|
@@ -166,13 +171,20 @@ program
|
|
|
166
171
|
snapshotPath: stopResult.snapshotPath
|
|
167
172
|
});
|
|
168
173
|
|
|
169
|
-
|
|
174
|
+
// Write upload result for stop command to read
|
|
175
|
+
processManager.writeUploadResult({
|
|
176
|
+
shareLink: uploadResult.shareLink,
|
|
177
|
+
replayId: uploadResult.replay?.id
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
log('✅ Upload complete!');
|
|
181
|
+
log('📹 Watch your recording:', uploadResult.shareLink);
|
|
170
182
|
}
|
|
171
183
|
|
|
172
184
|
// Clean up process files
|
|
173
185
|
processManager.cleanup();
|
|
174
186
|
} catch (error) {
|
|
175
|
-
|
|
187
|
+
logError('Error during shutdown:', error.message);
|
|
176
188
|
logger.error('Error during shutdown:', error);
|
|
177
189
|
}
|
|
178
190
|
process.exit(0);
|
|
@@ -184,12 +196,12 @@ program
|
|
|
184
196
|
// Keep the process alive
|
|
185
197
|
await new Promise(() => {});
|
|
186
198
|
} catch (error) {
|
|
187
|
-
|
|
199
|
+
logError('Failed to start recording:', error.message);
|
|
188
200
|
process.exit(1);
|
|
189
201
|
}
|
|
190
202
|
} catch (error) {
|
|
191
203
|
logger.error('Failed to start recording:', error);
|
|
192
|
-
console.error('Failed to start recording:', error.message);
|
|
204
|
+
if (!options.silent) console.error('Failed to start recording:', error.message);
|
|
193
205
|
process.exit(1);
|
|
194
206
|
}
|
|
195
207
|
});
|
|
@@ -296,7 +308,17 @@ program
|
|
|
296
308
|
|
|
297
309
|
if (!filesExist) {
|
|
298
310
|
console.log('✅ Recording was already uploaded by background process');
|
|
299
|
-
|
|
311
|
+
|
|
312
|
+
// Try to read the upload result from the background process
|
|
313
|
+
const uploadResult = processManager.readUploadResult();
|
|
314
|
+
if (uploadResult && uploadResult.shareLink) {
|
|
315
|
+
console.log('✅ Recording stopped and uploaded');
|
|
316
|
+
console.log('📹 Watch your recording:', uploadResult.shareLink);
|
|
317
|
+
} else {
|
|
318
|
+
console.log('✅ Recording stopped and uploaded');
|
|
319
|
+
logger.warn('Upload result not available from background process');
|
|
320
|
+
}
|
|
321
|
+
|
|
300
322
|
process.exit(0);
|
|
301
323
|
}
|
|
302
324
|
|
|
@@ -315,7 +337,8 @@ program
|
|
|
315
337
|
snapshotPath: result.snapshotPath
|
|
316
338
|
});
|
|
317
339
|
|
|
318
|
-
console.log('✅ Upload complete!
|
|
340
|
+
console.log('✅ Upload complete!');
|
|
341
|
+
console.log('📹 Watch your recording:', uploadResult.shareLink);
|
|
319
342
|
} catch (uploadError) {
|
|
320
343
|
console.error('Upload failed:', uploadError.message);
|
|
321
344
|
console.log('Recording saved locally:', result.outputPath);
|
package/lib/processManager.js
CHANGED
|
@@ -8,6 +8,7 @@ import { logger } from './logger.js';
|
|
|
8
8
|
const PROCESS_DIR = path.join(os.homedir(), '.dashcam-cli');
|
|
9
9
|
const PID_FILE = path.join(PROCESS_DIR, 'recording.pid');
|
|
10
10
|
const STATUS_FILE = path.join(PROCESS_DIR, 'status.json');
|
|
11
|
+
const RESULT_FILE = path.join(PROCESS_DIR, 'upload-result.json');
|
|
11
12
|
|
|
12
13
|
// Ensure process directory exists
|
|
13
14
|
if (!fs.existsSync(PROCESS_DIR)) {
|
|
@@ -47,6 +48,29 @@ class ProcessManager {
|
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
50
|
|
|
51
|
+
writeUploadResult(result) {
|
|
52
|
+
try {
|
|
53
|
+
fs.writeFileSync(RESULT_FILE, JSON.stringify({
|
|
54
|
+
...result,
|
|
55
|
+
timestamp: Date.now()
|
|
56
|
+
}, null, 2));
|
|
57
|
+
logger.debug('Wrote upload result to file', { shareLink: result.shareLink });
|
|
58
|
+
} catch (error) {
|
|
59
|
+
logger.error('Failed to write upload result file', { error });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
readUploadResult() {
|
|
64
|
+
try {
|
|
65
|
+
if (!fs.existsSync(RESULT_FILE)) return null;
|
|
66
|
+
const data = fs.readFileSync(RESULT_FILE, 'utf8');
|
|
67
|
+
return JSON.parse(data);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
logger.error('Failed to read upload result file', { error });
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
50
74
|
writePid(pid = process.pid) {
|
|
51
75
|
try {
|
|
52
76
|
fs.writeFileSync(PID_FILE, pid.toString());
|
|
@@ -96,6 +120,7 @@ class ProcessManager {
|
|
|
96
120
|
try {
|
|
97
121
|
if (fs.existsSync(PID_FILE)) fs.unlinkSync(PID_FILE);
|
|
98
122
|
if (fs.existsSync(STATUS_FILE)) fs.unlinkSync(STATUS_FILE);
|
|
123
|
+
if (fs.existsSync(RESULT_FILE)) fs.unlinkSync(RESULT_FILE);
|
|
99
124
|
} catch (error) {
|
|
100
125
|
logger.error('Failed to cleanup process files', { error });
|
|
101
126
|
}
|