node-mac-recorder 2.16.25 โ†’ 2.16.27

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.
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "permissions": {
3
3
  "allow": [
4
- "Bash(FORCE_AVFOUNDATION=1 node -e \"\nconsole.log(''๐Ÿงช Testing external display recording WITH AUDIO - debug version...'');\nconst MacRecorder = require(''./index.js'');\nconst recorder = new MacRecorder();\n\nrecorder.startRecording(''/tmp/external-audio-debug.mov'', {\n displayId: 3, // External display\n includeMicrophone: true,\n includeSystemAudio: true,\n captureCursor: true\n})\n .then(success => {\n console.log(''Start result:'', success ? ''โœ… SUCCESS'' : ''โŒ FAILED'');\n if (success) {\n setTimeout(() => {\n console.log(''โน๏ธ Stopping recording...'');\n recorder.stopRecording().then(() => {\n console.log(''โœ… Recording stopped'');\n const fs = require(''fs'');\n if (fs.existsSync(''/tmp/external-audio-debug.mov'')) {\n const size = Math.round(fs.statSync(''/tmp/external-audio-debug.mov'').size/1024);\n console.log(''๐Ÿ“น File size:'', size + ''KB'');\n if (size > 100) {\n console.log(''๐ŸŽ‰ External display recording with audio SUCCESS!'');\n } else {\n console.log(''โš ๏ธ File too small, may have failed'');\n }\n } else {\n console.log(''โŒ No output file created'');\n }\n });\n }, 4000); // 4 seconds recording\n }\n })\n .catch(console.error);\n\")"
4
+ "Bash(FORCE_AVFOUNDATION=1 node test-sequential.js)",
5
+ "Bash(grep:*)"
5
6
  ],
6
7
  "deny": [],
7
8
  "ask": []
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-mac-recorder",
3
- "version": "2.16.25",
3
+ "version": "2.16.27",
4
4
  "description": "Native macOS screen recording package for Node.js applications",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -329,7 +329,6 @@ static NSString *g_outputPath = nil;
329
329
  }
330
330
 
331
331
  NSLog(@"๐Ÿ›‘ Stopping pure ScreenCaptureKit recording");
332
- g_isCleaningUp = YES;
333
332
 
334
333
  // Store stream reference to prevent it from being deallocated
335
334
  SCStream *streamToStop = g_stream;
@@ -340,11 +339,12 @@ static NSString *g_outputPath = nil;
340
339
  }
341
340
  NSLog(@"โœ… Pure stream stopped");
342
341
 
342
+ // Immediately reset recording state to allow new recordings
343
+ g_isRecording = NO;
344
+
343
345
  // Finalize on main queue to prevent threading issues
344
346
  dispatch_async(dispatch_get_main_queue(), ^{
345
- if (g_isCleaningUp) { // Only finalize if we initiated cleanup
346
- [ScreenCaptureKitRecorder finalizeRecording];
347
- }
347
+ [ScreenCaptureKitRecorder cleanupVideoWriter];
348
348
  });
349
349
  }];
350
350
  }
@@ -360,13 +360,10 @@ static NSString *g_outputPath = nil;
360
360
 
