node-mac-recorder 2.5.10 → 2.6.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/index.js CHANGED
@@ -37,7 +37,7 @@ class MacRecorder extends EventEmitter {
37
37
 
38
38
  this.options = {
39
39
  includeMicrophone: false, // Default olarak mikrofon kapalı
40
- includeSystemAudio: true, // Default olarak sistem sesi açık
40
+ includeSystemAudio: false, // Default olarak sistem sesi kapalı - kullanıcı explicit olarak açmalı
41
41
  quality: "medium",
42
42
  frameRate: 30,
43
43
  captureArea: null, // { x, y, width, height }
@@ -110,8 +110,8 @@ class MacRecorder extends EventEmitter {
110
110
  */
111
111
  setOptions(options = {}) {
112
112
  this.options = {
113
- includeMicrophone: options.includeMicrophone || false,
114
- includeSystemAudio: options.includeSystemAudio !== false, // Default true unless explicitly disabled
113
+ includeMicrophone: options.includeMicrophone === true, // Explicit true required, default false
114
+ includeSystemAudio: options.includeSystemAudio === true, // Explicit true required, default false
115
115
  captureCursor: options.captureCursor || false,
116
116
  displayId: options.displayId || null, // null = ana ekran
117
117
  windowId: options.windowId || null, // null = tam ekran
@@ -121,6 +121,53 @@ class MacRecorder extends EventEmitter {
121
121
  };
122
122
  }
123
123
 
124
+ /**
125
+ * Mikrofon kaydını açar/kapatır
126
+ */
127
+ setMicrophoneEnabled(enabled) {
128
+ this.options.includeMicrophone = enabled === true;
129
+ return this.options.includeMicrophone;
130
+ }
131
+
132
+ /**
133
+ * Sistem sesi kaydını açar/kapatır
134
+ */
135
+ setSystemAudioEnabled(enabled) {
136
+ this.options.includeSystemAudio = enabled === true;
137
+ return this.options.includeSystemAudio;
138
+ }
139
+
140
+ /**
141
+ * Mikrofon durumunu döndürür
142
+ */
143
+ isMicrophoneEnabled() {
144
+ return this.options.includeMicrophone === true;
145
+ }
146
+
147
+ /**
148
+ * Sistem sesi durumunu döndürür
149
+ */
150
+ isSystemAudioEnabled() {
151
+ return this.options.includeSystemAudio === true;
152
+ }
153
+
154
+ /**
155
+ * Audio ayarlarını toplu olarak değiştirir
156
+ */
157
+ setAudioSettings(settings = {}) {
158
+ if (typeof settings.microphone === 'boolean') {
159
+ this.setMicrophoneEnabled(settings.microphone);
160
+ }
161
+ if (typeof settings.systemAudio === 'boolean') {
162
+ this.setSystemAudioEnabled(settings.systemAudio);
163
+ }
164
+
165
+ return {
166
+ microphone: this.isMicrophoneEnabled(),
167
+ systemAudio: this.isSystemAudioEnabled()
168
+ };
169
+ }
170
+
124
171
  /**
125
172
  * Ekran kaydını başlatır (macOS native AVFoundation kullanarak)
126
173
  */
@@ -266,8 +313,8 @@ class MacRecorder extends EventEmitter {
266
313
  try {
267
314
  // Native kayıt başlat
268
315
  const recordingOptions = {
269
- includeMicrophone: this.options.includeMicrophone || false,
270
- includeSystemAudio: this.options.includeSystemAudio !== false, // Default true unless explicitly disabled
316
+ includeMicrophone: this.options.includeMicrophone === true, // Only if explicitly enabled
317
+ includeSystemAudio: this.options.includeSystemAudio === true, // Only if explicitly enabled
271
318
  captureCursor: this.options.captureCursor || false,
272
319
  displayId: this.options.displayId || null, // null = ana ekran
273
320
  windowId: this.options.windowId || null, // null = tam ekran
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-mac-recorder",
3
- "version": "2.5.10",
3
+ "version": "2.6.1",
4
4
  "description": "Native macOS screen recording package for Node.js applications",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -62,14 +62,6 @@ bool hideScreenRecordingPreview();
62
62
  // Ensure no borders or decorations
63
63
  self.layer.borderWidth = 0.0;
64
64
  self.layer.cornerRadius = 0.0;
65
- self.layer.borderColor = [[NSColor clearColor] CGColor];
66
- self.layer.shadowOpacity = 0.0;
67
- self.layer.shadowRadius = 0.0;
68
- self.layer.shadowOffset = NSMakeSize(0, 0);
69
- self.layer.masksToBounds = YES;
70
-
71
- // Disable focus ring and other default behaviors
72
- [self setFocusRingType:NSFocusRingTypeNone];
73
65
  }
74
66
  return self;
75
67
  }
@@ -79,9 +71,9 @@ bool hideScreenRecordingPreview();
79
71
 
80
72
  if (!self.windowInfo) return;
81
73
 
82
- // No background fill - completely transparent overlay
83
- // [[NSColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:0.15] setFill];
84
- // NSRectFill(self.bounds);
74
+ // Background with transparency - purple tone (no border)
75
+ [[NSColor colorWithRed:0.5 green:0.3 blue:0.8 alpha:0.25] setFill];
76
+ NSRectFill(self.bounds);
85
77
 
86
78
  // Ensure no borders or frames are drawn
87
79
  // Text will be handled by separate label above button
@@ -104,14 +96,6 @@ bool hideScreenRecordingPreview();
104
96
  // Ensure no borders or decorations
105
97
  self.layer.borderWidth = 0.0;
106
98
  self.layer.cornerRadius = 0.0;
107
- self.layer.borderColor = [[NSColor clearColor] CGColor];
108
- self.layer.shadowOpacity = 0.0;
109
- self.layer.shadowRadius = 0.0;
110
- self.layer.shadowOffset = NSMakeSize(0, 0);
111
- self.layer.masksToBounds = YES;
112
-
113
- // Disable focus ring and other default behaviors
114
- [self setFocusRingType:NSFocusRingTypeNone];
115
99
  }
116
100
  return self;
117
101
  }
@@ -167,14 +151,6 @@ bool hideScreenRecordingPreview();
167
151
  // Ensure no borders or decorations
168
152
  self.layer.borderWidth = 0.0;
169
153
  self.layer.cornerRadius = 0.0;
170
- self.layer.borderColor = [[NSColor clearColor] CGColor];
171
- self.layer.shadowOpacity = 0.0;
172
- self.layer.shadowRadius = 0.0;
173
- self.layer.shadowOffset = NSMakeSize(0, 0);
174
- self.layer.masksToBounds = YES;
175
-
176
- // Disable focus ring and other default behaviors
177
- [self setFocusRingType:NSFocusRingTypeNone];
178
154
  }
179
155
  return self;
180
156
  }
@@ -184,10 +160,10 @@ bool hideScreenRecordingPreview();
184
160
 
185
161
  if (!self.screenInfo) return;
186
162
 
187
- // No background fill - completely transparent overlay
163
+ // Background with transparency - purple tone (no border)
188
164
  // Ensure no borders or frames are drawn
189
- // [[NSColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:0.2] setFill];
190
- // NSRectFill(self.bounds);
165
+ [[NSColor colorWithRed:0.5 green:0.3 blue:0.8 alpha:0.3] setFill];
166
+ NSRectFill(self.bounds);
191
167
 
192
168
  // Text will be handled by separate label above button
193
169
  }
