- Replace filename column with activation count - Add pagination (10 items per page) and search functionality - Add delete functionality (removes DB entry and file) - Remove manual title/artist input (auto-extract from ID3 tags) - Replace text buttons with emoji icons (Edit, Delete, Save, Cancel) - Implement weighted random selection for daily puzzles - Add custom favicon - Fix docker-compose.yml configuration
74 lines
2.3 KiB
TypeScript
74 lines
2.3 KiB
TypeScript
import { NextResponse } from 'next/server';
|
|
import { PrismaClient } from '@prisma/client';
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
export async function GET() {
|
|
try {
|
|
const today = new Date().toISOString().split('T')[0];
|
|
|
|
let dailyPuzzle = await prisma.dailyPuzzle.findUnique({
|
|
where: { date: today },
|
|
include: { song: true },
|
|
});
|
|
|
|
if (!dailyPuzzle) {
|
|
// Get all songs with their usage count
|
|
const allSongs = await prisma.song.findMany({
|
|
include: {
|
|
puzzles: true,
|
|
},
|
|
});
|
|
|
|
if (allSongs.length === 0) {
|
|
return NextResponse.json({ error: 'No songs available' }, { status: 404 });
|
|
}
|
|
|
|
// Calculate weights: songs never used get weight 1.0,
|
|
// songs used once get 0.5, twice 0.33, etc.
|
|
const weightedSongs = allSongs.map(song => ({
|
|
song,
|
|
weight: 1.0 / (song.puzzles.length + 1),
|
|
}));
|
|
|
|
// Calculate total weight
|
|
const totalWeight = weightedSongs.reduce((sum, item) => sum + item.weight, 0);
|
|
|
|
// Pick a random song based on weights
|
|
let random = Math.random() * totalWeight;
|
|
let selectedSong = weightedSongs[0].song;
|
|
|
|
for (const item of weightedSongs) {
|
|
random -= item.weight;
|
|
if (random <= 0) {
|
|
selectedSong = item.song;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Create the daily puzzle
|
|
dailyPuzzle = await prisma.dailyPuzzle.create({
|
|
data: {
|
|
date: today,
|
|
songId: selectedSong.id,
|
|
},
|
|
include: { song: true },
|
|
});
|
|
}
|
|
|
|
if (!dailyPuzzle) {
|
|
return NextResponse.json({ error: 'Failed to create puzzle' }, { status: 500 });
|
|
}
|
|
|
|
return NextResponse.json({
|
|
id: dailyPuzzle.id,
|
|
audioUrl: `/uploads/${dailyPuzzle.song.filename}`,
|
|
songId: dailyPuzzle.songId
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('Error fetching daily puzzle:', error);
|
|
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
|
|
}
|
|
}
|