UNPKG

vidclip

Version:

A highly customizable, lightweight screen recorder.

98 lines (97 loc) 5.17 kB
"use strict"; // if there is an error while recording make sure the // ffmpeg process is terminated by checking task manager. var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Recorder = void 0; const fs_1 = __importDefault(require("fs")); const os_1 = __importDefault(require("os")); const path_1 = __importDefault(require("path")); const ffmpeg_1 = __importDefault(require("@ffmpeg-installer/ffmpeg")); const child_process_1 = require("child_process"); const ffmpegPath = ffmpeg_1.default.path; class Recorder { constructor({ resolution, frameRate, fileFormat, audioSource, outputFile, replaceExisting, verbose, rateControl, codec, preset, pixelFormat, } = {}) { this.ffmpegProcess = null; this.isRecording = false; const format = fileFormat !== null && fileFormat !== void 0 ? fileFormat : 'mp4'; // config object this.config = { resolution: resolution !== null && resolution !== void 0 ? resolution : '1920x1080', frameRate: frameRate !== null && frameRate !== void 0 ? frameRate : 30, fileFormat: format, audioSource, outputFile: outputFile !== null && outputFile !== void 0 ? outputFile : `recordings/recording.${format}`, replaceExisting: replaceExisting !== null && replaceExisting !== void 0 ? replaceExisting : true, verbose: verbose !== null && verbose !== void 0 ? verbose : false, rateControl: rateControl !== null && rateControl !== void 0 ? rateControl : { mode: 'crf', value: 18 }, codec: codec !== null && codec !== void 0 ? codec : 'libx264', preset: preset !== null && preset !== void 0 ? preset : 'fast', pixelFormat: pixelFormat !== null && pixelFormat !== void 0 ? pixelFormat : 'yuv420p', }; const dir = path_1.default.dirname(this.config.outputFile); if (!fs_1.default.existsSync(dir)) { fs_1.default.mkdirSync(dir, { recursive: true }); } } // get functions get getConfig() { return { ...this.config }; } // public functions start({ stopAfter } = {}) { const platform = os_1.default.platform(); // prettier-ignore const ffmpegArgs = [ ...(this.config.replaceExisting ? ['-y'] : ['-n']), '-thread_queue_size', '512', '-f', platform === 'win32' ? 'gdigrab' : platform === 'darwin' ? 'avfoundation' : 'x11grab', '-framerate', String(this.config.frameRate), '-video_size', this.config.resolution, '-i', platform === 'darwin' ? '1' : platform === 'win32' ? 'desktop' : ':0.0', // AUDIO INPUT ...(this.config.audioSource ? platform === 'win32' ? ['-f', 'dshow', '-i', `audio=${this.config.audioSource}`] : platform === 'darwin' ? ['-f', 'avfoundation', '-i', this.config.audioSource] : ['-f', 'pulse', '-i', 'default'] : []), // VIDEO ENCODING '-c:v', this.config.codec, ...(this.config.preset ? ['-preset', this.config.preset] : []), ...(this.config.pixelFormat ? ['-pix_fmt', this.config.pixelFormat] : []), // RATE CONTROL ...(this.config.rateControl ? [this.config.rateControl.mode === 'crf' ? '-crf' : this.config.rateControl.mode === 'cq' ? '-cq' : this.config.rateControl.mode === 'bitrate' ? '-b:v' : this.config.rateControl.mode === 'qp' ? '-qp' : '', this.config.rateControl.mode === 'bitrate' ? `${this.config.rateControl.value}k` : String(this.config.rateControl.value)] : []), ...(stopAfter ? ['-t', String(stopAfter)] : []), this.config.outputFile ]; try { this.ffmpegProcess = (0, child_process_1.spawn)(ffmpegPath, ffmpegArgs, { stdio: this.config.verbose ? ['pipe', 'inherit', 'inherit'] : ['pipe', 'ignore', 'ignore'], }); this.isRecording = true; this.ffmpegProcess.on('error', (error) => { var _a; console.error(`ffmpegProcess error: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`); return this.stop(true); }); } catch (error) { this.stop(true); throw error; } } stop(force) { var _a, _b; this.isRecording = false; if (this.ffmpegProcess) { // perform multiple checks so ffmpegProcess gets terminated force ? this.ffmpegProcess.kill('SIGKILL') : this.ffmpegProcess.kill('SIGINT'); (_a = this.ffmpegProcess.stdin) === null || _a === void 0 ? void 0 : _a.write('q'); (_b = this.ffmpegProcess.stdin) === null || _b === void 0 ? void 0 : _b.end(); this.ffmpegProcess = null; console.log('ffmpegProcess successfully terminated.'); } else { console.warn('ffmpegProcess is nullish.'); } } } exports.Recorder = Recorder;