UNPKG

node-mac-recorder

Version:

Native macOS screen recording package for Node.js applications

234 lines (196 loc) 7.01 kB
const MacRecorder = require('./index.js'); const path = require('path'); const fs = require('fs'); const http = require('http'); async function startHttpServer(port = 8080) { return new Promise((resolve, reject) => { const server = http.createServer((req, res) => { const rootDir = __dirname; let filePath = path.join(rootDir, req.url === '/' ? 'canvas-player.html' : req.url); // Security: prevent directory traversal if (!filePath.startsWith(rootDir)) { res.writeHead(403); res.end('Forbidden'); return; } // Check if file exists if (!fs.existsSync(filePath)) { res.writeHead(404); res.end('Not found'); return; } // Determine content type const ext = path.extname(filePath); const contentTypes = { '.html': 'text/html', '.js': 'text/javascript', '.json': 'application/json', '.mov': 'video/quicktime', '.mp4': 'video/mp4', '.webm': 'video/webm', '.css': 'text/css' }; const contentType = contentTypes[ext] || 'application/octet-stream'; // Read and serve file fs.readFile(filePath, (err, data) => { if (err) { res.writeHead(500); res.end('Error loading file'); return; } res.writeHead(200, { 'Content-Type': contentType, 'Access-Control-Allow-Origin': '*' }); res.end(data); }); }); server.listen(port, () => { console.log(`\n🌐 HTTP Server started at http://localhost:${port}`); resolve(server); }); server.on('error', (err) => { if (err.code === 'EADDRINUSE') { console.log(` Port ${port} is busy, trying ${port + 1}...`); startHttpServer(port + 1).then(resolve).catch(reject); } else { reject(err); } }); }); } async function runCanvasTest() { console.log('🎬 Canvas Test: Starting 10-second recording with all features...\n'); const recorder = new MacRecorder(); const outputDir = path.join(__dirname, 'test-output'); // Ensure output directory exists if (!fs.existsSync(outputDir)) { fs.mkdirSync(outputDir, { recursive: true }); } try { // Check permissions first const permissions = await recorder.checkPermissions(); console.log('📋 Permissions:', permissions); if (!permissions.screenRecording) { console.error('❌ Screen recording permission not granted!'); console.error(' Please enable screen recording in System Preferences > Security & Privacy'); process.exit(1); } // Get available devices console.log('\n🔍 Detecting devices...'); const cameras = await recorder.getCameraDevices(); const audioDevices = await recorder.getAudioDevices(); const displays = await recorder.getDisplays(); console.log(` 📹 Cameras found: ${cameras.length}`); if (cameras.length > 0) { cameras.forEach((cam, i) => { console.log(` ${i + 1}. ${cam.name} (${cam.position})`); }); } console.log(` 🎙️ Audio devices found: ${audioDevices.length}`); if (audioDevices.length > 0) { audioDevices.forEach((dev, i) => { console.log(` ${i + 1}. ${dev.name}${dev.isDefault ? ' (default)' : ''}`); }); } console.log(` 🖥️ Displays found: ${displays.length}`); displays.forEach((display, i) => { console.log(` ${i + 1}. ${display.name} ${display.resolution}${display.isPrimary ? ' (primary)' : ''}`); }); // Setup recording options const outputPath = path.join(outputDir, 'screen.mov'); const recordingOptions = { includeMicrophone: true, includeSystemAudio: false, // Typically off to avoid feedback captureCursor: true, captureCamera: cameras.length > 0, cameraDeviceId: cameras.length > 0 ? cameras[0].id : null, quality: 'high', frameRate: 60 }; console.log('\n⚙️ Recording options:', recordingOptions); console.log('\n🎥 Starting recording...'); // Event listeners for tracking recorder.on('recordingStarted', (info) => { console.log('\n✅ Recording started!'); console.log(' Screen output:', info.outputPath); if (info.cameraOutputPath) { console.log(' Camera output:', info.cameraOutputPath); } if (info.audioOutputPath) { console.log(' Audio output:', info.audioOutputPath); } if (info.cursorOutputPath) { console.log(' Cursor data:', info.cursorOutputPath); } console.log(' Session timestamp:', info.sessionTimestamp); }); recorder.on('timeUpdate', (seconds) => { process.stdout.write(`\r⏱️ Recording: ${seconds}/10 seconds`); }); // Start recording await recorder.startRecording(outputPath, recordingOptions); // Record for 10 seconds await new Promise(resolve => setTimeout(resolve, 10000)); console.log('\n\n🛑 Stopping recording...'); const result = await recorder.stopRecording(); console.log('\n✅ Recording completed!'); console.log(' Screen:', result.outputPath); if (result.cameraOutputPath) { console.log(' Camera:', result.cameraOutputPath); } if (result.audioOutputPath) { console.log(' Audio:', result.audioOutputPath); } // Find cursor data file const files = fs.readdirSync(outputDir); const cursorFile = files.find(f => f.startsWith('temp_cursor_') && f.endsWith('.json')); const cursorPath = cursorFile ? path.join(outputDir, cursorFile) : null; if (cursorPath && fs.existsSync(cursorPath)) { console.log(' Cursor:', cursorPath); // Validate cursor data const cursorData = JSON.parse(fs.readFileSync(cursorPath, 'utf8')); console.log(` Cursor events captured: ${cursorData.length}`); } // Create metadata file for the player const metadata = { recordingTimestamp: result.sessionTimestamp, syncTimestamp: result.syncTimestamp, duration: 10, files: { screen: path.basename(result.outputPath), camera: result.cameraOutputPath ? path.basename(result.cameraOutputPath) : null, audio: result.audioOutputPath ? path.basename(result.audioOutputPath) : null, cursor: cursorFile }, options: recordingOptions }; const metadataPath = path.join(outputDir, 'recording-metadata.json'); fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2)); console.log(' Metadata:', metadataPath); // Start HTTP server to avoid CORS issues console.log('\n🎨 Starting Canvas Player...'); const server = await startHttpServer(8080); const serverPort = server.address().port; const url = `http://localhost:${serverPort}/canvas-player.html`; console.log(` URL: ${url}`); console.log('\n✨ Opening player in browser...'); console.log(' Press Ctrl+C to stop the server when done.\n'); // Open in browser (macOS) const { exec } = require('child_process'); exec(`open "${url}"`); // Keep server running process.on('SIGINT', () => { console.log('\n\n👋 Shutting down server...'); server.close(() => { console.log('✅ Server closed. Goodbye!'); process.exit(0); }); }); } catch (error) { console.error('\n❌ Error:', error.message); console.error(error.stack); process.exit(1); } } runCanvasTest();