perf: improve audio streaming, font loading, and video provider timeouts

- Fix audio route content-type handling by using HeadObject metadata first
- Add JetBrains Mono font optimization with display:swap and preload
- Add blur placeholder to video card thumbnails for improved loading
- Fix YouTube API loading with proper state tracking to prevent race conditions
- Simplify timeout handling in YouTube and Vimeo providers using AbortSignal.timeout
This commit is contained in:
Yusuf İpek
2026-02-14 17:10:59 +03:00
parent d302875e25
commit e4b29f5829
6 changed files with 74 additions and 24 deletions
+2
View File
@@ -187,6 +187,8 @@ export function VideoCard({ video, projectId }: VideoCardProps) {
fill
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
className="object-cover transition-transform group-hover:scale-105"
placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMCwsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAAIAAoDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAUH/8QAIhAAAQMDBQADAAAAAAAAAAAAAQIDBAAFEQYSITFBE1FR/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAX/xAAYEQADAQEAAAAAAAAAAAAAAAAAAQIhMf/aAAwDAQACEQMRAD8Adu3bgZt8NqM2y6sNJCQTjJ+dKz/9k="
/>
<div className="absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center">
<Play className="h-12 w-12 text-white" fill="white" />
+20 -3
View File
@@ -198,6 +198,9 @@ export function VideoPageContent({ mode, videoId, projectId: propProjectId }: Vi
const [showResumePrompt, setShowResumePrompt] = useState(false);
const progressSaveTimerRef = useRef<ReturnType<typeof setInterval> | null>(null);
const lastSavedProgressRef = useRef<number>(0);
// YouTube API loading state
const [isApiLoaded, setIsApiLoaded] = useState(false);
const [progressFetchKey, setProgressFetchKey] = useState(0);
const [replyingTo, setReplyingTo] = useState<string | null>(null);
@@ -374,16 +377,30 @@ export function VideoPageContent({ mode, videoId, projectId: propProjectId }: Vi
fetchTags();
}, [projectId]);
// Load YouTube API immediately on component mount (async, non-blocking)
useEffect(() => {
if (window.YT) return;
// Already loaded
if (isApiLoaded) return;
// Already in progress
if (window.YT) {
setIsApiLoaded(true);
return;
}
const tag = document.createElement('script');
tag.src = 'https://www.youtube.com/iframe_api';
const firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode?.insertBefore(tag, firstScriptTag);
}, []);
window.onYouTubeIframeAPIReady = () => {
setIsApiLoaded(true);
};
}, [isApiLoaded]);
useEffect(() => {
if (!activeVersion || activeVersion.providerId !== 'youtube') return;
if (!isApiLoaded) return;
setIsReady(false);
setCurrentTime(0);
@@ -428,7 +445,7 @@ export function VideoPageContent({ mode, videoId, projectId: propProjectId }: Vi
clearTimeout(timeout);
window.onYouTubeIframeAPIReady = undefined;
};
}, [activeVersionId]);
}, [activeVersionId, isApiLoaded]);
// Save detected duration to DB if the version doesn't have one stored
useEffect(() => {