Created
March 14, 2025 07:36
-
-
Save librz/3df7287e38776782aea564f399b4cd10 to your computer and use it in GitHub Desktop.
Get video size(in bytes) and duraiton(in seconds) on the frontend
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useQuery } from "@tanstack/react-query"; | |
import { useRef, useState } from "react"; | |
async function fetchVideoContentLength(videoUrl: string) { | |
const controller = new AbortController(); | |
const signal = controller.signal; | |
try { | |
const response = await fetch(videoUrl, { | |
// the idiomatic way of requesting only the response headers(without the content) is using a HEAD request, but server may not support the HEAD method | |
method: "GET", | |
headers: { | |
// do not use something like "bytes=0-1", in chrome, it may throw the `net::ERR_CONTENT_LENGTH_MISMATCH)` error and prevent reading reponse.headers | |
// instead, try request the whole video, but abort request immediately after reading response headers | |
Range: "bytes=0-", | |
}, | |
signal: signal, | |
}); | |
if (!response.ok) { | |
throw new Error(`HTTP error! status: ${response.status}`); | |
} | |
const contentRange = response.headers.get("Content-Range"); | |
if (contentRange) { | |
// e.g. Content-Range: bytes 0-100/210981431 | |
const totalSizeStr = contentRange.split("/")[1] as string; | |
controller.abort(); | |
return parseInt(totalSizeStr); | |
} else { | |
// if content-range is not present, try use content-length | |
const contentLength = response.headers.get("Content-Length"); | |
controller.abort(); | |
return contentLength ? parseInt(contentLength) : null; | |
} | |
} catch (error) { | |
console.error("Error getting video content length:", error); | |
return null; | |
} | |
} | |
export function VideoInfo(props: { url: string }) { | |
const { isLoading, data: bytes } = useQuery({ | |
queryKey: [props.url], | |
queryFn: () => fetchVideoContentLength(props.url), | |
}); | |
const videoRef = useRef<HTMLVideoElement>(null); | |
const [duration, setDuration] = useState(0); | |
return ( | |
<div> | |
<video | |
hidden //hide since <video /> is used only to load meta data | |
ref={videoRef} | |
src={props.url} | |
preload={"metadata"} | |
onLoadedMetadata={() => { | |
setDuration(videoRef.current?.duration ?? 0); | |
}} | |
/> | |
{isLoading && "Loading..."} | |
{bytes && duration && <div>{`bytes: ${bytes}; durtaion: ${duration}s`}</div>} | |
</div> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment