full update
This commit is contained in:
84
src/lib/videoPreload.ts
Normal file
84
src/lib/videoPreload.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { Post } from "@/types/types";
|
||||
import { buildStorageUrl } from "@/components/main/BaseUrl";
|
||||
import { resolvePostMediaType } from "@/lib/reelsMediaType";
|
||||
|
||||
const MAX_WARM_VIDEOS = 8;
|
||||
const warmVideos = new Map<string, HTMLVideoElement>();
|
||||
const prefetchedLinks = new Set<string>();
|
||||
|
||||
export function getPostVideoSrc(post: Pick<Post, "files" | "type">): string | undefined {
|
||||
const videoFile =
|
||||
post.files?.find((file) => file.type === "video") ??
|
||||
(resolvePostMediaType(post) === "video" ? post.files?.[0] : undefined);
|
||||
|
||||
if (!videoFile?.path) return undefined;
|
||||
return buildStorageUrl(videoFile.path);
|
||||
}
|
||||
|
||||
function evictOldestWarmVideo() {
|
||||
const firstKey = warmVideos.keys().next().value as string | undefined;
|
||||
if (!firstKey) return;
|
||||
warmVideos.get(firstKey)?.remove();
|
||||
warmVideos.delete(firstKey);
|
||||
}
|
||||
|
||||
function warmVideoElement(url: string) {
|
||||
if (typeof window === "undefined" || !url || warmVideos.has(url)) return;
|
||||
|
||||
const video = document.createElement("video");
|
||||
video.preload = "auto";
|
||||
video.muted = true;
|
||||
video.playsInline = true;
|
||||
video.setAttribute("playsinline", "");
|
||||
video.setAttribute("webkit-playsinline", "");
|
||||
video.src = url;
|
||||
video.style.cssText =
|
||||
"position:fixed;width:0;height:0;opacity:0;pointer-events:none;z-index:-1";
|
||||
|
||||
document.body.appendChild(video);
|
||||
video.load();
|
||||
|
||||
if (warmVideos.size >= MAX_WARM_VIDEOS) evictOldestWarmVideo();
|
||||
warmVideos.set(url, video);
|
||||
}
|
||||
|
||||
function linkPrefetchVideo(url: string) {
|
||||
if (typeof window === "undefined" || !url || prefetchedLinks.has(url)) return;
|
||||
prefetchedLinks.add(url);
|
||||
|
||||
const link = document.createElement("link");
|
||||
link.rel = "prefetch";
|
||||
link.as = "video";
|
||||
link.href = url;
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
|
||||
export type VideoPrefetchPriority = "high" | "low";
|
||||
|
||||
/** پیشبارگذاری ویدئو در HTTP cache + buffer مخفی */
|
||||
export function prefetchVideoUrl(
|
||||
url: string | undefined,
|
||||
priority: VideoPrefetchPriority = "high"
|
||||
) {
|
||||
if (!url) return;
|
||||
linkPrefetchVideo(url);
|
||||
if (priority === "high") warmVideoElement(url);
|
||||
}
|
||||
|
||||
export function prefetchPostVideo(
|
||||
post: Pick<Post, "files" | "type" | "_id"> | null | undefined,
|
||||
priority: VideoPrefetchPriority = "high"
|
||||
) {
|
||||
prefetchVideoUrl(getPostVideoSrc(post ?? undefined), priority);
|
||||
}
|
||||
|
||||
export function prefetchPostVideos(
|
||||
posts: Array<Pick<Post, "files" | "type" | "_id">>,
|
||||
priority: VideoPrefetchPriority = "low"
|
||||
) {
|
||||
posts.forEach((post) => prefetchPostVideo(post, priority));
|
||||
}
|
||||
|
||||
export function isVideoWarming(url: string | undefined): boolean {
|
||||
return !!url && warmVideos.has(url);
|
||||
}
|
||||
Reference in New Issue
Block a user