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(); const prefetchedLinks = new Set(); export function getPostVideoSrc(post: Pick): 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 | null | undefined, priority: VideoPrefetchPriority = "high" ) { prefetchVideoUrl(post ? getPostVideoSrc(post) : undefined, priority); } export function prefetchPostVideos( posts: Array>, priority: VideoPrefetchPriority = "low" ) { posts.forEach((post) => prefetchPostVideo(post, priority)); } export function isVideoWarming(url: string | undefined): boolean { return !!url && warmVideos.has(url); }