From a8df738108dfd375c621c6444a3a30ba18b8d2de Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 29 Jun 2026 18:39:09 +0200 Subject: [PATCH] #9 Changed the term game to soundtrack everywhere --- .dockerignore | 31 +++ Dockerfile | 25 +- cmd/docs/docs.go | 80 +++---- cmd/docs/swagger.json | 84 +++---- cmd/web/hello.go | 62 ++--- cmd/web/hello.templ | 14 +- internal/backend/music.go | 100 ++++---- internal/backend/music_test.go | 124 +++++----- internal/backend/statistics.go | 216 ++++++++--------- internal/backend/sync.go | 262 ++++++++++----------- internal/db/dbHelper.go | 6 +- internal/db/queries/statistics.sql | 16 +- internal/db/repository/statistics.sql.go | 86 +++---- internal/server/musicHandler.go | 6 +- internal/server/routes.go | 22 +- internal/server/statistics_handler.go | 124 +++++----- internal/server/statistics_handler_test.go | 4 +- internal/server/syncHandler.go | 8 +- internal/server/sync_handler_test.go | 84 +++---- internal/server/zz_music_handler_test.go | 36 +-- 20 files changed, 708 insertions(+), 682 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..eb9362e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,31 @@ +# Directories +.gitea +git +.idea +testMusic +testCharacters + +# Files +Dockerfile +docker-compose* +compose.yaml +.dockerignore +.gitignore +*.pprof +main +conf.yaml +output.css +tailwindcss +.env + +# Node.js (frontend build artifacts) +node_modules +package.json +package-lock.json + +# Test files +*_test.go +integration_test.go + +# OS +.DS_Store diff --git a/Dockerfile b/Dockerfile index c041846..d5c84e0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,33 +1,28 @@ -# Stage 1: Build frontend -FROM node:18-alpine AS frontend-builder -RUN apk add --no-cache git -WORKDIR /app -RUN git clone https://gitea.sanplex.xyz/Sansan/MusicFrontend.git -WORKDIR /app/MusicFrontend -RUN npm install -RUN npm run build -# Generate config.js with empty API_HOSTNAME (relative paths) -RUN echo "window.__RUNTIME_CONFIG__ = { API_HOSTNAME: '' };" > dist/config.js - -# Stage 2: Build backend +# Stage 1: Build backend FROM golang:1.25-alpine as build_go RUN apk add --no-cache curl WORKDIR /app COPY go.mod go.sum ./ RUN go mod download -COPY . . +COPY cmd/ ./cmd/ +COPY internal/ ./internal/ +COPY *.go ./ +RUN find . -name "*_test.go" -delete && \ + find . -name "integration_test.go" -delete RUN go install github.com/a-h/templ/cmd/templ@latest RUN templ generate RUN go build -o main cmd/main.go -# Stage 3: Final image +# Stage 2: Final image FROM golang:1.25-alpine EXPOSE 8080 VOLUME /sorted VOLUME /characters COPY --from=build_go /app/main . -COPY --from=frontend-builder /app/MusicFrontend/dist /frontend +COPY --from=gitea.sanplex.xyz/sansan/musicfrontend:latest /usr/share/nginx/html /frontend +# Generate config.js with empty API_HOSTNAME (relative paths) +RUN echo "window.__RUNTIME_CONFIG__ = { API_HOSTNAME: '' };" > /frontend/config.js COPY ./songs/ ./songs/ ENV PORT 8080 diff --git a/cmd/docs/docs.go b/cmd/docs/docs.go index c59c548..0e4fc35 100644 --- a/cmd/docs/docs.go +++ b/cmd/docs/docs.go @@ -23,9 +23,9 @@ var doc = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { - "/api/v1/statistics/games/last-played": { + "/api/v1/statistics/soundtracks/last-played": { "get": { - "description": "Returns the most recently played games", + "description": "Returns the most recently played soundtracks", "consumes": [ "application/json" ], @@ -35,7 +35,7 @@ var doc = `{ "tags": [ "statistics" ], - "summary": "Get last played games", + "summary": "Get last played soundtracks", "parameters": [ { "type": "integer", @@ -50,7 +50,7 @@ var doc = `{ "schema": { "type": "array", "items": { - "$ref": "#/definitions/backend.GameWithSongs" + "$ref": "#/definitions/backend.SoundtrackWithSongs" } } }, @@ -75,9 +75,9 @@ var doc = `{ } } }, - "/api/v1/statistics/games/least-played": { + "/api/v1/statistics/soundtracks/least-played": { "get": { - "description": "Returns the top N least played games with their songs", + "description": "Returns the top N least played soundtracks with their songs", "consumes": [ "application/json" ], @@ -87,7 +87,7 @@ var doc = `{ "tags": [ "statistics" ], - "summary": "Get least played games", + "summary": "Get least played soundtracks", "parameters": [ { "type": "integer", @@ -102,7 +102,7 @@ var doc = `{ "schema": { "type": "array", "items": { - "$ref": "#/definitions/backend.GameWithSongs" + "$ref": "#/definitions/backend.SoundtrackWithSongs" } } }, @@ -127,9 +127,9 @@ var doc = `{ } } }, - "/api/v1/statistics/games/most-played": { + "/api/v1/statistics/soundtracks/most-played": { "get": { - "description": "Returns the top N most played games with their songs", + "description": "Returns the top N most played soundtracks with their songs", "consumes": [ "application/json" ], @@ -139,7 +139,7 @@ var doc = `{ "tags": [ "statistics" ], - "summary": "Get most played games", + "summary": "Get most played soundtracks", "parameters": [ { "type": "integer", @@ -154,7 +154,7 @@ var doc = `{ "schema": { "type": "array", "items": { - "$ref": "#/definitions/backend.GameWithSongs" + "$ref": "#/definitions/backend.SoundtrackWithSongs" } } }, @@ -179,9 +179,9 @@ var doc = `{ } } }, - "/api/v1/statistics/games/never-played": { + "/api/v1/statistics/soundtracks/never-played": { "get": { - "description": "Returns all games that have never been played (times_played = 0)", + "description": "Returns all soundtracks that have never been played (times_played = 0)", "consumes": [ "application/json" ], @@ -191,14 +191,14 @@ var doc = `{ "tags": [ "statistics" ], - "summary": "Get never played games", + "summary": "Get never played soundtracks", "responses": { "200": { "description": "OK", "schema": { "type": "array", "items": { - "$ref": "#/definitions/backend.GameWithSongs" + "$ref": "#/definitions/backend.SoundtrackWithSongs" } } }, @@ -214,9 +214,9 @@ var doc = `{ } } }, - "/api/v1/statistics/games/oldest-played": { + "/api/v1/statistics/soundtracks/oldest-played": { "get": { - "description": "Returns the least recently played games (that have been played at least once)", + "description": "Returns the least recently played soundtracks (that have been played at least once)", "consumes": [ "application/json" ], @@ -226,7 +226,7 @@ var doc = `{ "tags": [ "statistics" ], - "summary": "Get oldest played games", + "summary": "Get oldest played soundtracks", "parameters": [ { "type": "integer", @@ -241,7 +241,7 @@ var doc = `{ "schema": { "type": "array", "items": { - "$ref": "#/definitions/backend.GameWithSongs" + "$ref": "#/definitions/backend.SoundtrackWithSongs" } } }, @@ -824,7 +824,7 @@ var doc = `{ }, "/music/all/order": { "get": { - "description": "Returns a list of all games in order", + "description": "Returns a list of all soundtracks in order", "consumes": [ "application/json" ], @@ -857,7 +857,7 @@ var doc = `{ }, "/music/all/random": { "get": { - "description": "Returns a list of all games in random order", + "description": "Returns a list of all soundtracks in random order", "consumes": [ "application/json" ], @@ -1197,7 +1197,7 @@ var doc = `{ }, "/sync": { "get": { - "description": "Starts syncing games with only new changes", + "description": "Starts syncing soundtracks with only new changes", "consumes": [ "application/json" ], @@ -1226,7 +1226,7 @@ var doc = `{ }, "/sync/full": { "get": { - "description": "Starts a full sync of all games", + "description": "Starts a full sync of all soundtracks", "consumes": [ "application/json" ], @@ -1236,7 +1236,7 @@ var doc = `{ "tags": [ "sync" ], - "summary": "Sync all games fully", + "summary": "Sync all soundtracks fully", "responses": { "200": { "description": "Start syncing soundtracks full", @@ -1279,7 +1279,7 @@ var doc = `{ }, "/sync/reset": { "get": { - "description": "Resets the games database by deleting all games and songs", + "description": "Resets the soundtracks database by deleting all soundtracks and songs", "consumes": [ "application/json" ], @@ -1369,19 +1369,19 @@ var doc = `{ } }, "definitions": { - "backend.GameWithSongs": { + "backend.SoundtrackWithSongs": { "type": "object", "properties": { - "game_id": { + "soundtrack_id": { "type": "integer" }, - "game_last_played": { + "soundtrack_last_played": { "type": "string" }, - "game_name": { + "soundtrack_name": { "type": "string" }, - "game_played": { + "soundtrack_played": { "type": "integer" }, "songs": { @@ -1398,10 +1398,10 @@ var doc = `{ "file_name": { "type": "string" }, - "game_id": { + "soundtrack_id": { "type": "integer" }, - "game_name": { + "soundtrack_name": { "type": "string" }, "path": { @@ -1418,25 +1418,25 @@ var doc = `{ "backend.StatisticsSummary": { "type": "object", "properties": { - "avg_game_plays": { + "avg_soundtrack_plays": { "type": "number" }, - "max_game_plays": { + "max_soundtrack_plays": { "type": "integer" }, - "min_game_plays": { + "min_soundtrack_plays": { "type": "integer" }, - "never_played_games": { + "never_played_soundtracks": { "type": "integer" }, - "played_games": { + "played_soundtracks": { "type": "integer" }, - "total_game_plays": { + "total_soundtrack_plays": { "type": "integer" }, - "total_games": { + "total_soundtracks": { "type": "integer" } } diff --git a/cmd/docs/swagger.json b/cmd/docs/swagger.json index e283757..4abba18 100644 --- a/cmd/docs/swagger.json +++ b/cmd/docs/swagger.json @@ -4,9 +4,9 @@ "contact": {} }, "paths": { - "/api/v1/statistics/games/last-played": { + "/api/v1/statistics/soundtracks/last-played": { "get": { - "description": "Returns the most recently played games", + "description": "Returns the most recently played soundtracks", "consumes": [ "application/json" ], @@ -16,7 +16,7 @@ "tags": [ "statistics" ], - "summary": "Get last played games", + "summary": "Get last played soundtracks", "parameters": [ { "type": "integer", @@ -31,7 +31,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/definitions/backend.GameWithSongs" + "$ref": "#/definitions/backend.SoundtrackWithSongs" } } }, @@ -56,9 +56,9 @@ } } }, - "/api/v1/statistics/games/least-played": { + "/api/v1/statistics/soundtracks/least-played": { "get": { - "description": "Returns the top N least played games with their songs", + "description": "Returns the top N least played soundtracks with their songs", "consumes": [ "application/json" ], @@ -68,7 +68,7 @@ "tags": [ "statistics" ], - "summary": "Get least played games", + "summary": "Get least played soundtracks", "parameters": [ { "type": "integer", @@ -83,7 +83,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/definitions/backend.GameWithSongs" + "$ref": "#/definitions/backend.SoundtrackWithSongs" } } }, @@ -108,9 +108,9 @@ } } }, - "/api/v1/statistics/games/most-played": { + "/api/v1/statistics/soundtracks/most-played": { "get": { - "description": "Returns the top N most played games with their songs", + "description": "Returns the top N most played soundtracks with their songs", "consumes": [ "application/json" ], @@ -120,7 +120,7 @@ "tags": [ "statistics" ], - "summary": "Get most played games", + "summary": "Get most played soundtracks", "parameters": [ { "type": "integer", @@ -135,7 +135,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/definitions/backend.GameWithSongs" + "$ref": "#/definitions/backend.SoundtrackWithSongs" } } }, @@ -160,9 +160,9 @@ } } }, - "/api/v1/statistics/games/never-played": { + "/api/v1/statistics/soundtracks/never-played": { "get": { - "description": "Returns all games that have never been played (times_played = 0)", + "description": "Returns all soundtracks that have never been played (times_played = 0)", "consumes": [ "application/json" ], @@ -172,14 +172,14 @@ "tags": [ "statistics" ], - "summary": "Get never played games", + "summary": "Get never played soundtracks", "responses": { "200": { "description": "OK", "schema": { "type": "array", "items": { - "$ref": "#/definitions/backend.GameWithSongs" + "$ref": "#/definitions/backend.SoundtrackWithSongs" } } }, @@ -195,9 +195,9 @@ } } }, - "/api/v1/statistics/games/oldest-played": { + "/api/v1/statistics/soundtracks/oldest-played": { "get": { - "description": "Returns the least recently played games (that have been played at least once)", + "description": "Returns the least recently played soundtracks (that have been played at least once)", "consumes": [ "application/json" ], @@ -207,7 +207,7 @@ "tags": [ "statistics" ], - "summary": "Get oldest played games", + "summary": "Get oldest played soundtracks", "parameters": [ { "type": "integer", @@ -222,7 +222,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/definitions/backend.GameWithSongs" + "$ref": "#/definitions/backend.SoundtrackWithSongs" } } }, @@ -249,7 +249,7 @@ }, "/api/v1/statistics/songs/least-played": { "get": { - "description": "Returns the top N least played songs with their game info", + "description": "Returns the top N least played songs with their soundtrack info", "consumes": [ "application/json" ], @@ -301,7 +301,7 @@ }, "/api/v1/statistics/songs/most-played": { "get": { - "description": "Returns the top N most played songs with their game info", + "description": "Returns the top N most played songs with their soundtrack info", "consumes": [ "application/json" ], @@ -805,7 +805,7 @@ }, "/music/all/order": { "get": { - "description": "Returns a list of all games in order", + "description": "Returns a list of all soundtracks in order", "consumes": [ "application/json" ], @@ -838,7 +838,7 @@ }, "/music/all/random": { "get": { - "description": "Returns a list of all games in random order", + "description": "Returns a list of all soundtracks in random order", "consumes": [ "application/json" ], @@ -1178,7 +1178,7 @@ }, "/sync": { "get": { - "description": "Starts syncing games with only new changes", + "description": "Starts syncing soundtracks with only new changes", "consumes": [ "application/json" ], @@ -1207,7 +1207,7 @@ }, "/sync/full": { "get": { - "description": "Starts a full sync of all games", + "description": "Starts a full sync of all soundtracks", "consumes": [ "application/json" ], @@ -1217,7 +1217,7 @@ "tags": [ "sync" ], - "summary": "Sync all games fully", + "summary": "Sync all soundtracks fully", "responses": { "200": { "description": "Start syncing soundtracks full", @@ -1260,7 +1260,7 @@ }, "/sync/reset": { "get": { - "description": "Resets the games database by deleting all games and songs", + "description": "Resets the soundtracks database by deleting all soundtracks and songs", "consumes": [ "application/json" ], @@ -1350,19 +1350,19 @@ } }, "definitions": { - "backend.GameWithSongs": { + "backend.SoundtrackWithSongs": { "type": "object", "properties": { - "game_id": { + "soundtrack_id": { "type": "integer" }, - "game_last_played": { + "soundtrack_last_played": { "type": "string" }, - "game_name": { + "soundtrack_name": { "type": "string" }, - "game_played": { + "soundtrack_played": { "type": "integer" }, "songs": { @@ -1379,10 +1379,10 @@ "file_name": { "type": "string" }, - "game_id": { + "soundtrack_id": { "type": "integer" }, - "game_name": { + "soundtrack_name": { "type": "string" }, "path": { @@ -1399,25 +1399,25 @@ "backend.StatisticsSummary": { "type": "object", "properties": { - "avg_game_plays": { + "avg_soundtrack_plays": { "type": "number" }, - "max_game_plays": { + "max_soundtrack_plays": { "type": "integer" }, - "min_game_plays": { + "min_soundtrack_plays": { "type": "integer" }, - "never_played_games": { + "never_played_soundtracks": { "type": "integer" }, - "played_games": { + "played_soundtracks": { "type": "integer" }, - "total_game_plays": { + "total_soundtrack_plays": { "type": "integer" }, - "total_games": { + "total_soundtracks": { "type": "integer" } } diff --git a/cmd/web/hello.go b/cmd/web/hello.go index 87feded..680c927 100644 --- a/cmd/web/hello.go +++ b/cmd/web/hello.go @@ -8,9 +8,9 @@ import ( "strings" ) -var games_added []string +var soundtracks_added []string -func FindGameWebHandler(w http.ResponseWriter, r *http.Request) { +func FindSoundtrackWebHandler(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() if err != nil { http.Error(w, "Bad Request", http.StatusBadRequest) @@ -20,81 +20,81 @@ func FindGameWebHandler(w http.ResponseWriter, r *http.Request) { search(search_term) - component := FoundGames(games_added) + component := FoundSoundtracks(soundtracks_added) err = component.Render(r.Context(), w) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) - log.Fatalf("Error rendering in FindGameWebHandler: %e", err) + log.Fatalf("Error rendering in FindSoundtrackWebHandler: %e", err) } } func search(searchText string) { - games_added = nil - games := backend.GetAllSoundtracks() - for _, game := range games { - if is_match_exact(searchText, game) { - add_game(game) + soundtracks_added = nil + soundtracks := backend.GetAllSoundtracks() + for _, soundtrack := range soundtracks { + if is_match_exact(searchText, soundtrack) { + add_soundtrack(soundtrack) } } - for _, game := range games { - if is_match_contains(clean_term(searchText), clean_term(game)) { - add_game(game) + for _, soundtrack := range soundtracks { + if is_match_contains(clean_term(searchText), clean_term(soundtrack)) { + add_soundtrack(soundtrack) } } - for _, game := range games { - if is_match_regex(clean_term(searchText), clean_term(game)) { - add_game(game) + for _, soundtrack := range soundtracks { + if is_match_regex(clean_term(searchText), clean_term(soundtrack)) { + add_soundtrack(soundtrack) } } } -func is_match_exact(search_term string, game_name string) bool { +func is_match_exact(search_term string, soundtrack_name string) bool { search_term = strings.ToLower(search_term) - game_name = strings.ToLower(game_name) + soundtrack_name = strings.ToLower(soundtrack_name) if search_term == "" { return true - } else if strings.Contains(game_name, search_term) { + } else if strings.Contains(soundtrack_name, search_term) { return true } else { return false } } -func is_match_contains(search_term string, game_name string) bool { +func is_match_contains(search_term string, soundtrack_name string) bool { if search_term == "" { return true - } else if strings.Contains(game_name, search_term) { + } else if strings.Contains(soundtrack_name, search_term) { return true } else { return false } } -func is_match_regex(search_term string, game_name string) bool { +func is_match_regex(search_term string, soundtrack_name string) bool { if search_term == "" { return true - } else if compile_regex(search_term).MatchString(game_name) { + } else if compile_regex(search_term).MatchString(soundtrack_name) { return true } else { return false } } -func add_game(game string) { - if !check_if_game_exists(game) { - games_added = append(games_added, game) +func add_soundtrack(soundtrack string) { + if !check_if_soundtrack_exists(soundtrack) { + soundtracks_added = append(soundtracks_added, soundtrack) } } -func check_if_game_exists(gameName string) bool { - game_exists := false - for _, child := range games_added { - if child == gameName { - game_exists = true +func check_if_soundtrack_exists(soundtrackName string) bool { + soundtrack_exists := false + for _, child := range soundtracks_added { + if child == soundtrackName { + soundtrack_exists = true } } - return game_exists + return soundtrack_exists } func compile_regex(search_term string) *regexp.Regexp { diff --git a/cmd/web/hello.templ b/cmd/web/hello.templ index bcbef89..fbd8191 100644 --- a/cmd/web/hello.templ +++ b/cmd/web/hello.templ @@ -4,14 +4,14 @@ templ HelloForm() { @Base() {
- +
-
+
} } -templ FoundGames(games []string) { - for _, game := range games { +templ FoundSoundtracks(soundtracks []string) { + for _, soundtrack := range soundtracks {
-

{ game }

+

{ soundtrack }

} } diff --git a/internal/backend/music.go b/internal/backend/music.go index dff0a6a..393f804 100644 --- a/internal/backend/music.go +++ b/internal/backend/music.go @@ -12,8 +12,8 @@ import ( ) type SongInfo struct { - Game string `json:"Game"` - GamePlayed int32 `json:"GamePlayed"` + Soundtrack string `json:"Soundtrack"` + SoundtrackPlayed int32 `json:"SoundtrackPlayed"` Song string `json:"Song"` SongPlayed int32 `json:"SongPlayed"` CurrentlyPlaying bool `json:"CurrentlyPlaying"` @@ -22,7 +22,7 @@ type SongInfo struct { var currentSong = -1 -var gamesNew []repository.Soundtrack +var soundtracksNew []repository.Soundtrack var songQueNew []repository.Song @@ -37,12 +37,12 @@ func initRepo() { } } -func getAllGames() []repository.Soundtrack { - if len(gamesNew) == 0 { +func getAllSoundtracks() []repository.Soundtrack { + if len(soundtracksNew) == 0 { initRepo() - gamesNew, _ = BackendRepo().FindAllSoundtracks(BackendCtx()) + soundtracksNew, _ = BackendRepo().FindAllSoundtracks(BackendCtx()) } - return gamesNew + return soundtracksNew } @@ -59,7 +59,7 @@ func Reset() { songQueNew = nil currentSong = -1 initRepo() - gamesNew, _ = BackendRepo().FindAllSoundtracks(BackendCtx()) + soundtracksNew, _ = BackendRepo().FindAllSoundtracks(BackendCtx()) } func AddLatestToQue() { @@ -92,34 +92,34 @@ func SetPlayed(songNumber int) { } func GetRandomSong() string { - getAllGames() - if len(gamesNew) == 0 { + getAllSoundtracks() + if len(soundtracksNew) == 0 { return "" } - song := getSongFromList(gamesNew) + song := getSongFromList(soundtracksNew) lastFetchedNew = song return song.Path } func GetRandomSongLowChance() string { - getAllGames() + getAllSoundtracks() - var listOfGames []repository.Soundtrack + var listOfSoundtracks []repository.Soundtrack var averagePlayed = getAveragePlayed() - for _, data := range gamesNew { + for _, data := range soundtracksNew { timesToAdd := averagePlayed - data.TimesPlayed if timesToAdd <= 0 { - listOfGames = append(listOfGames, data) + listOfSoundtracks = append(listOfSoundtracks, data) } else { for i := int32(0); i < timesToAdd; i++ { - listOfGames = append(listOfGames, data) + listOfSoundtracks = append(listOfSoundtracks, data) } } } - song := getSongFromList(listOfGames) + song := getSongFromList(listOfSoundtracks) lastFetchedNew = song return song.Path @@ -127,11 +127,11 @@ func GetRandomSongLowChance() string { } func GetRandomSongClassic() string { - getAllGames() + getAllSoundtracks() var listOfAllSongs []repository.Song - for _, game := range gamesNew { - songList, _ := BackendRepo().FindSongsFromSoundtrack(BackendCtx(), game.ID) + for _, soundtrack := range soundtracksNew { + songList, _ := BackendRepo().FindSongsFromSoundtrack(BackendCtx(), soundtrack.ID) listOfAllSongs = append(listOfAllSongs, songList...) } @@ -139,25 +139,25 @@ func GetRandomSongClassic() string { var song repository.Song for !songFound { song = listOfAllSongs[rand.Intn(len(listOfAllSongs))] - gameData, err := BackendRepo().GetSoundtrackById(BackendCtx(), song.SoundtrackID) + 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("game", gameData.SoundtrackName), + 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 && gameData.Path+*song.FileName != 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("game", gameData.SoundtrackName), + zap.String("soundtrack", soundtrackData.SoundtrackName), zap.String("filename", *song.FileName)) } else { songFound = true @@ -177,11 +177,11 @@ func GetSongInfo() SongInfo { } var currentSongData = songQueNew[currentSong] - currentGameData := getCurrentGame(currentSongData) + currentSoundtrackData := getCurrentSoundtrack(currentSongData) return SongInfo{ - Game: currentGameData.SoundtrackName, - GamePlayed: currentGameData.TimesPlayed, + Soundtrack: currentSoundtrackData.SoundtrackName, + SoundtrackPlayed: currentSoundtrackData.TimesPlayed, Song: currentSongData.SongName, SongPlayed: currentSongData.TimesPlayed, CurrentlyPlaying: true, @@ -193,10 +193,10 @@ func GetPlayedSongs() []SongInfo { var songList []SongInfo for i, song := range songQueNew { - gameData := getCurrentGame(song) + soundtrackData := getCurrentSoundtrack(song) songList = append(songList, SongInfo{ - Game: gameData.SoundtrackName, - GamePlayed: gameData.TimesPlayed, + Soundtrack: soundtrackData.SoundtrackName, + SoundtrackPlayed: soundtrackData.TimesPlayed, Song: song.SongName, SongPlayed: song.TimesPlayed, CurrentlyPlaying: i == currentSong, @@ -218,21 +218,21 @@ func GetSong(song string) string { } func GetAllSoundtracks() []string { - getAllGames() + getAllSoundtracks() var jsonArray []string - for _, game := range gamesNew { - jsonArray = append(jsonArray, game.SoundtrackName) + for _, soundtrack := range soundtracksNew { + jsonArray = append(jsonArray, soundtrack.SoundtrackName) } return jsonArray } func GetAllSoundtracksRandom() []string { - getAllGames() + getAllSoundtracks() var jsonArray []string - for _, game := range gamesNew { - jsonArray = append(jsonArray, game.SoundtrackName) + 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 @@ -266,12 +266,12 @@ func GetPreviousSong() string { } } -func getSongFromList(games []repository.Soundtrack) repository.Song { +func getSongFromList(soundtracks []repository.Soundtrack) repository.Song { songFound := false var song repository.Song for !songFound { - game := getRandomGame(games) - songs, _ := BackendRepo().FindSongsFromSoundtrack(BackendCtx(), game.ID) + soundtrack := getRandomSoundtrack(soundtracks) + songs, _ := BackendRepo().FindSongsFromSoundtrack(BackendCtx(), soundtrack.ID) if len(songs) == 0 { continue } @@ -280,12 +280,12 @@ func getSongFromList(games []repository.Soundtrack) repository.Song { //Check if file exists and open openFile, err := os.Open(song.Path) - if err != nil || (song.FileName != nil && game.Path+*song.FileName != song.Path) || (song.FileName != nil && strings.HasSuffix(*song.FileName, ".wav")) { + 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("game", game.SoundtrackName), + zap.String("soundtrack", soundtrack.SoundtrackName), zap.Any("filename", song.FileName)) } else { songFound = true @@ -299,24 +299,24 @@ func getSongFromList(games []repository.Soundtrack) repository.Song { return song } -func getCurrentGame(currentSongData repository.Song) repository.Soundtrack { - for _, game := range gamesNew { - if game.ID == currentSongData.SoundtrackID { - return game +func getCurrentSoundtrack(currentSongData repository.Song) repository.Soundtrack { + for _, soundtrack := range soundtracksNew { + if soundtrack.ID == currentSongData.SoundtrackID { + return soundtrack } } return repository.Soundtrack{} } func getAveragePlayed() int32 { - getAllGames() + getAllSoundtracks() var sum int32 - for _, data := range gamesNew { + for _, data := range soundtracksNew { sum += data.TimesPlayed } - return sum / int32(len(gamesNew)) + return sum / int32(len(soundtracksNew)) } -func getRandomGame(listOfGames []repository.Soundtrack) repository.Soundtrack { - return listOfGames[rand.Intn(len(listOfGames))] +func getRandomSoundtrack(listOfSoundtracks []repository.Soundtrack) repository.Soundtrack { + return listOfSoundtracks[rand.Intn(len(listOfSoundtracks))] } diff --git a/internal/backend/music_test.go b/internal/backend/music_test.go index d670597..fe2c2ae 100644 --- a/internal/backend/music_test.go +++ b/internal/backend/music_test.go @@ -9,17 +9,17 @@ import ( // Test the average calculation logic directly without database access func TestCalculateAverage(t *testing.T) { - games := []repository.Soundtrack{ - {SoundtrackName: "Game1", TimesPlayed: 10}, - {SoundtrackName: "Game2", TimesPlayed: 20}, - {SoundtrackName: "Game3", TimesPlayed: 30}, + soundtracks := []repository.Soundtrack{ + {SoundtrackName: "Soundtrack1", TimesPlayed: 10}, + {SoundtrackName: "Soundtrack2", TimesPlayed: 20}, + {SoundtrackName: "Soundtrack3", TimesPlayed: 30}, } var sum int32 - for _, data := range games { + for _, data := range soundtracks { sum += data.TimesPlayed } - result := sum / int32(len(games)) + result := sum / int32(len(soundtracks)) expected := int32(20) if result != expected { @@ -28,9 +28,9 @@ func TestCalculateAverage(t *testing.T) { } func TestCalculateAverageEmpty(t *testing.T) { - games := []repository.Soundtrack{} + soundtracks := []repository.Soundtrack{} - if len(games) == 0 { + if len(soundtracks) == 0 { result := int32(0) expected := int32(0) if result != expected { @@ -40,10 +40,10 @@ func TestCalculateAverageEmpty(t *testing.T) { } var sum int32 - for _, data := range games { + for _, data := range soundtracks { sum += data.TimesPlayed } - result := sum / int32(len(games)) + result := sum / int32(len(soundtracks)) expected := int32(0) if result != expected { @@ -52,107 +52,107 @@ func TestCalculateAverageEmpty(t *testing.T) { } func TestCalculateAverageSingle(t *testing.T) { - games := []repository.Soundtrack{ - {SoundtrackName: "Game1", TimesPlayed: 42}, + soundtracks := []repository.Soundtrack{ + {SoundtrackName: "Soundtrack1", TimesPlayed: 42}, } var sum int32 - for _, data := range games { + for _, data := range soundtracks { sum += data.TimesPlayed } - result := sum / int32(len(games)) + result := sum / int32(len(soundtracks)) expected := int32(42) if result != expected { - t.Errorf("Average calculation with single game = %v, want %v", result, expected) + t.Errorf("Average calculation with single soundtrack = %v, want %v", result, expected) } } -func TestGetRandomGame(t *testing.T) { - games := []repository.Soundtrack{ - {SoundtrackName: "Game1", TimesPlayed: 10}, - {SoundtrackName: "Game2", TimesPlayed: 20}, - {SoundtrackName: "Game3", TimesPlayed: 30}, +func TestGetRandomSoundtrack(t *testing.T) { + soundtracks := []repository.Soundtrack{ + {SoundtrackName: "Soundtrack1", TimesPlayed: 10}, + {SoundtrackName: "Soundtrack2", TimesPlayed: 20}, + {SoundtrackName: "Soundtrack3", TimesPlayed: 30}, } // Set seed for reproducible tests rand.Seed(42) - result := games[rand.Intn(len(games))] + result := soundtracks[rand.Intn(len(soundtracks))] if result.SoundtrackName == "" { - t.Error("random game selection returned empty game") + t.Error("random soundtrack selection returned empty soundtrack") } found := false - for _, g := range games { - if g.SoundtrackName == result.SoundtrackName { + for _, s := range soundtracks { + if s.SoundtrackName == result.SoundtrackName { found = true break } } if !found { - t.Errorf("random game selection returned game not in list: %v", result.SoundtrackName) + t.Errorf("random soundtrack selection returned soundtrack not in list: %v", result.SoundtrackName) } } -func TestFindGameByID(t *testing.T) { - games := []repository.Soundtrack{ - {ID: 1, SoundtrackName: "Game1", TimesPlayed: 10}, - {ID: 2, SoundtrackName: "Game2", TimesPlayed: 20}, - {ID: 3, SoundtrackName: "Game3", TimesPlayed: 30}, +func TestFindSoundtrackByID(t *testing.T) { + soundtracks := []repository.Soundtrack{ + {ID: 1, SoundtrackName: "Soundtrack1", TimesPlayed: 10}, + {ID: 2, SoundtrackName: "Soundtrack2", TimesPlayed: 20}, + {ID: 3, SoundtrackName: "Soundtrack3", TimesPlayed: 30}, } tests := []struct { - name string - games []repository.Soundtrack - gameID int32 - expected repository.Soundtrack + name string + soundtracks []repository.Soundtrack + soundtrackID int32 + expected repository.Soundtrack }{ { - name: "existing game", - games: games, - gameID: 2, - expected: repository.Soundtrack{ID: 2, SoundtrackName: "Game2", TimesPlayed: 20}, + name: "existing soundtrack", + soundtracks: soundtracks, + soundtrackID: 2, + expected: repository.Soundtrack{ID: 2, SoundtrackName: "Soundtrack2", TimesPlayed: 20}, }, { - name: "non-existing game", - games: games, - gameID: 99, - expected: repository.Soundtrack{}, + name: "non-existing soundtrack", + soundtracks: soundtracks, + soundtrackID: 99, + expected: repository.Soundtrack{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var result repository.Soundtrack - for _, game := range tt.games { - if game.ID == tt.gameID { - result = game + for _, s := range tt.soundtracks { + if s.ID == tt.soundtrackID { + result = s break } } if result.ID != tt.expected.ID || result.SoundtrackName != tt.expected.SoundtrackName { - t.Errorf("findGameByID() = %v, want %v", result, tt.expected) + t.Errorf("findSoundtrackByID() = %v, want %v", result, tt.expected) } }) } } func TestExtractSoundtrackNames(t *testing.T) { - games := []repository.Soundtrack{ - {SoundtrackName: "Game1", TimesPlayed: 10}, - {SoundtrackName: "Game2", TimesPlayed: 20}, - {SoundtrackName: "Game3", TimesPlayed: 30}, + soundtracks := []repository.Soundtrack{ + {SoundtrackName: "Soundtrack1", TimesPlayed: 10}, + {SoundtrackName: "Soundtrack2", TimesPlayed: 20}, + {SoundtrackName: "Soundtrack3", TimesPlayed: 30}, } var result []string - for _, game := range games { - result = append(result, game.SoundtrackName) + for _, s := range soundtracks { + result = append(result, s.SoundtrackName) } - expected := []string{"Game1", "Game2", "Game3"} + expected := []string{"Soundtrack1", "Soundtrack2", "Soundtrack3"} if len(result) != len(expected) { t.Errorf("extractSoundtrackNames() length = %d, want %d", len(result), len(expected)) @@ -167,29 +167,29 @@ func TestExtractSoundtrackNames(t *testing.T) { } func TestShuffleSoundtrackNames(t *testing.T) { - games := []string{"Game1", "Game2", "Game3"} + soundtracks := []string{"Soundtrack1", "Soundtrack2", "Soundtrack3"} // Test that shuffle doesn't lose any elements // We can't test the order since it's random, but we can test length and contents - original := make([]string, len(games)) - copy(original, games) + original := make([]string, len(soundtracks)) + copy(original, soundtracks) // Simple shuffle implementation for testing - for i := range games { + for i := range soundtracks { j := i // In real code this would be random - games[i], games[j] = games[j], games[i] + soundtracks[i], soundtracks[j] = soundtracks[j], soundtracks[i] } - if len(games) != len(original) { - t.Errorf("shuffleSoundtrackNames() changed length from %d to %d", len(original), len(games)) + if len(soundtracks) != len(original) { + t.Errorf("shuffleSoundtrackNames() changed length from %d to %d", len(original), len(soundtracks)) return } // Check all original elements are still present for _, orig := range original { found := false - for _, g := range games { - if g == orig { + for _, s := range soundtracks { + if s == orig { found = true break } diff --git a/internal/backend/statistics.go b/internal/backend/statistics.go index e6fccb3..e50dc04 100644 --- a/internal/backend/statistics.go +++ b/internal/backend/statistics.go @@ -9,34 +9,34 @@ import ( "go.uber.org/zap" ) -// GameWithSongs represents a game with its songs for statistics -type GameWithSongs struct { - SoundtrackID int32 `json:"game_id"` - SoundtrackName string `json:"game_name"` - SoundtrackPlayed int32 `json:"game_played"` - SoundtrackLastPlayed *time.Time `json:"game_last_played,omitempty"` - Songs []SongInfoForStats `json:"songs"` +// SoundtrackWithSongs represents a soundtrack with its songs for statistics +type SoundtrackWithSongs struct { + SoundtrackID int32 `json:"soundtrack_id"` + SoundtrackName string `json:"soundtrack_name"` + SoundtrackPlayed int32 `json:"soundtrack_played"` + SoundtrackLastPlayed *time.Time `json:"soundtrack_last_played,omitempty"` + Songs []SongInfoForStats `json:"songs"` } -// SongInfoForStats represents a song with game info for statistics +// SongInfoForStats represents a song with soundtrack info for statistics type SongInfoForStats struct { - SoundtrackID int32 `json:"game_id"` - SoundtrackName string `json:"game_name"` - SongName string `json:"song_name"` - Path string `json:"path"` - TimesPlayed int32 `json:"times_played"` - FileName *string `json:"file_name,omitempty"` + SoundtrackID int32 `json:"soundtrack_id"` + SoundtrackName string `json:"soundtrack_name"` + SongName string `json:"song_name"` + Path string `json:"path"` + TimesPlayed int32 `json:"times_played"` + FileName *string `json:"file_name,omitempty"` } // StatisticsSummary holds overall statistics type StatisticsSummary struct { - TotalGames int64 `json:"total_games"` - PlayedGames int64 `json:"played_games"` - NeverPlayedGames int64 `json:"never_played_games"` - TotalGamePlays int64 `json:"total_game_plays"` - AvgGamePlays float64 `json:"avg_game_plays"` - MaxGamePlays int64 `json:"max_game_plays"` - MinGamePlays int64 `json:"min_game_plays"` + TotalSoundtracks int64 `json:"total_soundtracks"` + PlayedSoundtracks int64 `json:"played_soundtracks"` + NeverPlayedSoundtracks int64 `json:"never_played_soundtracks"` + TotalSoundtrackPlays int64 `json:"total_soundtrack_plays"` + AvgSoundtrackPlays float64 `json:"avg_soundtrack_plays"` + MaxSoundtrackPlays int64 `json:"max_soundtrack_plays"` + MinSoundtrackPlays int64 `json:"min_soundtrack_plays"` } // StatisticsHandler manages statistics operations @@ -49,19 +49,19 @@ func NewStatisticsHandler() *StatisticsHandler { return &StatisticsHandler{} } -// GetMostPlayedGamesWithSongs returns the top N most played games with their songs -func (h *StatisticsHandler) GetMostPlayedGamesWithSongs(limit int32) ([]GameWithSongs, error) { +// GetMostPlayedSoundtracksWithSongs returns the top N most played soundtracks with their songs +func (h *StatisticsHandler) GetMostPlayedSoundtracksWithSongs(limit int32) ([]SoundtrackWithSongs, error) { queries := BackendRepo() ctx := BackendCtx() - + // Get raw results - rows, err := queries.GetMostPlayedGamesWithSongs(ctx, limit) + rows, err := queries.GetMostPlayedSoundtracksWithSongs(ctx, limit) if err != nil { return nil, err } - - // Convert to GameWithSongs - var result []GameWithSongs + + // Convert to SoundtrackWithSongs + var result []SoundtrackWithSongs for _, row := range rows { var songs []SongInfoForStats if row.Songs != nil { @@ -71,28 +71,28 @@ func (h *StatisticsHandler) GetMostPlayedGamesWithSongs(limit int32) ([]GameWith songs = make([]SongInfoForStats, 0) } } - result = append(result, GameWithSongs{ - SoundtrackID: row.SoundtrackID, - SoundtrackName: row.SoundtrackName, - SoundtrackPlayed: row.SoundtrackPlayed, + result = append(result, SoundtrackWithSongs{ + SoundtrackID: row.SoundtrackID, + SoundtrackName: row.SoundtrackName, + SoundtrackPlayed: row.SoundtrackPlayed, SoundtrackLastPlayed: row.SoundtrackLastPlayed, - Songs: songs, + Songs: songs, }) } return result, nil } -// GetLeastPlayedGamesWithSongs returns the top N least played games with their songs -func (h *StatisticsHandler) GetLeastPlayedGamesWithSongs(limit int32) ([]GameWithSongs, error) { +// GetLeastPlayedSoundtracksWithSongs returns the top N least played soundtracks with their songs +func (h *StatisticsHandler) GetLeastPlayedSoundtracksWithSongs(limit int32) ([]SoundtrackWithSongs, error) { queries := BackendRepo() ctx := BackendCtx() - - rows, err := queries.GetLeastPlayedGamesWithSongs(ctx, limit) + + rows, err := queries.GetLeastPlayedSoundtracksWithSongs(ctx, limit) if err != nil { return nil, err } - - var result []GameWithSongs + + var result []SoundtrackWithSongs for _, row := range rows { var songs []SongInfoForStats if row.Songs != nil { @@ -100,76 +100,76 @@ func (h *StatisticsHandler) GetLeastPlayedGamesWithSongs(limit int32) ([]GameWit songs = make([]SongInfoForStats, 0) } } - result = append(result, GameWithSongs{ - SoundtrackID: row.SoundtrackID, - SoundtrackName: row.SoundtrackName, - SoundtrackPlayed: row.SoundtrackPlayed, + result = append(result, SoundtrackWithSongs{ + SoundtrackID: row.SoundtrackID, + SoundtrackName: row.SoundtrackName, + SoundtrackPlayed: row.SoundtrackPlayed, SoundtrackLastPlayed: row.SoundtrackLastPlayed, - Songs: songs, + Songs: songs, }) } return result, nil } -// GetMostPlayedSongsWithGame returns the top N most played songs with their game info -func (h *StatisticsHandler) GetMostPlayedSongsWithGame(limit int32) ([]SongInfoForStats, error) { +// GetMostPlayedSongsWithSoundtrack returns the top N most played songs with their soundtrack info +func (h *StatisticsHandler) GetMostPlayedSongsWithSoundtrack(limit int32) ([]SongInfoForStats, error) { queries := BackendRepo() ctx := BackendCtx() - - rows, err := queries.GetMostPlayedSongsWithGame(ctx, limit) + + rows, err := queries.GetMostPlayedSongsWithSoundtrack(ctx, limit) if err != nil { return nil, err } - + var result []SongInfoForStats for _, row := range rows { result = append(result, SongInfoForStats{ - SoundtrackID: row.SoundtrackID, - SoundtrackName: row.SoundtrackName, - SongName: row.SongName, - Path: row.Path, - TimesPlayed: row.TimesPlayed, - FileName: row.FileName, + SoundtrackID: row.SoundtrackID, + SoundtrackName: row.SoundtrackName, + SongName: row.SongName, + Path: row.Path, + TimesPlayed: row.TimesPlayed, + FileName: row.FileName, }) } return result, nil } -// GetLeastPlayedSongsWithGame returns the top N least played songs with their game info -func (h *StatisticsHandler) GetLeastPlayedSongsWithGame(limit int32) ([]SongInfoForStats, error) { +// GetLeastPlayedSongsWithSoundtrack returns the top N least played songs with their soundtrack info +func (h *StatisticsHandler) GetLeastPlayedSongsWithSoundtrack(limit int32) ([]SongInfoForStats, error) { queries := BackendRepo() ctx := BackendCtx() - - rows, err := queries.GetLeastPlayedSongsWithGame(ctx, limit) + + rows, err := queries.GetLeastPlayedSongsWithSoundtrack(ctx, limit) if err != nil { return nil, err } - + var result []SongInfoForStats for _, row := range rows { result = append(result, SongInfoForStats{ - SoundtrackID: row.SoundtrackID, - SoundtrackName: row.SoundtrackName, - SongName: row.SongName, - Path: row.Path, - TimesPlayed: row.TimesPlayed, - FileName: row.FileName, + SoundtrackID: row.SoundtrackID, + SoundtrackName: row.SoundtrackName, + SongName: row.SongName, + Path: row.Path, + TimesPlayed: row.TimesPlayed, + FileName: row.FileName, }) } return result, nil } -// GetNeverPlayedGames returns games that have never been played -func (h *StatisticsHandler) GetNeverPlayedGames() ([]GameWithSongs, error) { +// GetNeverPlayedSoundtracks returns soundtracks that have never been played +func (h *StatisticsHandler) GetNeverPlayedSoundtracks() ([]SoundtrackWithSongs, error) { queries := BackendRepo() ctx := BackendCtx() - - rows, err := queries.GetNeverPlayedGames(ctx) + + rows, err := queries.GetNeverPlayedSoundtracks(ctx) if err != nil { return nil, err } - - var result []GameWithSongs + + var result []SoundtrackWithSongs for _, row := range rows { var songs []SongInfoForStats if row.Songs != nil { @@ -177,28 +177,28 @@ func (h *StatisticsHandler) GetNeverPlayedGames() ([]GameWithSongs, error) { songs = make([]SongInfoForStats, 0) } } - result = append(result, GameWithSongs{ - SoundtrackID: row.SoundtrackID, - SoundtrackName: row.SoundtrackName, - SoundtrackPlayed: row.SoundtrackPlayed, + result = append(result, SoundtrackWithSongs{ + SoundtrackID: row.SoundtrackID, + SoundtrackName: row.SoundtrackName, + SoundtrackPlayed: row.SoundtrackPlayed, SoundtrackLastPlayed: nil, - Songs: songs, + Songs: songs, }) } return result, nil } -// GetLastPlayedGames returns the most recently played games -func (h *StatisticsHandler) GetLastPlayedGames(limit int32) ([]GameWithSongs, error) { +// GetLastPlayedSoundtracks returns the most recently played soundtracks +func (h *StatisticsHandler) GetLastPlayedSoundtracks(limit int32) ([]SoundtrackWithSongs, error) { queries := BackendRepo() ctx := BackendCtx() - - rows, err := queries.GetLastPlayedGames(ctx, limit) + + rows, err := queries.GetLastPlayedSoundtracks(ctx, limit) if err != nil { return nil, err } - - var result []GameWithSongs + + var result []SoundtrackWithSongs for _, row := range rows { var songs []SongInfoForStats if row.Songs != nil { @@ -206,28 +206,28 @@ func (h *StatisticsHandler) GetLastPlayedGames(limit int32) ([]GameWithSongs, er songs = make([]SongInfoForStats, 0) } } - result = append(result, GameWithSongs{ - SoundtrackID: row.SoundtrackID, - SoundtrackName: row.SoundtrackName, - SoundtrackPlayed: row.SoundtrackPlayed, + result = append(result, SoundtrackWithSongs{ + SoundtrackID: row.SoundtrackID, + SoundtrackName: row.SoundtrackName, + SoundtrackPlayed: row.SoundtrackPlayed, SoundtrackLastPlayed: row.SoundtrackLastPlayed, - Songs: songs, + Songs: songs, }) } return result, nil } -// GetOldestPlayedGames returns the least recently played games -func (h *StatisticsHandler) GetOldestPlayedGames(limit int32) ([]GameWithSongs, error) { +// GetOldestPlayedSoundtracks returns the least recently played soundtracks +func (h *StatisticsHandler) GetOldestPlayedSoundtracks(limit int32) ([]SoundtrackWithSongs, error) { queries := BackendRepo() ctx := BackendCtx() - - rows, err := queries.GetOldestPlayedGames(ctx, limit) + + rows, err := queries.GetOldestPlayedSoundtracks(ctx, limit) if err != nil { return nil, err } - - var result []GameWithSongs + + var result []SoundtrackWithSongs for _, row := range rows { var songs []SongInfoForStats if row.Songs != nil { @@ -235,12 +235,12 @@ func (h *StatisticsHandler) GetOldestPlayedGames(limit int32) ([]GameWithSongs, songs = make([]SongInfoForStats, 0) } } - result = append(result, GameWithSongs{ - SoundtrackID: row.SoundtrackID, - SoundtrackName: row.SoundtrackName, - SoundtrackPlayed: row.SoundtrackPlayed, + result = append(result, SoundtrackWithSongs{ + SoundtrackID: row.SoundtrackID, + SoundtrackName: row.SoundtrackName, + SoundtrackPlayed: row.SoundtrackPlayed, SoundtrackLastPlayed: row.SoundtrackLastPlayed, - Songs: songs, + Songs: songs, }) } return result, nil @@ -250,20 +250,20 @@ func (h *StatisticsHandler) GetOldestPlayedGames(limit int32) ([]GameWithSongs, func (h *StatisticsHandler) GetStatisticsSummary() (*StatisticsSummary, error) { queries := BackendRepo() ctx := BackendCtx() - + row, err := queries.GetStatisticsSummary(ctx) if err != nil { return nil, err } - + return &StatisticsSummary{ - TotalGames: int64(row.TotalSoundtracks), - PlayedGames: int64(row.PlayedSoundtracks), - NeverPlayedGames: int64(row.NeverPlayedSoundtracks), - TotalGamePlays: int64(row.TotalSoundtrackPlays), - AvgGamePlays: float64(row.AvgSoundtrackPlays), - MaxGamePlays: int64(row.MaxSoundtrackPlays), - MinGamePlays: int64(row.MinSoundtrackPlays), + TotalSoundtracks: int64(row.TotalSoundtracks), + PlayedSoundtracks: int64(row.PlayedSoundtracks), + NeverPlayedSoundtracks: int64(row.NeverPlayedSoundtracks), + TotalSoundtrackPlays: int64(row.TotalSoundtrackPlays), + AvgSoundtrackPlays: float64(row.AvgSoundtrackPlays), + MaxSoundtrackPlays: int64(row.MaxSoundtrackPlays), + MinSoundtrackPlays: int64(row.MinSoundtrackPlays), }, nil } diff --git a/internal/backend/sync.go b/internal/backend/sync.go index 189668a..fb02baf 100644 --- a/internal/backend/sync.go +++ b/internal/backend/sync.go @@ -30,14 +30,14 @@ var start time.Time var totalTime time.Duration var timeSpent time.Duration -var allGames []repository.Soundtrack -var gamesBeforeSync []repository.Soundtrack -var gamesAfterSync []repository.Soundtrack -var gamesAdded []string -var gamesReAdded []string -var gamesChangedTitle map[string]string -var gamesChangedContent []string -var gamesRemoved []string +var allSoundtracks []repository.Soundtrack +var soundtracksBeforeSync []repository.Soundtrack +var soundtracksAfterSync []repository.Soundtrack +var soundtracksAdded []string +var soundtracksReAdded []string +var soundtracksChangedTitle map[string]string +var soundtracksChangedContent []string +var soundtracksRemoved []string var catchedErrors []string type brokenSong struct { @@ -50,13 +50,13 @@ var pool *ants.Pool var poolSong *ants.Pool type SyncResponse struct { - GamesAdded []string `json:"games_added"` - GamesReAdded []string `json:"games_re_added"` - GamesChangedTitle map[string]string `json:"games_changed_title"` - GamesChangedContent []string `json:"games_changed_content"` - GamesRemoved []string `json:"games_removed"` - CatchedErrors []string `json:"catched_errors"` - TotalTime string `json:"total_time"` + SoundtracksAdded []string `json:"soundtracks_added"` + SoundtracksReAdded []string `json:"soundtracks_re_added"` + SoundtracksChangedTitle map[string]string `json:"soundtracks_changed_title"` + SoundtracksChangedContent []string `json:"soundtracks_changed_content"` + SoundtracksRemoved []string `json:"soundtracks_removed"` + CatchedErrors []string `json:"catched_errors"` + TotalTime string `json:"total_time"` } type ProgressResponse struct { @@ -64,24 +64,24 @@ type ProgressResponse struct { TimeSpent string `json:"time_spent"` } -type GameStatus int +type SoundtrackStatus int const ( - NotChanged GameStatus = iota + NotChanged SoundtrackStatus = iota TitleChanged - GameChanged - NewGame + SoundtrackChanged + NewSoundtrack ) -var statusName = map[GameStatus]string{ - NotChanged: "Not changed", - TitleChanged: "Title changed", - GameChanged: "Game changed", - NewGame: "New game", +var statusName = map[SoundtrackStatus]string{ + NotChanged: "Not changed", + TitleChanged: "Title changed", + SoundtrackChanged: "Soundtrack changed", + NewSoundtrack: "New soundtrack", } -func (gs GameStatus) String() string { - return statusName[gs] +func (ss SoundtrackStatus) String() string { + return statusName[ss] } func ResetDB() { @@ -107,54 +107,54 @@ func SyncProgress() ProgressResponse { func SyncResult() SyncResponse { logging.GetLogger().Info("Sync completed", - zap.Int("games_before", len(gamesBeforeSync)), - zap.Int("games_after", len(gamesAfterSync))) + zap.Int("soundtracks_before", len(soundtracksBeforeSync)), + zap.Int("soundtracks_after", len(soundtracksAfterSync))) - if len(gamesAdded) > 0 { - logging.GetLogger().Debug("Games added", zap.Strings("games", gamesAdded)) + if len(soundtracksAdded) > 0 { + logging.GetLogger().Debug("Soundtracks added", zap.Strings("soundtracks", soundtracksAdded)) } - if len(gamesReAdded) > 0 { - logging.GetLogger().Debug("Games readded", zap.Strings("games", gamesReAdded)) + if len(soundtracksReAdded) > 0 { + logging.GetLogger().Debug("Soundtracks readded", zap.Strings("soundtracks", soundtracksReAdded)) } - if len(gamesChangedTitle) > 0 { - logging.GetLogger().Debug("Games with changed title", zap.Any("changes", gamesChangedTitle)) + if len(soundtracksChangedTitle) > 0 { + logging.GetLogger().Debug("Soundtracks with changed title", zap.Any("changes", soundtracksChangedTitle)) } - if len(gamesChangedContent) > 0 { - logging.GetLogger().Debug("Games with changed content", zap.Strings("games", gamesChangedContent)) + if len(soundtracksChangedContent) > 0 { + logging.GetLogger().Debug("Soundtracks with changed content", zap.Strings("soundtracks", soundtracksChangedContent)) } - var gamesRemovedTemp []string - for _, beforeGame := range gamesBeforeSync { + var soundtracksRemovedTemp []string + for _, beforeSoundtrack := range soundtracksBeforeSync { var found = false - for _, afterGame := range gamesAfterSync { - if beforeGame.SoundtrackName == afterGame.SoundtrackName { + for _, afterSoundtrack := range soundtracksAfterSync { + if beforeSoundtrack.SoundtrackName == afterSoundtrack.SoundtrackName { found = true break } } if !found { - gamesRemovedTemp = append(gamesRemovedTemp, beforeGame.SoundtrackName) + soundtracksRemovedTemp = append(soundtracksRemovedTemp, beforeSoundtrack.SoundtrackName) } } - for _, game := range gamesRemovedTemp { + for _, soundtrack := range soundtracksRemovedTemp { var found bool = false - for key := range gamesChangedTitle { - if game == key { + for key := range soundtracksChangedTitle { + if soundtrack == key { found = true break } } if !found { - gamesRemoved = append(gamesRemoved, game) + soundtracksRemoved = append(soundtracksRemoved, soundtrack) } } - if len(gamesRemoved) > 0 { - logging.GetLogger().Debug("Games removed", zap.Strings("games", gamesRemoved)) + if len(soundtracksRemoved) > 0 { + logging.GetLogger().Debug("Soundtracks removed", zap.Strings("soundtracks", soundtracksRemoved)) } if len(catchedErrors) > 0 { @@ -165,27 +165,27 @@ func SyncResult() SyncResponse { logging.GetLogger().Info("Sync completed", zap.String("total_time", out.Format("15:04:05.00000"))) return SyncResponse{ - GamesAdded: gamesAdded, - GamesReAdded: gamesReAdded, - GamesChangedTitle: gamesChangedTitle, - GamesChangedContent: gamesChangedContent, - GamesRemoved: gamesRemoved, - CatchedErrors: catchedErrors, - TotalTime: out.Format("15:04:05"), + SoundtracksAdded: soundtracksAdded, + SoundtracksReAdded: soundtracksReAdded, + SoundtracksChangedTitle: soundtracksChangedTitle, + SoundtracksChangedContent: soundtracksChangedContent, + SoundtracksRemoved: soundtracksRemoved, + CatchedErrors: catchedErrors, + TotalTime: out.Format("15:04:05"), } } func SyncSoundtracksNewFull() { - syncGamesNew(true) + syncSoundtracksNew(true) Reset() } func SyncSoundtracksNewOnlyChanges() { - syncGamesNew(false) + syncSoundtracksNew(false) Reset() } -func syncGamesNew(full bool) { +func syncSoundtracksNew(full bool) { musicPath := os.Getenv("MUSIC_PATH") fmt.Printf("dir: %s\n", musicPath) logging.GetLogger().Debug("Folder to sync", zap.String("MUSIC_PATH", musicPath)) @@ -201,19 +201,19 @@ func syncGamesNew(full bool) { logging.GetLogger().Debug("Folders to skip during sync", zap.Strings("folders", foldersToSkip)) var err error - gamesAdded = nil - gamesReAdded = nil - gamesChangedTitle = nil - gamesChangedContent = nil - gamesRemoved = nil + soundtracksAdded = nil + soundtracksReAdded = nil + soundtracksChangedTitle = nil + soundtracksChangedContent = nil + soundtracksRemoved = nil catchedErrors = nil brokenSongs = nil - gamesBeforeSync, err = repo.FindAllSoundtracks(BackendCtx()) + soundtracksBeforeSync, err = repo.FindAllSoundtracks(BackendCtx()) handleError("FindAllSoundtracks Before", err, "") - logging.GetLogger().Info("Starting sync", zap.Int("games_before", len(gamesBeforeSync))) + logging.GetLogger().Info("Starting sync", zap.Int("soundtracks_before", len(soundtracksBeforeSync))) - allGames, err = repo.GetAllSoundtracksIncludingDeleted(BackendCtx()) + allSoundtracks, err = repo.GetAllSoundtracksIncludingDeleted(BackendCtx()) handleError("GetAllSoundtracksIncludingDeleted", err, "") err = repo.SetSoundtrackDeletionDate(BackendCtx()) handleError("SetSoundtrackDeletionDate", err, "") @@ -233,13 +233,13 @@ func syncGamesNew(full bool) { for _, dir := range directories { pool.Submit(func() { defer syncWg.Done() - syncGameNew(dir, foldersToSkip, musicPath, full) + syncSoundtrackNew(dir, foldersToSkip, musicPath, full) }) } syncWg.Wait() checkBrokenSongsNew() - gamesAfterSync, err = repo.FindAllSoundtracks(BackendCtx()) + soundtracksAfterSync, err = repo.FindAllSoundtracks(BackendCtx()) handleError("FindAllSoundtracks After", err, "") finished := time.Now() @@ -286,48 +286,48 @@ func checkBrokenSongNew(song repository.Song) { } } -func syncGameNew(file os.DirEntry, foldersToSkip []string, baseDir string, full bool) { +func syncSoundtrackNew(file os.DirEntry, foldersToSkip []string, baseDir string, full bool) { if file.IsDir() && !contains(foldersToSkip, file.Name()) { - logging.GetLogger().Debug("Syncing game", zap.String("game", file.Name())) - gameDir := baseDir + file.Name() + "/" - dirHash := getHashForDir(gameDir) + logging.GetLogger().Debug("Syncing soundtrack", zap.String("soundtrack", file.Name())) + soundtrackDir := baseDir + file.Name() + "/" + dirHash := getHashForDir(soundtrackDir) - var status GameStatus = NewGame - var oldGame repository.Soundtrack + var status SoundtrackStatus = NewSoundtrack + var oldSoundtrack repository.Soundtrack var id int32 = -1 - //fmt.Printf("Games before: %d\n", len(gamesBeforeSync)) + //fmt.Printf("Soundtracks before: %d\n", len(soundtracksBeforeSync)) - for _, currentGame := range allGames { - oldGame = currentGame - //fmt.Printf("%s | %s\n", oldGame.SoundtrackName, oldGame.Hash) - if oldGame.SoundtrackName == file.Name() && oldGame.Hash == dirHash { + for _, currentSoundtrack := range allSoundtracks { + oldSoundtrack = currentSoundtrack + //fmt.Printf("%s | %s\n", oldSoundtrack.SoundtrackName, oldSoundtrack.Hash) + if oldSoundtrack.SoundtrackName == file.Name() && oldSoundtrack.Hash == dirHash { status = NotChanged - id = oldGame.ID - //fmt.Printf("Game not changed\n") + id = oldSoundtrack.ID + //fmt.Printf("Soundtrack not changed\n") break - } else if oldGame.SoundtrackName == file.Name() && oldGame.Hash != dirHash { - status = GameChanged - id = oldGame.ID - //fmt.Printf("Game changed\n") + } else if oldSoundtrack.SoundtrackName == file.Name() && oldSoundtrack.Hash != dirHash { + status = SoundtrackChanged + id = oldSoundtrack.ID + //fmt.Printf("Soundtrack changed\n") break - } else if oldGame.SoundtrackName != file.Name() && oldGame.Hash == dirHash { + } else if oldSoundtrack.SoundtrackName != file.Name() && oldSoundtrack.Hash == dirHash { status = TitleChanged - id = oldGame.ID + id = oldSoundtrack.ID //fmt.Printf("SoundtrackName changed\n") break } } - if full && status != NewGame { + if full && status != NewSoundtrack { status = TitleChanged } - entries, err := os.ReadDir(gameDir) + entries, err := os.ReadDir(soundtrackDir) if err != nil { - logging.GetLogger().Error("Failed to read game directory", zap.String("path", gameDir), zap.String("error", err.Error())) + logging.GetLogger().Error("Failed to read soundtrack directory", zap.String("path", soundtrackDir), zap.String("error", err.Error())) } switch status { - case NewGame: + case NewSoundtrack: if id != -1 { for _, entry := range entries { fileInfo, err := entry.Info() @@ -340,13 +340,13 @@ func syncGameNew(file os.DirEntry, foldersToSkip []string, baseDir string, full break } } - err = repo.InsertSoundtrackWithExistingId(BackendCtx(), repository.InsertSoundtrackWithExistingIdParams{ID: id, SoundtrackName: file.Name(), Path: gameDir, Hash: dirHash}) + err = repo.InsertSoundtrackWithExistingId(BackendCtx(), repository.InsertSoundtrackWithExistingIdParams{ID: id, SoundtrackName: file.Name(), Path: soundtrackDir, Hash: dirHash}) handleError("InsertSoundtrackWithExistingId", err, "") if err != nil { - logging.GetLogger().Debug("Game already exists, removing old ID file", + logging.GetLogger().Debug("Soundtrack already exists, removing old ID file", zap.Int32("id", id), - zap.String("game_dir", gameDir)) - fileName := gameDir + "/." + strconv.Itoa(int(id)) + ".id" + zap.String("soundtrack_dir", soundtrackDir)) + fileName := soundtrackDir + "/." + strconv.Itoa(int(id)) + ".id" logging.GetLogger().Debug("Removing ID file", zap.String("filename", fileName)) err := os.Remove(fileName) @@ -354,50 +354,50 @@ func syncGameNew(file os.DirEntry, foldersToSkip []string, baseDir string, full logging.GetLogger().Error("Failed to remove ID file", zap.String("filename", fileName), zap.String("error", err.Error())) } - newDirHash := getHashForDir(gameDir) + newDirHash := getHashForDir(soundtrackDir) - id = insertGameNew(file.Name(), gameDir, newDirHash) + id = insertSoundtrackNew(file.Name(), soundtrackDir, newDirHash) } } else { - id = insertGameNew(file.Name(), gameDir, dirHash) + id = insertSoundtrackNew(file.Name(), soundtrackDir, dirHash) } - logging.GetLogger().Debug("New game detected", + logging.GetLogger().Debug("New soundtrack detected", zap.Int32("id", id), - zap.String("game", file.Name()), + zap.String("soundtrack", file.Name()), zap.String("hash", dirHash), zap.String("status", status.String())) - gamesAdded = append(gamesAdded, file.Name()) - newCheckSongs(entries, gameDir, id) - case GameChanged: - logging.GetLogger().Debug("Game changed", + soundtracksAdded = append(soundtracksAdded, file.Name()) + newCheckSongs(entries, soundtrackDir, id) + case SoundtrackChanged: + logging.GetLogger().Debug("Soundtrack changed", zap.Int32("id", id), - zap.String("game", file.Name()), + zap.String("soundtrack", file.Name()), zap.String("hash", dirHash), zap.String("status", status.String())) err = repo.UpdateSoundtrackHash(BackendCtx(), repository.UpdateSoundtrackHashParams{Hash: dirHash, ID: id}) handleError("UpdateSoundtrackHash", err, "") - gamesChangedContent = append(gamesChangedContent, file.Name()) - newCheckSongs(entries, gameDir, id) + soundtracksChangedContent = append(soundtracksChangedContent, file.Name()) + newCheckSongs(entries, soundtrackDir, id) case TitleChanged: - logging.GetLogger().Debug("Game title changed", + logging.GetLogger().Debug("Soundtrack title changed", zap.Int32("id", id), - zap.String("oldName", oldGame.SoundtrackName), + zap.String("oldName", oldSoundtrack.SoundtrackName), zap.String("newName", file.Name()), zap.String("hash", dirHash), zap.String("status", status.String())) - err = repo.UpdateSoundtrackName(BackendCtx(), repository.UpdateSoundtrackNameParams{Name: file.Name(), Path: gameDir, ID: id}) + err = repo.UpdateSoundtrackName(BackendCtx(), repository.UpdateSoundtrackNameParams{Name: file.Name(), Path: soundtrackDir, ID: id}) handleError("UpdateSoundtrackName", err, "") - newCheckSongs(entries, gameDir, id) - if gamesChangedTitle == nil { - gamesChangedTitle = make(map[string]string) + newCheckSongs(entries, soundtrackDir, id) + if soundtracksChangedTitle == nil { + soundtracksChangedTitle = make(map[string]string) } - gamesChangedTitle[oldGame.SoundtrackName] = file.Name() + soundtracksChangedTitle[oldSoundtrack.SoundtrackName] = file.Name() case NotChanged: var found bool = false - for _, beforeGame := range gamesBeforeSync { - if dirHash == beforeGame.Hash { + for _, beforeSoundtrack := range soundtracksBeforeSync { + if dirHash == beforeSoundtrack.Hash { found = true - logging.GetLogger().Debug("Game not changed", + logging.GetLogger().Debug("Soundtrack not changed", zap.Int32("id", id), zap.String("newName", file.Name()), zap.String("hash", dirHash), @@ -405,9 +405,9 @@ func syncGameNew(file os.DirEntry, foldersToSkip []string, baseDir string, full } } if !found { - newCheckSongs(entries, gameDir, id) - gamesReAdded = append(gamesReAdded, file.Name()) - logging.GetLogger().Debug("Game added again", + newCheckSongs(entries, soundtrackDir, id) + soundtracksReAdded = append(soundtracksReAdded, file.Name()) + logging.GetLogger().Debug("Soundtrack added again", zap.Int32("id", id), zap.String("newName", file.Name()), zap.String("hash", dirHash), @@ -415,9 +415,9 @@ func syncGameNew(file os.DirEntry, foldersToSkip []string, baseDir string, full } } - logging.GetLogger().Debug("Game sync status", + logging.GetLogger().Debug("Soundtrack sync status", zap.Int32("id", id), - zap.String("game", file.Name()), + zap.String("soundtrack", file.Name()), zap.String("hash", dirHash), zap.String("status", status.String())) err = repo.RemoveSoundtrackDeletionDate(BackendCtx(), id) @@ -430,24 +430,24 @@ func syncGameNew(file os.DirEntry, foldersToSkip []string, baseDir string, full zap.Int("percent", int((foldersSynced/numberOfFoldersToSync)*100))) } -func insertGameNew(name string, path string, hash string) int32 { +func insertSoundtrackNew(name string, path string, hash string) int32 { var duplicateError = errors.New("ERROR: duplicate key value violates unique") id, err := repo.InsertSoundtrack(BackendCtx(), repository.InsertSoundtrackParams{SoundtrackName: name, Path: path, Hash: hash}) handleError("InsertSoundtrack", err, "") if err != nil { logging.GetLogger().Warn("ID collision detected, resetting sequence") if strings.HasPrefix(err.Error(), duplicateError.Error()) { - logging.GetLogger().Debug("Resetting game ID sequence") + logging.GetLogger().Debug("Resetting soundtrack ID sequence") _, err = repo.ResetSoundtrackIdSeq(BackendCtx()) handleError("ResetSoundtrackIdSeq", err, "") - id = insertGameNew(name, path, hash) + id = insertSoundtrackNew(name, path, hash) } } return id } -func newCheckSongs(entries []os.DirEntry, gameDir string, id int32) int32 { +func newCheckSongs(entries []os.DirEntry, soundtrackDir string, id int32) int32 { //hasher := md5.New() var numberOfSongs int32 numberOfFiles := len(entries) @@ -457,7 +457,7 @@ func newCheckSongs(entries []os.DirEntry, gameDir string, id int32) int32 { for _, entry := range entries { poolSong.Submit(func() { defer songWg.Done() - if newCheckSong(entry, gameDir, id) { + if newCheckSong(entry, soundtrackDir, id) { numberOfSongs++ } }) @@ -466,7 +466,7 @@ func newCheckSongs(entries []os.DirEntry, gameDir string, id int32) int32 { return numberOfSongs } -func newCheckSong(entry os.DirEntry, gameDir string, id int32) bool { +func newCheckSong(entry os.DirEntry, soundtrackDir string, id int32) bool { fileInfo, err := entry.Info() if err != nil { logging.GetLogger().Error("Failed to get file info", zap.String("filename", entry.Name()), zap.String("error", err.Error())) @@ -474,7 +474,7 @@ func newCheckSong(entry os.DirEntry, gameDir string, id int32) bool { } if isSong(fileInfo) { - path := gameDir + entry.Name() + path := soundtrackDir + entry.Name() songHash := getHashForFile(path) //numberOfSongs++ @@ -490,7 +490,7 @@ func newCheckSong(entry os.DirEntry, gameDir string, id int32) bool { } } logging.GetLogger().Debug("Song changed", - zap.Int32("game_id", id), + zap.Int32("soundtrack_id", id), zap.String("path", path), zap.String("song_name", songName), zap.String("song_hash", songHash)) @@ -548,8 +548,8 @@ func handleError(funcName string, err error, msg string) { } } -func getHashForDir(gameDir string) string { - directory, _ := directory_checksum.ScanDirectory(gameDir, afero.NewOsFs()) +func getHashForDir(soundtrackDir string) string { + directory, _ := directory_checksum.ScanDirectory(soundtrackDir, afero.NewOsFs()) hash, _ := directory.ComputeDirectoryChecksums() return hash diff --git a/internal/db/dbHelper.go b/internal/db/dbHelper.go index e87877f..bc2e25c 100644 --- a/internal/db/dbHelper.go +++ b/internal/db/dbHelper.go @@ -56,10 +56,10 @@ func CloseDb() { Dbpool.Close() } -func ResetGameIdSeq() { - _, err := Dbpool.Query(Ctx, "SELECT setval('game_id_seq', (SELECT MAX(id) FROM game)+1);") +func ResetSoundtrackIdSeq() { + _, err := Dbpool.Query(Ctx, "SELECT setval('soundtrack_id_seq', (SELECT MAX(id) FROM soundtrack)+1);") if err != nil { - logging.GetLogger().Error("Failed to reset game ID sequence", zap.String("error", err.Error())) + logging.GetLogger().Error("Failed to reset soundtrack ID sequence", zap.String("error", err.Error())) } } diff --git a/internal/db/queries/statistics.sql b/internal/db/queries/statistics.sql index f7204c4..a5bfc7a 100644 --- a/internal/db/queries/statistics.sql +++ b/internal/db/queries/statistics.sql @@ -1,5 +1,5 @@ -- Most played soundtracks with their songs --- name: GetMostPlayedGamesWithSongs :many +-- name: GetMostPlayedSoundtracksWithSongs :many SELECT g.id as soundtrack_id, g.soundtrack_name, @@ -21,7 +21,7 @@ ORDER BY g.times_played DESC, g.soundtrack_name LIMIT $1; -- Least played soundtracks with their songs --- name: GetLeastPlayedGamesWithSongs :many +-- name: GetLeastPlayedSoundtracksWithSongs :many SELECT g.id as soundtrack_id, g.soundtrack_name, @@ -43,7 +43,7 @@ ORDER BY g.times_played ASC, g.soundtrack_name LIMIT $1; -- Most played songs with their soundtrack info --- name: GetMostPlayedSongsWithGame :many +-- name: GetMostPlayedSongsWithSoundtrack :many SELECT s.soundtrack_id as soundtrack_id, g.soundtrack_name, @@ -58,7 +58,7 @@ ORDER BY s.times_played DESC, s.song_name LIMIT $1; -- Least played songs with their soundtrack info --- name: GetLeastPlayedSongsWithGame :many +-- name: GetLeastPlayedSongsWithSoundtrack :many SELECT s.soundtrack_id as soundtrack_id, g.soundtrack_name, @@ -72,8 +72,8 @@ WHERE g.deleted IS NULL ORDER BY s.times_played ASC, s.song_name LIMIT $1; --- Games that have never been played (times_played = 0) --- name: GetNeverPlayedGames :many +-- Soundtracks that have never been played (times_played = 0) +-- name: GetNeverPlayedSoundtracks :many SELECT g.id as soundtrack_id, g.soundtrack_name, @@ -93,7 +93,7 @@ GROUP BY g.id, g.soundtrack_name, g.times_played, g.added ORDER BY g.soundtrack_name; -- Last played soundtracks (most recently played) --- name: GetLastPlayedGames :many +-- name: GetLastPlayedSoundtracks :many SELECT g.id as soundtrack_id, g.soundtrack_name, @@ -114,7 +114,7 @@ ORDER BY g.last_played DESC LIMIT $1; -- Oldest played soundtracks (least recently played, but has been played at least once) --- name: GetOldestPlayedGames :many +-- name: GetOldestPlayedSoundtracks :many SELECT g.id as soundtrack_id, g.soundtrack_name, diff --git a/internal/db/repository/statistics.sql.go b/internal/db/repository/statistics.sql.go index a29da58..603dd01 100644 --- a/internal/db/repository/statistics.sql.go +++ b/internal/db/repository/statistics.sql.go @@ -10,7 +10,7 @@ import ( "time" ) -const getLastPlayedGames = `-- name: GetLastPlayedGames :many +const getLastPlayedSoundtracks = `-- name: GetLastPlayedSoundtracks :many SELECT g.id as soundtrack_id, g.soundtrack_name, @@ -31,7 +31,7 @@ ORDER BY g.last_played DESC LIMIT $1 ` -type GetLastPlayedGamesRow struct { +type GetLastPlayedSoundtracksRow struct { SoundtrackID int32 `json:"soundtrack_id"` SoundtrackName string `json:"soundtrack_name"` SoundtrackPlayed int32 `json:"soundtrack_played"` @@ -40,15 +40,15 @@ type GetLastPlayedGamesRow struct { } // Last played soundtracks (most recently played) -func (q *Queries) GetLastPlayedGames(ctx context.Context, limit int32) ([]GetLastPlayedGamesRow, error) { - rows, err := q.db.Query(ctx, getLastPlayedGames, limit) +func (q *Queries) GetLastPlayedSoundtracks(ctx context.Context, limit int32) ([]GetLastPlayedSoundtracksRow, error) { + rows, err := q.db.Query(ctx, getLastPlayedSoundtracks, limit) if err != nil { return nil, err } defer rows.Close() - var items []GetLastPlayedGamesRow + var items []GetLastPlayedSoundtracksRow for rows.Next() { - var i GetLastPlayedGamesRow + var i GetLastPlayedSoundtracksRow if err := rows.Scan( &i.SoundtrackID, &i.SoundtrackName, @@ -66,7 +66,7 @@ func (q *Queries) GetLastPlayedGames(ctx context.Context, limit int32) ([]GetLas return items, nil } -const getLeastPlayedGamesWithSongs = `-- name: GetLeastPlayedGamesWithSongs :many +const getLeastPlayedSoundtracksWithSongs = `-- name: GetLeastPlayedSoundtracksWithSongs :many SELECT g.id as soundtrack_id, g.soundtrack_name, @@ -88,7 +88,7 @@ ORDER BY g.times_played ASC, g.soundtrack_name LIMIT $1 ` -type GetLeastPlayedGamesWithSongsRow struct { +type GetLeastPlayedSoundtracksWithSongsRow struct { SoundtrackID int32 `json:"soundtrack_id"` SoundtrackName string `json:"soundtrack_name"` SoundtrackPlayed int32 `json:"soundtrack_played"` @@ -97,15 +97,15 @@ type GetLeastPlayedGamesWithSongsRow struct { } // Least played soundtracks with their songs -func (q *Queries) GetLeastPlayedGamesWithSongs(ctx context.Context, limit int32) ([]GetLeastPlayedGamesWithSongsRow, error) { - rows, err := q.db.Query(ctx, getLeastPlayedGamesWithSongs, limit) +func (q *Queries) GetLeastPlayedSoundtracksWithSongs(ctx context.Context, limit int32) ([]GetLeastPlayedSoundtracksWithSongsRow, error) { + rows, err := q.db.Query(ctx, getLeastPlayedSoundtracksWithSongs, limit) if err != nil { return nil, err } defer rows.Close() - var items []GetLeastPlayedGamesWithSongsRow + var items []GetLeastPlayedSoundtracksWithSongsRow for rows.Next() { - var i GetLeastPlayedGamesWithSongsRow + var i GetLeastPlayedSoundtracksWithSongsRow if err := rows.Scan( &i.SoundtrackID, &i.SoundtrackName, @@ -123,7 +123,7 @@ func (q *Queries) GetLeastPlayedGamesWithSongs(ctx context.Context, limit int32) return items, nil } -const getLeastPlayedSongsWithGame = `-- name: GetLeastPlayedSongsWithGame :many +const getLeastPlayedSongsWithSoundtrack = `-- name: GetLeastPlayedSongsWithSoundtrack :many SELECT s.soundtrack_id as soundtrack_id, g.soundtrack_name, @@ -138,7 +138,7 @@ ORDER BY s.times_played ASC, s.song_name LIMIT $1 ` -type GetLeastPlayedSongsWithGameRow struct { +type GetLeastPlayedSongsWithSoundtrackRow struct { SoundtrackID int32 `json:"soundtrack_id"` SoundtrackName string `json:"soundtrack_name"` SongName string `json:"song_name"` @@ -148,15 +148,15 @@ type GetLeastPlayedSongsWithGameRow struct { } // Least played songs with their soundtrack info -func (q *Queries) GetLeastPlayedSongsWithGame(ctx context.Context, limit int32) ([]GetLeastPlayedSongsWithGameRow, error) { - rows, err := q.db.Query(ctx, getLeastPlayedSongsWithGame, limit) +func (q *Queries) GetLeastPlayedSongsWithSoundtrack(ctx context.Context, limit int32) ([]GetLeastPlayedSongsWithSoundtrackRow, error) { + rows, err := q.db.Query(ctx, getLeastPlayedSongsWithSoundtrack, limit) if err != nil { return nil, err } defer rows.Close() - var items []GetLeastPlayedSongsWithGameRow + var items []GetLeastPlayedSongsWithSoundtrackRow for rows.Next() { - var i GetLeastPlayedSongsWithGameRow + var i GetLeastPlayedSongsWithSoundtrackRow if err := rows.Scan( &i.SoundtrackID, &i.SoundtrackName, @@ -175,7 +175,7 @@ func (q *Queries) GetLeastPlayedSongsWithGame(ctx context.Context, limit int32) return items, nil } -const getMostPlayedGamesWithSongs = `-- name: GetMostPlayedGamesWithSongs :many +const getMostPlayedSoundtracksWithSongs = `-- name: GetMostPlayedSoundtracksWithSongs :many SELECT g.id as soundtrack_id, g.soundtrack_name, @@ -197,7 +197,7 @@ ORDER BY g.times_played DESC, g.soundtrack_name LIMIT $1 ` -type GetMostPlayedGamesWithSongsRow struct { +type GetMostPlayedSoundtracksWithSongsRow struct { SoundtrackID int32 `json:"soundtrack_id"` SoundtrackName string `json:"soundtrack_name"` SoundtrackPlayed int32 `json:"soundtrack_played"` @@ -206,15 +206,15 @@ type GetMostPlayedGamesWithSongsRow struct { } // Most played soundtracks with their songs -func (q *Queries) GetMostPlayedGamesWithSongs(ctx context.Context, limit int32) ([]GetMostPlayedGamesWithSongsRow, error) { - rows, err := q.db.Query(ctx, getMostPlayedGamesWithSongs, limit) +func (q *Queries) GetMostPlayedSoundtracksWithSongs(ctx context.Context, limit int32) ([]GetMostPlayedSoundtracksWithSongsRow, error) { + rows, err := q.db.Query(ctx, getMostPlayedSoundtracksWithSongs, limit) if err != nil { return nil, err } defer rows.Close() - var items []GetMostPlayedGamesWithSongsRow + var items []GetMostPlayedSoundtracksWithSongsRow for rows.Next() { - var i GetMostPlayedGamesWithSongsRow + var i GetMostPlayedSoundtracksWithSongsRow if err := rows.Scan( &i.SoundtrackID, &i.SoundtrackName, @@ -232,7 +232,7 @@ func (q *Queries) GetMostPlayedGamesWithSongs(ctx context.Context, limit int32) return items, nil } -const getMostPlayedSongsWithGame = `-- name: GetMostPlayedSongsWithGame :many +const getMostPlayedSongsWithSoundtrack = `-- name: GetMostPlayedSongsWithSoundtrack :many SELECT s.soundtrack_id as soundtrack_id, g.soundtrack_name, @@ -247,7 +247,7 @@ ORDER BY s.times_played DESC, s.song_name LIMIT $1 ` -type GetMostPlayedSongsWithGameRow struct { +type GetMostPlayedSongsWithSoundtrackRow struct { SoundtrackID int32 `json:"soundtrack_id"` SoundtrackName string `json:"soundtrack_name"` SongName string `json:"song_name"` @@ -257,15 +257,15 @@ type GetMostPlayedSongsWithGameRow struct { } // Most played songs with their soundtrack info -func (q *Queries) GetMostPlayedSongsWithGame(ctx context.Context, limit int32) ([]GetMostPlayedSongsWithGameRow, error) { - rows, err := q.db.Query(ctx, getMostPlayedSongsWithGame, limit) +func (q *Queries) GetMostPlayedSongsWithSoundtrack(ctx context.Context, limit int32) ([]GetMostPlayedSongsWithSoundtrackRow, error) { + rows, err := q.db.Query(ctx, getMostPlayedSongsWithSoundtrack, limit) if err != nil { return nil, err } defer rows.Close() - var items []GetMostPlayedSongsWithGameRow + var items []GetMostPlayedSongsWithSoundtrackRow for rows.Next() { - var i GetMostPlayedSongsWithGameRow + var i GetMostPlayedSongsWithSoundtrackRow if err := rows.Scan( &i.SoundtrackID, &i.SoundtrackName, @@ -284,7 +284,7 @@ func (q *Queries) GetMostPlayedSongsWithGame(ctx context.Context, limit int32) ( return items, nil } -const getNeverPlayedGames = `-- name: GetNeverPlayedGames :many +const getNeverPlayedSoundtracks = `-- name: GetNeverPlayedSoundtracks :many SELECT g.id as soundtrack_id, g.soundtrack_name, @@ -304,7 +304,7 @@ GROUP BY g.id, g.soundtrack_name, g.times_played, g.added ORDER BY g.soundtrack_name ` -type GetNeverPlayedGamesRow struct { +type GetNeverPlayedSoundtracksRow struct { SoundtrackID int32 `json:"soundtrack_id"` SoundtrackName string `json:"soundtrack_name"` SoundtrackPlayed int32 `json:"soundtrack_played"` @@ -312,16 +312,16 @@ type GetNeverPlayedGamesRow struct { Songs []byte `json:"songs"` } -// Games that have never been played (times_played = 0) -func (q *Queries) GetNeverPlayedGames(ctx context.Context) ([]GetNeverPlayedGamesRow, error) { - rows, err := q.db.Query(ctx, getNeverPlayedGames) +// Soundtracks that have never been played (times_played = 0) +func (q *Queries) GetNeverPlayedSoundtracks(ctx context.Context) ([]GetNeverPlayedSoundtracksRow, error) { + rows, err := q.db.Query(ctx, getNeverPlayedSoundtracks) if err != nil { return nil, err } defer rows.Close() - var items []GetNeverPlayedGamesRow + var items []GetNeverPlayedSoundtracksRow for rows.Next() { - var i GetNeverPlayedGamesRow + var i GetNeverPlayedSoundtracksRow if err := rows.Scan( &i.SoundtrackID, &i.SoundtrackName, @@ -339,7 +339,7 @@ func (q *Queries) GetNeverPlayedGames(ctx context.Context) ([]GetNeverPlayedGame return items, nil } -const getOldestPlayedGames = `-- name: GetOldestPlayedGames :many +const getOldestPlayedSoundtracks = `-- name: GetOldestPlayedSoundtracks :many SELECT g.id as soundtrack_id, g.soundtrack_name, @@ -360,7 +360,7 @@ ORDER BY g.last_played ASC LIMIT $1 ` -type GetOldestPlayedGamesRow struct { +type GetOldestPlayedSoundtracksRow struct { SoundtrackID int32 `json:"soundtrack_id"` SoundtrackName string `json:"soundtrack_name"` SoundtrackPlayed int32 `json:"soundtrack_played"` @@ -369,15 +369,15 @@ type GetOldestPlayedGamesRow struct { } // Oldest played soundtracks (least recently played, but has been played at least once) -func (q *Queries) GetOldestPlayedGames(ctx context.Context, limit int32) ([]GetOldestPlayedGamesRow, error) { - rows, err := q.db.Query(ctx, getOldestPlayedGames, limit) +func (q *Queries) GetOldestPlayedSoundtracks(ctx context.Context, limit int32) ([]GetOldestPlayedSoundtracksRow, error) { + rows, err := q.db.Query(ctx, getOldestPlayedSoundtracks, limit) if err != nil { return nil, err } defer rows.Close() - var items []GetOldestPlayedGamesRow + var items []GetOldestPlayedSoundtracksRow for rows.Next() { - var i GetOldestPlayedGamesRow + var i GetOldestPlayedSoundtracksRow if err := rows.Scan( &i.SoundtrackID, &i.SoundtrackName, diff --git a/internal/server/musicHandler.go b/internal/server/musicHandler.go index 946dab9..917e367 100644 --- a/internal/server/musicHandler.go +++ b/internal/server/musicHandler.go @@ -231,7 +231,7 @@ func (m *MusicHandler) GetPreviousSong(ctx *echo.Context) error { // GetAllSoundtracks godoc // @Summary Get all soundtracks -// @Description Returns a list of all games in order +// @Description Returns a list of all soundtracks in order // @Tags music // @Accept json // @Produce json @@ -249,7 +249,7 @@ func (m *MusicHandler) GetAllSoundtracks(ctx *echo.Context) error { // GetAllSoundtracksRandom godoc // @Summary Get all soundtracks random -// @Description Returns a list of all games in random order +// @Description Returns a list of all soundtracks in random order // @Tags music // @Accept json // @Produce json @@ -285,7 +285,7 @@ func (m *MusicHandler) PutPlayed(ctx *echo.Context) error { if err != nil { return ctx.JSON(http.StatusBadRequest, err.Error()) } - logging.GetLogger().Info("Marking song as played", zap.Int("song_id", song)) + logging.GetLogger().Info("Marking song as played", zap.Int("song_id", song)) backend.SetPlayed(song) return ctx.NoContent(http.StatusOK) } diff --git a/internal/server/routes.go b/internal/server/routes.go index 17a4f92..913485b 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -51,7 +51,7 @@ func (s *Server) RegisterRoutes() http.Handler { e.GET("/assets/*", echo.WrapHandler(fileServer)) e.GET("/search", echo.WrapHandler(templ.Handler(web.HelloForm()))) - e.POST("/find", echo.WrapHandler(http.HandlerFunc(web.FindGameWebHandler))) + e.POST("/find", echo.WrapHandler(http.HandlerFunc(web.FindSoundtrackWebHandler))) e.Static("/", "/frontend") @@ -136,20 +136,20 @@ func (s *Server) RegisterRoutes() http.Handler { // Statistics API endpoints (protected by token auth) statistics := s.statisticsHandler - protectedV1.GET("/statistics/games/most-played", func(c *echo.Context) error { - return statistics.GetMostPlayedGames(c) + protectedV1.GET("/statistics/soundtracks/most-played", func(c *echo.Context) error { + return statistics.GetMostPlayedSoundtracks(c) }) - protectedV1.GET("/statistics/games/least-played", func(c *echo.Context) error { - return statistics.GetLeastPlayedGames(c) + protectedV1.GET("/statistics/soundtracks/least-played", func(c *echo.Context) error { + return statistics.GetLeastPlayedSoundtracks(c) }) - protectedV1.GET("/statistics/games/never-played", func(c *echo.Context) error { - return statistics.GetNeverPlayedGames(c) + protectedV1.GET("/statistics/soundtracks/never-played", func(c *echo.Context) error { + return statistics.GetNeverPlayedSoundtracks(c) }) - protectedV1.GET("/statistics/games/last-played", func(c *echo.Context) error { - return statistics.GetLastPlayedGames(c) + protectedV1.GET("/statistics/soundtracks/last-played", func(c *echo.Context) error { + return statistics.GetLastPlayedSoundtracks(c) }) - protectedV1.GET("/statistics/games/oldest-played", func(c *echo.Context) error { - return statistics.GetOldestPlayedGames(c) + protectedV1.GET("/statistics/soundtracks/oldest-played", func(c *echo.Context) error { + return statistics.GetOldestPlayedSoundtracks(c) }) protectedV1.GET("/statistics/songs/most-played", func(c *echo.Context) error { return statistics.GetMostPlayedSongs(c) diff --git a/internal/server/statistics_handler.go b/internal/server/statistics_handler.go index 614d247..d413e74 100644 --- a/internal/server/statistics_handler.go +++ b/internal/server/statistics_handler.go @@ -23,20 +23,20 @@ func NewStatisticsHandler() *StatisticsHandler { } } -// GetMostPlayedGames returns top N most played games with songs -// GET /api/v1/statistics/games/most-played +// GetMostPlayedSoundtracks returns top N most played soundtracks with songs +// GET /api/v1/statistics/soundtracks/most-played // -// @Summary Get most played games -// @Description Returns the top N most played games with their songs +// @Summary Get most played soundtracks +// @Description Returns the top N most played soundtracks with their songs // @Tags statistics // @Accept json // @Produce json // @Param limit query int false "Number of results (default: 10)" -// @Success 200 {array} backend.GameWithSongs +// @Success 200 {array} backend.SoundtrackWithSongs // @Failure 400 {object} map[string]string // @Failure 500 {object} map[string]string -// @Router /api/v1/statistics/games/most-played [get] -func (h *StatisticsHandler) GetMostPlayedGames(ctx *echo.Context) error { +// @Router /api/v1/statistics/soundtracks/most-played [get] +func (h *StatisticsHandler) GetMostPlayedSoundtracks(ctx *echo.Context) error { limit := 10 // default limitStr := ctx.QueryParam("limit") if limitStr != "" { @@ -50,29 +50,29 @@ func (h *StatisticsHandler) GetMostPlayedGames(ctx *echo.Context) error { limit = 100 } } - - games, err := h.statsBackend.GetMostPlayedGamesWithSongs(int32(limit)) + + soundtracks, err := h.statsBackend.GetMostPlayedSoundtracksWithSongs(int32(limit)) if err != nil { - logging.GetLogger().Error("Failed to get most played games", zap.String("error", err.Error())) + logging.GetLogger().Error("Failed to get most played soundtracks", zap.String("error", err.Error())) return ctx.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to get statistics"}) } - return ctx.JSON(http.StatusOK, games) + return ctx.JSON(http.StatusOK, soundtracks) } -// GetLeastPlayedGames returns top N least played games with songs -// GET /api/v1/statistics/games/least-played +// GetLeastPlayedSoundtracks returns top N least played soundtracks with songs +// GET /api/v1/statistics/soundtracks/least-played // -// @Summary Get least played games -// @Description Returns the top N least played games with their songs +// @Summary Get least played soundtracks +// @Description Returns the top N least played soundtracks with their songs // @Tags statistics // @Accept json // @Produce json // @Param limit query int false "Number of results (default: 10)" -// @Success 200 {array} backend.GameWithSongs +// @Success 200 {array} backend.SoundtrackWithSongs // @Failure 400 {object} map[string]string // @Failure 500 {object} map[string]string -// @Router /api/v1/statistics/games/least-played [get] -func (h *StatisticsHandler) GetLeastPlayedGames(ctx *echo.Context) error { +// @Router /api/v1/statistics/soundtracks/least-played [get] +func (h *StatisticsHandler) GetLeastPlayedSoundtracks(ctx *echo.Context) error { limit := 10 limitStr := ctx.QueryParam("limit") if limitStr != "" { @@ -85,20 +85,20 @@ func (h *StatisticsHandler) GetLeastPlayedGames(ctx *echo.Context) error { limit = 100 } } - - games, err := h.statsBackend.GetLeastPlayedGamesWithSongs(int32(limit)) + + soundtracks, err := h.statsBackend.GetLeastPlayedSoundtracksWithSongs(int32(limit)) if err != nil { - logging.GetLogger().Error("Failed to get least played games", zap.String("error", err.Error())) + logging.GetLogger().Error("Failed to get least played soundtracks", zap.String("error", err.Error())) return ctx.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to get statistics"}) } - return ctx.JSON(http.StatusOK, games) + return ctx.JSON(http.StatusOK, soundtracks) } -// GetMostPlayedSongs returns top N most played songs with game info +// GetMostPlayedSongs returns top N most played songs with soundtrack info // GET /api/v1/statistics/songs/most-played // // @Summary Get most played songs -// @Description Returns the top N most played songs with their game info +// @Description Returns the top N most played songs with their soundtrack info // @Tags statistics // @Accept json // @Produce json @@ -120,8 +120,8 @@ func (h *StatisticsHandler) GetMostPlayedSongs(ctx *echo.Context) error { limit = 100 } } - - songs, err := h.statsBackend.GetMostPlayedSongsWithGame(int32(limit)) + + songs, err := h.statsBackend.GetMostPlayedSongsWithSoundtrack(int32(limit)) if err != nil { logging.GetLogger().Error("Failed to get most played songs", zap.String("error", err.Error())) return ctx.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to get statistics"}) @@ -129,11 +129,11 @@ func (h *StatisticsHandler) GetMostPlayedSongs(ctx *echo.Context) error { return ctx.JSON(http.StatusOK, songs) } -// GetLeastPlayedSongs returns top N least played songs with game info +// GetLeastPlayedSongs returns top N least played songs with soundtrack info // GET /api/v1/statistics/songs/least-played // // @Summary Get least played songs -// @Description Returns the top N least played songs with their game info +// @Description Returns the top N least played songs with their soundtrack info // @Tags statistics // @Accept json // @Produce json @@ -155,8 +155,8 @@ func (h *StatisticsHandler) GetLeastPlayedSongs(ctx *echo.Context) error { limit = 100 } } - - songs, err := h.statsBackend.GetLeastPlayedSongsWithGame(int32(limit)) + + songs, err := h.statsBackend.GetLeastPlayedSongsWithSoundtrack(int32(limit)) if err != nil { logging.GetLogger().Error("Failed to get least played songs", zap.String("error", err.Error())) return ctx.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to get statistics"}) @@ -164,40 +164,40 @@ func (h *StatisticsHandler) GetLeastPlayedSongs(ctx *echo.Context) error { return ctx.JSON(http.StatusOK, songs) } -// GetNeverPlayedGames returns games that have never been played -// GET /api/v1/statistics/games/never-played +// GetNeverPlayedSoundtracks returns soundtracks that have never been played +// GET /api/v1/statistics/soundtracks/never-played // -// @Summary Get never played games -// @Description Returns all games that have never been played (times_played = 0) +// @Summary Get never played soundtracks +// @Description Returns all soundtracks that have never been played (times_played = 0) // @Tags statistics // @Accept json // @Produce json -// @Success 200 {array} backend.GameWithSongs +// @Success 200 {array} backend.SoundtrackWithSongs // @Failure 500 {object} map[string]string -// @Router /api/v1/statistics/games/never-played [get] -func (h *StatisticsHandler) GetNeverPlayedGames(ctx *echo.Context) error { - games, err := h.statsBackend.GetNeverPlayedGames() +// @Router /api/v1/statistics/soundtracks/never-played [get] +func (h *StatisticsHandler) GetNeverPlayedSoundtracks(ctx *echo.Context) error { + soundtracks, err := h.statsBackend.GetNeverPlayedSoundtracks() if err != nil { - logging.GetLogger().Error("Failed to get never played games", zap.String("error", err.Error())) + logging.GetLogger().Error("Failed to get never played soundtracks", zap.String("error", err.Error())) return ctx.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to get statistics"}) } - return ctx.JSON(http.StatusOK, games) + return ctx.JSON(http.StatusOK, soundtracks) } -// GetLastPlayedGames returns most recently played games -// GET /api/v1/statistics/games/last-played +// GetLastPlayedSoundtracks returns most recently played soundtracks +// GET /api/v1/statistics/soundtracks/last-played // -// @Summary Get last played games -// @Description Returns the most recently played games +// @Summary Get last played soundtracks +// @Description Returns the most recently played soundtracks // @Tags statistics // @Accept json // @Produce json // @Param limit query int false "Number of results (default: 10)" -// @Success 200 {array} backend.GameWithSongs +// @Success 200 {array} backend.SoundtrackWithSongs // @Failure 400 {object} map[string]string // @Failure 500 {object} map[string]string -// @Router /api/v1/statistics/games/last-played [get] -func (h *StatisticsHandler) GetLastPlayedGames(ctx *echo.Context) error { +// @Router /api/v1/statistics/soundtracks/last-played [get] +func (h *StatisticsHandler) GetLastPlayedSoundtracks(ctx *echo.Context) error { limit := 10 limitStr := ctx.QueryParam("limit") if limitStr != "" { @@ -210,29 +210,29 @@ func (h *StatisticsHandler) GetLastPlayedGames(ctx *echo.Context) error { limit = 100 } } - - games, err := h.statsBackend.GetLastPlayedGames(int32(limit)) + + soundtracks, err := h.statsBackend.GetLastPlayedSoundtracks(int32(limit)) if err != nil { - logging.GetLogger().Error("Failed to get last played games", zap.String("error", err.Error())) + logging.GetLogger().Error("Failed to get last played soundtracks", zap.String("error", err.Error())) return ctx.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to get statistics"}) } - return ctx.JSON(http.StatusOK, games) + return ctx.JSON(http.StatusOK, soundtracks) } -// GetOldestPlayedGames returns least recently played games -// GET /api/v1/statistics/games/oldest-played +// GetOldestPlayedSoundtracks returns least recently played soundtracks +// GET /api/v1/statistics/soundtracks/oldest-played // -// @Summary Get oldest played games -// @Description Returns the least recently played games (that have been played at least once) +// @Summary Get oldest played soundtracks +// @Description Returns the least recently played soundtracks (that have been played at least once) // @Tags statistics // @Accept json // @Produce json // @Param limit query int false "Number of results (default: 10)" -// @Success 200 {array} backend.GameWithSongs +// @Success 200 {array} backend.SoundtrackWithSongs // @Failure 400 {object} map[string]string // @Failure 500 {object} map[string]string -// @Router /api/v1/statistics/games/oldest-played [get] -func (h *StatisticsHandler) GetOldestPlayedGames(ctx *echo.Context) error { +// @Router /api/v1/statistics/soundtracks/oldest-played [get] +func (h *StatisticsHandler) GetOldestPlayedSoundtracks(ctx *echo.Context) error { limit := 10 limitStr := ctx.QueryParam("limit") if limitStr != "" { @@ -245,13 +245,13 @@ func (h *StatisticsHandler) GetOldestPlayedGames(ctx *echo.Context) error { limit = 100 } } - - games, err := h.statsBackend.GetOldestPlayedGames(int32(limit)) + + soundtracks, err := h.statsBackend.GetOldestPlayedSoundtracks(int32(limit)) if err != nil { - logging.GetLogger().Error("Failed to get oldest played games", zap.String("error", err.Error())) + logging.GetLogger().Error("Failed to get oldest played soundtracks", zap.String("error", err.Error())) return ctx.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to get statistics"}) } - return ctx.JSON(http.StatusOK, games) + return ctx.JSON(http.StatusOK, soundtracks) } // GetStatisticsSummary returns overall statistics diff --git a/internal/server/statistics_handler_test.go b/internal/server/statistics_handler_test.go index 3a663c0..966ae9b 100644 --- a/internal/server/statistics_handler_test.go +++ b/internal/server/statistics_handler_test.go @@ -91,8 +91,8 @@ func TestPartialMigrationThenSyncThenComplete(t *testing.T) { require.NoError(t, err) // After sync with /sync/new, only soundtracks matching filesystem remain - // testMusic has 3 games - require.Equal(t, int64(3), summary.TotalGames) + // testMusic has 3 soundtracks + require.Equal(t, int64(3), summary.TotalSoundtracks) } // insertTestData inserts 5 test soundtracks with songs into the database diff --git a/internal/server/syncHandler.go b/internal/server/syncHandler.go index 4ee7ce4..497f0e9 100644 --- a/internal/server/syncHandler.go +++ b/internal/server/syncHandler.go @@ -36,7 +36,7 @@ func (s *SyncHandler) SyncProgress(ctx *echo.Context) error { // SyncSoundtracksNewOnlyChanges godoc // @Summary Sync soundtracks with only changes -// @Description Starts syncing games with only new changes +// @Description Starts syncing soundtracks with only new changes // @Tags sync // @Accept json // @Produce json @@ -55,8 +55,8 @@ func (s *SyncHandler) SyncSoundtracksNewOnlyChanges(ctx *echo.Context) error { } // SyncSoundtracksNewFull godoc -// @Summary Sync all games fully -// @Description Starts a full sync of all games +// @Summary Sync all soundtracks fully +// @Description Starts a full sync of all soundtracks // @Tags sync // @Accept json // @Produce json @@ -76,7 +76,7 @@ func (s *SyncHandler) SyncSoundtracksNewFull(ctx *echo.Context) error { // ResetDB godoc // @Summary Reset soundtracks database -// @Description Resets the games database by deleting all games and songs +// @Description Resets the soundtracks database by deleting all soundtracks and songs // @Tags sync // @Accept json // @Produce json diff --git a/internal/server/sync_handler_test.go b/internal/server/sync_handler_test.go index 561182d..fd4b83b 100644 --- a/internal/server/sync_handler_test.go +++ b/internal/server/sync_handler_test.go @@ -28,7 +28,7 @@ func waitForSyncCompletion(t *testing.T, e *echo.Echo, maxAttempts int) bool { if err == nil && progress.Progress != "" { // Successfully parsed as ProgressResponse with non-empty progress t.Logf("Sync progress: %s%%", progress.Progress) - if progress.Progress == "100" { + if progress.Progress == "100" { t.Log("Sync completed!") // Wait for Syncing flag to be updated for j := 0; j < 50; j++ { @@ -61,7 +61,7 @@ func waitForSyncCompletion(t *testing.T, e *echo.Echo, maxAttempts int) bool { return false } -// TestSyncPopulatesDatabase verifies that sync populates the database with games +// TestSyncPopulatesDatabase verifies that sync populates the database with soundtracks func TestSyncPopulatesDatabase(t *testing.T) { db.TestSetupDB(t) defer db.TestTearDownDB(t) @@ -74,12 +74,12 @@ func TestSyncPopulatesDatabase(t *testing.T) { // Clear any existing data first db.TestClearDatabase(t) - // Before sync - should have no games + // Before sync - should have no soundtracks repo := repository.New(backend.BackendPool()) - gamesBefore, err := repo.FindAllSoundtracks(backend.BackendCtx()) + soundtracksBefore, err := repo.FindAllSoundtracks(backend.BackendCtx()) assert.NoError(t, err) - beforeCount := len(gamesBefore) - t.Logf("Games before sync: %d", beforeCount) + beforeCount := len(soundtracksBefore) + t.Logf("Soundtracks before sync: %d", beforeCount) assert.Equal(t, 0, beforeCount, "Database should be empty after clear") // Run sync @@ -91,14 +91,14 @@ func TestSyncPopulatesDatabase(t *testing.T) { t.Error("Sync did not complete within timeout") } - // After sync - should have games - gamesAfter, err := repo.FindAllSoundtracks(backend.BackendCtx()) + // After sync - should have soundtracks + soundtracksAfter, err := repo.FindAllSoundtracks(backend.BackendCtx()) assert.NoError(t, err) - afterCount := len(gamesAfter) - t.Logf("Games after sync: %d", afterCount) + afterCount := len(soundtracksAfter) + t.Logf("Soundtracks after sync: %d", afterCount) - // Should have more games than before (unless database was already populated) - assert.True(t, afterCount > 0, "Database should have games after sync") + // Should have more soundtracks than before (unless database was already populated) + assert.True(t, afterCount > 0, "Database should have soundtracks after sync") } // TestSyncMakesDifference verifies that sync actually changes the database state @@ -111,11 +111,11 @@ func TestSyncMakesDifference(t *testing.T) { // Clear any existing data first db.TestClearDatabase(t) - // Before sync - should have no games + // Before sync - should have no soundtracks repo := repository.New(backend.BackendPool()) - gamesBefore, err := repo.FindAllSoundtracks(backend.BackendCtx()) + soundtracksBefore, err := repo.FindAllSoundtracks(backend.BackendCtx()) assert.NoError(t, err) - assert.Equal(t, 0, len(gamesBefore), "Should have no games before sync") + assert.Equal(t, 0, len(soundtracksBefore), "Should have no soundtracks before sync") // Run sync resp := MakeTestRequest(t, e, "GET", "/sync/full") @@ -126,10 +126,10 @@ func TestSyncMakesDifference(t *testing.T) { t.Error("Sync did not complete within timeout") } - // After sync - should have games - gamesAfter, err := repo.FindAllSoundtracks(backend.BackendCtx()) + // After sync - should have soundtracks + soundtracksAfter, err := repo.FindAllSoundtracks(backend.BackendCtx()) assert.NoError(t, err) - assert.True(t, len(gamesAfter) > 0, "Should have games after sync") + assert.True(t, len(soundtracksAfter) > 0, "Should have soundtracks after sync") } // TestSyncProgress verifies the sync progress endpoint @@ -183,8 +183,8 @@ func TestSyncProgress(t *testing.T) { assert.True(t, foundComplete, "Should have seen completion") } -// TestSyncGamesNewOnlyChanges verifies the incremental sync endpoint -func TestSyncGamesNewOnlyChanges(t *testing.T) { +// TestSyncSoundtracksNewOnlyChanges verifies the incremental sync endpoint +func TestSyncSoundtracksNewOnlyChanges(t *testing.T) { db.TestSetupDB(t) defer db.TestTearDownDB(t) @@ -200,8 +200,8 @@ func TestSyncGamesNewOnlyChanges(t *testing.T) { // Get initial count repo := repository.New(backend.BackendPool()) - gamesBefore, _ := repo.FindAllSoundtracks(backend.BackendCtx()) - beforeCount := len(gamesBefore) + soundtracksBefore, _ := repo.FindAllSoundtracks(backend.BackendCtx()) + beforeCount := len(soundtracksBefore) // Run incremental sync (should not change count if nothing changed) resp := MakeTestRequest(t, e, "GET", "/sync/new") @@ -211,16 +211,16 @@ func TestSyncGamesNewOnlyChanges(t *testing.T) { time.Sleep(2 * time.Second) // Count should be the same - gamesAfter, _ := repo.FindAllSoundtracks(backend.BackendCtx()) - afterCount := len(gamesAfter) + soundtracksAfter, _ := repo.FindAllSoundtracks(backend.BackendCtx()) + afterCount := len(soundtracksAfter) // Note: This might not be exactly equal due to timing, but should be close - t.Logf("Games before incremental sync: %d, after: %d", beforeCount, afterCount) + t.Logf("Soundtracks before incremental sync: %d, after: %d", beforeCount, afterCount) } -// TestResetGames verifies the reset endpoint clears the database +// TestResetSoundtracks verifies the reset endpoint clears the database // RUN THIS LAST -func TestResetGames(t *testing.T) { +func TestResetSoundtracks(t *testing.T) { db.TestSetupDB(t) defer db.TestTearDownDB(t) @@ -228,8 +228,8 @@ func TestResetGames(t *testing.T) { // First ensure we have data repo := repository.New(backend.BackendPool()) - gamesBefore, _ := repo.FindAllSoundtracks(backend.BackendCtx()) - beforeCount := len(gamesBefore) + soundtracksBefore, _ := repo.FindAllSoundtracks(backend.BackendCtx()) + beforeCount := len(soundtracksBefore) if beforeCount == 0 { // Run sync to populate @@ -238,12 +238,12 @@ func TestResetGames(t *testing.T) { t.Error("Sync did not complete within timeout") return } - gamesBefore, _ = repo.FindAllSoundtracks(backend.BackendCtx()) - beforeCount = len(gamesBefore) + soundtracksBefore, _ = repo.FindAllSoundtracks(backend.BackendCtx()) + beforeCount = len(soundtracksBefore) } - t.Logf("Games before reset: %d", beforeCount) - assert.True(t, beforeCount > 0, "Should have games to reset") + t.Logf("Soundtracks before reset: %d", beforeCount) + assert.True(t, beforeCount > 0, "Should have soundtracks to reset") // Call reset resp := MakeTestRequest(t, e, "GET", "/sync/reset") @@ -253,16 +253,16 @@ func TestResetGames(t *testing.T) { // Note: reset might take a moment to propagate time.Sleep(1 * time.Second) - gamesAfter, _ := repo.FindAllSoundtracks(backend.BackendCtx()) - afterCount := len(gamesAfter) + soundtracksAfter, _ := repo.FindAllSoundtracks(backend.BackendCtx()) + afterCount := len(soundtracksAfter) - t.Logf("Games after reset: %d", afterCount) + t.Logf("Soundtracks after reset: %d", afterCount) assert.Equal(t, 0, afterCount, "Database should be empty after reset") } -// TestSyncGamesNewFull verifies the full sync endpoint -// RUN THIS LAST (before TestResetGames) -func TestSyncGamesNewFull(t *testing.T) { +// TestSyncSoundtracksNewFull verifies the full sync endpoint +// RUN THIS LAST (before TestResetSoundtracks) +func TestSyncSoundtracksNewFull(t *testing.T) { db.TestSetupDB(t) defer db.TestTearDownDB(t) @@ -282,8 +282,8 @@ func TestSyncGamesNewFull(t *testing.T) { // Verify database is populated repo := repository.New(backend.BackendPool()) - games, err := repo.FindAllSoundtracks(backend.BackendCtx()) + soundtracks, err := repo.FindAllSoundtracks(backend.BackendCtx()) assert.NoError(t, err) - assert.True(t, len(games) > 0, "Database should be populated after full sync") - t.Logf("Full sync populated %d games", len(games)) + assert.True(t, len(soundtracks) > 0, "Database should be populated after full sync") + t.Logf("Full sync populated %d soundtracks", len(soundtracks)) } diff --git a/internal/server/zz_music_handler_test.go b/internal/server/zz_music_handler_test.go index 1b4c9b6..4cbbb3d 100644 --- a/internal/server/zz_music_handler_test.go +++ b/internal/server/zz_music_handler_test.go @@ -16,12 +16,12 @@ import ( // ensureSyncRan ensures that sync has been run before testing music endpoints func ensureSyncRan(t *testing.T, e *echo.Echo) { repo := repository.New(backend.BackendPool()) - games, err := repo.FindAllSoundtracks(backend.BackendCtx()) + soundtracks, err := repo.FindAllSoundtracks(backend.BackendCtx()) assert.NoError(t, err) - if len(games) == 0 { + if len(soundtracks) == 0 { // Run sync - t.Log("No games found, running sync first...") + t.Log("No soundtracks found, running sync first...") resp := MakeTestRequest(t, e, "GET", "/sync/full") assert.Equal(t, http.StatusOK, resp.Code) @@ -32,8 +32,8 @@ func ensureSyncRan(t *testing.T, e *echo.Echo) { } } -// TestGetAllGames verifies the /music/all/order endpoint -func TestZGetAllGames(t *testing.T) { +// TestGetAllSoundtracks verifies the /music/all/order endpoint +func TestZGetAllSoundtracks(t *testing.T) { db.TestSetupDB(t) defer db.TestTearDownDB(t) @@ -45,15 +45,15 @@ func TestZGetAllGames(t *testing.T) { resp := MakeTestRequest(t, e, "GET", "/music/all/order") assert.Equal(t, http.StatusOK, resp.Code) - var games []string - err := json.Unmarshal(resp.Body.Bytes(), &games) + var soundtracks []string + err := json.Unmarshal(resp.Body.Bytes(), &soundtracks) assert.NoError(t, err) - assert.NotEmpty(t, games, "Should have games after sync") - t.Logf("Found %d games", len(games)) + assert.NotEmpty(t, soundtracks, "Should have soundtracks after sync") + t.Logf("Found %d soundtracks", len(soundtracks)) } -// TestGetAllGamesRandom verifies the /music/all/random endpoint -func TestZGetAllGamesRandom(t *testing.T) { +// TestGetAllSoundtracksRandom verifies the /music/all/random endpoint +func TestZGetAllSoundtracksRandom(t *testing.T) { db.TestSetupDB(t) defer db.TestTearDownDB(t) @@ -65,17 +65,17 @@ func TestZGetAllGamesRandom(t *testing.T) { resp := MakeTestRequest(t, e, "GET", "/music/all/random") assert.Equal(t, http.StatusOK, resp.Code) - var games []string - err := json.Unmarshal(resp.Body.Bytes(), &games) + var soundtracks []string + err := json.Unmarshal(resp.Body.Bytes(), &soundtracks) assert.NoError(t, err) - assert.NotEmpty(t, games, "Should have games after sync") + assert.NotEmpty(t, soundtracks, "Should have soundtracks after sync") // Verify it's shuffled (not in original order) // We can't easily verify randomness, but we can check it's the same length resp2 := MakeTestRequest(t, e, "GET", "/music/all/order") - var gamesOrdered []string - json.Unmarshal(resp2.Body.Bytes(), &gamesOrdered) - assert.Equal(t, len(games), len(gamesOrdered), "Random and ordered should have same count") + var soundtracksOrdered []string + json.Unmarshal(resp2.Body.Bytes(), &soundtracksOrdered) + assert.Equal(t, len(soundtracks), len(soundtracksOrdered), "Random and ordered should have same count") } // TestGetRandomSong verifies the /music/rand endpoint @@ -153,7 +153,7 @@ func TestZGetSongInfo(t *testing.T) { assert.NoError(t, err) // Note: CurrentlyPlaying might be false if no song is currently set // Just verify we got a valid response - t.Logf("Song info: Game=%s, Song=%s", info.Game, info.Song) + t.Logf("Song info: Soundtrack=%s, Song=%s", info.Soundtrack, info.Song) } // TestGetPlayedSongs verifies the /music/list endpoint