TelegramPWA/src/hooks/useMediaWithLoadProgress.ts
2025-11-11 14:37:51 +01:00

92 lines
2.8 KiB
TypeScript

import {
useEffect, useRef, useState,
} from '../lib/teact/teact';
import { ApiMediaFormat } from '../api/types';
import { selectIsSynced } from '../global/selectors';
import { IS_PROGRESSIVE_SUPPORTED } from '../util/browser/windowEnvironment';
import * as mediaLoader from '../util/mediaLoader';
import useSelector from './data/useSelector';
import useForceUpdate from './useForceUpdate';
import useThrottledCallback from './useThrottledCallback';
import useUniqueId from './useUniqueId';
const STREAMING_PROGRESS = 0.75;
const STREAMING_TIMEOUT = 1500;
const PROGRESS_THROTTLE = 500;
export default function useMediaWithLoadProgress(
mediaHash: string | undefined,
noLoad = false,
mediaFormat = ApiMediaFormat.BlobUrl,
delay?: number | false,
isHtmlAllowed = false,
) {
const isStreaming = IS_PROGRESSIVE_SUPPORTED && mediaFormat === ApiMediaFormat.Progressive;
const mediaData = mediaHash
? (isStreaming && !noLoad ? mediaLoader.getProgressiveUrl(mediaHash)
: mediaLoader.getFromMemory(mediaHash)) : undefined;
const forceUpdate = useForceUpdate();
const isSynced = useSelector(selectIsSynced);
const id = useUniqueId();
const [loadProgress, setLoadProgress] = useState(mediaData && !isStreaming ? 1 : 0);
const startedAtRef = useRef<number>();
const handleProgress = useThrottledCallback((progress: number) => {
if (startedAtRef.current && id && (!delay || (Date.now() - startedAtRef.current > delay))) {
setLoadProgress(progress);
}
}, [delay, id], PROGRESS_THROTTLE, true);
useEffect(() => {
if (!noLoad && mediaHash) {
if (!mediaData) {
setLoadProgress(0);
if (startedAtRef.current) {
mediaLoader.cancelProgress(handleProgress);
}
startedAtRef.current = Date.now();
mediaLoader.fetch(mediaHash, mediaFormat, isHtmlAllowed, handleProgress, id).then(() => {
const spentTime = Date.now() - startedAtRef.current!;
startedAtRef.current = undefined;
if (!delay || spentTime >= delay) {
forceUpdate();
} else {
setTimeout(forceUpdate, delay - spentTime);
}
});
} else if (isStreaming) {
setTimeout(() => {
setLoadProgress(STREAMING_PROGRESS);
}, STREAMING_TIMEOUT);
}
}
}, [
noLoad, mediaHash, mediaData, mediaFormat, isStreaming, delay, handleProgress, isHtmlAllowed, id, isSynced,
]);
useEffect(() => {
if (noLoad && startedAtRef.current) {
mediaLoader.cancelProgress(handleProgress);
setLoadProgress(0);
startedAtRef.current = undefined;
}
}, [handleProgress, noLoad]);
useEffect(() => {
return () => {
if (mediaHash) {
mediaLoader.removeCallback(mediaHash, id);
}
};
}, [id, mediaHash]);
return { mediaData, loadProgress };
}