improved preloading

This commit is contained in:
Dmitri 2026-04-09 07:22:18 +04:00
parent d98ab24f6e
commit 42cc3456eb
3 changed files with 31 additions and 20 deletions

View File

@ -20,10 +20,10 @@ export const PRELOAD_CONFIG = {
currentPage: 1000,
neighborBase: 500,
assetType: {
transition: 150, // Transitions preloaded for faster start
image: 100, // Backgrounds load first
audio: 50,
video: 30,
// Note: transitions are cached on first playback, not preloaded
} as Record<string, number>,
variant: {
thumbnail: 50,
@ -68,11 +68,11 @@ export const PRELOAD_CONFIG = {
// Partial preload settings (online mode only)
// Download only first N bytes of videos/audio for faster Phase 1 completion
// Playback uses presigned URL directly (browser handles remaining buffering)
// Note: Transitions are cached on first playback, not preloaded
partialPreload: {
enabled: true,
videoMaxBytes: 5 * 1024 * 1024, // 5MB (~5 seconds of video)
audioMaxBytes: 512 * 1024, // 512KB (~5 seconds of audio)
transitionMaxBytes: 3 * 1024 * 1024, // 3MB (~3 seconds of transition video)
},
// Asset URL field names in element content_json (camelCase)

View File

@ -74,14 +74,12 @@ function extractAssetsFromContent(
for (const [key, value] of Object.entries(obj)) {
if (typeof value === 'string' && value && urlFields.includes(key)) {
// Classify asset type based on field name
// Skip transition fields - transitions are cached on first playback
const lowerKey = key.toLowerCase();
if (lowerKey.includes('transition')) {
continue; // Skip transitions
}
let assetType: 'video' | 'audio' | 'image';
if (lowerKey.includes('video')) {
let assetType: 'video' | 'audio' | 'image' | 'transition';
if (lowerKey.includes('transition')) {
assetType = 'transition';
} else if (lowerKey.includes('video')) {
assetType = 'video';
} else if (lowerKey.includes('audio')) {
assetType = 'audio';
@ -239,14 +237,25 @@ export function useNeighborGraph(
});
});
// Add transition videos (transition is eagerly loaded in page_links)
// Extract transition videos from page_links for preloading
const matchingLinks = pageLinks.filter(
(link) =>
link.is_active !== false && pageIds.includes(link.from_pageId || ''),
);
// Note: Transition videos are NOT extracted for preloading.
// They are cached on first playback via useTransitionPlayback.cacheBlob()
matchingLinks.forEach((link) => {
// Extract transition video URL from link.transition
const transition = link.transition as { video_url?: string } | undefined;
if (transition?.video_url && !seenUrls.has(transition.video_url)) {
seenUrls.add(transition.video_url);
assets.push({
url: transition.video_url,
pageId: link.from_pageId || '',
assetType: 'transition',
priority: 0, // Will be calculated later with transition priority
});
}
});
return assets;
};

View File

@ -529,12 +529,18 @@ export function usePreloadOrchestrator(
) => {
// Helper to determine max bytes for partial preload (online mode only)
// IMPORTANT: Only applies to NEIGHBOR pages, not the current page
// Transitions always use partial preload (regardless of page)
const getMaxBytesForAsset = (
assetType: 'image' | 'video' | 'audio' | 'transition' | 'other',
isNeighborPage: boolean,
): number | undefined => {
if (!PRELOAD_CONFIG.partialPreload.enabled) return undefined;
// Transitions always use partial preload - they need just enough to start quickly
if (assetType === 'transition') {
return PRELOAD_CONFIG.partialPreload.transitionMaxBytes;
}
// Current page assets should be fully downloaded for best UX
if (!isNeighborPage) return undefined;
@ -557,11 +563,6 @@ export function usePreloadOrchestrator(
assetType: 'image' | 'video' | 'audio' | 'transition' | 'other',
pageId: string,
): Promise<void> | null => {
// Skip transitions - they're cached on first playback via useTransitionPlayback
if (assetType === 'transition') {
return null;
}
const resolvedUrl = resolveUrl(storageKey, presignedUrls);
if (!resolvedUrl) return null;
@ -577,8 +578,9 @@ export function usePreloadOrchestrator(
// Determine if partial preload applies (neighbor pages only, media files only)
const isNeighborPage = pageId !== currentPageId;
const maxBytes = getMaxBytesForAsset(assetType, isNeighborPage);
// For partial downloads, don't create blob URL - playback uses presigned URL
const createBlobUrl = maxBytes === undefined;
// Create blob URL for images (instant navigation) and full downloads
// Partial downloads (video/audio/transition) use presigned URL directly for playback
const createBlobUrl = assetType === 'image' || maxBytes === undefined;
return downloadManager
.addJob({
@ -690,11 +692,11 @@ export function usePreloadOrchestrator(
// ============================================
// PHASE 2: Preload everything else (don't wait)
// - Current page element assets (full downloads)
// - Transition videos (partial preload - 3MB)
// - Neighbor page backgrounds (partial preload for video/audio)
// - Neighbor page element assets (partial preload for video/audio)
// - Transition videos from page links (partial preload - 3MB)
// ============================================
logger.info('[PRELOAD] Phase 2: Preloading transitions and neighbors');
logger.info('[PRELOAD] Phase 2: Preloading neighbors and transitions');
// Current page element assets (moved from Phase 1 for faster startup)
const currentPageAssets = assets.filter(