forked from wulkano/Aperture
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathindex.js
More file actions
117 lines (98 loc) · 2.99 KB
/
index.js
File metadata and controls
117 lines (98 loc) · 2.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
'use strict';
const os = require('os');
const util = require('util');
const path = require('path');
const execa = require('execa');
const tmp = require('tmp');
const debuglog = util.debuglog('aperture');
const isYosemiteOrHigher = process.platform === 'darwin' && Number(os.release().split('.')[0]) >= 14;
class Aperture {
constructor() {
if (!isYosemiteOrHigher) {
throw new Error('Requires macOS 10.10 or higher');
}
}
getAudioSources() {
return execa.stdout(path.join(__dirname, 'swift/main'), ['list-audio-devices']).then(JSON.parse);
}
startRecording({
fps = 30,
cropArea = 'none',
showCursor = true,
highlightClicks = false,
displayId = 'main',
audioSourceId = 'none'
} = {}) {
return new Promise((resolve, reject) => {
if (this.recorder !== undefined) {
reject(new Error('Call `.stopRecording()` first'));
return;
}
if (highlightClicks === true) {
showCursor = true;
}
this.tmpPath = tmp.tmpNameSync({postfix: '.mp4'});
if (typeof cropArea === 'object') {
if (typeof cropArea.x !== 'number' ||
typeof cropArea.y !== 'number' ||
typeof cropArea.width !== 'number' ||
typeof cropArea.height !== 'number') {
reject(new Error('Invalid `cropArea` option object'));
return;
}
cropArea = `${cropArea.x}:${cropArea.y}:${cropArea.width}:${cropArea.height}`;
}
const recorderOpts = [
this.tmpPath,
fps,
cropArea,
showCursor,
highlightClicks,
displayId,
audioSourceId
];
this.recorder = execa(path.join(__dirname, 'swift', 'main'), recorderOpts);
const timeout = setTimeout(() => {
// `.stopRecording()` was called already
if (this.recorder === undefined) {
return;
}
const err = new Error('Could not start recording within 5 seconds');
err.code = 'RECORDER_TIMEOUT';
this.recorder.kill();
delete this.recorder;
reject(err);
}, 5000);
this.recorder.catch(err => {
clearTimeout(timeout);
delete this.recorder;
reject(err.stderr ? new Error(err.stderr) : err);
});
this.recorder.stdout.setEncoding('utf8');
this.recorder.stdout.on('data', data => {
debuglog(data);
if (data.trim() === 'R') {
// `R` is printed by Swift when the recording **actually** starts
clearTimeout(timeout);
resolve(this.tmpPath);
}
});
});
}
stopRecording() {
return new Promise((resolve, reject) => {
if (this.recorder === undefined) {
reject(new Error('Call `.startRecording()` first'));
return;
}
this.recorder.then(() => {
delete this.recorder;
resolve(this.tmpPath);
}).catch(err => {
reject(err.stderr ? new Error(err.stderr) : err);
});
this.recorder.kill();
});
}
}
module.exports = () => new Aperture();