node-mac-recorder 2.21.13 → 2.21.15
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/.claude/settings.local.json +3 -1
- package/index.js +82 -28
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -437,9 +437,9 @@ class MacRecorder extends EventEmitter {
|
|
|
437
437
|
|
|
438
438
|
this.outputPath = outputPath;
|
|
439
439
|
|
|
440
|
-
return new Promise((resolve, reject) => {
|
|
440
|
+
return new Promise(async (resolve, reject) => {
|
|
441
441
|
try {
|
|
442
|
-
//
|
|
442
|
+
// SYNC FIX: Create unified session timestamp FIRST for all components
|
|
443
443
|
const sessionTimestamp = Date.now();
|
|
444
444
|
this.sessionTimestamp = sessionTimestamp;
|
|
445
445
|
const outputDir = path.dirname(outputPath);
|
|
@@ -507,15 +507,45 @@ class MacRecorder extends EventEmitter {
|
|
|
507
507
|
};
|
|
508
508
|
}
|
|
509
509
|
|
|
510
|
+
// CRITICAL SYNC FIX: Start native recording FIRST (video/audio/camera)
|
|
511
|
+
// Then IMMEDIATELY start cursor tracking with the SAME timestamp
|
|
512
|
+
// This ensures ALL components capture their first frame at the same time
|
|
513
|
+
|
|
510
514
|
let success;
|
|
511
515
|
try {
|
|
516
|
+
console.log('🎯 SYNC: Starting native recording (screen/audio/camera) at timestamp:', sessionTimestamp);
|
|
512
517
|
success = nativeBinding.startRecording(
|
|
513
518
|
outputPath,
|
|
514
519
|
recordingOptions
|
|
515
520
|
);
|
|
521
|
+
if (success) {
|
|
522
|
+
console.log('✅ SYNC: Native recording started successfully');
|
|
523
|
+
}
|
|
516
524
|
} catch (error) {
|
|
517
|
-
// console.log('Native recording failed, trying alternative method');
|
|
518
525
|
success = false;
|
|
526
|
+
console.warn('❌ Native recording failed to start:', error.message);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// Only start cursor if native recording started successfully
|
|
530
|
+
if (success) {
|
|
531
|
+
const standardCursorOptions = {
|
|
532
|
+
videoRelative: true,
|
|
533
|
+
displayInfo: this.recordingDisplayInfo,
|
|
534
|
+
recordingType: this.options.windowId ? 'window' :
|
|
535
|
+
this.options.captureArea ? 'area' : 'display',
|
|
536
|
+
captureArea: this.options.captureArea,
|
|
537
|
+
windowId: this.options.windowId,
|
|
538
|
+
startTimestamp: sessionTimestamp // Use the same timestamp base
|
|
539
|
+
};
|
|
540
|
+
|
|
541
|
+
try {
|
|
542
|
+
console.log('🎯 SYNC: Starting cursor tracking at timestamp:', sessionTimestamp);
|
|
543
|
+
await this.startCursorCapture(cursorFilePath, standardCursorOptions);
|
|
544
|
+
console.log('✅ SYNC: Cursor tracking started successfully');
|
|
545
|
+
} catch (cursorError) {
|
|
546
|
+
console.warn('⚠️ Cursor tracking failed to start:', cursorError.message);
|
|
547
|
+
// Continue with recording even if cursor fails - don't stop native recording
|
|
548
|
+
}
|
|
519
549
|
}
|
|
520
550
|
|
|
521
551
|
if (success) {
|
|
@@ -546,10 +576,12 @@ class MacRecorder extends EventEmitter {
|
|
|
546
576
|
}
|
|
547
577
|
}
|
|
548
578
|
this.isRecording = true;
|
|
549
|
-
|
|
579
|
+
// SYNC FIX: Use session timestamp for consistent timing across all components
|
|
580
|
+
this.recordingStartTime = sessionTimestamp;
|
|
550
581
|
|
|
551
582
|
if (this.options.captureCamera === true && cameraFilePath) {
|
|
552
583
|
this.cameraCaptureActive = true;
|
|
584
|
+
console.log('📹 SYNC: Camera recording started at timestamp:', sessionTimestamp);
|
|
553
585
|
this.emit("cameraCaptureStarted", {
|
|
554
586
|
outputPath: cameraFilePath,
|
|
555
587
|
deviceId: this.options.cameraDeviceId || null,
|
|
@@ -560,6 +592,7 @@ class MacRecorder extends EventEmitter {
|
|
|
560
592
|
|
|
561
593
|
if (captureAudio && audioFilePath) {
|
|
562
594
|
this.audioCaptureActive = true;
|
|
595
|
+
console.log('🎙️ SYNC: Audio recording started at timestamp:', sessionTimestamp);
|
|
563
596
|
this.emit("audioCaptureStarted", {
|
|
564
597
|
outputPath: audioFilePath,
|
|
565
598
|
deviceIds: {
|
|
@@ -571,20 +604,17 @@ class MacRecorder extends EventEmitter {
|
|
|
571
604
|
});
|
|
572
605
|
}
|
|
573
606
|
|
|
574
|
-
//
|
|
575
|
-
//
|
|
576
|
-
const standardCursorOptions = {
|
|
577
|
-
videoRelative: true,
|
|
578
|
-
displayInfo: this.recordingDisplayInfo,
|
|
579
|
-
recordingType: this.options.windowId ? 'window' :
|
|
580
|
-
this.options.captureArea ? 'area' : 'display',
|
|
581
|
-
captureArea: this.options.captureArea,
|
|
582
|
-
windowId: this.options.windowId
|
|
583
|
-
};
|
|
607
|
+
// SYNC FIX: Cursor tracking already started BEFORE recording for perfect sync
|
|
608
|
+
// (Removed duplicate cursor start code)
|
|
584
609
|
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
610
|
+
// Log synchronized recording summary
|
|
611
|
+
const activeComponents = [];
|
|
612
|
+
activeComponents.push('Screen');
|
|
613
|
+
if (this.cursorCaptureInterval) activeComponents.push('Cursor');
|
|
614
|
+
if (this.cameraCaptureActive) activeComponents.push('Camera');
|
|
615
|
+
if (this.audioCaptureActive) activeComponents.push('Audio');
|
|
616
|
+
console.log(`✅ SYNC COMPLETE: All components synchronized at timestamp ${sessionTimestamp}`);
|
|
617
|
+
console.log(` Active components: ${activeComponents.join(', ')}`);
|
|
588
618
|
|
|
589
619
|
// Timer başlat (progress tracking için)
|
|
590
620
|
this.recordingTimer = setInterval(() => {
|
|
@@ -696,20 +726,38 @@ class MacRecorder extends EventEmitter {
|
|
|
696
726
|
|
|
697
727
|
|
|
698
728
|
/**
|
|
699
|
-
* Ekran kaydını durdurur
|
|
729
|
+
* Ekran kaydını durdurur - SYNCHRONIZED stop for all components
|
|
700
730
|
*/
|
|
701
731
|
async stopRecording() {
|
|
702
732
|
if (!this.isRecording) {
|
|
703
733
|
throw new Error("No recording in progress");
|
|
704
734
|
}
|
|
705
735
|
|
|
706
|
-
return new Promise((resolve, reject) => {
|
|
736
|
+
return new Promise(async (resolve, reject) => {
|
|
707
737
|
try {
|
|
738
|
+
console.log('🛑 SYNC: Stopping all recording components simultaneously');
|
|
739
|
+
|
|
740
|
+
// SYNC FIX: Stop ALL components at the same time for perfect sync
|
|
741
|
+
// 1. Stop cursor tracking FIRST (it's instant)
|
|
742
|
+
if (this.cursorCaptureInterval) {
|
|
743
|
+
try {
|
|
744
|
+
console.log('🛑 SYNC: Stopping cursor tracking');
|
|
745
|
+
await this.stopCursorCapture();
|
|
746
|
+
console.log('✅ SYNC: Cursor tracking stopped');
|
|
747
|
+
} catch (cursorError) {
|
|
748
|
+
console.warn('⚠️ Cursor tracking failed to stop:', cursorError.message);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
708
752
|
let success = false;
|
|
709
|
-
|
|
710
|
-
//
|
|
753
|
+
|
|
754
|
+
// 2. Stop native screen recording
|
|
711
755
|
try {
|
|
756
|
+
console.log('🛑 SYNC: Stopping screen recording');
|
|
712
757
|
success = nativeBinding.stopRecording();
|
|
758
|
+
if (success) {
|
|
759
|
+
console.log('✅ SYNC: Screen recording stopped');
|
|
760
|
+
}
|
|
713
761
|
} catch (nativeError) {
|
|
714
762
|
// console.log('Native stop failed:', nativeError.message);
|
|
715
763
|
success = true; // Assume success to avoid throwing
|
|
@@ -744,6 +792,7 @@ class MacRecorder extends EventEmitter {
|
|
|
744
792
|
|
|
745
793
|
if (this.cameraCaptureActive) {
|
|
746
794
|
this.cameraCaptureActive = false;
|
|
795
|
+
console.log('📹 SYNC: Camera recording stopped');
|
|
747
796
|
this.emit("cameraCaptureStopped", {
|
|
748
797
|
outputPath: this.cameraCaptureFile || null,
|
|
749
798
|
success: success === true,
|
|
@@ -753,6 +802,7 @@ class MacRecorder extends EventEmitter {
|
|
|
753
802
|
|
|
754
803
|
if (this.audioCaptureActive) {
|
|
755
804
|
this.audioCaptureActive = false;
|
|
805
|
+
console.log('🎙️ SYNC: Audio recording stopped');
|
|
756
806
|
this.emit("audioCaptureStopped", {
|
|
757
807
|
outputPath: this.audioCaptureFile || null,
|
|
758
808
|
success: success === true,
|
|
@@ -760,12 +810,11 @@ class MacRecorder extends EventEmitter {
|
|
|
760
810
|
});
|
|
761
811
|
}
|
|
762
812
|
|
|
763
|
-
//
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
}
|
|
813
|
+
// SYNC FIX: Cursor tracking already stopped at the beginning for sync
|
|
814
|
+
// (Removed duplicate cursor stop code)
|
|
815
|
+
|
|
816
|
+
// Log synchronized stop summary
|
|
817
|
+
console.log('✅ SYNC STOP COMPLETE: All recording components stopped simultaneously');
|
|
769
818
|
|
|
770
819
|
// Timer durdur
|
|
771
820
|
if (this.recordingTimer) {
|
|
@@ -964,6 +1013,7 @@ class MacRecorder extends EventEmitter {
|
|
|
964
1013
|
* @param {string} options.recordingType - Type of recording: 'display', 'window', 'area'
|
|
965
1014
|
* @param {Object} options.captureArea - Capture area for area recording coordinate transformation
|
|
966
1015
|
* @param {number} options.windowId - Window ID for window recording coordinate transformation
|
|
1016
|
+
* @param {number} options.startTimestamp - Pre-defined start timestamp for synchronization (optional)
|
|
967
1017
|
*/
|
|
968
1018
|
async startCursorCapture(intervalOrFilepath = 100, options = {}) {
|
|
969
1019
|
let filepath;
|
|
@@ -985,6 +1035,9 @@ class MacRecorder extends EventEmitter {
|
|
|
985
1035
|
throw new Error("Cursor capture is already running");
|
|
986
1036
|
}
|
|
987
1037
|
|
|
1038
|
+
// SYNC FIX: Use pre-defined timestamp if provided for synchronization
|
|
1039
|
+
const syncStartTime = options.startTimestamp || Date.now();
|
|
1040
|
+
|
|
988
1041
|
// Use video-relative coordinate system for all recording types
|
|
989
1042
|
if (options.videoRelative && options.displayInfo) {
|
|
990
1043
|
// Calculate video offset based on recording type
|
|
@@ -1068,7 +1121,8 @@ class MacRecorder extends EventEmitter {
|
|
|
1068
1121
|
fs.writeFileSync(filepath, "[");
|
|
1069
1122
|
|
|
1070
1123
|
this.cursorCaptureFile = filepath;
|
|
1071
|
-
|
|
1124
|
+
// SYNC FIX: Use synchronized start time for accurate timestamp calculation
|
|
1125
|
+
this.cursorCaptureStartTime = syncStartTime;
|
|
1072
1126
|
this.cursorCaptureFirstWrite = true;
|
|
1073
1127
|
this.lastCapturedData = null;
|
|
1074
1128
|
|