feat(special-curation): complete implementation with all components
- Database: SpecialSong model with startTime - Backend: API endpoints for curation - Admin: Waveform editor and curation page - Game: startTime support in AudioPlayer - UI: Curate button in admin dashboard
This commit is contained in:
@@ -146,32 +146,36 @@ export async function getOrCreateSpecialPuzzle(specialName: string) {
|
||||
});
|
||||
|
||||
if (!dailyPuzzle) {
|
||||
// Get songs available for this special
|
||||
const allSongs = await prisma.song.findMany({
|
||||
where: { specials: { some: { id: special.id } } },
|
||||
// Get songs available for this special through SpecialSong
|
||||
const specialSongs = await prisma.specialSong.findMany({
|
||||
where: { specialId: special.id },
|
||||
include: {
|
||||
puzzles: {
|
||||
where: { specialId: special.id }
|
||||
},
|
||||
},
|
||||
song: {
|
||||
include: {
|
||||
puzzles: {
|
||||
where: { specialId: special.id }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (allSongs.length === 0) return null;
|
||||
if (specialSongs.length === 0) return null;
|
||||
|
||||
// Calculate weights
|
||||
const weightedSongs = allSongs.map(song => ({
|
||||
song,
|
||||
weight: 1.0 / (song.puzzles.length + 1),
|
||||
const weightedSongs = specialSongs.map(specialSong => ({
|
||||
specialSong,
|
||||
weight: 1.0 / (specialSong.song.puzzles.length + 1),
|
||||
}));
|
||||
|
||||
const totalWeight = weightedSongs.reduce((sum, item) => sum + item.weight, 0);
|
||||
let random = Math.random() * totalWeight;
|
||||
let selectedSong = weightedSongs[0].song;
|
||||
let selectedSpecialSong = weightedSongs[0].specialSong;
|
||||
|
||||
for (const item of weightedSongs) {
|
||||
random -= item.weight;
|
||||
if (random <= 0) {
|
||||
selectedSong = item.song;
|
||||
selectedSpecialSong = item.specialSong;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -180,7 +184,7 @@ export async function getOrCreateSpecialPuzzle(specialName: string) {
|
||||
dailyPuzzle = await prisma.dailyPuzzle.create({
|
||||
data: {
|
||||
date: today,
|
||||
songId: selectedSong.id,
|
||||
songId: selectedSpecialSong.songId,
|
||||
specialId: special.id
|
||||
},
|
||||
include: { song: true },
|
||||
@@ -198,6 +202,16 @@ export async function getOrCreateSpecialPuzzle(specialName: string) {
|
||||
|
||||
if (!dailyPuzzle) return null;
|
||||
|
||||
// Fetch the startTime from SpecialSong
|
||||
const specialSong = await prisma.specialSong.findUnique({
|
||||
where: {
|
||||
specialId_songId: {
|
||||
specialId: special.id,
|
||||
songId: dailyPuzzle.songId
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Calculate puzzle number
|
||||
const puzzleCount = await prisma.dailyPuzzle.count({
|
||||
where: {
|
||||
@@ -218,7 +232,8 @@ export async function getOrCreateSpecialPuzzle(specialName: string) {
|
||||
coverImage: dailyPuzzle.song.coverImage ? `/uploads/covers/${dailyPuzzle.song.coverImage}` : null,
|
||||
special: specialName,
|
||||
maxAttempts: special.maxAttempts,
|
||||
unlockSteps: JSON.parse(special.unlockSteps)
|
||||
unlockSteps: JSON.parse(special.unlockSteps),
|
||||
startTime: specialSong?.startTime || 0
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user