Welcome Folks In this blog post I will be talking about how to make a screen recorder desktop app using the Electron-Forge and Node.js Full Project.
This is the pic of the desktop app where you can select first of all which screen to record as a video and then click the start button to start recording and if you want to stop the recording you can press the stop button to stop the recording and save the video file on your local computer.
Practical Video
Initial Setup
Electron Forge
Create a new app with Electron Forge – it provides a solid starting point for building and distributing the app.
1 |
npx create-electron-app screen-recorder |
This is the command to create the electron boilerplate demo app which will have electron-forge tool to build and distribute your app automatically when you are done with building your app.
index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
const { app, BrowserWindow } = require('electron'); const path = require('path'); // Handle creating/removing shortcuts on Windows when installing/uninstalling. if (require('electron-squirrel-startup')) { // eslint-disable-line global-require app.quit(); } const createWindow = () => { // Create the browser window. const mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences:{ nodeIntegration:true } }); // and load the index.html of the app. mainWindow.loadFile(path.join(__dirname, 'index.html')); // Open the DevTools. mainWindow.webContents.openDevTools(); }; // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. app.on('ready', createWindow); // Quit when all windows are closed. app.on('window-all-closed', () => { // On OS X it is common for applications and their menu bar // to stay active until the user quits explicitly with Cmd + Q if (process.platform !== 'darwin') { app.quit(); } }); app.on('activate', () => { // On OS X it's common to re-create a window in the app when the // dock icon is clicked and there are no other windows open. if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } }); // In this file you can include the rest of your app's specific main process // code. You can also put them in separate files and import them here. |
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Simple Screen Recorder</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.8.0/css/bulma.min.css" /> <link rel="stylesheet" href="index.css" /> <script defer src="render.js"></script> </head> <body class="content"> <h1>⚡ Electron Screen Recorder</h1> <video></video> <button id="startBtn" class="button is-primary">Start</button> <button id="stopBtn" class="button is-warning">Stop</button> <hr /> <button id="videoSelectBtn" class="button is-text"> Choose a Video Source </button> </body> </html> |
render.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
const { desktopCapturer, remote } = require('electron'); const { writeFile } = require('fs'); const { dialog, Menu } = remote; // Global state let mediaRecorder; // MediaRecorder instance to capture footage const recordedChunks = []; // Buttons const videoElement = document.querySelector('video'); const startBtn = document.getElementById('startBtn'); startBtn.onclick = e => { mediaRecorder.start(); startBtn.classList.add('is-danger'); startBtn.innerText = 'Recording'; }; const stopBtn = document.getElementById('stopBtn'); stopBtn.onclick = e => { mediaRecorder.stop(); startBtn.classList.remove('is-danger'); startBtn.innerText = 'Start'; }; const videoSelectBtn = document.getElementById('videoSelectBtn'); videoSelectBtn.onclick = getVideoSources; // Get the available video sources async function getVideoSources() { const inputSources = await desktopCapturer.getSources({ types: ['window', 'screen'] }); const videoOptionsMenu = Menu.buildFromTemplate( inputSources.map(source => { return { label: source.name, click: () => selectSource(source) }; }) ); videoOptionsMenu.popup(); } // Change the videoSource window to record async function selectSource(source) { videoSelectBtn.innerText = source.name; const constraints = { audio: false, video: { mandatory: { chromeMediaSource: 'desktop', chromeMediaSourceId: source.id } } }; // Create a Stream const stream = await navigator.mediaDevices .getUserMedia(constraints); // Preview the source in a video element videoElement.srcObject = stream; videoElement.play(); // Create the Media Recorder const options = { mimeType: 'video/webm; codecs=vp9' }; mediaRecorder = new MediaRecorder(stream, options); // Register Event Handlers mediaRecorder.ondataavailable = handleDataAvailable; mediaRecorder.onstop = handleStop; // Updates the UI } // Captures all recorded chunks function handleDataAvailable(e) { console.log('video data available'); recordedChunks.push(e.data); } // Saves the video file on stop async function handleStop(e) { const blob = new Blob(recordedChunks, { type: 'video/webm; codecs=vp9' }); const buffer = Buffer.from(await blob.arrayBuffer()); const { filePath } = await dialog.showSaveDialog({ buttonLabel: 'Save video', defaultPath: `vid-${Date.now()}.webm` }); if (filePath) { writeFile(filePath, buffer, () => console.log('video saved successfully!')); } } |
index.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; margin: auto; max-width: 38rem; padding: 2rem; } video { width: 100%; height: auto; } body { text-align: center; padding-top: 20px; } |