Add screen capturing

This commit is contained in:
Dustin Brett 2023-01-14 17:29:53 -08:00
parent 62d450e9f3
commit 9833c34599
5 changed files with 121 additions and 1 deletions

View File

@ -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

View File

@ -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,

View File

@ -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",

View File

@ -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

View File

@ -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"