node-mac-recorder 1.0.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 node-mac-recorder
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,492 @@
1
+ # node-mac-recorder
2
+
3
+ A powerful native macOS screen recording Node.js package with advanced window selection, multi-display support, and granular audio controls. Built with AVFoundation for optimal performance.
4
+
5
+ ## Features
6
+
7
+ ✨ **Advanced Recording Capabilities**
8
+
9
+ - 🖥️ **Full Screen Recording** - Capture entire displays
10
+ - 🪟 **Window-Specific Recording** - Record individual application windows
11
+ - 🎯 **Area Selection** - Record custom screen regions
12
+ - 🖱️ **Multi-Display Support** - Automatic display detection and selection
13
+ - 🎨 **Cursor Control** - Toggle cursor visibility in recordings
14
+
15
+ 🎵 **Granular Audio Controls**
16
+
17
+ - 🎤 **Microphone Audio** - Separate microphone control (default: off)
18
+ - 🔊 **System Audio** - System audio capture (default: on)
19
+ - 📻 **Audio Device Listing** - Enumerate available audio devices
20
+ - 🎛️ **Device Selection** - Choose specific audio input devices
21
+
22
+ 🔧 **Smart Window Management**
23
+
24
+ - 📋 **Window Discovery** - List all visible application windows
25
+ - 🎯 **Automatic Coordinate Conversion** - Handle multi-display coordinate systems
26
+ - 📐 **Display ID Detection** - Automatically select correct display for window recording
27
+ - 🖼️ **Window Filtering** - Smart filtering of recordable windows
28
+
29
+ ⚙️ **Customization Options**
30
+
31
+ - 🎬 **Quality Control** - Adjustable recording quality presets
32
+ - 🎞️ **Frame Rate Control** - Custom frame rate settings
33
+ - 📁 **Flexible Output** - Custom output paths and formats
34
+ - 🔐 **Permission Management** - Built-in permission checking
35
+
36
+ ## Installation
37
+
38
+ ```bash
39
+ npm install node-mac-recorder
40
+ ```
41
+
42
+ ### Requirements
43
+
44
+ - **macOS 10.15+** (Catalina or later)
45
+ - **Node.js 14+**
46
+ - **Xcode Command Line Tools**
47
+ - **Screen Recording Permission** (automatically requested)
48
+
49
+ ### Build Requirements
50
+
51
+ ```bash
52
+ # Install Xcode Command Line Tools
53
+ xcode-select --install
54
+
55
+ # The package will automatically build native modules during installation
56
+ ```
57
+
58
+ ## Quick Start
59
+
60
+ ```javascript
61
+ const MacRecorder = require("node-mac-recorder");
62
+
63
+ const recorder = new MacRecorder();
64
+
65
+ // Simple full-screen recording
66
+ await recorder.startRecording("./output.mov");
67
+ await new Promise((resolve) => setTimeout(resolve, 5000)); // Record for 5 seconds
68
+ await recorder.stopRecording();
69
+ ```
70
+
71
+ ## API Reference
72
+
73
+ ### Constructor
74
+
75
+ ```javascript
76
+ const recorder = new MacRecorder();
77
+ ```
78
+
79
+ ### Methods
80
+
81
+ #### `startRecording(outputPath, options?)`
82
+
83
+ Starts screen recording with the specified options.
84
+
85
+ ```javascript
86
+ await recorder.startRecording("./recording.mov", {
87
+ // Audio Controls
88
+ includeMicrophone: false, // Enable microphone (default: false)
89
+ includeSystemAudio: true, // Enable system audio (default: true)
90
+
91
+ // Display & Window Selection
92
+ displayId: 0, // Display index (null = main display)
93
+ windowId: 12345, // Specific window ID
94
+ captureArea: {
95
+ // Custom area selection
96
+ x: 100,
97
+ y: 100,
98
+ width: 800,
99
+ height: 600,
100
+ },
101
+
102
+ // Recording Options
103
+ quality: "high", // 'low', 'medium', 'high'
104
+ frameRate: 30, // FPS (15, 30, 60)
105
+ captureCursor: false, // Show cursor (default: false)
106
+ });
107
+ ```
108
+
109
+ #### `stopRecording()`
110
+
111
+ Stops the current recording.
112
+
113
+ ```javascript
114
+ const result = await recorder.stopRecording();
115
+ console.log("Recording saved to:", result.outputPath);
116
+ ```
117
+
118
+ #### `getWindows()`
119
+
120
+ Returns a list of all recordable windows.
121
+
122
+ ```javascript
123
+ const windows = await recorder.getWindows();
124
+ console.log(windows);
125
+ // [
126
+ // {
127
+ // id: 12345,
128
+ // name: "My App Window",
129
+ // appName: "MyApp",
130
+ // x: 100, y: 200,
131
+ // width: 800, height: 600
132
+ // },
133
+ // ...
134
+ // ]
135
+ ```
136
+
137
+ #### `getDisplays()`
138
+
139
+ Returns information about all available displays.
140
+
141
+ ```javascript
142
+ const displays = await recorder.getDisplays();
143
+ console.log(displays);
144
+ // [
145
+ // {
146
+ // id: 69733504,
147
+ // name: "Display 1",
148
+ // resolution: "2048x1330",
149
+ // x: 0, y: 0
150
+ // },
151
+ // ...
152
+ // ]
153
+ ```
154
+
155
+ #### `getAudioDevices()`
156
+
157
+ Lists all available audio input devices.
158
+
159
+ ```javascript
160
+ const devices = await recorder.getAudioDevices();
161
+ console.log(devices);
162
+ // [
163
+ // {
164
+ // id: "device-id-123",
165
+ // name: "Built-in Microphone",
166
+ // manufacturer: "Apple Inc.",
167
+ // isDefault: true
168
+ // },
169
+ // ...
170
+ // ]
171
+ ```
172
+
173
+ #### `checkPermissions()`
174
+
175
+ Checks macOS recording permissions.
176
+
177
+ ```javascript
178
+ const permissions = await recorder.checkPermissions();
179
+ console.log(permissions);
180
+ // {
181
+ // screenRecording: true,
182
+ // microphone: true,
183
+ // accessibility: true
184
+ // }
185
+ ```
186
+
187
+ #### `getStatus()`
188
+
189
+ Returns current recording status and options.
190
+
191
+ ```javascript
192
+ const status = recorder.getStatus();
193
+ console.log(status);
194
+ // {
195
+ // isRecording: true,
196
+ // outputPath: "./recording.mov",
197
+ // options: { ... },
198
+ // recordingTime: 15
199
+ // }
200
+ ```
201
+
202
+ ## Usage Examples
203
+
204
+ ### Window-Specific Recording
205
+
206
+ ```javascript
207
+ const recorder = new MacRecorder();
208
+
209
+ // List available windows
210
+ const windows = await recorder.getWindows();
211
+ console.log("Available windows:");
212
+ windows.forEach((win, i) => {
213
+ console.log(`${i + 1}. ${win.appName} - ${win.name}`);
214
+ });
215
+
216
+ // Record a specific window
217
+ const targetWindow = windows.find((w) => w.appName === "Safari");
218
+ await recorder.startRecording("./safari-recording.mov", {
219
+ windowId: targetWindow.id,
220
+ includeSystemAudio: false,
221
+ includeMicrophone: true,
222
+ captureCursor: true,
223
+ });
224
+
225
+ await new Promise((resolve) => setTimeout(resolve, 10000)); // 10 seconds
226
+ await recorder.stopRecording();
227
+ ```
228
+
229
+ ### Multi-Display Recording
230
+
231
+ ```javascript
232
+ const recorder = new MacRecorder();
233
+
234
+ // List available displays
235
+ const displays = await recorder.getDisplays();
236
+ console.log("Available displays:");
237
+ displays.forEach((display, i) => {
238
+ console.log(`${i}: ${display.resolution} at (${display.x}, ${display.y})`);
239
+ });
240
+
241
+ // Record from second display
242
+ await recorder.startRecording("./second-display.mov", {
243
+ displayId: 1, // Second display
244
+ quality: "high",
245
+ frameRate: 60,
246
+ });
247
+
248
+ await new Promise((resolve) => setTimeout(resolve, 5000));
249
+ await recorder.stopRecording();
250
+ ```
251
+
252
+ ### Custom Area Recording
253
+
254
+ ```javascript
255
+ const recorder = new MacRecorder();
256
+
257
+ // Record specific screen area
258
+ await recorder.startRecording("./area-recording.mov", {
259
+ captureArea: {
260
+ x: 200,
261
+ y: 100,
262
+ width: 1200,
263
+ height: 800,
264
+ },
265
+ quality: "medium",
266
+ captureCursor: false,
267
+ });
268
+
269
+ await new Promise((resolve) => setTimeout(resolve, 8000));
270
+ await recorder.stopRecording();
271
+ ```
272
+
273
+ ### Audio-Only System Recording
274
+
275
+ ```javascript
276
+ const recorder = new MacRecorder();
277
+
278
+ // Record system audio without microphone
279
+ await recorder.startRecording("./system-audio.mov", {
280
+ includeMicrophone: false,
281
+ includeSystemAudio: true,
282
+ captureArea: { x: 0, y: 0, width: 1, height: 1 }, // Minimal video
283
+ });
284
+ ```
285
+
286
+ ### Event-Driven Recording
287
+
288
+ ```javascript
289
+ const recorder = new MacRecorder();
290
+
291
+ // Listen to recording events
292
+ recorder.on("started", (outputPath) => {
293
+ console.log("Recording started:", outputPath);
294
+ });
295
+
296
+ recorder.on("stopped", (result) => {
297
+ console.log("Recording stopped:", result);
298
+ });
299
+
300
+ recorder.on("timeUpdate", (seconds) => {
301
+ console.log(`Recording time: ${seconds}s`);
302
+ });
303
+
304
+ recorder.on("completed", (outputPath) => {
305
+ console.log("Recording completed:", outputPath);
306
+ });
307
+
308
+ await recorder.startRecording("./event-recording.mov");
309
+ ```
310
+
311
+ ## Integration Examples
312
+
313
+ ### Electron Integration
314
+
315
+ ```javascript
316
+ // In main process
317
+ const { ipcMain } = require("electron");
318
+ const MacRecorder = require("node-mac-recorder");
319
+
320
+ const recorder = new MacRecorder();
321
+
322
+ ipcMain.handle("start-recording", async (event, options) => {
323
+ try {
324
+ await recorder.startRecording("./recording.mov", options);
325
+ return { success: true };
326
+ } catch (error) {
327
+ return { success: false, error: error.message };
328
+ }
329
+ });
330
+
331
+ ipcMain.handle("stop-recording", async () => {
332
+ const result = await recorder.stopRecording();
333
+ return result;
334
+ });
335
+
336
+ ipcMain.handle("get-windows", async () => {
337
+ return await recorder.getWindows();
338
+ });
339
+ ```
340
+
341
+ ### Express.js API
342
+
343
+ ```javascript
344
+ const express = require("express");
345
+ const MacRecorder = require("node-mac-recorder");
346
+
347
+ const app = express();
348
+ const recorder = new MacRecorder();
349
+
350
+ app.post("/start-recording", async (req, res) => {
351
+ try {
352
+ const { windowId, duration } = req.body;
353
+ await recorder.startRecording("./api-recording.mov", { windowId });
354
+
355
+ setTimeout(async () => {
356
+ await recorder.stopRecording();
357
+ }, duration * 1000);
358
+
359
+ res.json({ status: "started" });
360
+ } catch (error) {
361
+ res.status(500).json({ error: error.message });
362
+ }
363
+ });
364
+
365
+ app.get("/windows", async (req, res) => {
366
+ const windows = await recorder.getWindows();
367
+ res.json(windows);
368
+ });
369
+ ```
370
+
371
+ ## Advanced Features
372
+
373
+ ### Automatic Display Detection
374
+
375
+ When recording windows, the package automatically:
376
+
377
+ 1. **Detects Window Location** - Determines which display contains the window
378
+ 2. **Converts Coordinates** - Translates global coordinates to display-relative coordinates
379
+ 3. **Sets Display ID** - Automatically selects the correct display for recording
380
+ 4. **Handles Multi-Monitor** - Works seamlessly across multiple displays
381
+
382
+ ```javascript
383
+ // Window at (-2000, 100) on second display
384
+ // Automatically converts to (440, 100) on display 1
385
+ await recorder.startRecording("./auto-display.mov", {
386
+ windowId: 12345, // Package handles display detection automatically
387
+ });
388
+ ```
389
+
390
+ ### Smart Window Filtering
391
+
392
+ The `getWindows()` method automatically filters out:
393
+
394
+ - System windows (Dock, Menu Bar)
395
+ - Hidden windows
396
+ - Very small windows (< 50x50 pixels)
397
+ - Windows without names
398
+
399
+ ### Performance Optimization
400
+
401
+ - **Native Implementation** - Uses AVFoundation for optimal performance
402
+ - **Minimal Overhead** - Low CPU usage during recording
403
+ - **Memory Efficient** - Proper memory management in native layer
404
+ - **Quality Presets** - Balanced quality/performance options
405
+
406
+ ## Troubleshooting
407
+
408
+ ### Permission Issues
409
+
410
+ If recording fails, check macOS permissions:
411
+
412
+ ```bash
413
+ # Open System Preferences > Security & Privacy > Screen Recording
414
+ # Ensure your app/terminal has permission
415
+ ```
416
+
417
+ ### Build Errors
418
+
419
+ ```bash
420
+ # Reinstall with verbose output
421
+ npm install node-mac-recorder --verbose
422
+
423
+ # Clear npm cache
424
+ npm cache clean --force
425
+
426
+ # Ensure Xcode tools are installed
427
+ xcode-select --install
428
+ ```
429
+
430
+ ### Recording Issues
431
+
432
+ 1. **Empty/Black Video**: Check screen recording permissions
433
+ 2. **No Audio**: Verify audio permissions and device availability
434
+ 3. **Window Not Found**: Ensure target window is visible and not minimized
435
+ 4. **Coordinate Issues**: Window may be on different display (handled automatically)
436
+
437
+ ### Debug Information
438
+
439
+ ```javascript
440
+ // Get module information
441
+ const info = recorder.getModuleInfo();
442
+ console.log("Module info:", info);
443
+
444
+ // Check recording status
445
+ const status = recorder.getStatus();
446
+ console.log("Recording status:", status);
447
+
448
+ // Verify permissions
449
+ const permissions = await recorder.checkPermissions();
450
+ console.log("Permissions:", permissions);
451
+ ```
452
+
453
+ ## Performance Considerations
454
+
455
+ - **Recording Quality**: Higher quality increases file size and CPU usage
456
+ - **Frame Rate**: 30fps recommended for most use cases, 60fps for smooth motion
457
+ - **Audio**: System audio capture adds minimal overhead
458
+ - **Window Recording**: Slightly more efficient than full-screen recording
459
+ - **Multi-Display**: No significant performance impact
460
+
461
+ ## File Formats
462
+
463
+ - **Output Format**: MOV (QuickTime)
464
+ - **Video Codec**: H.264
465
+ - **Audio Codec**: AAC
466
+ - **Container**: QuickTime compatible
467
+
468
+ ## Contributing
469
+
470
+ 1. Fork the repository
471
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
472
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
473
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
474
+ 5. Open a Pull Request
475
+
476
+ ## License
477
+
478
+ MIT License - see [LICENSE](LICENSE) file for details.
479
+
480
+ ## Changelog
481
+
482
+ ### Latest Updates
483
+
484
+ - ✅ **Window Recording**: Automatic coordinate conversion for multi-display setups
485
+ - ✅ **Audio Controls**: Separate microphone and system audio controls
486
+ - ✅ **Display Selection**: Multi-monitor support with automatic detection
487
+ - ✅ **Smart Filtering**: Improved window detection and filtering
488
+ - ✅ **Performance**: Optimized native implementation
489
+
490
+ ---
491
+
492
+ **Made for macOS** 🍎 | **Built with AVFoundation** 📹 | **Node.js Ready** 🚀
package/binding.gyp ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "targets": [
3
+ {
4
+ "target_name": "mac_recorder",
5
+ "sources": [
6
+ "src/mac_recorder.mm",
7
+ "src/screen_capture.mm",
8
+ "src/audio_capture.mm"
9
+ ],
10
+ "include_dirs": [
11
+ "<!@(node -p \"require('node-addon-api').include\")"
12
+ ],
13
+ "dependencies": [
14
+ "<!(node -p \"require('node-addon-api').gyp\")"
15
+ ],
16
+ "cflags!": [ "-fno-exceptions" ],
17
+ "cflags_cc!": [ "-fno-exceptions" ],
18
+ "xcode_settings": {
19
+ "GCC_ENABLE_CPP_EXCEPTIONS": "YES",
20
+ "CLANG_CXX_LIBRARY": "libc++",
21
+ "MACOSX_DEPLOYMENT_TARGET": "10.14",
22
+ "OTHER_CFLAGS": [
23
+ "-ObjC++"
24
+ ]
25
+ },
26
+ "link_settings": {
27
+ "libraries": [
28
+ "-framework AVFoundation",
29
+ "-framework CoreMedia",
30
+ "-framework CoreVideo",
31
+ "-framework Foundation",
32
+ "-framework AppKit",
33
+ "-framework ScreenCaptureKit"
34
+ ]
35
+ },
36
+ "defines": [ "NAPI_DISABLE_CPP_EXCEPTIONS" ]
37
+ }
38
+ ]
39
+ }