node-mac-recorder 1.2.10 → 1.3.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.
@@ -6,7 +6,14 @@
6
6
  "Bash(rm:*)",
7
7
  "Bash(python3:*)",
8
8
  "Bash(grep:*)",
9
- "Bash(cat:*)"
9
+ "Bash(cat:*)",
10
+ "Bash(brew install:*)",
11
+ "Bash(open:*)",
12
+ "Bash(curl:*)",
13
+ "Bash(system_profiler:*)",
14
+ "Bash(mkdir:*)",
15
+ "Bash(/dev/null)",
16
+ "Bash(ls:*)"
10
17
  ],
11
18
  "deny": []
12
19
  }
package/README.md CHANGED
@@ -93,6 +93,7 @@ await recorder.startRecording("./recording.mov", {
93
93
  includeMicrophone: false, // Enable microphone (default: false)
94
94
  includeSystemAudio: true, // Enable system audio (default: true)
95
95
  audioDeviceId: "device-id", // Specific audio input device (default: system default)
96
+ systemAudioDeviceId: "system-device-id", // Specific system audio device (auto-detected by default)
96
97
 
97
98
  // Display & Window Selection
98
99
  displayId: 0, // Display index (null = main display)
@@ -348,19 +349,62 @@ await new Promise((resolve) => setTimeout(resolve, 8000));
348
349
  await recorder.stopRecording();
349
350
  ```
350
351
 
351
- ### Audio-Only System Recording
352
+ ### Advanced System Audio Recording
352
353
 
353
354
  ```javascript
354
355
  const recorder = new MacRecorder();
355
356
 
356
- // Record system audio without microphone
357
- await recorder.startRecording("./system-audio.mov", {
358
- includeMicrophone: false,
359
- includeSystemAudio: true,
360
- captureArea: { x: 0, y: 0, width: 1, height: 1 }, // Minimal video
357
+ // List available audio devices to find system audio devices
358
+ const audioDevices = await recorder.getAudioDevices();
359
+ console.log("Available audio devices:");
360
+ audioDevices.forEach((device, i) => {
361
+ console.log(`${i + 1}. ${device.name} (ID: ${device.id})`);
361
362
  });
363
+
364
+ // Find system audio device (like BlackHole, Soundflower, etc.)
365
+ const systemAudioDevice = audioDevices.find(device =>
366
+ device.name.toLowerCase().includes('blackhole') ||
367
+ device.name.toLowerCase().includes('soundflower') ||
368
+ device.name.toLowerCase().includes('loopback') ||
369
+ device.name.toLowerCase().includes('aggregate')
370
+ );
371
+
372
+ if (systemAudioDevice) {
373
+ console.log(`Using system audio device: ${systemAudioDevice.name}`);
374
+
375
+ // Record with specific system audio device
376
+ await recorder.startRecording("./system-audio-specific.mov", {
377
+ includeMicrophone: false,
378
+ includeSystemAudio: true,
379
+ systemAudioDeviceId: systemAudioDevice.id, // Specify exact device
380
+ captureArea: { x: 0, y: 0, width: 1, height: 1 }, // Minimal video
381
+ });
382
+ } else {
383
+ console.log("No system audio device found. Installing BlackHole or Soundflower recommended.");
384
+
385
+ // Record with default system audio capture (may not work without virtual audio device)
386
+ await recorder.startRecording("./system-audio-default.mov", {
387
+ includeMicrophone: false,
388
+ includeSystemAudio: true, // Auto-detect system audio device
389
+ captureArea: { x: 0, y: 0, width: 1, height: 1 },
390
+ });
391
+ }
392
+
393
+ // Record for 10 seconds
394
+ await new Promise(resolve => setTimeout(resolve, 10000));
395
+ await recorder.stopRecording();
362
396
  ```
363
397
 
398
+ **System Audio Setup:**
399
+
400
+ For reliable system audio capture, install a virtual audio device:
401
+
402
+ 1. **BlackHole** (Free): https://github.com/ExistentialAudio/BlackHole
403
+ 2. **Soundflower** (Free): https://github.com/mattingalls/Soundflower
404
+ 3. **Loopback** (Paid): https://rogueamoeba.com/loopback/
405
+
406
+ These create aggregate audio devices that the package can detect and use for system audio capture.
407
+
364
408
  ### Event-Driven Recording
365
409
 
366
410
  ```javascript
@@ -0,0 +1,396 @@
1
+ # Window Selector
2
+
3
+ **macOS Window Selection Tool with Real-time Visual Overlay**
4
+
5
+ Bu modül, macOS'ta sistem imleci ile pencere seçimi yapabilmenizi sağlayan güçlü bir araçtır. İmleç hangi pencerenin üstüne gelirse, o pencereyi mavi kapsayıcı ile highlight eder ve merkeze yerleştirilen "Select Window" butonu ile seçim yapabilirsiniz.
6
+
7
+ ## ✨ Özellikler
8
+
9
+ - **Real-time Window Detection**: İmleç hangi pencereye gelirse otomatik olarak tespit eder
10
+ - **Visual Overlay**: Seçilebilir pencereleri mavi transparant kapsayıcı ile highlight eder
11
+ - **Interactive Selection**: Merkeze yerleştirilen "Select Window" butonu ile kolay seçim
12
+ - **Multi-display Support**: Çoklu ekran kurulumlarında çalışır
13
+ - **Detailed Window Info**: Pencere pozisyonu, boyutu ve hangi ekranda olduğunu döndürür
14
+ - **Event-driven API**: Pencere hover, seçim ve hata durumları için event'ler
15
+ - **Permission Management**: macOS izin kontrolü ve yönetimi
16
+
17
+ ## 🚀 Kurulum
18
+
19
+ ```bash
20
+ # Ana proje dizininde
21
+ npm install
22
+
23
+ # Native modülü build edin
24
+ npm run build
25
+ ```
26
+
27
+ ## 📋 Sistem Gereksinimleri
28
+
29
+ - **macOS 10.15+** (Catalina veya üzeri)
30
+ - **Node.js 14+**
31
+ - **Xcode Command Line Tools**
32
+ - **System Permissions**:
33
+ - Screen Recording permission
34
+ - Accessibility permission
35
+
36
+ ## 🔐 İzinler
37
+
38
+ İlk kullanımda macOS aşağıdaki izinleri isteyecektir:
39
+
40
+ 1. **System Preferences > Security & Privacy > Privacy > Screen Recording**
41
+ - Terminal veya kullandığınız IDE'yi (VSCode, WebStorm, vb.) etkinleştirin
42
+
43
+ 2. **System Preferences > Security & Privacy > Privacy > Accessibility**
44
+ - Terminal veya kullandığınız IDE'yi etkinleştirin
45
+
46
+ ## 🎯 Temel Kullanım
47
+
48
+ ### Basit Pencere Seçimi
49
+
50
+ ```javascript
51
+ const WindowSelector = require('./window-selector');
52
+
53
+ async function selectWindow() {
54
+ const selector = new WindowSelector();
55
+
56
+ try {
57
+ console.log('Bir pencere seçin...');
58
+ const selectedWindow = await selector.selectWindow();
59
+
60
+ console.log('Seçilen pencere:', {
61
+ title: selectedWindow.title,
62
+ app: selectedWindow.appName,
63
+ position: `(${selectedWindow.x}, ${selectedWindow.y})`,
64
+ size: `${selectedWindow.width}x${selectedWindow.height}`,
65
+ screen: selectedWindow.screenId
66
+ });
67
+
68
+ return selectedWindow;
69
+
70
+ } catch (error) {
71
+ console.error('Hata:', error.message);
72
+ } finally {
73
+ await selector.cleanup();
74
+ }
75
+ }
76
+
77
+ selectWindow();
78
+ ```
79
+
80
+ ### Manuel Kontrol
81
+
82
+ ```javascript
83
+ const WindowSelector = require('./window-selector');
84
+
85
+ async function manualSelection() {
86
+ const selector = new WindowSelector();
87
+
88
+ // Event listener'lar
89
+ selector.on('windowEntered', (window) => {
90
+ console.log(`Pencere üstünde: ${window.title} (${window.appName})`);
91
+ });
92
+
93
+ selector.on('windowSelected', (window) => {
94
+ console.log(`Seçildi: ${window.title}`);
95
+ });
96
+
97
+ // Seçimi başlat
98
+ await selector.startSelection();
99
+
100
+ // Kullanıcı seçim yapana kadar bekle
101
+ // Seçim tamamlandığında 'windowSelected' event'i tetiklenir
102
+
103
+ // Seçimi durdurmak için:
104
+ // await selector.stopSelection();
105
+ }
106
+ ```
107
+
108
+ ## 📚 API Reference
109
+
110
+ ### WindowSelector Class
111
+
112
+ #### Constructor
113
+ ```javascript
114
+ const selector = new WindowSelector();
115
+ ```
116
+
117
+ #### Methods
118
+
119
+ ##### `async selectWindow()`
120
+ Promise tabanlı pencere seçimi. Kullanıcı bir pencere seçene kadar bekler.
121
+
122
+ **Returns:** `Promise<WindowInfo>`
123
+
124
+ ```javascript
125
+ const window = await selector.selectWindow();
126
+ ```
127
+
128
+ ##### `async startSelection()`
129
+ Pencere seçim modunu başlatır.
130
+
131
+ **Returns:** `Promise<boolean>`
132
+
133
+ ##### `async stopSelection()`
134
+ Pencere seçim modunu durdurur.
135
+
136
+ **Returns:** `Promise<boolean>`
137
+
138
+ ##### `getSelectedWindow()`
139
+ Son seçilen pencere bilgisini döndürür.
140
+
141
+ **Returns:** `WindowInfo | null`
142
+
143
+ ##### `getStatus()`
144
+ Seçici durumunu döndürür.
145
+
146
+ **Returns:** `SelectionStatus`
147
+
148
+ ##### `async checkPermissions()`
149
+ macOS izinlerini kontrol eder.
150
+
151
+ **Returns:** `Promise<PermissionStatus>`
152
+
153
+ ##### `async cleanup()`
154
+ Tüm kaynakları temizler ve seçimi durdurur.
155
+
156
+ #### Events
157
+
158
+ ##### `selectionStarted`
159
+ Seçim modu başladığında tetiklenir.
160
+
161
+ ```javascript
162
+ selector.on('selectionStarted', () => {
163
+ console.log('Seçim başladı');
164
+ });
165
+ ```
166
+
167
+ ##### `windowEntered`
168
+ İmleç bir pencereye geldiğinde tetiklenir.
169
+
170
+ ```javascript
171
+ selector.on('windowEntered', (windowInfo) => {
172
+ console.log(`Pencere: ${windowInfo.title}`);
173
+ });
174
+ ```
175
+
176
+ ##### `windowLeft`
177
+ İmleç bir pencereden ayrıldığında tetiklenir.
178
+
179
+ ```javascript
180
+ selector.on('windowLeft', (windowInfo) => {
181
+ console.log(`Ayrıldı: ${windowInfo.title}`);
182
+ });
183
+ ```
184
+
185
+ ##### `windowSelected`
186
+ Bir pencere seçildiğinde tetiklenir.
187
+
188
+ ```javascript
189
+ selector.on('windowSelected', (windowInfo) => {
190
+ console.log('Seçilen pencere:', windowInfo);
191
+ });
192
+ ```
193
+
194
+ ##### `selectionStopped`
195
+ Seçim modu durduğunda tetiklenir.
196
+
197
+ ##### `error`
198
+ Bir hata oluştuğunda tetiklenir.
199
+
200
+ ```javascript
201
+ selector.on('error', (error) => {
202
+ console.error('Hata:', error.message);
203
+ });
204
+ ```
205
+
206
+ ## 📊 Data Types
207
+
208
+ ### WindowInfo
209
+ ```javascript
210
+ {
211
+ id: number, // Pencere ID'si
212
+ title: string, // Pencere başlığı
213
+ appName: string, // Uygulama adı
214
+ x: number, // Global X pozisyonu
215
+ y: number, // Global Y pozisyonu
216
+ width: number, // Pencere genişliği
217
+ height: number, // Pencere yüksekliği
218
+ screenId: number, // Hangi ekranda olduğu
219
+ screenX: number, // Ekranın X pozisyonu
220
+ screenY: number, // Ekranın Y pozisyonu
221
+ screenWidth: number, // Ekran genişliği
222
+ screenHeight: number // Ekran yüksekliği
223
+ }
224
+ ```
225
+
226
+ ### SelectionStatus
227
+ ```javascript
228
+ {
229
+ isSelecting: boolean, // Seçim modunda mı?
230
+ hasSelectedWindow: boolean, // Seçilmiş pencere var mı?
231
+ selectedWindow: WindowInfo | null,
232
+ nativeStatus: object // Native durum bilgisi
233
+ }
234
+ ```
235
+
236
+ ### PermissionStatus
237
+ ```javascript
238
+ {
239
+ screenRecording: boolean, // Ekran kaydı izni
240
+ accessibility: boolean, // Erişilebilirlik izni
241
+ microphone: boolean // Mikrofon izni
242
+ }
243
+ ```
244
+
245
+ ## 🎮 Test Etme
246
+
247
+ ### Test Dosyasını Çalıştır
248
+ ```bash
249
+ # Interaktif test
250
+ node window-selector-test.js
251
+
252
+ # API test modu
253
+ node window-selector-test.js --api-test
254
+ ```
255
+
256
+ ### Örnekleri Çalıştır
257
+ ```bash
258
+ # Basit örnek
259
+ node examples/window-selector-example.js
260
+
261
+ # Gelişmiş örnek (event'lerle)
262
+ node examples/window-selector-example.js --advanced
263
+
264
+ # Çoklu seçim
265
+ node examples/window-selector-example.js --multiple
266
+
267
+ # Detaylı analiz
268
+ node examples/window-selector-example.js --analysis
269
+
270
+ # Yardım
271
+ node examples/window-selector-example.js --help
272
+ ```
273
+
274
+ ## ⚡ Nasıl Çalışır?
275
+
276
+ 1. **Window Detection**: macOS `CGWindowListCopyWindowInfo` API'si ile açık pencereleri tespit eder
277
+ 2. **Cursor Tracking**: Real-time olarak imleç pozisyonunu takip eder
278
+ 3. **Overlay Rendering**: NSWindow ile transparant overlay penceresi oluşturur
279
+ 4. **Hit Testing**: İmlecin hangi pencere üstünde olduğunu hesaplar
280
+ 5. **Visual Feedback**: Pencereyi highlight eden mavi kapsayıcı çizer
281
+ 6. **User Interaction**: Merkeze yerleştirilen button ile seçim yapar
282
+ 7. **Data Collection**: Seçilen pencerenin tüm bilgilerini toplar
283
+
284
+ ## 🔧 Troubleshooting
285
+
286
+ ### Build Hataları
287
+ ```bash
288
+ # Xcode Command Line Tools'u yükle
289
+ xcode-select --install
290
+
291
+ # Node-gyp'i yeniden build et
292
+ npm run clean
293
+ npm run build
294
+ ```
295
+
296
+ ### İzin Hataları
297
+ 1. **System Preferences > Security & Privacy > Privacy** bölümüne git
298
+ 2. **Screen Recording** ve **Accessibility** sekmelerinde Terminal'i etkinleştir
299
+ 3. Uygulamayı yeniden başlat
300
+
301
+ ### Runtime Hataları
302
+ ```javascript
303
+ // İzinleri kontrol et
304
+ const permissions = await selector.checkPermissions();
305
+ if (!permissions.screenRecording) {
306
+ console.log('Screen recording permission required');
307
+ }
308
+ ```
309
+
310
+ ## 🌟 Gelişmiş Örnekler
311
+
312
+ ### Otomatik Pencere Kaydı
313
+ ```javascript
314
+ const WindowSelector = require('./window-selector');
315
+ const MacRecorder = require('./index');
316
+
317
+ async function recordSelectedWindow() {
318
+ const selector = new WindowSelector();
319
+ const recorder = new MacRecorder();
320
+
321
+ try {
322
+ // Pencere seç
323
+ const window = await selector.selectWindow();
324
+ console.log(`Recording: ${window.title}`);
325
+
326
+ // Seçilen pencereyi kaydet
327
+ const outputPath = `./recordings/${window.appName}-${Date.now()}.mov`;
328
+ await recorder.startRecording(outputPath, {
329
+ windowId: window.id,
330
+ captureCursor: true,
331
+ includeMicrophone: true
332
+ });
333
+
334
+ // 10 saniye kaydet
335
+ setTimeout(async () => {
336
+ await recorder.stopRecording();
337
+ console.log(`Recording saved: ${outputPath}`);
338
+ }, 10000);
339
+
340
+ } finally {
341
+ await selector.cleanup();
342
+ }
343
+ }
344
+ ```
345
+
346
+ ### Pencere Monitoring
347
+ ```javascript
348
+ const WindowSelector = require('./window-selector');
349
+
350
+ async function monitorWindowChanges() {
351
+ const selector = new WindowSelector();
352
+ const visitedWindows = new Set();
353
+
354
+ selector.on('windowEntered', (window) => {
355
+ const key = `${window.appName}-${window.title}`;
356
+ if (!visitedWindows.has(key)) {
357
+ visitedWindows.add(key);
358
+ console.log(`Yeni pencere keşfedildi: ${window.title} (${window.appName})`);
359
+ }
360
+ });
361
+
362
+ await selector.startSelection();
363
+
364
+ // İptal etmek için Ctrl+C
365
+ process.on('SIGINT', async () => {
366
+ console.log(`\nToplam keşfedilen pencere: ${visitedWindows.size}`);
367
+ await selector.cleanup();
368
+ process.exit(0);
369
+ });
370
+ }
371
+ ```
372
+
373
+ ## 📄 Lisans
374
+
375
+ Bu modül ana projenin lisansı altındadır.
376
+
377
+ ## 🤝 Katkıda Bulunma
378
+
379
+ 1. Fork edin
380
+ 2. Feature branch oluşturun (`git checkout -b feature/amazing-feature`)
381
+ 3. Commit edin (`git commit -m 'Add amazing feature'`)
382
+ 4. Push edin (`git push origin feature/amazing-feature`)
383
+ 5. Pull Request açın
384
+
385
+ ## ⭐ Özellik İstekleri
386
+
387
+ - [ ] Pencere gruplandırma
388
+ - [ ] Hotkey desteği
389
+ - [ ] Pencere filtreleme
390
+ - [ ] Çoklu seçim modu
391
+ - [ ] Screenshot alma
392
+ - [ ] Window history
393
+
394
+ ---
395
+
396
+ **Not**: Bu modül sadece macOS'ta çalışır ve sistem izinleri gerektirir.
package/binding.gyp CHANGED
@@ -6,7 +6,8 @@
6
6
  "src/mac_recorder.mm",
7
7
  "src/screen_capture.mm",
8
8
  "src/audio_capture.mm",
9
- "src/cursor_tracker.mm"
9
+ "src/cursor_tracker.mm",
10
+ "src/window_selector.mm"
10
11
  ],
11
12
  "include_dirs": [
12
13
  "<!@(node -p \"require('node-addon-api').include\")"
package/debug-audio.js ADDED
@@ -0,0 +1,79 @@
1
+ const MacRecorder = require('./index');
2
+
3
+ async function debugAudio() {
4
+ const recorder = new MacRecorder();
5
+
6
+ console.log('🔍 SES CİHAZI DEBUG RAPORU\n');
7
+
8
+ try {
9
+ // Tüm ses cihazlarını detayları ile listele
10
+ const devices = await recorder.getAudioDevices();
11
+ console.log('📋 TÜM SES CİHAZLARI:');
12
+ devices.forEach((device, index) => {
13
+ console.log(`${index + 1}. ${device.name}`);
14
+ console.log(` ID: ${device.id || 'N/A'}`);
15
+ console.log(` Type: ${device.type || 'N/A'}`);
16
+ console.log(` Manufacturer: ${device.manufacturer || 'N/A'}`);
17
+ console.log(` Default: ${device.isDefault ? 'Yes' : 'No'}`);
18
+ console.log('');
19
+ });
20
+
21
+ // Sistem sesi için uygun cihazları bul
22
+ const systemDevices = devices.filter(device => {
23
+ const name = device.name.toLowerCase();
24
+ return name.includes('aggregate') ||
25
+ name.includes('blackhole') ||
26
+ name.includes('soundflower') ||
27
+ name.includes('loopback') ||
28
+ name.includes('system') ||
29
+ name.includes('imobie');
30
+ });
31
+
32
+ console.log('🎵 SİSTEM SESİ İÇİN UYGUN CİHAZLAR:');
33
+ if (systemDevices.length > 0) {
34
+ systemDevices.forEach((device, index) => {
35
+ console.log(`${index + 1}. ${device.name} (ID: ${device.id})`);
36
+ });
37
+ } else {
38
+ console.log('❌ Sistem sesi cihazı bulunamadı!');
39
+ }
40
+
41
+ console.log('\n💡 ÇÖZÜMLERİ:');
42
+ console.log('1. BlackHole kur: https://github.com/ExistentialAudio/BlackHole/releases');
43
+ console.log('2. Audio MIDI Setup ile Aggregate Device oluştur');
44
+ console.log('3. Sistem sesini aggregate device\'a yönlendir');
45
+
46
+ console.log('\n🔧 MANUAL AGGREGATE DEVICE OLUŞTURMA:');
47
+ console.log('1. Spotlight\'ta "Audio MIDI Setup" ara ve aç');
48
+ console.log('2. Sol alt köşedeki "+" butonuna tıkla');
49
+ console.log('3. "Create Aggregate Device" seç');
50
+ console.log('4. Hem built-in output hem de built-in input\'u seç');
51
+ console.log('5. İsim ver (örn: "System Audio Capture")');
52
+ console.log('6. System Preferences > Sound > Output\'ta yeni cihazı seç');
53
+
54
+ // Test kayıt yap
55
+ console.log('\n🧪 TEST KAYIT YAPILIYOR...');
56
+ console.log('🎵 Şimdi müzik çal veya YouTube video aç!');
57
+
58
+ const testDevice = systemDevices[0]; // İlk sistem ses cihazını kullan
59
+
60
+ await recorder.startRecording('./test-output/debug-audio.mov', {
61
+ includeSystemAudio: true,
62
+ includeMicrophone: false,
63
+ systemAudioDeviceId: testDevice?.id,
64
+ captureArea: { x: 0, y: 0, width: 300, height: 200 }
65
+ });
66
+
67
+ // 3 saniye kayıt
68
+ await new Promise(resolve => setTimeout(resolve, 3000));
69
+ await recorder.stopRecording();
70
+
71
+ console.log('✅ Test kayıt tamamlandı: ./test-output/debug-audio.mov');
72
+ console.log('🔍 Dosyayı QuickTime Player ile açıp ses kontrolü yap');
73
+
74
+ } catch (error) {
75
+ console.error('❌ Debug hatası:', error.message);
76
+ }
77
+ }
78
+
79
+ debugAudio();