dashcam 1.4.13-beta.2 → 1.4.13-beta.3
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 +0 -2
- package/lib/recorder.js +2 -2
- package/package.json +1 -1
- package/691cc08dc2fc02f59ae66f08 (1).mp4 +0 -0
- package/LINUX_PERF_FIX.md +0 -184
- package/LOG_TRACKING_GUIDE.md +0 -225
- package/NPM_PUBLISH_FIX.md +0 -104
- package/PERFORMANCE_TRACKING.md +0 -139
- package/SINGLE_FRAME_VIDEO_FIX.md +0 -129
- package/examples/execute-script.js +0 -150
- package/examples/simple-test.js +0 -37
- package/recording.log +0 -814
- package/sea-bundle.mjs +0 -34595
- package/test-page.html +0 -15
- package/test-perf-linux.js +0 -208
- package/test-perf-tracker.js +0 -52
- package/test-performance-tracking.js +0 -108
- package/test-short-recording.js +0 -287
- package/test-top-processes.js +0 -23
- package/test.log +0 -1
- package/test_run.log +0 -48
package/test-page.html
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<title>Test Page for Extension</title>
|
|
5
|
-
</head>
|
|
6
|
-
<body>
|
|
7
|
-
<h1>Simple Test Page</h1>
|
|
8
|
-
<p>This is a test page for the Chrome extension script execution.</p>
|
|
9
|
-
<p id="result">Waiting for script execution...</p>
|
|
10
|
-
|
|
11
|
-
<script>
|
|
12
|
-
console.log('Test page loaded, title:', document.title);
|
|
13
|
-
</script>
|
|
14
|
-
</body>
|
|
15
|
-
</html>
|
package/test-perf-linux.js
DELETED
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Linux-specific performance tracking test
|
|
5
|
-
* Tests each component individually to identify issues
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { performanceTracker } from './lib/performanceTracker.js';
|
|
9
|
-
import { getTopProcesses } from './lib/topProcesses.js';
|
|
10
|
-
import { logger, setVerbose } from './lib/logger.js';
|
|
11
|
-
import pidusage from 'pidusage';
|
|
12
|
-
import os from 'os';
|
|
13
|
-
import fs from 'fs';
|
|
14
|
-
|
|
15
|
-
// Enable verbose logging
|
|
16
|
-
setVerbose(true);
|
|
17
|
-
|
|
18
|
-
async function testPidUsage() {
|
|
19
|
-
logger.info('=== Testing pidusage ===');
|
|
20
|
-
try {
|
|
21
|
-
const stats = await pidusage(process.pid);
|
|
22
|
-
logger.info('pidusage SUCCESS', {
|
|
23
|
-
cpu: stats.cpu?.toFixed(2),
|
|
24
|
-
memory: (stats.memory / (1024 * 1024)).toFixed(1) + ' MB',
|
|
25
|
-
pid: stats.pid,
|
|
26
|
-
ppid: stats.ppid
|
|
27
|
-
});
|
|
28
|
-
return true;
|
|
29
|
-
} catch (error) {
|
|
30
|
-
logger.error('pidusage FAILED', { error: error.message, stack: error.stack });
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async function testTopProcesses() {
|
|
36
|
-
logger.info('=== Testing getTopProcesses ===');
|
|
37
|
-
try {
|
|
38
|
-
const topProcs = await getTopProcesses(5);
|
|
39
|
-
logger.info('getTopProcesses SUCCESS', {
|
|
40
|
-
count: topProcs.length,
|
|
41
|
-
processes: topProcs.map(p => `${p.name} (PID: ${p.pid}, CPU: ${p.cpu}%)`)
|
|
42
|
-
});
|
|
43
|
-
return topProcs.length > 0;
|
|
44
|
-
} catch (error) {
|
|
45
|
-
logger.error('getTopProcesses FAILED', { error: error.message, stack: error.stack });
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async function testNetworkMetrics() {
|
|
51
|
-
logger.info('=== Testing Network Metrics ===');
|
|
52
|
-
try {
|
|
53
|
-
if (process.platform === 'linux') {
|
|
54
|
-
// Test /proc/net/dev reading
|
|
55
|
-
if (fs.existsSync('/proc/net/dev')) {
|
|
56
|
-
const content = fs.readFileSync('/proc/net/dev', 'utf8');
|
|
57
|
-
const lines = content.split('\n');
|
|
58
|
-
let totalRx = 0;
|
|
59
|
-
let totalTx = 0;
|
|
60
|
-
|
|
61
|
-
logger.info('/proc/net/dev file found');
|
|
62
|
-
logger.debug('First few lines:', lines.slice(0, 5));
|
|
63
|
-
|
|
64
|
-
for (const line of lines) {
|
|
65
|
-
if (line.includes(':')) {
|
|
66
|
-
const parts = line.split(':')[1].trim().split(/\s+/);
|
|
67
|
-
if (parts.length >= 9) {
|
|
68
|
-
const rx = parseInt(parts[0]) || 0;
|
|
69
|
-
const tx = parseInt(parts[8]) || 0;
|
|
70
|
-
totalRx += rx;
|
|
71
|
-
totalTx += tx;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
logger.info('Network stats parsed', {
|
|
77
|
-
totalRx: (totalRx / (1024 * 1024)).toFixed(2) + ' MB',
|
|
78
|
-
totalTx: (totalTx / (1024 * 1024)).toFixed(2) + ' MB'
|
|
79
|
-
});
|
|
80
|
-
return true;
|
|
81
|
-
} else {
|
|
82
|
-
logger.warn('/proc/net/dev not found - running in container?');
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
} else {
|
|
86
|
-
logger.info('Skipping network test (not Linux)');
|
|
87
|
-
return true;
|
|
88
|
-
}
|
|
89
|
-
} catch (error) {
|
|
90
|
-
logger.error('Network metrics FAILED', { error: error.message, stack: error.stack });
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
async function testSystemMetrics() {
|
|
96
|
-
logger.info('=== Testing System Metrics ===');
|
|
97
|
-
try {
|
|
98
|
-
const totalMem = os.totalmem();
|
|
99
|
-
const freeMem = os.freemem();
|
|
100
|
-
const usedMem = totalMem - freeMem;
|
|
101
|
-
const cpus = os.cpus();
|
|
102
|
-
|
|
103
|
-
logger.info('System metrics SUCCESS', {
|
|
104
|
-
totalMemory: (totalMem / (1024 * 1024 * 1024)).toFixed(2) + ' GB',
|
|
105
|
-
freeMemory: (freeMem / (1024 * 1024 * 1024)).toFixed(2) + ' GB',
|
|
106
|
-
usedMemory: (usedMem / (1024 * 1024 * 1024)).toFixed(2) + ' GB',
|
|
107
|
-
memoryUsagePercent: ((usedMem / totalMem) * 100).toFixed(1) + '%',
|
|
108
|
-
cpuCount: cpus.length,
|
|
109
|
-
platform: os.platform(),
|
|
110
|
-
arch: os.arch()
|
|
111
|
-
});
|
|
112
|
-
return true;
|
|
113
|
-
} catch (error) {
|
|
114
|
-
logger.error('System metrics FAILED', { error: error.message });
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
async function testPerformanceTracker() {
|
|
120
|
-
logger.info('=== Testing PerformanceTracker ===');
|
|
121
|
-
try {
|
|
122
|
-
logger.info('Starting performance tracker for 10 seconds...');
|
|
123
|
-
|
|
124
|
-
// Use temp directory for performance file
|
|
125
|
-
const tmpDir = os.tmpdir();
|
|
126
|
-
performanceTracker.start(tmpDir);
|
|
127
|
-
|
|
128
|
-
// Wait 10 seconds
|
|
129
|
-
await new Promise(resolve => setTimeout(resolve, 10000));
|
|
130
|
-
|
|
131
|
-
// Stop tracking
|
|
132
|
-
const result = performanceTracker.stop();
|
|
133
|
-
|
|
134
|
-
logger.info('PerformanceTracker stopped', {
|
|
135
|
-
sampleCount: result.samples?.length || 0,
|
|
136
|
-
hasSummary: !!result.summary
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
if (result.summary) {
|
|
140
|
-
logger.info('Performance Summary', {
|
|
141
|
-
duration: (result.summary.durationMs / 1000).toFixed(1) + 's',
|
|
142
|
-
avgCPU: result.summary.avgProcessCPU?.toFixed(1) + '%',
|
|
143
|
-
maxCPU: result.summary.maxProcessCPU?.toFixed(1) + '%',
|
|
144
|
-
avgMemory: result.summary.avgProcessMemoryMB?.toFixed(1) + ' MB',
|
|
145
|
-
maxMemory: result.summary.maxProcessMemoryMB?.toFixed(1) + ' MB'
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (result.samples && result.samples.length > 0) {
|
|
150
|
-
const lastSample = result.samples[result.samples.length - 1];
|
|
151
|
-
logger.info('Last sample data', {
|
|
152
|
-
hasSystem: !!lastSample.system,
|
|
153
|
-
hasProcess: !!lastSample.process,
|
|
154
|
-
hasNetwork: !!lastSample.network,
|
|
155
|
-
hasTopProcesses: !!lastSample.topProcesses,
|
|
156
|
-
topProcessesCount: lastSample.topProcesses?.length || 0
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
if (lastSample.topProcesses && lastSample.topProcesses.length > 0) {
|
|
160
|
-
logger.info('Top 3 processes from last sample:');
|
|
161
|
-
lastSample.topProcesses.slice(0, 3).forEach((proc, i) => {
|
|
162
|
-
logger.info(` ${i + 1}. ${proc.name} - CPU: ${proc.cpu?.toFixed(1)}%, Mem: ${(proc.memory / (1024 * 1024)).toFixed(1)} MB`);
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Clean up
|
|
168
|
-
performanceTracker.cleanup();
|
|
169
|
-
|
|
170
|
-
return result.samples && result.samples.length > 0;
|
|
171
|
-
} catch (error) {
|
|
172
|
-
logger.error('PerformanceTracker FAILED', { error: error.message, stack: error.stack });
|
|
173
|
-
return false;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
async function runAllTests() {
|
|
178
|
-
logger.info('Starting Linux Performance Tracking Tests');
|
|
179
|
-
logger.info('Platform:', os.platform());
|
|
180
|
-
logger.info('Architecture:', os.arch());
|
|
181
|
-
logger.info('Node version:', process.version);
|
|
182
|
-
logger.info('');
|
|
183
|
-
|
|
184
|
-
const results = {
|
|
185
|
-
pidusage: await testPidUsage(),
|
|
186
|
-
topProcesses: await testTopProcesses(),
|
|
187
|
-
networkMetrics: await testNetworkMetrics(),
|
|
188
|
-
systemMetrics: await testSystemMetrics(),
|
|
189
|
-
performanceTracker: await testPerformanceTracker()
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
logger.info('');
|
|
193
|
-
logger.info('=== Test Results Summary ===');
|
|
194
|
-
Object.entries(results).forEach(([test, passed]) => {
|
|
195
|
-
logger.info(`${test}: ${passed ? '✓ PASS' : '✗ FAIL'}`);
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
const allPassed = Object.values(results).every(r => r);
|
|
199
|
-
logger.info('');
|
|
200
|
-
logger.info(`Overall: ${allPassed ? '✓ ALL TESTS PASSED' : '✗ SOME TESTS FAILED'}`);
|
|
201
|
-
|
|
202
|
-
process.exit(allPassed ? 0 : 1);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
runAllTests().catch(error => {
|
|
206
|
-
logger.error('Test suite failed', { error: error.message, stack: error.stack });
|
|
207
|
-
process.exit(1);
|
|
208
|
-
});
|
package/test-perf-tracker.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { PerformanceTracker } from './lib/performanceTracker.js';
|
|
4
|
-
import { logger, setVerbose } from './lib/logger.js';
|
|
5
|
-
|
|
6
|
-
setVerbose(true);
|
|
7
|
-
|
|
8
|
-
async function testPerformanceTracking() {
|
|
9
|
-
console.log('Testing performance tracking with top processes...\n');
|
|
10
|
-
|
|
11
|
-
const tracker = new PerformanceTracker();
|
|
12
|
-
|
|
13
|
-
// Start tracking
|
|
14
|
-
tracker.start();
|
|
15
|
-
console.log('Started tracking...');
|
|
16
|
-
|
|
17
|
-
// Wait for 6 seconds to get at least one sample
|
|
18
|
-
console.log('Waiting 6 seconds for sample...');
|
|
19
|
-
await new Promise(resolve => setTimeout(resolve, 6000));
|
|
20
|
-
|
|
21
|
-
// Stop tracking
|
|
22
|
-
const result = tracker.stop();
|
|
23
|
-
|
|
24
|
-
console.log('\n=== Performance Tracking Results ===');
|
|
25
|
-
console.log(`Total samples: ${result.samples.length}`);
|
|
26
|
-
|
|
27
|
-
if (result.samples.length > 0) {
|
|
28
|
-
const firstSample = result.samples[0];
|
|
29
|
-
console.log('\nFirst sample keys:', Object.keys(firstSample));
|
|
30
|
-
console.log('Has topProcesses:', !!firstSample.topProcesses);
|
|
31
|
-
console.log('topProcesses count:', firstSample.topProcesses?.length || 0);
|
|
32
|
-
|
|
33
|
-
if (firstSample.topProcesses && firstSample.topProcesses.length > 0) {
|
|
34
|
-
console.log('\nTop 3 processes:');
|
|
35
|
-
firstSample.topProcesses.slice(0, 3).forEach((proc, i) => {
|
|
36
|
-
console.log(`${i + 1}. ${proc.name} (PID: ${proc.pid})`);
|
|
37
|
-
console.log(` CPU: ${proc.cpu.toFixed(1)}%`);
|
|
38
|
-
console.log(` Memory: ${(proc.memory / (1024 * 1024)).toFixed(1)} MB`);
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (result.summary) {
|
|
44
|
-
console.log('\nSummary:');
|
|
45
|
-
console.log(` Duration: ${(result.summary.durationMs / 1000).toFixed(1)}s`);
|
|
46
|
-
console.log(` Sample count: ${result.summary.sampleCount}`);
|
|
47
|
-
console.log(` Avg CPU: ${result.summary.avgProcessCPU.toFixed(1)}%`);
|
|
48
|
-
console.log(` Max CPU: ${result.summary.maxProcessCPU.toFixed(1)}%`);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
testPerformanceTracking().catch(console.error);
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Test script to verify performance tracking during recording
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { startRecording, stopRecording } from './lib/recorder.js';
|
|
8
|
-
import { logger, setVerbose } from './lib/logger.js';
|
|
9
|
-
import fs from 'fs';
|
|
10
|
-
|
|
11
|
-
// Enable verbose logging
|
|
12
|
-
setVerbose(true);
|
|
13
|
-
|
|
14
|
-
async function testPerformanceTracking() {
|
|
15
|
-
try {
|
|
16
|
-
logger.info('Starting performance tracking test...');
|
|
17
|
-
|
|
18
|
-
// Start recording
|
|
19
|
-
logger.info('Starting recording...');
|
|
20
|
-
const startResult = await startRecording({
|
|
21
|
-
fps: 10,
|
|
22
|
-
includeAudio: false
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
logger.info('Recording started', {
|
|
26
|
-
outputPath: startResult.outputPath,
|
|
27
|
-
startTime: startResult.startTime
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
// Record for 10 seconds
|
|
31
|
-
logger.info('Recording for 10 seconds...');
|
|
32
|
-
await new Promise(resolve => setTimeout(resolve, 10000));
|
|
33
|
-
|
|
34
|
-
// Stop recording
|
|
35
|
-
logger.info('Stopping recording...');
|
|
36
|
-
const result = await stopRecording();
|
|
37
|
-
|
|
38
|
-
logger.info('Recording stopped successfully');
|
|
39
|
-
|
|
40
|
-
// Display performance results
|
|
41
|
-
if (result.performance) {
|
|
42
|
-
logger.info('=== Performance Tracking Results ===');
|
|
43
|
-
|
|
44
|
-
if (result.performance.summary) {
|
|
45
|
-
const summary = result.performance.summary;
|
|
46
|
-
logger.info('Summary Statistics:');
|
|
47
|
-
logger.info(` Duration: ${(summary.durationMs / 1000).toFixed(1)}s`);
|
|
48
|
-
logger.info(` Sample Count: ${summary.sampleCount}`);
|
|
49
|
-
logger.info(` Monitor Interval: ${summary.monitorInterval}ms`);
|
|
50
|
-
logger.info('');
|
|
51
|
-
logger.info('Process Metrics:');
|
|
52
|
-
logger.info(` Average CPU: ${summary.avgProcessCPU.toFixed(1)}%`);
|
|
53
|
-
logger.info(` Max CPU: ${summary.maxProcessCPU.toFixed(1)}%`);
|
|
54
|
-
logger.info(` Average Memory: ${summary.avgProcessMemoryMB.toFixed(1)} MB`);
|
|
55
|
-
logger.info(` Max Memory: ${summary.maxProcessMemoryMB.toFixed(1)} MB`);
|
|
56
|
-
logger.info('');
|
|
57
|
-
logger.info('System Metrics:');
|
|
58
|
-
logger.info(` Average System Memory Usage: ${summary.avgSystemMemoryUsagePercent.toFixed(1)}%`);
|
|
59
|
-
logger.info(` Max System Memory Usage: ${summary.maxSystemMemoryUsagePercent.toFixed(1)}%`);
|
|
60
|
-
logger.info(` Total System Memory: ${summary.totalSystemMemoryGB.toFixed(2)} GB`);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (result.performance.samples && result.performance.samples.length > 0) {
|
|
64
|
-
logger.info('');
|
|
65
|
-
logger.info(`Collected ${result.performance.samples.length} performance samples`);
|
|
66
|
-
|
|
67
|
-
// Show top processes from the last sample
|
|
68
|
-
const lastSample = result.performance.samples[result.performance.samples.length - 1];
|
|
69
|
-
if (lastSample.topProcesses && lastSample.topProcesses.length > 0) {
|
|
70
|
-
logger.info('');
|
|
71
|
-
logger.info('Top 10 Processes (from last sample):');
|
|
72
|
-
lastSample.topProcesses.forEach((proc, index) => {
|
|
73
|
-
logger.info(` ${index + 1}. ${proc.name} (PID: ${proc.pid})`);
|
|
74
|
-
logger.info(` CPU: ${proc.cpu.toFixed(1)}%, Memory: ${(proc.memory / (1024 * 1024)).toFixed(1)} MB`);
|
|
75
|
-
});
|
|
76
|
-
logger.info(`Total processes on system: ${lastSample.totalProcesses}`);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
} else {
|
|
80
|
-
logger.warn('No performance data in result');
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Display other results
|
|
84
|
-
logger.info('');
|
|
85
|
-
logger.info('=== Recording Results ===');
|
|
86
|
-
logger.info(`Output: ${result.outputPath}`);
|
|
87
|
-
logger.info(`Duration: ${result.duration}ms`);
|
|
88
|
-
logger.info(`File Size: ${(result.fileSize / 1024 / 1024).toFixed(2)} MB`);
|
|
89
|
-
logger.info(`Apps Tracked: ${result.apps?.length || 0}`);
|
|
90
|
-
logger.info(`Log Events: ${result.logs?.reduce((sum, log) => sum + log.count, 0) || 0}`);
|
|
91
|
-
|
|
92
|
-
// Verify file exists
|
|
93
|
-
if (fs.existsSync(result.outputPath)) {
|
|
94
|
-
logger.info('Recording file created successfully');
|
|
95
|
-
} else {
|
|
96
|
-
logger.error('Recording file not found!');
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
logger.info('Test completed successfully!');
|
|
100
|
-
|
|
101
|
-
} catch (error) {
|
|
102
|
-
logger.error('Test failed:', error);
|
|
103
|
-
process.exit(1);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Run the test
|
|
108
|
-
testPerformanceTracking();
|
package/test-short-recording.js
DELETED
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Test script for analyzing short recording issues
|
|
5
|
-
*
|
|
6
|
-
* This tests whether very short recordings produce valid multi-frame videos
|
|
7
|
-
* with properly finalized WebM container metadata.
|
|
8
|
-
*
|
|
9
|
-
* Known issue: If ffmpeg/VP9 encoder is killed too quickly, the WebM container
|
|
10
|
-
* metadata (especially duration) may be incomplete, causing playback issues.
|
|
11
|
-
*
|
|
12
|
-
* Usage:
|
|
13
|
-
* node test-short-recording.js # Run recording tests
|
|
14
|
-
* node test-short-recording.js analyze <file> # Analyze existing video
|
|
15
|
-
* node test-short-recording.js fix <input> <output> # Fix broken video container
|
|
16
|
-
*
|
|
17
|
-
* Platform notes:
|
|
18
|
-
* - macOS: Uses AVFoundation for screen capture
|
|
19
|
-
* - Linux: Uses X11grab for screen capture
|
|
20
|
-
* - Windows: Uses gdigrab for screen capture
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
import { startRecording, stopRecording, fixVideoContainer } from './lib/recorder.js';
|
|
24
|
-
import { execa } from 'execa';
|
|
25
|
-
import { getFfprobePath } from './lib/binaries.js';
|
|
26
|
-
import fs from 'fs';
|
|
27
|
-
import path from 'path';
|
|
28
|
-
import os from 'os';
|
|
29
|
-
|
|
30
|
-
async function analyzeVideo(videoPath) {
|
|
31
|
-
const ffprobePath = await getFfprobePath();
|
|
32
|
-
|
|
33
|
-
console.log(`\nAnalyzing video: ${videoPath}`);
|
|
34
|
-
console.log('='.repeat(80));
|
|
35
|
-
|
|
36
|
-
// Check if file exists
|
|
37
|
-
if (!fs.existsSync(videoPath)) {
|
|
38
|
-
console.error(`Video file does not exist: ${videoPath}`);
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const stats = fs.statSync(videoPath);
|
|
43
|
-
console.log(`File size: ${(stats.size / 1024).toFixed(2)} KB`);
|
|
44
|
-
|
|
45
|
-
try {
|
|
46
|
-
// Get basic format info
|
|
47
|
-
const formatResult = await execa(ffprobePath, [
|
|
48
|
-
'-v', 'error',
|
|
49
|
-
'-show_entries', 'format=duration,size,bit_rate',
|
|
50
|
-
'-of', 'json',
|
|
51
|
-
videoPath
|
|
52
|
-
]);
|
|
53
|
-
|
|
54
|
-
const formatData = JSON.parse(formatResult.stdout);
|
|
55
|
-
console.log(`Duration: ${formatData.format.duration || 'unknown'}s`);
|
|
56
|
-
console.log(`Bit rate: ${formatData.format.bit_rate || 'unknown'} bits/s`);
|
|
57
|
-
|
|
58
|
-
// Get stream info
|
|
59
|
-
const streamResult = await execa(ffprobePath, [
|
|
60
|
-
'-v', 'error',
|
|
61
|
-
'-show_entries', 'stream=codec_name,width,height,r_frame_rate,duration',
|
|
62
|
-
'-of', 'json',
|
|
63
|
-
videoPath
|
|
64
|
-
]);
|
|
65
|
-
|
|
66
|
-
const streamData = JSON.parse(streamResult.stdout);
|
|
67
|
-
const videoStream = streamData.streams.find(s => s.codec_name);
|
|
68
|
-
|
|
69
|
-
if (videoStream) {
|
|
70
|
-
console.log(`Codec: ${videoStream.codec_name}`);
|
|
71
|
-
console.log(`Resolution: ${videoStream.width}x${videoStream.height}`);
|
|
72
|
-
console.log(`Frame rate: ${videoStream.r_frame_rate}`);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Count actual frames
|
|
76
|
-
const frameResult = await execa(ffprobePath, [
|
|
77
|
-
'-v', 'error',
|
|
78
|
-
'-count_frames',
|
|
79
|
-
'-select_streams', 'v:0',
|
|
80
|
-
'-show_entries', 'stream=nb_read_frames',
|
|
81
|
-
'-of', 'default=nokey=1:noprint_wrappers=1',
|
|
82
|
-
videoPath
|
|
83
|
-
], { reject: false });
|
|
84
|
-
|
|
85
|
-
const frameCount = parseInt(frameResult.stdout.trim());
|
|
86
|
-
console.log(`Frame count: ${frameCount || 'unknown'}`);
|
|
87
|
-
|
|
88
|
-
if (frameResult.stderr) {
|
|
89
|
-
console.log(`FFprobe warnings: ${frameResult.stderr.trim()}`);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Check if duration is available in container
|
|
93
|
-
const hasDuration = formatData.format.duration && !isNaN(parseFloat(formatData.format.duration));
|
|
94
|
-
|
|
95
|
-
// Determine if this is a single-frame video issue
|
|
96
|
-
const isSingleFrame = frameCount === 1;
|
|
97
|
-
const hasEncodingIssues = frameResult.stderr.includes('File ended prematurely');
|
|
98
|
-
const hasMissingMetadata = !hasDuration;
|
|
99
|
-
|
|
100
|
-
console.log('\nAnalysis Result:');
|
|
101
|
-
console.log(` Single frame: ${isSingleFrame ? 'YES (BUG!)' : 'NO'}`);
|
|
102
|
-
console.log(` Encoding issues: ${hasEncodingIssues ? 'YES' : 'NO'}`);
|
|
103
|
-
console.log(` Missing metadata: ${hasMissingMetadata ? 'YES (container incomplete)' : 'NO'}`);
|
|
104
|
-
console.log(` Platform: ${os.platform()}`);
|
|
105
|
-
|
|
106
|
-
return {
|
|
107
|
-
exists: true,
|
|
108
|
-
size: stats.size,
|
|
109
|
-
duration: parseFloat(formatData.format.duration),
|
|
110
|
-
frameCount,
|
|
111
|
-
codec: videoStream?.codec_name,
|
|
112
|
-
resolution: videoStream ? `${videoStream.width}x${videoStream.height}` : 'unknown',
|
|
113
|
-
isSingleFrame,
|
|
114
|
-
hasEncodingIssues,
|
|
115
|
-
hasMissingMetadata,
|
|
116
|
-
platform: os.platform()
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
} catch (error) {
|
|
120
|
-
console.error(`Error analyzing video: ${error.message}`);
|
|
121
|
-
return null;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
async function testShortRecording(duration = 3000) {
|
|
126
|
-
console.log(`\nTesting ${duration}ms recording...`);
|
|
127
|
-
console.log('='.repeat(80));
|
|
128
|
-
|
|
129
|
-
try {
|
|
130
|
-
// Start recording
|
|
131
|
-
console.log('Starting recording...');
|
|
132
|
-
const { outputPath, startTime } = await startRecording({
|
|
133
|
-
fps: 30,
|
|
134
|
-
includeAudio: false
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
console.log(`Recording started at: ${outputPath}`);
|
|
138
|
-
|
|
139
|
-
// Wait for specified duration
|
|
140
|
-
console.log(`Recording for ${duration}ms...`);
|
|
141
|
-
await new Promise(resolve => setTimeout(resolve, duration));
|
|
142
|
-
|
|
143
|
-
// Stop recording
|
|
144
|
-
console.log('Stopping recording...');
|
|
145
|
-
const result = await stopRecording();
|
|
146
|
-
|
|
147
|
-
console.log(`Recording stopped`);
|
|
148
|
-
console.log(` Duration: ${result.duration}ms`);
|
|
149
|
-
console.log(` File: ${result.outputPath}`);
|
|
150
|
-
|
|
151
|
-
// Analyze the output
|
|
152
|
-
await analyzeVideo(result.outputPath);
|
|
153
|
-
|
|
154
|
-
return result;
|
|
155
|
-
|
|
156
|
-
} catch (error) {
|
|
157
|
-
console.error(`Test failed: ${error.message}`);
|
|
158
|
-
console.error(error.stack);
|
|
159
|
-
throw error;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
async function testExistingVideo(videoPath) {
|
|
164
|
-
console.log('\nTesting existing video...');
|
|
165
|
-
console.log('='.repeat(80));
|
|
166
|
-
|
|
167
|
-
return await analyzeVideo(videoPath);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Main test runner
|
|
171
|
-
async function main() {
|
|
172
|
-
const args = process.argv.slice(2);
|
|
173
|
-
|
|
174
|
-
console.log('\nShort Recording Test Suite');
|
|
175
|
-
console.log('='.repeat(80));
|
|
176
|
-
console.log(`Platform: ${os.platform()}`);
|
|
177
|
-
console.log(`Architecture: ${os.arch()}`);
|
|
178
|
-
console.log(`Node version: ${process.version}`);
|
|
179
|
-
|
|
180
|
-
if (args[0] === 'analyze' && args[1]) {
|
|
181
|
-
// Analyze existing video
|
|
182
|
-
const videoPath = path.resolve(args[1]);
|
|
183
|
-
const result = await testExistingVideo(videoPath);
|
|
184
|
-
|
|
185
|
-
if (result?.isSingleFrame) {
|
|
186
|
-
console.log('\nSINGLE-FRAME VIDEO DETECTED!');
|
|
187
|
-
process.exit(1);
|
|
188
|
-
} else if (result?.hasMissingMetadata) {
|
|
189
|
-
console.log('\nWARNING: Video container metadata is incomplete!');
|
|
190
|
-
console.log(' This can cause playback issues in some players.');
|
|
191
|
-
console.log(' The video has frames but duration is not in the container.');
|
|
192
|
-
console.log('\nTry fixing it with:');
|
|
193
|
-
console.log(` node test-short-recording.js fix ${args[1]} ${args[1].replace(/\.(webm|mp4)$/, '-fixed.$1')}`);
|
|
194
|
-
process.exit(1);
|
|
195
|
-
}
|
|
196
|
-
} else if (args[0] === 'fix' && args[1] && args[2]) {
|
|
197
|
-
// Fix existing broken video
|
|
198
|
-
const inputPath = path.resolve(args[1]);
|
|
199
|
-
const outputPath = path.resolve(args[2]);
|
|
200
|
-
|
|
201
|
-
console.log('\nFixing video container...');
|
|
202
|
-
console.log('='.repeat(80));
|
|
203
|
-
console.log(`Input: ${inputPath}`);
|
|
204
|
-
console.log(`Output: ${outputPath}`);
|
|
205
|
-
|
|
206
|
-
if (!fs.existsSync(inputPath)) {
|
|
207
|
-
console.error(`Input file does not exist: ${inputPath}`);
|
|
208
|
-
process.exit(1);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Analyze before
|
|
212
|
-
console.log('\nBEFORE:');
|
|
213
|
-
const beforeResult = await analyzeVideo(inputPath);
|
|
214
|
-
|
|
215
|
-
// Fix the video
|
|
216
|
-
const fixSuccess = await fixVideoContainer(inputPath, outputPath);
|
|
217
|
-
|
|
218
|
-
if (!fixSuccess) {
|
|
219
|
-
console.error('\nFailed to fix video!');
|
|
220
|
-
process.exit(1);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Analyze after
|
|
224
|
-
console.log('\nAFTER:');
|
|
225
|
-
const afterResult = await analyzeVideo(outputPath);
|
|
226
|
-
|
|
227
|
-
console.log('\nVideo fixed successfully!');
|
|
228
|
-
console.log(` Before: ${beforeResult?.hasMissingMetadata ? 'Missing metadata' : 'Has metadata'}`);
|
|
229
|
-
console.log(` After: ${afterResult?.hasMissingMetadata ? 'Missing metadata' : 'Has metadata'}`);
|
|
230
|
-
|
|
231
|
-
if (afterResult?.hasMissingMetadata) {
|
|
232
|
-
console.log('\nWarning: Metadata still missing after fix. The source file may be corrupted.');
|
|
233
|
-
process.exit(1);
|
|
234
|
-
}
|
|
235
|
-
} else {
|
|
236
|
-
// Run recording tests with different durations
|
|
237
|
-
const testDurations = [1000, 2000, 3000, 5000];
|
|
238
|
-
const results = [];
|
|
239
|
-
|
|
240
|
-
for (const duration of testDurations) {
|
|
241
|
-
try {
|
|
242
|
-
const result = await testShortRecording(duration);
|
|
243
|
-
results.push({ duration, success: true, result });
|
|
244
|
-
|
|
245
|
-
// Clean up
|
|
246
|
-
try {
|
|
247
|
-
fs.unlinkSync(result.outputPath);
|
|
248
|
-
if (result.gifPath && fs.existsSync(result.gifPath)) {
|
|
249
|
-
fs.unlinkSync(result.gifPath);
|
|
250
|
-
}
|
|
251
|
-
if (result.snapshotPath && fs.existsSync(result.snapshotPath)) {
|
|
252
|
-
fs.unlinkSync(result.snapshotPath);
|
|
253
|
-
}
|
|
254
|
-
} catch (cleanupError) {
|
|
255
|
-
console.warn(`Cleanup warning: ${cleanupError.message}`);
|
|
256
|
-
}
|
|
257
|
-
} catch (error) {
|
|
258
|
-
results.push({ duration, success: false, error: error.message });
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// Wait between tests
|
|
262
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// Summary
|
|
266
|
-
console.log('\n\nTEST SUMMARY');
|
|
267
|
-
console.log('='.repeat(80));
|
|
268
|
-
|
|
269
|
-
for (const result of results) {
|
|
270
|
-
const status = result.success ? 'PASS' : 'FAIL';
|
|
271
|
-
console.log(`${status} ${result.duration}ms recording: ${result.success ? 'PASSED' : result.error}`);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
const allPassed = results.every(r => r.success);
|
|
275
|
-
if (!allPassed) {
|
|
276
|
-
console.log('\nSome tests failed!');
|
|
277
|
-
process.exit(1);
|
|
278
|
-
} else {
|
|
279
|
-
console.log('\nAll tests passed!');
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
main().catch(error => {
|
|
285
|
-
console.error('Fatal error:', error);
|
|
286
|
-
process.exit(1);
|
|
287
|
-
});
|
package/test-top-processes.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { getTopProcesses } from './lib/topProcesses.js';
|
|
4
|
-
import { logger, setVerbose } from './lib/logger.js';
|
|
5
|
-
|
|
6
|
-
setVerbose(true);
|
|
7
|
-
|
|
8
|
-
async function test() {
|
|
9
|
-
console.log('Testing getTopProcesses...\n');
|
|
10
|
-
|
|
11
|
-
const processes = await getTopProcesses(10);
|
|
12
|
-
|
|
13
|
-
console.log(`Found ${processes.length} processes:\n`);
|
|
14
|
-
|
|
15
|
-
processes.forEach((proc, index) => {
|
|
16
|
-
console.log(`${index + 1}. ${proc.name} (PID: ${proc.pid})`);
|
|
17
|
-
console.log(` CPU: ${proc.cpu}%`);
|
|
18
|
-
console.log(` Memory: ${proc.mem || proc.memBytes}${proc.memBytes ? ' bytes' : '%'}`);
|
|
19
|
-
console.log();
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
test().catch(console.error);
|
package/test.log
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"message": "test log entry", "level": "info", "timestamp": 1761692597000}
|