@@ -747,24 +723,12 @@ bool showRecordingPreview(NSDictionary *windowInfo) {
747
723
  [g_recordingPreviewWindow setAlphaValue:1.0];
748
724
  [g_recordingPreviewWindow setCollectionBehavior:NSWindowCollectionBehaviorStationary | NSWindowCollectionBehaviorCanJoinAllSpaces];
749
725
 
750
- // Ensure window layer has no borders or decorations
751
- [g_recordingPreviewWindow setWantsLayer:YES];
752
- [g_recordingPreviewWindow.layer setBorderWidth:0.0];
753
- [g_recordingPreviewWindow.layer setCornerRadius:0.0];
754
- [g_recordingPreviewWindow.layer setBorderColor:[[NSColor clearColor] CGColor]];
755
- [g_recordingPreviewWindow.layer setMasksToBounds:YES];
756
-
757
726
  // Remove any default window decorations and borders
758
727
  [g_recordingPreviewWindow setTitlebarAppearsTransparent:YES];
759
728
  [g_recordingPreviewWindow setTitleVisibility:NSWindowTitleHidden];
760
729
  [g_recordingPreviewWindow setMovable:NO];
761
730
  [g_recordingPreviewWindow setMovableByWindowBackground:NO];
762
731
 
763
- // Additional window styling to completely remove borders
764
- [g_recordingPreviewWindow setToolbar:nil];
765
- [g_recordingPreviewWindow setShowsResizeIndicator:NO];
766
- [g_recordingPreviewWindow setShowsToolbarButton:NO];
767
-
768
732
  // Create preview view
769
733
  g_recordingPreviewView = [[RecordingPreviewView alloc] initWithFrame:screenFrame];
770
734
  [(RecordingPreviewView *)g_recordingPreviewView setRecordingWindowInfo:windowInfo];
@@ -872,31 +836,17 @@ bool startScreenSelection() {
872
836
  [overlayWindow setAlphaValue:1.0];
873
837
  [overlayWindow setCollectionBehavior:NSWindowCollectionBehaviorStationary | NSWindowCollectionBehaviorCanJoinAllSpaces];
874
838
 
875
- // Ensure window layer has no borders or decorations
876
- [overlayWindow setWantsLayer:YES];
877
- [overlayWindow.layer setBorderWidth:0.0];
878
- [overlayWindow.layer setCornerRadius:0.0];
879
- [overlayWindow.layer setBorderColor:[[NSColor clearColor] CGColor]];
880
- [overlayWindow.layer setMasksToBounds:YES];
881
-
882
839
  // Remove any default window decorations and borders
883
840
  [overlayWindow setTitlebarAppearsTransparent:YES];
884
841
  [overlayWindow setTitleVisibility:NSWindowTitleHidden];
885
842
  [overlayWindow setMovable:NO];
886
843
  [overlayWindow setMovableByWindowBackground:NO];
887
844
 
888
-
889
-
890
845
  // Create overlay view
891
846
  ScreenSelectorOverlayView *overlayView = [[ScreenSelectorOverlayView alloc] initWithFrame:screenFrame];
892
847
  [overlayView setScreenInfo:screenInfo];
893
848
  [overlayWindow setContentView:overlayView];
894
849
 
895
- // Additional window styling to completely remove borders
896
- [overlayWindow setToolbar:nil];
897
- [overlayWindow setShowsResizeIndicator:NO];
898
- [overlayWindow setShowsToolbarButton:NO];
899
-
900
850
  // Create select button with more padding
901
851
  NSButton *selectButton = [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 200, 60)];
902
852
  [selectButton setTitle:@"Start Record"];
@@ -936,13 +886,9 @@ bool startScreenSelection() {
936
886
  [selectButton setTarget:g_delegate];
937
887
  [selectButton setAction:@selector(screenSelectButtonClicked:)];
938
888
 
939
- // Remove focus ring and other default button behaviors
940
- [selectButton setFocusRingType:NSFocusRingTypeNone];
941
- [selectButton setShowsBorderOnlyMouseInside:NO];
942
- [selectButton setBezelStyle:NSBezelStyleTexturedSquare];
943
- [selectButton setKeyEquivalent:@""];
944
- [selectButton setRefusesFirstResponder:YES];
945
- [selectButton setState:NSControlStateValueOff];
889
+ // Remove focus ring and other default button behaviors
890
+ [selectButton setFocusRingType:NSFocusRingTypeNone];
891
+ [selectButton setShowsBorderOnlyWhileMouseInside:NO];
946
892
 
947
893
  // Create cancel button for screen selection
948
894
  NSButton *screenCancelButton = [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 120, 40)];
@@ -977,11 +923,7 @@ bool startScreenSelection() {
977
923
 
978
924
  // Remove focus ring and other default button behaviors
979
925
  [screenCancelButton setFocusRingType:NSFocusRingTypeNone];
980
- [screenCancelButton setShowsBorderOnlyMouseInside:NO];
981
- [screenCancelButton setBezelStyle:NSBezelStyleTexturedSquare];
982
- [screenCancelButton setKeyEquivalent:@""];
983
- [screenCancelButton setRefusesFirstResponder:YES];
984
- [screenCancelButton setState:NSControlStateValueOff];
926
+ [screenCancelButton setShowsBorderOnlyWhileMouseInside:NO];
985
927
 
986
928
  // Create info label for screen
987
929
  NSTextField *screenInfoLabel = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, screenFrame.size.width - 40, 60)];
