Add GIF regeneration and diagnostic scripts

Added utility scripts for GIF management:

1. regenerate-all-gifs.ts:
   - Regenerates GIF previews for all existing videos
   - Deletes old GIFs before creating new ones
   - Provides progress feedback and summary statistics
   - Useful for bulk GIF generation after deployment

2. check-gifs.ts:
   - Quick diagnostic to list all GIF records in database
   - Shows term names and GIF URLs
   - Useful for verifying GIF generation

3. insert-gif-test.ts:
   - Test script to verify GIF enum value works in database
   - Creates, verifies, and cleans up test GIF record
   - Includes Prisma query logging for debugging

Usage:
  cd packages/backend
  npx tsx scripts/regenerate-all-gifs.ts
  npx tsx scripts/check-gifs.ts
  npx tsx scripts/insert-gif-test.ts

Co-Authored-By: Auggie
This commit is contained in:
2026-01-18 18:24:00 +01:00
parent 8c8ac8d1bb
commit 52e91b5ea6
3 changed files with 177 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function checkGifs() {
const gifs = await prisma.termMedia.findMany({
where: { kind: 'GIF' },
include: { term: true },
});
console.log(`Found ${gifs.length} GIF records in database:`);
gifs.forEach(gif => {
console.log(`- ${gif.term.wordText}: ${gif.url}`);
});
await prisma.$disconnect();
}
checkGifs();

View File

@@ -0,0 +1,53 @@
import { PrismaClient, MediaKind } from '@prisma/client';
const prisma = new PrismaClient({
log: ['query', 'info', 'warn', 'error'],
});
async function testInsert() {
console.log('Testing GIF insert...\n');
try {
// Get first video
const video = await prisma.termMedia.findFirst({
where: { kind: MediaKind.VIDEO },
});
if (!video) {
console.log('No video found');
return;
}
console.log(`Found video: ${video.url}`);
console.log(`Term ID: ${video.termId}\n`);
// Try to insert GIF
const gif = await prisma.termMedia.create({
data: {
termId: video.termId,
kind: MediaKind.GIF,
url: '/uploads/gifs/test.gif',
},
});
console.log('✅ GIF created:', gif);
// Verify it exists
const check = await prisma.termMedia.findUnique({
where: { id: gif.id },
});
console.log('\n✅ Verification:', check);
// Clean up
await prisma.termMedia.delete({ where: { id: gif.id } });
console.log('\n✅ Cleaned up test record');
} catch (error) {
console.error('❌ Error:', error);
} finally {
await prisma.$disconnect();
}
}
testInsert();

View File

@@ -0,0 +1,104 @@
import { PrismaClient, MediaKind } from '@prisma/client';
import { generateGifFromVideo } from '../src/utils/gifGenerator.js';
import path from 'path';
import fs from 'fs';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const prisma = new PrismaClient();
async function regenerateAllGifs() {
console.log('🎬 Starting GIF regeneration for all videos...\n');
try {
// Get all video media
const videoMedia = await prisma.termMedia.findMany({
where: { kind: MediaKind.VIDEO },
include: { term: true },
});
console.log(`Found ${videoMedia.length} videos to process\n`);
let successCount = 0;
let failCount = 0;
for (const media of videoMedia) {
const videoFilename = path.basename(media.url);
const videoPath = path.join(__dirname, '..', 'uploads', 'videos', videoFilename);
// Check if video file exists
if (!fs.existsSync(videoPath)) {
console.log(`❌ Video file not found: ${videoFilename}`);
failCount++;
continue;
}
try {
// Generate GIF filename
const gifFilename = videoFilename.replace(/\.(mp4|webm|mov)$/i, '.gif');
const gifsDir = path.join(__dirname, '..', 'uploads', 'gifs');
const gifPath = path.join(gifsDir, gifFilename);
const gifRelativeUrl = `/uploads/gifs/${gifFilename}`;
// Ensure gifs directory exists
if (!fs.existsSync(gifsDir)) {
fs.mkdirSync(gifsDir, { recursive: true });
}
// Delete old GIF if exists
const existingGif = await prisma.termMedia.findFirst({
where: {
termId: media.termId,
kind: MediaKind.GIF,
url: gifRelativeUrl,
},
});
if (existingGif) {
await prisma.termMedia.delete({ where: { id: existingGif.id } });
if (fs.existsSync(gifPath)) {
fs.unlinkSync(gifPath);
}
}
// Generate GIF
console.log(`🎨 Generating GIF for: ${media.term.wordText} (${videoFilename})`);
await generateGifFromVideo(videoPath, gifPath, {
fps: 10,
width: 300,
duration: 3,
startTime: 0,
});
// Create GIF media record
await prisma.termMedia.create({
data: {
termId: media.termId,
kind: MediaKind.GIF,
url: gifRelativeUrl,
},
});
console.log(`✅ Success: ${media.term.wordText}\n`);
successCount++;
} catch (error: any) {
console.log(`❌ Failed: ${media.term.wordText} - ${error.message}\n`);
failCount++;
}
}
console.log('\n📊 Summary:');
console.log(`✅ Success: ${successCount}`);
console.log(`❌ Failed: ${failCount}`);
console.log(`📝 Total: ${videoMedia.length}`);
} catch (error) {
console.error('Error:', error);
} finally {
await prisma.$disconnect();
}
}
regenerateAllGifs();