mirror of
https://github.com/rjNemo/screen_recorder
synced 2026-06-06 02:36:49 +00:00
v0 release
This commit is contained in:
commit
812a542dfe
7 changed files with 4915 additions and 0 deletions
89
.gitignore
vendored
Normal file
89
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
.DS_Store
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# Webpack
|
||||
.webpack/
|
||||
|
||||
# Electron-Forge
|
||||
out/
|
||||
4588
package-lock.json
generated
Normal file
4588
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
58
package.json
Normal file
58
package.json
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
"name": "screenrecorder",
|
||||
"productName": "screenrecorder",
|
||||
"version": "1.0.0",
|
||||
"description": "My Electron application description",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"start": "electron-forge start",
|
||||
"package": "electron-forge package",
|
||||
"make": "electron-forge make",
|
||||
"publish": "electron-forge publish",
|
||||
"lint": "echo \"No linting configured\""
|
||||
},
|
||||
"keywords": [],
|
||||
"author": {
|
||||
"name": "Ruidy Nemausat",
|
||||
"email": "ruidy.nemausat@gmail.com"
|
||||
},
|
||||
"license": "MIT",
|
||||
"config": {
|
||||
"forge": {
|
||||
"packagerConfig": {},
|
||||
"makers": [
|
||||
{
|
||||
"name": "@electron-forge/maker-squirrel",
|
||||
"config": {
|
||||
"name": "screenrecorder"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "@electron-forge/maker-zip",
|
||||
"platforms": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "@electron-forge/maker-deb",
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"name": "@electron-forge/maker-rpm",
|
||||
"config": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"electron-squirrel-startup": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@electron-forge/cli": "^6.0.0-beta.50",
|
||||
"@electron-forge/maker-deb": "^6.0.0-beta.50",
|
||||
"@electron-forge/maker-rpm": "^6.0.0-beta.50",
|
||||
"@electron-forge/maker-squirrel": "^6.0.0-beta.50",
|
||||
"@electron-forge/maker-zip": "^6.0.0-beta.50",
|
||||
"electron": "8.2.1"
|
||||
}
|
||||
}
|
||||
30
src/index.css
Normal file
30
src/index.css
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
|
||||
Arial, sans-serif;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: aliceblue;
|
||||
}
|
||||
|
||||
h1 {
|
||||
align-items: center;
|
||||
margin: auto;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
video {
|
||||
background-color: black;
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
bottom: -10px;
|
||||
margin: auto;
|
||||
width: 60%;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
27
src/index.html
Normal file
27
src/index.html
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>📹 Screen Recorder</title>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
|
||||
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
<link rel="stylesheet" href="index.css" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>📹 Screen Recorder</h1>
|
||||
<video src=""></video>
|
||||
<div>
|
||||
<button id="startBtn" class="btn btn-primary">Start</button>
|
||||
<button id="stopBtn" class="btn btn-warning">Stop</button>
|
||||
|
||||
<button id="videoSelectBtn" class="btn btn-outline-primary">
|
||||
Video source
|
||||
</button>
|
||||
</div>
|
||||
<script defer src="render.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
35
src/index.js
Normal file
35
src/index.js
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
const { app, BrowserWindow } = require("electron");
|
||||
const { join } = require("path");
|
||||
|
||||
if (require("electron-squirrel-startup")) {
|
||||
app.quit();
|
||||
}
|
||||
|
||||
const createWindow = () => {
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
},
|
||||
});
|
||||
|
||||
mainWindow.loadFile(join(__dirname, "index.html"));
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools();
|
||||
};
|
||||
|
||||
app.on("ready", createWindow);
|
||||
|
||||
app.on("window-all-closed", () => {
|
||||
if (process.platform !== "darwin") {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
|
||||
app.on("activate", () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow();
|
||||
}
|
||||
});
|
||||
88
src/render.js
Normal file
88
src/render.js
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
const { desktopCapturer, remote } = require("electron");
|
||||
const { writeFile } = require("fs");
|
||||
|
||||
const { dialog, Menu } = remote;
|
||||
|
||||
let mediaRecorder;
|
||||
const recordedChunks = [];
|
||||
|
||||
const startBtn = document.getElementById("startBtn");
|
||||
startBtn.onclick = (e) => {
|
||||
mediaRecorder.start();
|
||||
startBtn.classList.add("btn-danger");
|
||||
startBtn.innerText = "Recording";
|
||||
};
|
||||
|
||||
const stopBtn = document.getElementById("stopBtn");
|
||||
stopBtn.onclick = (e) => {
|
||||
mediaRecorder.stop();
|
||||
startBtn.classList.remove("btn-danger");
|
||||
startBtn.innerText = "Start";
|
||||
};
|
||||
|
||||
const handleDataAvailable = (e) => {
|
||||
recordedChunks.push(e.data);
|
||||
};
|
||||
|
||||
const handleStop = async (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",
|
||||
defaultPath: `capture-${Date.now()}.webm`,
|
||||
});
|
||||
writeFile(filePath, buffer, () => alert("Video saved successfully"));
|
||||
};
|
||||
|
||||
const videoPlayer = document.querySelector("video");
|
||||
const videoSelectBtn = document.getElementById("videoSelectBtn");
|
||||
|
||||
// selectsource changes the videoSource to record.
|
||||
const selectSource = async (src) => {
|
||||
videoSelectBtn.innerText = `Source: ${src.name}`;
|
||||
|
||||
const constraints = {
|
||||
audio: false,
|
||||
video: {
|
||||
mandatory: {
|
||||
chromeMediaSource: "desktop",
|
||||
chromeMediaSourceId: src.id,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia(constraints);
|
||||
|
||||
// Preview the source in videoPlayer
|
||||
videoPlayer.srcObject = stream;
|
||||
videoPlayer.play();
|
||||
|
||||
const options = { mimeType: "video/webm; codecs=vp9" };
|
||||
mediaRecorder = new MediaRecorder(stream, options);
|
||||
|
||||
mediaRecorder.ondataavailable = handleDataAvailable;
|
||||
mediaRecorder.onstop = handleStop;
|
||||
};
|
||||
|
||||
// videoSources gets the available video sources.
|
||||
const videoSources = async () => {
|
||||
const inputSources = await desktopCapturer.getSources({
|
||||
types: ["window", "screen"],
|
||||
});
|
||||
const optionsMenu = Menu.buildFromTemplate(
|
||||
inputSources.map((src) => {
|
||||
return {
|
||||
label: src.name,
|
||||
click: () => selectSource(src),
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
optionsMenu.popup();
|
||||
};
|
||||
|
||||
videoSelectBtn.onclick = videoSources;
|
||||
Loading…
Reference in a new issue