mirror of
https://github.com/DustinBrett/daedalOS.git
synced 2025-12-06 12:20:20 +01:00
Add screen capturing
This commit is contained in:
parent
62d450e9f3
commit
9833c34599
|
|
@ -70,6 +70,7 @@ docker run -dp 3000:3000 --rm --name daedalos daedalos
|
||||||
- Open with, Open file/folder location, Open in new window, Open Terminal here
|
- Open with, Open file/folder location, Open in new window, Open Terminal here
|
||||||
- Download, Add to archive, Extract here, Set as wallpaper, Convert audio/video/photo/spreadsheets
|
- Download, Add to archive, Extract here, Set as wallpaper, Convert audio/video/photo/spreadsheets
|
||||||
- Sort by, New Folder, New Text Document
|
- Sort by, New Folder, New Text Document
|
||||||
|
- Screen Capture
|
||||||
- Keyboard Shortcuts
|
- Keyboard Shortcuts
|
||||||
- CTRL+C, CTRL+V, CTRL+X, CTRL+A, Delete
|
- CTRL+C, CTRL+V, CTRL+X, CTRL+A, Delete
|
||||||
- F2, F5, Backspace, Arrows, Enter
|
- F2, F5, Backspace, Arrows, Enter
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,13 @@ import { useSession } from "contexts/session";
|
||||||
import { dirname, join } from "path";
|
import { dirname, join } from "path";
|
||||||
import { useCallback, useMemo } from "react";
|
import { useCallback, useMemo } from "react";
|
||||||
import {
|
import {
|
||||||
|
DEFAULT_LOCALE,
|
||||||
|
DESKTOP_PATH,
|
||||||
FOLDER_ICON,
|
FOLDER_ICON,
|
||||||
isFileSystemSupported,
|
isFileSystemSupported,
|
||||||
MENU_SEPERATOR,
|
MENU_SEPERATOR,
|
||||||
} from "utils/constants";
|
} from "utils/constants";
|
||||||
|
import { bufferToBlob } from "utils/functions";
|
||||||
|
|
||||||
const NEW_FOLDER = "New folder";
|
const NEW_FOLDER = "New folder";
|
||||||
const NEW_TEXT_DOCUMENT = "New Text Document.txt";
|
const NEW_TEXT_DOCUMENT = "New Text Document.txt";
|
||||||
|
|
@ -31,8 +34,21 @@ const updateSortBy =
|
||||||
|
|
||||||
const EASTER_EGG_CLICK_COUNT = 2;
|
const EASTER_EGG_CLICK_COUNT = 2;
|
||||||
|
|
||||||
|
const CAPTURE_FPS = 30;
|
||||||
|
const CAPTURE_TIME_DATE_FORMAT: Intl.DateTimeFormatOptions = {
|
||||||
|
day: "2-digit",
|
||||||
|
hour: "2-digit",
|
||||||
|
hour12: false,
|
||||||
|
minute: "2-digit",
|
||||||
|
month: "2-digit",
|
||||||
|
second: "2-digit",
|
||||||
|
year: "numeric",
|
||||||
|
};
|
||||||
|
|
||||||
let triggerEasterEggCountdown = EASTER_EGG_CLICK_COUNT;
|
let triggerEasterEggCountdown = EASTER_EGG_CLICK_COUNT;
|
||||||
|
|
||||||
|
let currentMediaStream: MediaStream | undefined;
|
||||||
|
|
||||||
const useFolderContextMenu = (
|
const useFolderContextMenu = (
|
||||||
url: string,
|
url: string,
|
||||||
{
|
{
|
||||||
|
|
@ -44,7 +60,13 @@ const useFolderContextMenu = (
|
||||||
isDesktop?: boolean
|
isDesktop?: boolean
|
||||||
): ContextMenuCapture => {
|
): ContextMenuCapture => {
|
||||||
const { contextMenu } = useMenu();
|
const { contextMenu } = useMenu();
|
||||||
const { mapFs, pasteList = {}, updateFolder } = useFileSystem();
|
const {
|
||||||
|
mapFs,
|
||||||
|
pasteList = {},
|
||||||
|
readFile,
|
||||||
|
writeFile,
|
||||||
|
updateFolder,
|
||||||
|
} = useFileSystem();
|
||||||
const {
|
const {
|
||||||
setWallpaper: setSessionWallpaper,
|
setWallpaper: setSessionWallpaper,
|
||||||
setIconPositions,
|
setIconPositions,
|
||||||
|
|
@ -88,6 +110,83 @@ const useFolderContextMenu = (
|
||||||
},
|
},
|
||||||
[setIconPositions, setSortBy, url]
|
[setIconPositions, setSortBy, url]
|
||||||
);
|
);
|
||||||
|
const captureScreen = useCallback(async () => {
|
||||||
|
if (currentMediaStream) {
|
||||||
|
const { active: wasActive } = currentMediaStream;
|
||||||
|
|
||||||
|
currentMediaStream.getTracks().forEach((track) => track.stop());
|
||||||
|
currentMediaStream = undefined;
|
||||||
|
|
||||||
|
if (wasActive) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const displayMediaOptions: DisplayMediaStreamOptions &
|
||||||
|
MediaStreamConstraints = {
|
||||||
|
preferCurrentTab: true,
|
||||||
|
video: {
|
||||||
|
frameRate: CAPTURE_FPS,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
currentMediaStream = await navigator.mediaDevices.getDisplayMedia(
|
||||||
|
displayMediaOptions
|
||||||
|
);
|
||||||
|
|
||||||
|
const [currentVideoTrack] = currentMediaStream.getVideoTracks();
|
||||||
|
const { height, width } = currentVideoTrack.getSettings();
|
||||||
|
const mediaRecorder = new MediaRecorder(currentMediaStream, {
|
||||||
|
bitsPerSecond: height && width ? height * width * CAPTURE_FPS : undefined,
|
||||||
|
mimeType: "video/webm",
|
||||||
|
});
|
||||||
|
const timeStamp = new Intl.DateTimeFormat(
|
||||||
|
DEFAULT_LOCALE,
|
||||||
|
CAPTURE_TIME_DATE_FORMAT
|
||||||
|
)
|
||||||
|
.format(new Date())
|
||||||
|
.replace(/[/:]/g, "-")
|
||||||
|
.replace(",", "");
|
||||||
|
const fileName = `Screen Capture ${timeStamp}.webm`;
|
||||||
|
const capturePath = join(DESKTOP_PATH, fileName);
|
||||||
|
const startTime = Date.now();
|
||||||
|
let hasCapturedData = false;
|
||||||
|
|
||||||
|
mediaRecorder.start();
|
||||||
|
mediaRecorder.addEventListener("dataavailable", async (event) => {
|
||||||
|
const { data } = event;
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
const bufferData = Buffer.from(await data.arrayBuffer());
|
||||||
|
|
||||||
|
await writeFile(
|
||||||
|
capturePath,
|
||||||
|
hasCapturedData
|
||||||
|
? Buffer.concat([await readFile(capturePath), bufferData])
|
||||||
|
: bufferData,
|
||||||
|
hasCapturedData
|
||||||
|
);
|
||||||
|
|
||||||
|
if (mediaRecorder.state === "inactive") {
|
||||||
|
const { default: fixWebmDuration } = await import(
|
||||||
|
"fix-webm-duration"
|
||||||
|
);
|
||||||
|
|
||||||
|
fixWebmDuration(
|
||||||
|
bufferToBlob(await readFile(capturePath)),
|
||||||
|
Date.now() - startTime,
|
||||||
|
async (capturedFile) => {
|
||||||
|
await writeFile(
|
||||||
|
capturePath,
|
||||||
|
Buffer.from(await capturedFile.arrayBuffer()),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
updateFolder(DESKTOP_PATH, fileName);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
hasCapturedData = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [readFile, updateFolder, writeFile]);
|
||||||
|
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() =>
|
() =>
|
||||||
|
|
@ -189,6 +288,18 @@ const useFolderContextMenu = (
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
...(isDesktop &&
|
||||||
|
"getDisplayMedia" in navigator.mediaDevices &&
|
||||||
|
window.MediaRecorder
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
action: captureScreen,
|
||||||
|
label: currentMediaStream?.active
|
||||||
|
? "Stop screen capture"
|
||||||
|
: "Capture screen",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
MENU_SEPERATOR,
|
MENU_SEPERATOR,
|
||||||
|
|
@ -239,6 +350,7 @@ const useFolderContextMenu = (
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
addToFolder,
|
addToFolder,
|
||||||
|
captureScreen,
|
||||||
contextMenu,
|
contextMenu,
|
||||||
isAscending,
|
isAscending,
|
||||||
isDesktop,
|
isDesktop,
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@
|
||||||
"butterchurn-presets": "^3.0.0-beta.4",
|
"butterchurn-presets": "^3.0.0-beta.4",
|
||||||
"fflate": "^0.7.4",
|
"fflate": "^0.7.4",
|
||||||
"file-type": "^18.1.0",
|
"file-type": "^18.1.0",
|
||||||
|
"fix-webm-duration": "^1.0.5",
|
||||||
"framer-motion": "^8.4.3",
|
"framer-motion": "^8.4.3",
|
||||||
"gif.js": "^0.2.0",
|
"gif.js": "^0.2.0",
|
||||||
"idb": "^7.1.1",
|
"idb": "^7.1.1",
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ This project is greatly augmented by code from the open source community. Thank
|
||||||
- [Matrix](https://github.com/Rezmason/matrix)
|
- [Matrix](https://github.com/Rezmason/matrix)
|
||||||
- [QOI Decoder](https://gist.github.com/nicolaslegland/f0577cb49b1e56b729a2c0fc0aa151ba)
|
- [QOI Decoder](https://gist.github.com/nicolaslegland/f0577cb49b1e56b729a2c0fc0aa151ba)
|
||||||
- [jxl.js](https://github.com/niutech/jxl.js)
|
- [jxl.js](https://github.com/niutech/jxl.js)
|
||||||
|
- [fix-webm-duration](https://github.com/yusitnikov/fix-webm-duration)
|
||||||
|
|
||||||
## App Libraries
|
## App Libraries
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3130,6 +3130,11 @@ find-up@^5.0.0:
|
||||||
locate-path "^6.0.0"
|
locate-path "^6.0.0"
|
||||||
path-exists "^4.0.0"
|
path-exists "^4.0.0"
|
||||||
|
|
||||||
|
fix-webm-duration@^1.0.5:
|
||||||
|
version "1.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/fix-webm-duration/-/fix-webm-duration-1.0.5.tgz#da4558a92196a677302bfc54780b494dd5336a96"
|
||||||
|
integrity sha512-b6oula3OfSknx0aWoLsxvp4DVIYbwsf+UAkr6EDAK3iuMYk/OSNKzmeSI61GXK0MmFTEuzle19BPvTxMIKjkZg==
|
||||||
|
|
||||||
flat-cache@^3.0.4:
|
flat-cache@^3.0.4:
|
||||||
version "3.0.4"
|
version "3.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
|
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user