Implement periodic synchronization for video metadata to ensure the database remains up-to-date with Bunny.net, including initial migration and recurring checks every 5 minutes. 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/yjIG1wi
121 lines
4.2 KiB
TypeScript
121 lines
4.2 KiB
TypeScript
import { db } from "./db";
|
|
import { sql } from "drizzle-orm";
|
|
import { videoSyncService } from "./videoSync";
|
|
|
|
export class VideoMigrator {
|
|
private isRunning = false;
|
|
private syncInterval: NodeJS.Timeout | null = null;
|
|
|
|
async initialize(): Promise<void> {
|
|
console.log("🔄 Initializing video metadata migrator...");
|
|
|
|
// Run initial migration
|
|
await this.migrateAllVideoMetadata();
|
|
|
|
// Set up periodic sync every 5 minutes to ensure database is always complete
|
|
this.syncInterval = setInterval(async () => {
|
|
console.log("⏰ Starting periodic video metadata sync...");
|
|
try {
|
|
await this.migrateAllVideoMetadata();
|
|
const count = await this.getVideoCount();
|
|
console.log(`✅ Periodic sync completed - Database: ${count.database}, Bunny: ${count.bunny}`);
|
|
} catch (error) {
|
|
console.error("❌ Periodic sync failed:", error);
|
|
}
|
|
}, 5 * 60 * 1000); // Every 5 minutes
|
|
|
|
console.log("✅ Video metadata migrator initialized with periodic sync");
|
|
}
|
|
|
|
async migrateAllVideoMetadata(): Promise<void> {
|
|
if (this.isRunning) {
|
|
console.log("🔄 Migration already running...");
|
|
return;
|
|
}
|
|
|
|
this.isRunning = true;
|
|
console.log("🔄 Migrating all video metadata from Bunny.net to PostgreSQL...");
|
|
|
|
try {
|
|
// Get all videos from cache
|
|
const videoList = videoSyncService.getVideos(1000, 0).videos;
|
|
console.log(`📥 Found ${videoList.length} videos in cache`);
|
|
|
|
let inserted = 0;
|
|
let updated = 0;
|
|
|
|
for (const video of videoList) {
|
|
try {
|
|
// Upsert video metadata with simple SQL
|
|
await db.execute(sql`
|
|
INSERT INTO video_metadata (
|
|
id, title, description, thumbnail_url, video_url,
|
|
duration, views, category, created_at, updated_at
|
|
) VALUES (
|
|
${video.id}, ${video.title}, ${video.description || ""},
|
|
${video.thumbnailUrl}, ${video.videoUrl},
|
|
${video.duration}, ${video.views}, ${video.category || ""},
|
|
${video.createdAt ? new Date(video.createdAt) : new Date()},
|
|
${new Date()}
|
|
) ON CONFLICT (id) DO UPDATE SET
|
|
title = EXCLUDED.title,
|
|
description = EXCLUDED.description,
|
|
thumbnail_url = EXCLUDED.thumbnail_url,
|
|
video_url = EXCLUDED.video_url,
|
|
duration = EXCLUDED.duration,
|
|
views = EXCLUDED.views,
|
|
category = EXCLUDED.category,
|
|
updated_at = EXCLUDED.updated_at
|
|
`);
|
|
|
|
inserted++;
|
|
|
|
// Log progress every 10 videos
|
|
if ((inserted + updated) % 10 === 0) {
|
|
console.log(`📊 Progress: ${inserted + updated}/${videoList.length} videos processed`);
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error(`❌ Error processing ${video.title}:`, error);
|
|
}
|
|
}
|
|
|
|
const dbCount = await this.getVideoCount();
|
|
|
|
console.log(`✅ Migration completed:`);
|
|
console.log(` 📥 Inserted: ${inserted} new videos`);
|
|
console.log(` 🔄 Updated: ${updated} existing videos`);
|
|
console.log(` 📊 Database total: ${dbCount.database} videos`);
|
|
console.log(` 🎥 Bunny.net total: ${dbCount.bunny} videos`);
|
|
|
|
// Verify all Bunny videos are in database
|
|
if (dbCount.database < dbCount.bunny) {
|
|
console.warn(`⚠️ Warning: Database has ${dbCount.database} videos but Bunny.net has ${dbCount.bunny}. Some videos may be missing!`);
|
|
} else {
|
|
console.log("✅ All Bunny.net videos are synchronized with database");
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error("❌ Migration failed:", error);
|
|
} finally {
|
|
this.isRunning = false;
|
|
}
|
|
}
|
|
|
|
async getVideoCount(): Promise<{ database: number; bunny: number }> {
|
|
try {
|
|
const dbResult = await db.execute(sql`SELECT COUNT(*) FROM video_metadata`);
|
|
const cachedVideos = videoSyncService.getVideos(1000, 0).videos;
|
|
|
|
return {
|
|
database: Number(dbResult.rows[0]?.count || 0),
|
|
bunny: cachedVideos.length
|
|
};
|
|
} catch (error) {
|
|
console.error("❌ Error counting videos:", error);
|
|
return { database: 0, bunny: 0 };
|
|
}
|
|
}
|
|
}
|
|
|
|
export const videoMigrator = new VideoMigrator(); |