Implement a background service to sync videos from Bunny.net every minute, optimize search debounce to 150ms, and cache videos for faster retrieval and instant search. Replit-Commit-Author: Agent Replit-Commit-Session-Id: d7424866-83d1-4486-a212-ac12b4c7becf Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8cc42625-c1f5-4e43-99bd-77f2c4dedee2/d7424866-83d1-4486-a212-ac12b4c7becf/F2OLMnq
120 lines
3.2 KiB
TypeScript
120 lines
3.2 KiB
TypeScript
import { BunnyService } from './bunny';
|
|
|
|
interface VideoSyncCache {
|
|
videos: any[];
|
|
lastUpdate: number;
|
|
isUpdating: boolean;
|
|
}
|
|
|
|
class VideoSyncService {
|
|
private cache: VideoSyncCache = {
|
|
videos: [],
|
|
lastUpdate: 0,
|
|
isUpdating: false
|
|
};
|
|
private bunnyService: BunnyService;
|
|
private syncInterval: NodeJS.Timeout | null = null;
|
|
|
|
constructor() {
|
|
this.bunnyService = new BunnyService();
|
|
}
|
|
|
|
async initialize() {
|
|
console.log('🔄 Initializing video sync service...');
|
|
try {
|
|
await this.syncVideos();
|
|
this.startPeriodicSync();
|
|
console.log('✅ Video sync service initialized successfully');
|
|
} catch (error) {
|
|
console.error('❌ Failed to initialize video sync service:', error);
|
|
// Continue without crashing the server
|
|
}
|
|
}
|
|
|
|
private async syncVideos() {
|
|
if (this.cache.isUpdating) {
|
|
console.log('⏳ Video sync already in progress, skipping...');
|
|
return;
|
|
}
|
|
|
|
this.cache.isUpdating = true;
|
|
const startTime = Date.now();
|
|
|
|
try {
|
|
console.log('🔍 Fetching latest videos from Bunny.net...');
|
|
const result = await this.bunnyService.getVideos(1, 100);
|
|
|
|
this.cache.videos = result.videos;
|
|
this.cache.lastUpdate = Date.now();
|
|
|
|
const duration = Date.now() - startTime;
|
|
console.log(`✅ Video sync completed: ${result.videos.length} videos cached in ${duration}ms`);
|
|
} catch (error) {
|
|
console.error('❌ Video sync failed:', error);
|
|
} finally {
|
|
this.cache.isUpdating = false;
|
|
}
|
|
}
|
|
|
|
private startPeriodicSync() {
|
|
// Sync every 60 seconds
|
|
this.syncInterval = setInterval(() => {
|
|
console.log('⏰ Starting scheduled video sync...');
|
|
this.syncVideos();
|
|
}, 60 * 1000);
|
|
|
|
console.log('📅 Scheduled video sync every 60 seconds');
|
|
}
|
|
|
|
getVideos(limit: number = 20, offset: number = 0, search?: string) {
|
|
let filteredVideos = this.cache.videos;
|
|
|
|
// Fast client-side search
|
|
if (search && search.length >= 2) {
|
|
const searchLower = search.toLowerCase();
|
|
filteredVideos = this.cache.videos.filter(video =>
|
|
video.title.toLowerCase().includes(searchLower) ||
|
|
video.description?.toLowerCase().includes(searchLower)
|
|
);
|
|
}
|
|
|
|
const paginatedVideos = filteredVideos.slice(offset, offset + limit);
|
|
|
|
return {
|
|
videos: paginatedVideos,
|
|
total: filteredVideos.length,
|
|
hasMore: offset + limit < filteredVideos.length,
|
|
cacheAge: Date.now() - this.cache.lastUpdate
|
|
};
|
|
}
|
|
|
|
async getVideo(id: string) {
|
|
// First try cache
|
|
const cachedVideo = this.cache.videos.find(v => v.id === id);
|
|
if (cachedVideo) {
|
|
return cachedVideo;
|
|
}
|
|
|
|
// Fallback to direct API call
|
|
return await this.bunnyService.getVideo(id);
|
|
}
|
|
|
|
getCacheStats() {
|
|
return {
|
|
videosCount: this.cache.videos.length,
|
|
lastUpdate: this.cache.lastUpdate,
|
|
isUpdating: this.cache.isUpdating,
|
|
cacheAge: Date.now() - this.cache.lastUpdate
|
|
};
|
|
}
|
|
|
|
stop() {
|
|
if (this.syncInterval) {
|
|
clearInterval(this.syncInterval);
|
|
this.syncInterval = null;
|
|
console.log('🛑 Video sync service stopped');
|
|
}
|
|
}
|
|
}
|
|
|
|
export const videoSyncService = new VideoSyncService(); |