Files
modstagram-next/src/lib/videoPreload.ts
payacom f364f989ed pay
2026-10-06 17:07:08 +03:30

94 lines
2.9 KiB
TypeScript

import { Post } from "@/types/types";
import { buildStorageUrl } from "@/components/main/BaseUrl";
import { resolvePostMediaType } from "@/lib/reelsMediaType";
const MAX_WARM_VIDEOS = 3;
export function isConstrainedNetwork(): boolean {
if (typeof navigator === "undefined") return false;
const connection = (navigator as Navigator & {
connection?: { saveData?: boolean; effectiveType?: string };
}).connection;
if (!connection) return false;
return connection.saveData === true || ["slow-2g", "2g", "3g"].includes(connection.effectiveType ?? "");
}
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) || isConstrainedNetwork()) 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(post ? 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);
}