videofolxtv/server/bunnyMigration.ts
sebastjanartic 443d92804e Migrate all videos from Bunny.net to the database
Introduces a migration script to import all videos from Bunny.net into the PostgreSQL database, populating the `videos` table with relevant metadata and handling both new and existing video entries. Updates schema to include Bunny.net specific fields.

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/t16ASiD
2025-08-28 17:18:48 +00:00

156 lines
4.9 KiB
TypeScript

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<void> {
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<void> {
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();