From 064ea6c674d361411056d0873c4dc09c6ca6239b Mon Sep 17 00:00:00 2001 From: lzw-723 Date: Tue, 7 Apr 2026 17:29:14 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=B0=E5=AF=8C=E8=89=BA=E6=9C=AF=E5=AE=B6?= =?UTF-8?q?=E5=92=8C=E4=B8=93=E8=BE=91=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/controller/library.go | 30 ++++++++ internal/model/dto.go | 14 ++++ internal/repository/library.go | 124 +++++++++++++++++++++++++++++++++ internal/service/library.go | 46 ++++++++++-- main.go | 3 + 5 files changed, 213 insertions(+), 4 deletions(-) diff --git a/internal/controller/library.go b/internal/controller/library.go index a277670..66fb22f 100644 --- a/internal/controller/library.go +++ b/internal/controller/library.go @@ -186,6 +186,36 @@ func (c *LibraryController) GetSongs(w http.ResponseWriter, r *http.Request) { jsonResponse(w, songs, http.StatusOK) } +func (c *LibraryController) GetSongsByArtist(w http.ResponseWriter, r *http.Request) { + idParam := chi.URLParam(r, "id") + id, err := strconv.Atoi(idParam) + if err != nil { + jsonError(w, err.Error(), http.StatusBadRequest) + return + } + songs, err := c.service.GetSongsByArtist(id) + if err != nil { + jsonError(w, err.Error(), http.StatusInternalServerError) + return + } + jsonResponse(w, songs, http.StatusOK) +} + +func (c *LibraryController) GetSongsByAlbum(w http.ResponseWriter, r *http.Request) { + idParam := chi.URLParam(r, "id") + id, err := strconv.Atoi(idParam) + if err != nil { + jsonError(w, err.Error(), http.StatusBadRequest) + return + } + songs, err := c.service.GetSongsByAlbum(id) + if err != nil { + jsonError(w, err.Error(), http.StatusInternalServerError) + return + } + jsonResponse(w, songs, http.StatusOK) +} + func (c *LibraryController) GetArtists(w http.ResponseWriter, r *http.Request) { artists, err := c.service.GetArtists() if err != nil { diff --git a/internal/model/dto.go b/internal/model/dto.go index 29ad6de..534e076 100644 --- a/internal/model/dto.go +++ b/internal/model/dto.go @@ -10,3 +10,17 @@ type SongDetail struct { Duration int `json:"duration"` Path string `json:"path"` } + +type ArtistDetail struct { + ID int `json:"id"` + Name string `json:"name"` + Songs []int `json:"songs"` + Albums []int `json:"albums"` +} + +type AlbumDetail struct { + ID int `json:"id"` + Title string `json:"title"` + Artist int `json:"artist"` + Songs []int `json:"songs"` +} diff --git a/internal/repository/library.go b/internal/repository/library.go index d8b0176..2126643 100644 --- a/internal/repository/library.go +++ b/internal/repository/library.go @@ -138,6 +138,58 @@ func (r *LibraryRepository) GetSongsByLibraryWithDetails(libraryID int) ([]SongD return songs, nil } +func (r *LibraryRepository) GetSongsByArtistWithDetails(artistID int) ([]SongDetail, error) { + rows, err := r.db.Query(` + SELECT s.id, s.title, a.name as artist_name, al.title as album_title, s.duration, mf.path + FROM songs s + INNER JOIN media_files mf ON s.media_file_id = mf.id + INNER JOIN artists a ON s.artist_id = a.id + INNER JOIN albums al ON s.album_id = al.id + WHERE s.artist_id = ? + ORDER BY s.title + `, artistID) + if err != nil { + return nil, err + } + defer rows.Close() + + songs := []SongDetail{} + for rows.Next() { + var song SongDetail + if err := rows.Scan(&song.ID, &song.Title, &song.Artist, &song.Album, &song.Duration, &song.Path); err != nil { + return nil, err + } + songs = append(songs, song) + } + return songs, nil +} + +func (r *LibraryRepository) GetSongsByAlbumWithDetails(albumID int) ([]SongDetail, error) { + rows, err := r.db.Query(` + SELECT s.id, s.title, a.name as artist_name, al.title as album_title, s.duration, mf.path + FROM songs s + INNER JOIN media_files mf ON s.media_file_id = mf.id + INNER JOIN artists a ON s.artist_id = a.id + INNER JOIN albums al ON s.album_id = al.id + WHERE s.album_id = ? + ORDER BY s.title + `, albumID) + if err != nil { + return nil, err + } + defer rows.Close() + + songs := []SongDetail{} + for rows.Next() { + var song SongDetail + if err := rows.Scan(&song.ID, &song.Title, &song.Artist, &song.Album, &song.Duration, &song.Path); err != nil { + return nil, err + } + songs = append(songs, song) + } + return songs, nil +} + func (r *LibraryRepository) GetMediaFileByPath(path string) (model.MediaFile, error) { row := r.db.QueryRow(` SELECT id, path, library_id, @@ -304,6 +356,60 @@ func (r *LibraryRepository) GetAlbums() ([]model.Album, error) { return albums, nil } +func (r *LibraryRepository) GetAlbumsByArtist(artistID int) ([]model.Album, error) { + rows, err := r.db.Query("SELECT id, title, artist_id FROM albums WHERE artist_id = ?", artistID) + if err != nil { + return nil, err + } + defer rows.Close() + + albums := []model.Album{} + for rows.Next() { + var album model.Album + if err := rows.Scan(&album.ID, &album.Title, &album.ArtistID); err != nil { + return nil, err + } + albums = append(albums, album) + } + return albums, nil +} + +func (r *LibraryRepository) GetAlbumIDsByArtist(artistID int) ([]int, error) { + rows, err := r.db.Query("SELECT id FROM albums WHERE artist_id = ?", artistID) + if err != nil { + return nil, err + } + defer rows.Close() + + ids := []int{} + for rows.Next() { + var id int + if err := rows.Scan(&id); err != nil { + return nil, err + } + ids = append(ids, id) + } + return ids, nil +} + +func (r *LibraryRepository) GetSongIDsByArtist(artistID int) ([]int, error) { + rows, err := r.db.Query("SELECT id FROM songs WHERE artist_id = ?", artistID) + if err != nil { + return nil, err + } + defer rows.Close() + + ids := []int{} + for rows.Next() { + var id int + if err := rows.Scan(&id); err != nil { + return nil, err + } + ids = append(ids, id) + } + return ids, nil +} + func (r *LibraryRepository) GetAlbum(id int) (model.Album, error) { row := r.db.QueryRow("SELECT id, title, artist_id FROM albums WHERE id = ?", id) @@ -313,3 +419,21 @@ func (r *LibraryRepository) GetAlbum(id int) (model.Album, error) { } return album, nil } + +func (r *LibraryRepository) GetSongIDsByAlbum(artistID int) ([]int, error) { + rows, err := r.db.Query("SELECT id FROM songs WHERE album_id = ?", artistID) + if err != nil { + return nil, err + } + defer rows.Close() + + ids := []int{} + for rows.Next() { + var id int + if err := rows.Scan(&id); err != nil { + return nil, err + } + ids = append(ids, id) + } + return ids, nil +} diff --git a/internal/service/library.go b/internal/service/library.go index f67865c..bf53f2d 100644 --- a/internal/service/library.go +++ b/internal/service/library.go @@ -67,20 +67,58 @@ func (s *LibraryService) GetSongs(id int) ([]repository.SongDetail, error) { return s.repo.GetSongsByLibraryWithDetails(id) } +func (s *LibraryService) GetSongsByArtist(id int) ([]repository.SongDetail, error) { + return s.repo.GetSongsByArtistWithDetails(id) +} + +func (s *LibraryService) GetSongsByAlbum(id int) ([]repository.SongDetail, error) { + return s.repo.GetSongsByAlbumWithDetails(id) +} + func (s *LibraryService) GetArtists() ([]model.Artist, error) { return s.repo.GetArtists() } -func (s *LibraryService) GetArtist(id int) (model.Artist, error) { - return s.repo.GetArtist(id) +func (s *LibraryService) GetArtist(id int) (model.ArtistDetail, error) { + artist, err := s.repo.GetArtist(id) + if err != nil { + return model.ArtistDetail{}, err + } + albums, err := s.repo.GetAlbumIDsByArtist(id) + if err != nil { + return model.ArtistDetail{}, err + } + songs, err := s.repo.GetSongIDsByArtist(id) + if err != nil { + return model.ArtistDetail{}, err + } + return model.ArtistDetail{ + ID: artist.ID, + Name: artist.Name, + Songs: songs, + Albums: albums, + }, nil } func (s *LibraryService) GetAlbums() ([]model.Album, error) { return s.repo.GetAlbums() } -func (s *LibraryService) GetAlbum(id int) (model.Album, error) { - return s.repo.GetAlbum(id) +func (s *LibraryService) GetAlbum(id int) (model.AlbumDetail, error) { + album, err := s.repo.GetAlbum(id) + if err != nil { + return model.AlbumDetail{}, err + } + songs, err := s.repo.GetSongIDsByAlbum(id) + if err != nil { + return model.AlbumDetail{}, err + } + return model.AlbumDetail{ + ID: id, + Title: album.Title, + Songs: songs, + Artist: album.ArtistID, + }, nil } func (s *LibraryService) Scan(id int) (*ScanReport, error) { diff --git a/main.go b/main.go index 796bd19..971d113 100644 --- a/main.go +++ b/main.go @@ -56,10 +56,13 @@ func main() { r.Route("/api/artists", func(r chi.Router) { r.Get("/", libraryController.GetArtists) r.Get("/{id}", libraryController.GetArtist) + r.Get("/{id}/songs", libraryController.GetSongsByArtist) }) + r.Route("/api/albums", func(r chi.Router) { r.Get("/", libraryController.GetAlbums) r.Get("/{id}", libraryController.GetAlbum) + r.Get("/{id}/songs", libraryController.GetSongsByAlbum) }) http.ListenAndServe(":8102", r)