@@ -1143,24 +1085,12 @@ bool showScreenRecordingPreview(NSDictionary *screenInfo) {
1143
1085
  [overlayWindow setAlphaValue:1.0];
1144
1086
  [overlayWindow setCollectionBehavior:NSWindowCollectionBehaviorStationary | NSWindowCollectionBehaviorCanJoinAllSpaces];
1145
1087
 
1146
- // Ensure window layer has no borders or decorations
1147
- [overlayWindow setWantsLayer:YES];
1148
- [overlayWindow.layer setBorderWidth:0.0];
1149
- [overlayWindow.layer setCornerRadius:0.0];
1150
- [overlayWindow.layer setBorderColor:[[NSColor clearColor] CGColor]];
1151
- [overlayWindow.layer setMasksToBounds:YES];
1152
-
1153
1088
  // Remove any default window decorations and borders
1154
1089
  [overlayWindow setTitlebarAppearsTransparent:YES];
1155
1090
  [overlayWindow setTitleVisibility:NSWindowTitleHidden];
1156
1091
  [overlayWindow setMovable:NO];
1157
1092
  [overlayWindow setMovableByWindowBackground:NO];
1158
1093
 
1159
- // Additional window styling to completely remove borders
1160
- [overlayWindow setToolbar:nil];
1161
- [overlayWindow setShowsResizeIndicator:NO];
1162
- [overlayWindow setShowsToolbarButton:NO];
1163
-
1164
1094
  [overlayWindow orderFront:nil];
1165
1095
  [overlayWindow makeKeyAndOrderFront:nil];
1166
1096
 
@@ -1218,37 +1148,19 @@ Napi::Value StartWindowSelection(const Napi::CallbackInfo& info) {
1218
1148
  [g_overlayWindow setAlphaValue:1.0];
1219
1149
  [g_overlayWindow setCollectionBehavior:NSWindowCollectionBehaviorStationary | NSWindowCollectionBehaviorCanJoinAllSpaces];
1220
1150
 
1221
- // Ensure window layer has no borders or decorations
1222
- [g_overlayWindow setWantsLayer:YES];
1223
- [g_overlayWindow.layer setBorderWidth:0.0];
1224
- [g_overlayWindow.layer setCornerRadius:0.0];
1225
- [g_overlayWindow.layer setBorderColor:[[NSColor clearColor] CGColor]];
1226
- [g_overlayWindow.layer setMasksToBounds:YES];
1227
-
1228
1151
  // Remove any default window decorations and borders
1229
1152
  [g_overlayWindow setTitlebarAppearsTransparent:YES];
1230
1153
  [g_overlayWindow setTitleVisibility:NSWindowTitleHidden];
1231
1154
  [g_overlayWindow setMovable:NO];
1232
1155
  [g_overlayWindow setMovableByWindowBackground:NO];
1233
1156
 
1234
- // Additional window styling to completely remove borders
1235
- [g_overlayWindow setToolbar:nil];
1236
- [g_overlayWindow setShowsResizeIndicator:NO];
1237
- [g_overlayWindow setShowsToolbarButton:NO];
1238
-
1239
1157
  // Create overlay view
1240
1158
  g_overlayView = [[WindowSelectorOverlayView alloc] initWithFrame:initialFrame];
1241
1159
  [g_overlayWindow setContentView:g_overlayView];
1242
1160
 
1243
- // Ensure view layer has no borders
1244
- [g_overlayView setWantsLayer:YES];
1245
- [g_overlayView.layer setBorderWidth:0.0];
1246
- [g_overlayView.layer setCornerRadius:0.0];
1247
- [g_overlayView.layer setBorderColor:[[NSColor clearColor] CGColor]];
1248
- [g_overlayView.layer setMasksToBounds:YES];
1249
- [g_overlayView.layer setShadowOpacity:0.0];
1250
- [g_overlayView.layer setShadowRadius:0.0];
1251
- [g_overlayView.layer setShadowOffset:NSMakeSize(0, 0)];
1161
+ // Additional window styling to ensure no borders or decorations
1162
+ [g_overlayWindow setMovable:NO];
1163
+ [g_overlayWindow setMovableByWindowBackground:NO];
1252
1164
 
1253
1165
  // Create select button with purple theme
1254
1166
  g_selectButton = [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 200, 60)];
@@ -1284,11 +1196,7 @@ Napi::Value StartWindowSelection(const Napi::CallbackInfo& info) {
1284
1196
 
1285
1197
  // Remove focus ring and other default button behaviors
1286
1198
  [g_selectButton setFocusRingType:NSFocusRingTypeNone];
1287
- [g_selectButton setShowsBorderOnlyMouseInside:NO];
1288
- [g_selectButton setBezelStyle:NSBezelStyleTexturedSquare];
1289
- [g_selectButton setKeyEquivalent:@""];
1290
- [g_selectButton setRefusesFirstResponder:YES];
1291
- [g_selectButton setState:NSControlStateValueOff];
1199
+ [g_selectButton setShowsBorderOnlyWhileMouseInside:NO];
1292
1200
 
1293
1201
  // Add select button directly to window (not view) for proper layering
1294
1202
  [g_overlayWindow.contentView addSubview:g_selectButton];
@@ -1325,11 +1233,7 @@ Napi::Value StartWindowSelection(const Napi::CallbackInfo& info) {
1325
1233
 
1326
1234
  // Remove focus ring and other default button behaviors
1327
1235
  [cancelButton setFocusRingType:NSFocusRingTypeNone];
1328
- [cancelButton setShowsBorderOnlyMouseInside:NO];
1329
- [cancelButton setBezelStyle:NSBezelStyleTexturedSquare];
1330
- [cancelButton setKeyEquivalent:@""];
1331
- [cancelButton setRefusesFirstResponder:YES];
1332
- [cancelButton setState:NSControlStateValueOff];
1236
+ [cancelButton setShowsBorderOnlyWhileMouseInside:NO];
1333
1237
 
1334
1238
  // Add cancel button to window
1335
1239
  [g_overlayWindow.contentView addSubview:cancelButton];
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env node
2
+
3
+ const MacRecorder = require('./index');
4
+
5
+ async function testAudioControls() {
6
+ console.log('🎵 Audio Control Test');
7
+ console.log('====================\n');
8
+
9
+ const recorder = new MacRecorder();
10
+
11
+ try {
12
+ // Test initial state
13
+ console.log('📋 Initial Audio State:');
14
+ console.log(` Microphone: ${recorder.isMicrophoneEnabled() ? '🎤 ON' : '🔇 OFF'}`);
15
+ console.log(` System Audio: ${recorder.isSystemAudioEnabled() ? '🔊 ON' : '🔇 OFF'}\n`);
16
+
17
+ // Test individual controls
18
+ console.log('🔧 Testing Individual Controls:\n');
19
+
20
+ console.log(' Enabling microphone...');
21
+ recorder.setMicrophoneEnabled(true);
22
+ console.log(` Microphone: ${recorder.isMicrophoneEnabled() ? '🎤 ON' : '🔇 OFF'}`);
23
+
24
+ console.log(' Enabling system audio...');
25
+ recorder.setSystemAudioEnabled(true);
26
+ console.log(` System Audio: ${recorder.isSystemAudioEnabled() ? '🔊 ON' : '🔇 OFF'}\n`);
27
+
28
+ console.log(' Disabling microphone...');
29
+ recorder.setMicrophoneEnabled(false);
30
+ console.log(` Microphone: ${recorder.isMicrophoneEnabled() ? '🎤 ON' : '🔇 OFF'}`);
31
+
32
+ console.log(' Disabling system audio...');
33
+ recorder.setSystemAudioEnabled(false);
34
+ console.log(` System Audio: ${recorder.isSystemAudioEnabled() ? '🔊 ON' : '🔇 OFF'}\n`);
35
+
36
+ // Test bulk settings
37
+ console.log('🔧 Testing Bulk Audio Settings:\n');
38
+
39
+ console.log(' Setting both to ON...');
40
+ let settings = recorder.setAudioSettings({
41
+ microphone: true,
42
+ systemAudio: true
43
+ });
44
+ console.log(` Result: Microphone=${settings.microphone ? 'ON' : 'OFF'}, System Audio=${settings.systemAudio ? 'ON' : 'OFF'}\n`);
45
+
46
+ console.log(' Setting microphone OFF, system audio ON...');
47
+ settings = recorder.setAudioSettings({
48
+ microphone: false,
49
+ systemAudio: true
50
+ });
51
+ console.log(` Result: Microphone=${settings.microphone ? 'ON' : 'OFF'}, System Audio=${settings.systemAudio ? 'ON' : 'OFF'}\n`);
52
+
53
+ // Test recording with different audio settings
54
+ const testOutput = `./test-output/audio-test-${Date.now()}.mov`;
55
+
56
+ console.log('🎬 Testing Recording with Audio Settings:\n');
57
+
58
+ // Test 1: No audio
59
+ console.log(' Test 1: No Audio Recording');
60
+ recorder.setAudioSettings({ microphone: false, systemAudio: false });
61
+ console.log(` Starting 3-second recording: ${testOutput}`);
62
+ console.log(` Audio settings: Mic=${recorder.isMicrophoneEnabled() ? 'ON' : 'OFF'}, System=${recorder.isSystemAudioEnabled() ? 'ON' : 'OFF'}`);
63
+
64
+ await recorder.startRecording(testOutput);
65
+ await new Promise(resolve => setTimeout(resolve, 3000));
66
+ await recorder.stopRecording();
67
+ console.log(' ✅ Recording completed (no audio)\n');
68
+
69
+ // Test 2: Microphone only
70
+ console.log(' Test 2: Microphone Only Recording');
71
+ recorder.setAudioSettings({ microphone: true, systemAudio: false });
72
+ const testOutput2 = `./test-output/audio-test-mic-${Date.now()}.mov`;
73
+ console.log(` Starting 3-second recording: ${testOutput2}`);
74
+ console.log(` Audio settings: Mic=${recorder.isMicrophoneEnabled() ? 'ON' : 'OFF'}, System=${recorder.isSystemAudioEnabled() ? 'ON' : 'OFF'}`);
75
+
76
+ await recorder.startRecording(testOutput2);
77
+ await new Promise(resolve => setTimeout(resolve, 3000));
78
+ await recorder.stopRecording();
79
+ console.log(' ✅ Recording completed (microphone only)\n');
80
+
81
+ // Test 3: System audio only
82
+ console.log(' Test 3: System Audio Only Recording');
83
+ recorder.setAudioSettings({ microphone: false, systemAudio: true });
84
+ const testOutput3 = `./test-output/audio-test-system-${Date.now()}.mov`;
85
+ console.log(` Starting 3-second recording: ${testOutput3}`);
86
+ console.log(` Audio settings: Mic=${recorder.isMicrophoneEnabled() ? 'ON' : 'OFF'}, System=${recorder.isSystemAudioEnabled() ? 'ON' : 'OFF'}`);
87
+
88
+ await recorder.startRecording(testOutput3);
89
+ await new Promise(resolve => setTimeout(resolve, 3000));
90
+ await recorder.stopRecording();
91
+ console.log(' ✅ Recording completed (system audio only)\n');
92
+
93
+ console.log('✅ All audio control tests completed successfully!');
94
+ console.log('\n📁 Check test-output/ directory for video files.');
95
+
96
+ } catch (error) {
97
+ console.error('\n❌ Test failed:', error.message);
98
+ process.exit(1);
99
+ }
100
+ }
101
+
102
+ if (require.main === module) {
103
+ testAudioControls();
104
+ }