116 lines
3.6 KiB
TypeScript
116 lines
3.6 KiB
TypeScript
import { Song, Choreography, DifficultyLevel, Move } from '../types';
|
|
|
|
class SongService {
|
|
/**
|
|
* Get all available songs
|
|
*/
|
|
async getSongs(): Promise<Song[]> {
|
|
try {
|
|
const response = await fetch('/index.json');
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch songs: ${response.statusText}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
// Transform the data to match our Song interface
|
|
return Object.entries(data.songs).map(([id, songData]: [string, any]) => ({
|
|
id,
|
|
...songData,
|
|
// Add default difficulty levels since they're not in the JSON
|
|
difficulty: ['medium', 'hard']
|
|
}));
|
|
} catch (error) {
|
|
console.error('Error fetching songs:', error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a specific song by ID
|
|
*/
|
|
async getSongById(id: string): Promise<Song | null> {
|
|
try {
|
|
const songs = await this.getSongs();
|
|
return songs.find(song => song.id === id) || null;
|
|
} catch (error) {
|
|
console.error(`Error fetching song ${id}:`, error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get choreography for a song at a specific difficulty
|
|
*/
|
|
async getChoreography(songId: string, difficulty: DifficultyLevel): Promise<Choreography | null> {
|
|
try {
|
|
const song = await this.getSongById(songId);
|
|
if (!song) {
|
|
return null;
|
|
}
|
|
|
|
// Fetch the moves data from the URL in song.GameData.moves
|
|
const response = await fetch(song.GameData.moves);
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch choreography: ${response.statusText}`);
|
|
}
|
|
|
|
const choreographyData = await response.json();
|
|
|
|
// Process the choreography data based on difficulty
|
|
// This would need to be adjusted based on the actual format of the moves data
|
|
return {
|
|
songId,
|
|
difficulty,
|
|
moves: this.processChoreographyData(choreographyData, difficulty)
|
|
};
|
|
} catch (error) {
|
|
console.error(`Error fetching choreography for song ${songId}:`, error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Process choreography data from the JSON file
|
|
* Note: This would need to be adjusted based on the actual data structure
|
|
*/
|
|
private processChoreographyData(data: any, difficulty: DifficultyLevel): Move[] {
|
|
// This is a placeholder implementation
|
|
// You'll need to adapt this based on the actual format of your poses.json files
|
|
const moves: Move[] = [];
|
|
|
|
// Example implementation assuming data has a moves array
|
|
if (Array.isArray(data.moves)) {
|
|
data.moves.forEach((moveData: any, index: number) => {
|
|
moves.push({
|
|
id: `${difficulty}-move-${index}`,
|
|
startTime: moveData.startTime || index * 3000,
|
|
duration: moveData.duration || 2000,
|
|
keyPosePoints: moveData.keyPoints || [],
|
|
difficulty,
|
|
score: difficulty === 'easy' ? 100 :
|
|
difficulty === 'medium' ? 150 :
|
|
difficulty === 'hard' ? 200 : 300
|
|
});
|
|
});
|
|
}
|
|
|
|
return moves;
|
|
}
|
|
|
|
/**
|
|
* Generate a choreography from a video (placeholder for future implementation)
|
|
*/
|
|
async generateChoreography(videoUrl: string, songId: string, difficulty: DifficultyLevel): Promise<Choreography | null> {
|
|
// This would use the pose detection API to analyze a video and generate choreography data
|
|
console.log(`Generating choreography for ${videoUrl}, song ${songId}, difficulty ${difficulty}`);
|
|
|
|
// This is a placeholder - in a real implementation,
|
|
// this would call an API to process the video and generate choreography
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// Create singleton instance
|
|
const songService = new SongService();
|
|
export default songService; |