node-mac-recorder 2.11.0 → 2.12.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-mac-recorder",
3
- "version": "2.11.0",
3
+ "version": "2.12.1",
4
4
  "description": "Native macOS screen recording package for Node.js applications",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -183,12 +183,13 @@ Napi::Value StartRecording(const Napi::CallbackInfo& info) {
183
183
  };
184
184
  }
185
185
 
186
- // Use ScreenCaptureKit (will exclude overlay windows automatically)
186
+ // Use ScreenCaptureKit with window exclusion
187
187
  NSError *sckError = nil;
188
188
  if ([ScreenCaptureKitRecorder startRecordingWithConfiguration:sckConfig
189
189
  delegate:g_delegate
190
190
  error:&sckError]) {
191
- NSLog(@" ScreenCaptureKit recording started with automatic overlay exclusion");
191
+ NSLog(@"🎬 RECORDING METHOD: ScreenCaptureKit");
192
+ NSLog(@"✅ ScreenCaptureKit recording started with window exclusion");
192
193
  g_isRecording = true;
193
194
  return Napi::Boolean::New(env, true);
194
195
  } else {
@@ -198,6 +199,7 @@ Napi::Value StartRecording(const Napi::CallbackInfo& info) {
198
199
  }
199
200
 
200
201
  // Fallback: Use AVFoundation (older macOS or ScreenCaptureKit failure)
202
+ NSLog(@"🎬 RECORDING METHOD: AVFoundation");
201
203
  NSLog(@"📼 Falling back to AVFoundation - overlay windows may appear in recording");
202
204
 
203
205
  // Create capture session
@@ -356,6 +358,7 @@ Napi::Value StartRecording(const Napi::CallbackInfo& info) {
356
358
  NSURL *outputURL = [NSURL fileURLWithPath:[NSString stringWithUTF8String:outputPath.c_str()]];
357
359
  [g_movieFileOutput startRecordingToOutputFileURL:outputURL recordingDelegate:g_delegate];
358
360
 
361
+ NSLog(@"✅ AVFoundation recording started");
359
362
  g_isRecording = true;
360
363
  return Napi::Boolean::New(env, true);
361
364
 
@@ -374,8 +377,17 @@ Napi::Value StopRecording(const Napi::CallbackInfo& info) {
374
377
  }
375
378
 
376
379
  @try {
377
- [g_movieFileOutput stopRecording];
378
- [g_captureSession stopRunning];
380
+ if (g_movieFileOutput) {
381
+ [g_movieFileOutput stopRecording];
382
+ }
383
+ if (g_captureSession) {
384
+ [g_captureSession stopRunning];
385
+ }
386
+
387
+ // Try to stop ScreenCaptureKit if it's being used
388
+ if (@available(macOS 12.3, *)) {
389
+ [ScreenCaptureKitRecorder stopRecording];
390
+ }
379
391
 
380
392
  g_isRecording = false;
381
393
  return Napi::Boolean::New(env, true);
@@ -59,19 +59,68 @@ static BOOL g_isRecording = NO;
59
59
  }
60
60
  }
61
61
 
62
- // Get current app windows to exclude
62
+ // Get current process and Electron app windows to exclude
63
63
  NSMutableArray *excludedWindows = [NSMutableArray array];
64
+ NSMutableArray *excludedApps = [NSMutableArray array];
65
+
66
+ // Exclude current Node.js process windows (overlay selectors)
64
67
  for (SCWindow *window in content.windows) {
65
68
  if (window.owningApplication.processID == currentPID) {
66
69
  [excludedWindows addObject:window];
67
- NSLog(@"🚫 Excluding overlay window: %@ (PID: %d)", window.title, currentPID);
70
+ NSLog(@"🚫 Excluding Node.js overlay window: %@ (PID: %d)", window.title, currentPID);
68
71
  }
69
72
  }
70
73
 
71
- // Create content filter - exclude current app windows
74
+ // Also try to exclude Electron app if running (common overlay use case)
75
+ for (SCWindow *window in content.windows) {
76
+ NSString *appName = window.owningApplication.applicationName;
77
+ NSString *windowTitle = window.title ? window.title : @"<No Title>";
78
+
79
+ // Debug: Log all windows to see what we're dealing with (only for small subset)
80
+ if ([appName containsString:@"Electron"] || [windowTitle containsString:@"camera"]) {
81
+ NSLog(@"📋 Found potential exclude window: '%@' from app: '%@' (PID: %d, Level: %ld)",
82
+ windowTitle, appName, window.owningApplication.processID, (long)window.windowLayer);
83
+ }
84
+
85
+ // Comprehensive Electron window detection
86
+ BOOL shouldExclude = NO;
87
+
88
+ // Check app name patterns
89
+ if ([appName containsString:@"Electron"] ||
90
+ [appName isEqualToString:@"electron"] ||
91
+ [appName isEqualToString:@"Electron Helper"]) {
92
+ shouldExclude = YES;
93
+ }
94
+
95
+ // Check window title patterns
96
+ if ([windowTitle containsString:@"Electron"] ||
97
+ [windowTitle containsString:@"camera"] ||
98
+ [windowTitle containsString:@"Camera"] ||
99
+ [windowTitle containsString:@"overlay"] ||
100
+ [windowTitle containsString:@"Overlay"]) {
101
+ shouldExclude = YES;
102
+ }
103
+
104
+ // Check window properties (transparent, always on top windows)
105
+ if (window.windowLayer > 100) { // High window levels (like alwaysOnTop)
106
+ shouldExclude = YES;
107
+ NSLog(@"📋 High-level window detected: '%@' (Level: %ld)", windowTitle, (long)window.windowLayer);
108
+ }
109
+
110
+ if (shouldExclude) {
111
+ [excludedWindows addObject:window];
112
+ NSLog(@"🚫 Excluding window: '%@' from %@ (PID: %d, Level: %ld)",
113
+ windowTitle, appName, window.owningApplication.processID, (long)window.windowLayer);
114
+ }
115
+ }
116
+
117
+ NSLog(@"📊 Total windows to exclude: %lu", (unsigned long)excludedWindows.count);
118
+
119
+ // Create content filter - exclude overlay windows from recording
72
120
  SCContentFilter *filter = [[SCContentFilter alloc]
73
121
  initWithDisplay:targetDisplay
74
122
  excludingWindows:excludedWindows];
123
+ NSLog(@"🎯 Using window-level exclusion for overlay prevention");
75
124
 
76
125
  // Create stream configuration
77
126
  SCStreamConfiguration *streamConfig = [[SCStreamConfiguration alloc] init];
@@ -15,6 +15,23 @@ static NSButton *g_selectButton = nil;
15
15
  static NSTimer *g_trackingTimer = nil;
16
16
  static NSDictionary *g_selectedWindowInfo = nil;
17
17
  static NSMutableArray *g_allWindows = nil;
18
+
19
+ // Functions to hide/show main overlay window during recording
20
+ void hideAllOverlayWindows() {
21
+ if (g_overlayWindow && [g_overlayWindow isVisible]) {
22
+ [g_overlayWindow setAlphaValue:0.0];
23
+ [g_overlayWindow orderOut:nil];
24
+ NSLog(@"🫥 Hidden main overlay window for recording");
25
+ }
26
+ }
27
+
28
+ void showAllOverlayWindows() {
29
+ if (g_overlayWindow) {
30
+ [g_overlayWindow setAlphaValue:1.0];
31
+ [g_overlayWindow orderFront:nil];
32
+ NSLog(@"👁️ Restored main overlay window after recording");
33
+ }
34
+ }
18
35
  static NSDictionary *g_currentWindowUnderCursor = nil;
19
36
  static bool g_bringToFrontEnabled = false; // Default disabled for overlay-only highlighting
20
37
  static bool g_hasToggledWindow = false; // Track if any window is currently toggled