add video duration metadata to blob

This commit is contained in:
MarconLP 2023-04-20 00:13:50 +02:00
parent 3aec440f1e
commit 09286a6ed8
No known key found for this signature in database
GPG key ID: A08A9C8B623F5EA5
4 changed files with 79 additions and 20 deletions

11
package-lock.json generated
View file

@ -27,6 +27,7 @@
"axios": "^1.3.5",
"dayjs": "^1.11.7",
"file-saver": "^2.0.5",
"fix-webm-duration": "^1.0.5",
"micro": "^10.0.1",
"micro-cors": "^0.1.1",
"next": "^13.3.0",
@ -4230,6 +4231,11 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/fix-webm-duration": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/fix-webm-duration/-/fix-webm-duration-1.0.5.tgz",
"integrity": "sha512-b6oula3OfSknx0aWoLsxvp4DVIYbwsf+UAkr6EDAK3iuMYk/OSNKzmeSI61GXK0MmFTEuzle19BPvTxMIKjkZg=="
},
"node_modules/flat-cache": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
@ -10338,6 +10344,11 @@
"path-exists": "^4.0.0"
}
},
"fix-webm-duration": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/fix-webm-duration/-/fix-webm-duration-1.0.5.tgz",
"integrity": "sha512-b6oula3OfSknx0aWoLsxvp4DVIYbwsf+UAkr6EDAK3iuMYk/OSNKzmeSI61GXK0MmFTEuzle19BPvTxMIKjkZg=="
},
"flat-cache": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",

View file

@ -34,6 +34,7 @@
"axios": "^1.3.5",
"dayjs": "^1.11.7",
"file-saver": "^2.0.5",
"fix-webm-duration": "^1.0.5",
"micro": "^10.0.1",
"micro-cors": "^0.1.1",
"next": "^13.3.0",

View file

@ -10,6 +10,7 @@ import axios from "axios";
import dayjs from "dayjs";
import { useRouter } from "next/router";
import { api } from "~/utils/api";
import fixWebmDuration from "fix-webm-duration";
export default function Recorder() {
const [steam, setStream] = useState<null | MediaStream>(null);
@ -26,6 +27,7 @@ export default function Recorder() {
const [submitting, setSubmitting] = useState<boolean>(false);
const apiUtils = api.useContext();
const getSignedUrl = api.video.getUploadUrl.useMutation();
const [duration, setDuration] = useState<number>(0);
const handleRecording = async () => {
const screenStream = await navigator.mediaDevices.getDisplayMedia({
@ -62,7 +64,13 @@ export default function Recorder() {
if (recorderRef.current === null) return;
recorderRef.current.stopRecording(() => {
if (recorderRef.current) {
setBlob(recorderRef.current.getBlob());
fixWebmDuration(
recorderRef.current.getBlob(),
duration * 1000,
(seekableBlob) => {
setBlob(seekableBlob);
}
);
steam?.getTracks().map((track) => track.stop());
}
});
@ -218,7 +226,11 @@ export default function Recorder() {
className="flex cursor-pointer flex-row items-center justify-center rounded pr-2 text-lg hover:bg-gray-200"
>
<StopIcon className="h-8 w-8 text-[#ff623f]" aria-hidden="true" />
<StopTime running={!pause} />
<StopTime
running={!pause}
duration={duration}
setDuration={setDuration}
/>
</div>
<div className="mx-2 h-6 w-px bg-[#E7E9EB]"></div>
<div
@ -253,18 +265,49 @@ export default function Recorder() {
style={{ width: "700px", margin: "1em" }}
/>
)}
<button
onClick={handleSave}
className="mt-2 rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
>
Download
</button>
<button
onClick={() => void handleUpload()}
className="ml-2 mt-2 rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
>
Upload
</button>
<div className="flex items-center justify-center">
<button
type="button"
className="inline-flex items-center rounded-md bg-indigo-500 px-4 py-2 text-sm font-semibold leading-6 text-white shadow transition duration-150 ease-in-out hover:bg-indigo-400 disabled:cursor-not-allowed"
onClick={() => void handleSave()}
>
Download
</button>
<button
type="button"
className="ml-2 inline-flex items-center rounded-md bg-indigo-500 px-4 py-2 text-sm font-semibold leading-6 text-white shadow transition duration-150 ease-in-out hover:bg-indigo-400 disabled:cursor-not-allowed"
disabled={submitting}
onClick={() => void handleUpload()}
>
{submitting ? (
<>
<svg
className="-ml-1 mr-3 h-5 w-5 animate-spin text-white"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
></circle>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
Uploading...
</>
) : (
<>Upload</>
)}
</button>
</div>
</div>
) : null}
</div>

View file

@ -1,8 +1,12 @@
import React, { useEffect, useState } from "react";
import React, { useEffect } from "react";
export default function StopTime({ running }: { running?: boolean }) {
const [secs, setSecs] = useState<number>(0);
interface Props {
running: boolean;
duration: number;
setDuration: React.Dispatch<React.SetStateAction<number>>;
}
export default function StopTime({ running, duration, setDuration }: Props) {
const calculateTimeDuration = (secs: number): string => {
const hr = Math.floor(secs / 3600).toString();
let min = Math.floor((secs - parseInt(hr) * 3600) / 60).toString();
@ -27,13 +31,13 @@ export default function StopTime({ running }: { running?: boolean }) {
useEffect(() => {
if (!running) return;
const interval = setInterval(() => setSecs((sec) => sec + 1), 1000);
const interval = setInterval(() => setDuration((sec) => sec + 1), 1000);
return () => clearInterval(interval);
}, [running]);
}, [running, setDuration]);
return (
<div className="ml-1 flex w-10 items-center justify-center">
<span className="text-sm">{calculateTimeDuration(secs)}</span>
<span className="text-sm">{calculateTimeDuration(duration)}</span>
</div>
);
}