package backend import ( "math/rand" "music-server/internal/db/repository" "music-server/internal/logging" "os" "strconv" "strings" "go.uber.org/zap" ) type SongInfo struct { Soundtrack string `json:"Soundtrack"` SoundtrackPlayed int32 `json:"SoundtrackPlayed"` Song string `json:"Song"` SongPlayed int32 `json:"SongPlayed"` CurrentlyPlaying bool `json:"CurrentlyPlaying"` SongNo int `json:"SongNo"` } var currentSong = -1 var soundtracksNew []repository.Soundtrack var songQueNew []repository.Song var lastFetchedNew repository.Song func initRepo() { // This function is kept for backward compatibility // but now uses the backend package's initialized repo // If not initialized, this will panic intentionally if BackendRepo() == nil { panic("backend not initialized - call backend.InitBackend() first") } } func getAllSoundtracks() []repository.Soundtrack { if len(soundtracksNew) == 0 { initRepo() soundtracksNew, _ = BackendRepo().FindAllSoundtracks(BackendCtx()) } return soundtracksNew } func GetSoundCheckSong() string { files, err := os.ReadDir("songs") if err != nil { logging.GetLogger().Fatal("Failed to read songs directory", zap.String("error", err.Error())) } fileInfo := files[rand.Intn(len(files))] return "songs/" + fileInfo.Name() } func Reset() { songQueNew = nil currentSong = -1 initRepo() soundtracksNew, _ = BackendRepo().FindAllSoundtracks(BackendCtx()) } func AddLatestToQue() { if lastFetchedNew.Path != "" { currentSong = len(songQueNew) songQueNew = append(songQueNew, lastFetchedNew) lastFetchedNew = repository.Song{} } } func AddLatestPlayed() { if len(songQueNew) == 0 { return } currentSongData := songQueNew[currentSong] initRepo() BackendRepo().AddSoundtrackPlayed(BackendCtx(), currentSongData.SoundtrackID) BackendRepo().AddSongPlayed(BackendCtx(), repository.AddSongPlayedParams{SoundtrackID: currentSongData.SoundtrackID, SongName: currentSongData.SongName}) } func SetPlayed(songNumber int) { if len(songQueNew) == 0 || songNumber >= len(songQueNew) { return } songData := songQueNew[songNumber] initRepo() BackendRepo().AddSoundtrackPlayed(BackendCtx(), songData.SoundtrackID) BackendRepo().AddSongPlayed(BackendCtx(), repository.AddSongPlayedParams{SoundtrackID: songData.SoundtrackID, SongName: songData.SongName}) } func GetRandomSong() string { getAllSoundtracks() if len(soundtracksNew) == 0 { return "" } song := getSongFromList(soundtracksNew) lastFetchedNew = song return song.Path } func GetRandomSongLowChance() string { getAllSoundtracks() var listOfSoundtracks []repository.Soundtrack var averagePlayed = getAveragePlayed() for _, data := range soundtracksNew { timesToAdd := averagePlayed - data.TimesPlayed if timesToAdd <= 0 { listOfSoundtracks = append(listOfSoundtracks, data) } else { for i := int32(0); i < timesToAdd; i++ { listOfSoundtracks = append(listOfSoundtracks, data) } } } song := getSongFromList(listOfSoundtracks) lastFetchedNew = song return song.Path } func GetRandomSongClassic() string { getAllSoundtracks() var listOfAllSongs []repository.Song for _, soundtrack := range soundtracksNew { songList, _ := BackendRepo().FindSongsFromSoundtrack(BackendCtx(), soundtrack.ID) listOfAllSongs = append(listOfAllSongs, songList...) } songFound := false var song repository.Song for !songFound { song = listOfAllSongs[rand.Intn(len(listOfAllSongs))] soundtrackData, err := BackendRepo().GetSoundtrackById(BackendCtx(), song.SoundtrackID) if err != nil { BackendRepo().RemoveBrokenSong(BackendCtx(), repository.RemoveBrokenSongParams{SoundtrackID: song.SoundtrackID, Path: song.Path}) logging.GetLogger().Warn("Song not found, removed from database", zap.String("song", song.SongName), zap.String("soundtrack", soundtrackData.SoundtrackName), zap.String("filename", *song.FileName)) continue } //Check if file exists and open openFile, err := os.Open(song.Path) if err != nil || (song.FileName != nil && soundtrackData.Path+*song.FileName != song.Path) { //File not found BackendRepo().RemoveBrokenSong(BackendCtx(), repository.RemoveBrokenSongParams{SoundtrackID: song.SoundtrackID, Path: song.Path}) logging.GetLogger().Warn("Song not found, removed from database", zap.String("song", song.SongName), zap.String("soundtrack", soundtrackData.SoundtrackName), zap.String("filename", *song.FileName)) } else { songFound = true } err = openFile.Close() if err != nil { logging.GetLogger().Error("Failed to close file", zap.String("error", err.Error())) } } lastFetchedNew = song return song.Path } func GetSongInfo() SongInfo { if songQueNew == nil { return SongInfo{} } var currentSongData = songQueNew[currentSong] currentSoundtrackData := getCurrentSoundtrack(currentSongData) return SongInfo{ Soundtrack: currentSoundtrackData.SoundtrackName, SoundtrackPlayed: currentSoundtrackData.TimesPlayed, Song: currentSongData.SongName, SongPlayed: currentSongData.TimesPlayed, CurrentlyPlaying: true, SongNo: currentSong, } } func GetPlayedSongs() []SongInfo { var songList []SongInfo for i, song := range songQueNew { soundtrackData := getCurrentSoundtrack(song) songList = append(songList, SongInfo{ Soundtrack: soundtrackData.SoundtrackName, SoundtrackPlayed: soundtrackData.TimesPlayed, Song: song.SongName, SongPlayed: song.TimesPlayed, CurrentlyPlaying: i == currentSong, SongNo: i, }) } return songList } func GetSong(song string) string { currentSong, _ = strconv.Atoi(song) if currentSong >= len(songQueNew) { currentSong = len(songQueNew) - 1 } else if currentSong < 0 { currentSong = 0 } songData := songQueNew[currentSong] return songData.Path } func GetAllSoundtracks() []string { getAllSoundtracks() var jsonArray []string for _, soundtrack := range soundtracksNew { jsonArray = append(jsonArray, soundtrack.SoundtrackName) } return jsonArray } func GetAllSoundtracksRandom() []string { getAllSoundtracks() var jsonArray []string for _, soundtrack := range soundtracksNew { jsonArray = append(jsonArray, soundtrack.SoundtrackName) } rand.Shuffle(len(jsonArray), func(i, j int) { jsonArray[i], jsonArray[j] = jsonArray[j], jsonArray[i] }) return jsonArray } func GetNextSong() string { if songQueNew == nil { return "" } if currentSong == len(songQueNew)-1 || currentSong == -1 { songData := songQueNew[currentSong] return songData.Path } else { currentSong = currentSong + 1 songData := songQueNew[currentSong] return songData.Path } } func GetPreviousSong() string { if songQueNew == nil { return "" } if currentSong == -1 || currentSong == 0 { songData := songQueNew[0] return songData.Path } else { currentSong = currentSong - 1 songData := songQueNew[currentSong] return songData.Path } } func getSongFromList(soundtracks []repository.Soundtrack) repository.Song { songFound := false var song repository.Song for !songFound { soundtrack := getRandomSoundtrack(soundtracks) songs, _ := BackendRepo().FindSongsFromSoundtrack(BackendCtx(), soundtrack.ID) if len(songs) == 0 { continue } song = songs[rand.Intn(len(songs))] logging.GetLogger().Debug("Selected song", zap.String("song", song.SongName), zap.String("path", song.Path)) //Check if file exists and open openFile, err := os.Open(song.Path) if err != nil || (song.FileName != nil && soundtrack.Path+*song.FileName != song.Path) || (song.FileName != nil && strings.HasSuffix(*song.FileName, ".wav")) { //File not found BackendRepo().RemoveBrokenSong(BackendCtx(), repository.RemoveBrokenSongParams{SoundtrackID: song.SoundtrackID, Path: song.Path}) logging.GetLogger().Warn("Song not found, removed from database", zap.String("song", song.SongName), zap.String("soundtrack", soundtrack.SoundtrackName), zap.Any("filename", song.FileName)) } else { songFound = true } err = openFile.Close() if err != nil { logging.GetLogger().Error("Failed to close file", zap.String("path", song.Path), zap.String("error", err.Error())) } } return song } func getCurrentSoundtrack(currentSongData repository.Song) repository.Soundtrack { for _, soundtrack := range soundtracksNew { if soundtrack.ID == currentSongData.SoundtrackID { return soundtrack } } return repository.Soundtrack{} } func getAveragePlayed() int32 { getAllSoundtracks() var sum int32 for _, data := range soundtracksNew { sum += data.TimesPlayed } return sum / int32(len(soundtracksNew)) } func getRandomSoundtrack(listOfSoundtracks []repository.Soundtrack) repository.Soundtrack { return listOfSoundtracks[rand.Intn(len(listOfSoundtracks))] }