@vorec/cli 1.0.1 → 1.1.1
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/dist/commands/run.js +70 -26
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/commands/run.js
CHANGED
|
@@ -10,6 +10,7 @@ export async function runCommand(manifestPath, opts) {
|
|
|
10
10
|
console.log(`Actions: ${manifest.actions.length}, URL: ${manifest.url}\n`);
|
|
11
11
|
// Record → upload → generate
|
|
12
12
|
let videoPath = opts.video;
|
|
13
|
+
let thumbPath;
|
|
13
14
|
let trackedActions = [];
|
|
14
15
|
let videoDuration = 0;
|
|
15
16
|
let videoWidth = manifest.viewport?.width || 1920;
|
|
@@ -20,6 +21,7 @@ export async function runCommand(manifestPath, opts) {
|
|
|
20
21
|
try {
|
|
21
22
|
const result = await recordAndTrack(manifest);
|
|
22
23
|
videoPath = result.videoPath;
|
|
24
|
+
thumbPath = result.thumbPath;
|
|
23
25
|
trackedActions = result.actions;
|
|
24
26
|
videoDuration = result.duration;
|
|
25
27
|
videoWidth = result.viewport.width;
|
|
@@ -60,31 +62,66 @@ export async function runCommand(manifestPath, opts) {
|
|
|
60
62
|
}
|
|
61
63
|
// Step 2: Create project + upload
|
|
62
64
|
const spinner = ora('Creating project...').start();
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
65
|
+
let createResult;
|
|
66
|
+
try {
|
|
67
|
+
createResult = await apiCall('create-project', {
|
|
68
|
+
title: manifest.title,
|
|
69
|
+
contentType,
|
|
70
|
+
fileSize,
|
|
71
|
+
actions: trackedActions.map(a => ({
|
|
72
|
+
type: a.interaction_type || a.type,
|
|
73
|
+
timestamp: a.timestamp,
|
|
74
|
+
coordinates: a.coordinates,
|
|
75
|
+
target: a.target,
|
|
76
|
+
description: a.description,
|
|
77
|
+
context: a.context,
|
|
78
|
+
typed_text: a.typed_text,
|
|
79
|
+
selected_value: a.selected_value,
|
|
80
|
+
})),
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
spinner.fail(err.message);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
spinner.text = 'Uploading video...';
|
|
89
|
+
await uploadVideo(createResult.upload_url, videoPath, contentType);
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
spinner.fail(`Upload failed: ${err.message}`);
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
// Upload thumbnail if available
|
|
96
|
+
let thumbnailKey;
|
|
97
|
+
if (thumbPath) {
|
|
98
|
+
try {
|
|
99
|
+
spinner.text = 'Uploading thumbnail...';
|
|
100
|
+
const thumbResult = await apiCall('upload-thumbnail', {
|
|
101
|
+
projectId: createResult.projectId,
|
|
102
|
+
});
|
|
103
|
+
if (thumbResult.upload_url) {
|
|
104
|
+
await uploadVideo(thumbResult.upload_url, thumbPath, 'image/jpeg');
|
|
105
|
+
thumbnailKey = thumbResult.storage_key;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch { /* thumbnail upload failed — not critical */ }
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
spinner.text = 'Confirming upload...';
|
|
112
|
+
await apiCall('confirm-upload', {
|
|
113
|
+
projectId: createResult.projectId,
|
|
114
|
+
storage_key: createResult.storage_key,
|
|
115
|
+
video_duration: videoDuration > 0 ? videoDuration : undefined,
|
|
116
|
+
video_width: videoWidth,
|
|
117
|
+
video_height: videoHeight,
|
|
118
|
+
thumbnail_key: thumbnailKey,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
spinner.fail(`Confirm failed: ${err.message}`);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
88
125
|
saveProjectState({
|
|
89
126
|
projectId: createResult.projectId,
|
|
90
127
|
storageKey: createResult.storage_key,
|
|
@@ -296,6 +333,13 @@ async function recordAndTrack(manifest) {
|
|
|
296
333
|
unlinkSync(webmPath);
|
|
297
334
|
}
|
|
298
335
|
catch { }
|
|
336
|
+
// Extract thumbnail at 2 seconds
|
|
337
|
+
const thumbPath = mp4Path.replace(/\.mp4$/, '_thumb.jpg');
|
|
338
|
+
try {
|
|
339
|
+
execSync(`ffmpeg -y -i "${mp4Path}" -ss 00:00:02 -frames:v 1 -q:v 2 "${thumbPath}"`, { stdio: 'pipe' });
|
|
340
|
+
console.log(' Thumbnail extracted');
|
|
341
|
+
}
|
|
342
|
+
catch { /* thumbnail extraction failed — not critical */ }
|
|
299
343
|
writeFileSync('.vorec/tracked-actions.json', JSON.stringify(tracked, null, 2));
|
|
300
|
-
return { videoPath: mp4Path, actions: tracked, duration, viewport };
|
|
344
|
+
return { videoPath: mp4Path, thumbPath: existsSync(thumbPath) ? thumbPath : undefined, actions: tracked, duration, viewport };
|
|
301
345
|
}
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { statusCommand } from './commands/status.js';
|
|
|
7
7
|
const program = new Command()
|
|
8
8
|
.name('vorec')
|
|
9
9
|
.description('Turn screen recordings into narrated tutorials')
|
|
10
|
-
.version('1.
|
|
10
|
+
.version('1.1.1');
|
|
11
11
|
program
|
|
12
12
|
.command('init')
|
|
13
13
|
.description('Save your Vorec API key')
|