361
361
  + (void)finalizeRecording {
362
362
  @synchronized([ScreenCaptureKitRecorder class]) {
363
- if (g_isCleaningUp && g_isRecording == NO) {
364
- NSLog(@"โš ๏ธ Already finalizing, skipping duplicate call");
365
- return;
366
- }
367
-
368
363
  NSLog(@"๐ŸŽฌ Finalizing pure ScreenCaptureKit recording");
369
364
 
365
+ // Set cleanup flag now that we're actually cleaning up
366
+ g_isCleaningUp = YES;
370
367
  g_isRecording = NO;
371
368
 
372
369
  if (g_recordingOutput) {
@@ -475,8 +475,45 @@ void updateScreenOverlays();
475
475
  NSLog(@"๐Ÿ”ฅ Current window under cursor: %@", g_currentWindowUnderCursor);
476
476
 
477
477
  if (g_currentWindowUnderCursor) {
478
- g_selectedWindowInfo = [g_currentWindowUnderCursor retain];
479
- NSLog(@"๐Ÿ”ฅ Selected window info set: %@", g_selectedWindowInfo);
478
+ // Get window's screen information for display ID
479
+ NSMutableDictionary *windowInfoWithDisplay = [g_currentWindowUnderCursor mutableCopy];
480
+
481
+ // Get window bounds to determine which screen it's on
482
+ NSNumber *windowX = [g_currentWindowUnderCursor objectForKey:@"x"];
483
+ NSNumber *windowY = [g_currentWindowUnderCursor objectForKey:@"y"];
484
+
485
+ if (windowX && windowY) {
486
+ CGFloat x = [windowX doubleValue];
487
+ CGFloat y = [windowY doubleValue];
488
+
489
+ // Find the display that contains this window
490
+ CGDirectDisplayID activeDisplays[32];
491
+ uint32_t displayCount;
492
+ CGGetActiveDisplayList(32, activeDisplays, &displayCount);
493
+
494
+ CGDirectDisplayID targetDisplayID = 0;
495
+ for (uint32_t i = 0; i < displayCount; i++) {
496
+ CGDirectDisplayID displayID = activeDisplays[i];
497
+ CGRect displayBounds = CGDisplayBounds(displayID);
498
+
499
+ // Check if window center is within this display
500
+ if (x >= displayBounds.origin.x && x < displayBounds.origin.x + displayBounds.size.width &&
501
+ y >= displayBounds.origin.y && y < displayBounds.origin.y + displayBounds.size.height) {
502
+ targetDisplayID = displayID;
503
+ break;
504
+ }
505
+ }
506
+
507
+ if (targetDisplayID != 0) {
508
+ [windowInfoWithDisplay setObject:@(targetDisplayID) forKey:@"screenId"];
509
+ NSLog(@"๐ŸŽฏ Window on display ID: %u", targetDisplayID);
510
+ } else {
511
+ NSLog(@"โš ๏ธ Could not determine display ID for window");
512
+ }
513
+ }
514
+
515
+ g_selectedWindowInfo = [windowInfoWithDisplay retain];
516
+ NSLog(@"๐Ÿ”ฅ Selected window info with display ID: %@", g_selectedWindowInfo);
480
517
  cleanupWindowSelector();
481
518
  } else {
482
519
  NSLog(@"โš ๏ธ No window under cursor when button clicked!");
@@ -2360,15 +2397,35 @@ Napi::Value GetSelectedWindowInfo(const Napi::CallbackInfo& info) {
2360
2397
  windowScreen = mainScreen;
2361
2398
  }
2362
2399
 
2363
- // Simple screen information - no complex mapping
2400
+ // Convert NSScreen to CGDirectDisplayID properly
2364
2401
  NSRect screenFrame = [windowScreen frame];
2365
2402
  NSNumber *screenNumber = [windowScreen deviceDescription][@"NSScreenNumber"];
2366
2403
 
2367
- NSLog(@"๐Ÿ” Window screen: Frame=(%.0f,%.0f,%.0fx%.0f) ScreenNumber=%@",
2404
+ // Find the actual CGDirectDisplayID that matches this screen's frame
2405
+ CGDirectDisplayID displayID = 0;
2406
+ CGDirectDisplayID activeDisplays[32];
2407
+ uint32_t displayCount;
2408
+ CGGetActiveDisplayList(32, activeDisplays, &displayCount);
2409
+
2410
+ for (uint32_t i = 0; i < displayCount; i++) {
2411
+ CGDirectDisplayID candidateID = activeDisplays[i];
2412
+ CGRect displayBounds = CGDisplayBounds(candidateID);
2413
+
2414
+ // Match by screen frame coordinates
2415
+ if (fabs(screenFrame.origin.x - displayBounds.origin.x) < 1.0 &&
2416
+ fabs(screenFrame.origin.y - displayBounds.origin.y) < 1.0 &&
2417
+ fabs(screenFrame.size.width - displayBounds.size.width) < 1.0 &&
2418
+ fabs(screenFrame.size.height - displayBounds.size.height) < 1.0) {
2419
+ displayID = candidateID;
2420
+ break;
2421
+ }
2422
+ }
2423
+
2424
+ NSLog(@"๐Ÿ” Window screen: Frame=(%.0f,%.0f,%.0fx%.0f) NSScreenNumber=%@ โ†’ CGDirectDisplayID=%u",
2368
2425
  screenFrame.origin.x, screenFrame.origin.y,
2369
- screenFrame.size.width, screenFrame.size.height, screenNumber);
2426
+ screenFrame.size.width, screenFrame.size.height, screenNumber, displayID);
2370
2427
 
2371
- result.Set("screenId", Napi::Number::New(env, [screenNumber unsignedIntValue]));
2428
+ result.Set("screenId", Napi::Number::New(env, displayID));
2372
2429
  result.Set("screenX", Napi::Number::New(env, (int)screenFrame.origin.x));
2373
2430
  result.Set("screenY", Napi::Number::New(env, (int)screenFrame.origin.y));
2374
2431
  result.Set("screenWidth", Napi::Number::New(env, (int)screenFrame.size.width));