Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import { AVPlaybackSource, Video } from "expo-av";
- import { cacheDirectory, downloadAsync } from "expo-file-system";
- import { useEffect, useReducer, useState } from "react";
- import { Button, View } from "react-native";
- const publicURL =
- "https://storage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4";
- type FileState = {
- fileSize: number | null;
- currentRange: number | null;
- targetRange: number | null;
- threshold: number | null;
- };
- type FileAction =
- | { type: "SET_FILE_SIZE"; payload: number }
- | {
- type: "UPDATE_RANGES";
- payload: { currentRange: number; targetRange: number };
- };
- const THRESHOLD_VALUE = 0.1;
- const contentRangeReducer = (
- state: FileState,
- action: FileAction
- ): FileState => {
- switch (action.type) {
- case "SET_FILE_SIZE":
- return {
- ...state,
- fileSize: action.payload,
- threshold: Math.floor(action.payload * THRESHOLD_VALUE),
- };
- case "UPDATE_RANGES": {
- return { ...state, ...action.payload };
- }
- default:
- return state;
- }
- };
- export default function VideoFetchTest() {
- const [fetchInfo, dispatch] = useReducer(contentRangeReducer, {
- fileSize: null,
- currentRange: null,
- targetRange: null,
- threshold: null,
- });
- const [videoSource, setVideoSource] = useState<AVPlaybackSource | null>(null);
- const [isFetching, setIsFetching] = useState<boolean>(false);
- useEffect(() => {
- if (videoSource) {
- console.log("observer: video updated!");
- }
- }, [videoSource]);
- const getFetchedFileSize = async (url: string) => {
- try {
- const response = await fetch(url, {
- method: "HEAD",
- });
- const contentLength = Number(response.headers.get("content-length"));
- if (isNaN(contentLength)) throw new Error("contentLength is NaN!");
- dispatch({ type: "SET_FILE_SIZE", payload: contentLength });
- return contentLength;
- } catch (error) {
- console.error("Error fetching file size:", error);
- }
- };
- const calculateRanges = () => {
- if (!fetchInfo.threshold) throw new Error("Threshold not specified!");
- const newCurrentRange =
- fetchInfo.currentRange !== null
- ? fetchInfo.currentRange + fetchInfo.threshold
- : 0;
- const newTargetRange = fetchInfo.targetRange
- ? fetchInfo.targetRange + fetchInfo.threshold
- : fetchInfo.threshold;
- console.log("newCurrent", newCurrentRange);
- console.log("newTarget", newTargetRange);
- dispatch({
- type: "UPDATE_RANGES",
- payload: { currentRange: newCurrentRange, targetRange: newTargetRange },
- });
- return {
- targetRange: newTargetRange,
- currentRange: newCurrentRange,
- };
- };
- const downloadVideo = async (downloadLink: string) => {
- try {
- const fileSize =
- fetchInfo.fileSize || (await getFetchedFileSize(downloadLink));
- if (!fileSize) throw new Error(`fileSize is undefined (${fileSize})`);
- const fileName = "video";
- const extension = "mp4";
- const { currentRange, targetRange } = calculateRanges();
- console.log({
- Range: `bytes=${currentRange}-${targetRange}`,
- });
- const downloadResult = await downloadAsync(
- downloadLink,
- cacheDirectory + [fileName, extension].join("."),
- {
- headers: {
- Range: `bytes=${currentRange}-${targetRange}`,
- },
- }
- );
- setVideoSource(downloadResult);
- setIsFetching(false);
- return console.log("isFetching false");
- } catch (err) {
- console.error(err);
- }
- };
- return (
- <View>
- <Button
- title="Get File Size"
- onPress={() => {
- getFetchedFileSize(publicURL);
- }}
- />
- {fetchInfo.fileSize && (
- <Button
- title="Download Video"
- onPress={() => {
- downloadVideo(publicURL);
- }}
- />
- )}
- {videoSource && (
- <Video
- shouldPlay
- useNativeControls
- style={{ width: 400, height: 300 }}
- source={videoSource}
- rate={4}
- progressUpdateIntervalMillis={1000}
- onPlaybackStatusUpdate={async (status) => {
- // TODO: change to Type-guard.
- console.log(status.isLoaded);
- if (!("positionMillis" in status)) {
- console.log("no positionMillis");
- return;
- }
- const { positionMillis, playableDurationMillis } = status;
- console.log({ playableDurationMillis, positionMillis });
- if (playableDurationMillis && !isFetching)
- if (positionMillis >= playableDurationMillis * 0.3) {
- console.log("dispatch");
- setIsFetching(true);
- console.log("isFetching true");
- await downloadVideo(publicURL);
- }
- }}
- />
- )}
- </View>
- );
- }
Advertisement
Add Comment
Please, Sign In to add comment