feat: Add cover art support and auto-migration
- Extract cover art from MP3s during upload - Display cover art in game result screens (win/loss) - Add coverImage field to Song model - Add migration script to backfill covers for existing songs - Configure Docker to run migration script on startup
This commit is contained in:
66
scripts/migrate-covers.mjs
Normal file
66
scripts/migrate-covers.mjs
Normal file
@@ -0,0 +1,66 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { parseBuffer } from 'music-metadata';
|
||||
import { readFile, writeFile } from 'fs/promises';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
// Adjust path to reach root from scripts/
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function migrate() {
|
||||
console.log('Starting cover art migration...');
|
||||
|
||||
try {
|
||||
// Find songs without cover image
|
||||
const songs = await prisma.song.findMany({
|
||||
where: {
|
||||
coverImage: null
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`Found ${songs.length} songs without cover image.`);
|
||||
|
||||
for (const song of songs) {
|
||||
try {
|
||||
const filePath = path.join(process.cwd(), 'public/uploads', song.filename);
|
||||
console.log(`Processing ${song.title} (${song.filename})...`);
|
||||
|
||||
const buffer = await readFile(filePath);
|
||||
const metadata = await parseBuffer(buffer);
|
||||
const picture = metadata.common.picture?.[0];
|
||||
|
||||
if (picture) {
|
||||
const extension = picture.format.split('/')[1] || 'jpg';
|
||||
const coverFilename = `cover-${Date.now()}-${Math.floor(Math.random() * 1000)}.${extension}`;
|
||||
const coverPath = path.join(process.cwd(), 'public/uploads/covers', coverFilename);
|
||||
|
||||
// Ensure directory exists
|
||||
await writeFile(coverPath, picture.data);
|
||||
|
||||
// Update DB
|
||||
await prisma.song.update({
|
||||
where: { id: song.id },
|
||||
data: { coverImage: coverFilename }
|
||||
});
|
||||
|
||||
console.log(`✅ Extracted cover for ${song.title}`);
|
||||
} else {
|
||||
console.log(`⚠️ No cover found for ${song.title}`);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`❌ Failed to process ${song.title}:`, e.message);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Migration completed.');
|
||||
} catch (e) {
|
||||
console.error('Migration failed:', e);
|
||||
} finally {
|
||||
await prisma.$disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
migrate();
|
||||
Reference in New Issue
Block a user