import { db } from "./db"; import { videos } from "@shared/schema"; import { eq } from "drizzle-orm"; import { bunnyService } from "./bunny"; export class BunnyMigrationService { private migrationInProgress = false; async migrateAllVideosToDatabase(): Promise { if (this.migrationInProgress) { console.log("🔄 Migration already in progress, skipping..."); return; } this.migrationInProgress = true; console.log("🔄 Starting migration of all Bunny.net videos to database..."); try { // Fetch all videos from Bunny.net const bunnyVideos = await bunnyService.getAllVideos(); console.log(`📥 Found ${bunnyVideos.length} videos in Bunny.net`); let insertedCount = 0; let updatedCount = 0; let skippedCount = 0; for (const bunnyVideo of bunnyVideos) { try { // Check if video already exists in database const existingVideo = await db .select() .from(videos) .where(eq(videos.id, bunnyVideo.id)) .limit(1); const videoData = { id: bunnyVideo.id, title: bunnyVideo.title, description: bunnyVideo.description || "", thumbnailUrl: bunnyVideo.thumbnailUrl, videoUrl: bunnyVideo.videoUrl, videoUrlMp4: bunnyVideo.videoUrlMp4, videoUrlIframe: bunnyVideo.videoUrlIframe, duration: bunnyVideo.duration, views: bunnyVideo.views, category: bunnyVideo.category || "", tags: bunnyVideo.tags || [], isPublic: true, uploadStatus: "completed", originalFileName: bunnyVideo.title, bunnyId: bunnyVideo.id, bunnyLibraryId: process.env.BUNNY_LIBRARY_ID || "476412", source: "bunny", updatedAt: new Date(), }; if (existingVideo.length === 0) { // Insert new video await db.insert(videos).values({ ...videoData, createdAt: bunnyVideo.createdAt ? new Date(bunnyVideo.createdAt) : new Date(), }); insertedCount++; } else { // Update existing video await db .update(videos) .set(videoData) .where(eq(videos.id, bunnyVideo.id)); updatedCount++; } } catch (error) { console.error(`❌ Error processing video ${bunnyVideo.title}:`, error); skippedCount++; } } console.log(`✅ Migration completed:`); console.log(` 📥 Inserted: ${insertedCount} videos`); console.log(` 🔄 Updated: ${updatedCount} videos`); console.log(` ⚠️ Skipped: ${skippedCount} videos`); } catch (error) { console.error("❌ Migration failed:", error); throw error; } finally { this.migrationInProgress = false; } } async syncVideoFromBunny(bunnyVideoId: string): Promise { try { const bunnyVideo = await bunnyService.getVideo(bunnyVideoId); if (!bunnyVideo) { console.warn(`⚠️ Video ${bunnyVideoId} not found in Bunny.net`); return; } const videoData = { id: bunnyVideo.id, title: bunnyVideo.title, description: bunnyVideo.description || "", thumbnailUrl: bunnyVideo.thumbnailUrl, videoUrl: bunnyVideo.videoUrl, videoUrlMp4: bunnyVideo.videoUrlMp4, videoUrlIframe: bunnyVideo.videoUrlIframe, duration: bunnyVideo.duration, views: bunnyVideo.views, category: bunnyVideo.category || "", tags: bunnyVideo.tags || [], isPublic: true, uploadStatus: "completed", originalFileName: bunnyVideo.title, bunnyId: bunnyVideo.id, bunnyLibraryId: process.env.BUNNY_LIBRARY_ID || "476412", source: "bunny", updatedAt: new Date(), }; // Upsert the video await db .insert(videos) .values({ ...videoData, createdAt: bunnyVideo.createdAt ? new Date(bunnyVideo.createdAt) : new Date(), }) .onConflictDoUpdate({ target: videos.id, set: videoData, }); console.log(`✅ Synced video: ${bunnyVideo.title}`); } catch (error) { console.error(`❌ Error syncing video ${bunnyVideoId}:`, error); } } async getVideoCount(): Promise<{ database: number; bunny: number }> { try { const [dbCount, bunnyVideos] = await Promise.all([ db.select().from(videos).then(result => result.length), bunnyService.getAllVideos() ]); return { database: dbCount, bunny: bunnyVideos.length }; } catch (error) { console.error("❌ Error getting video count:", error); return { database: 0, bunny: 0 }; } } } export const bunnyMigration = new BunnyMigrationService();