diff --git a/internal/repository/album_repo.go b/internal/repository/album_repo.go new file mode 100644 index 0000000..00dbbb7 --- /dev/null +++ b/internal/repository/album_repo.go @@ -0,0 +1,125 @@ +package repository + +import ( + "butterfliu/internal/model" + "database/sql" +) + +type AlbumRepository struct { + db *sql.DB +} + +func NewAlbumRepository(db *sql.DB) *AlbumRepository { + return &AlbumRepository{db: db} +} + +func (r *AlbumRepository) Get(id int) (model.Album, error) { + row := r.db.QueryRow("SELECT id, title, artist_id FROM albums WHERE id = ?", id) + var album model.Album + if err := row.Scan(&album.ID, &album.Title, &album.ArtistID); err != nil { + return model.Album{}, err + } + return album, nil +} + +func (r *AlbumRepository) GetByTitleAndArtist(title string, artistID int) (model.Album, error) { + row := r.db.QueryRow(` + SELECT id, title, artist_id, COALESCE(cover, ''), COALESCE(year, 0) + FROM albums WHERE title = ? AND artist_id = ? + `) + var album model.Album + if err := row.Scan(&album.ID, &album.Title, &album.ArtistID, &album.Cover, &album.Year); err != nil { + return model.Album{}, err + } + return album, nil +} + +func (r *AlbumRepository) Create(title string, artistID int) (model.Album, error) { + result, err := r.db.Exec("INSERT INTO albums (title, artist_id) VALUES (?, ?)", title, artistID) + if err != nil { + return model.Album{}, err + } + + id, err := result.LastInsertId() + if err != nil { + return model.Album{}, err + } + + return model.Album{ + ID: int(id), + Title: title, + ArtistID: artistID, + }, nil +} + +func (r *AlbumRepository) GetAll() ([]model.Album, error) { + rows, err := r.db.Query("SELECT id, title, artist_id FROM albums") + 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 *AlbumRepository) GetByArtist(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 *AlbumRepository) GetIDsByArtist(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 *AlbumRepository) GetSongIDs(albumID int) ([]int, error) { + rows, err := r.db.Query("SELECT id FROM songs WHERE album_id = ?", albumID) + 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/repository/artist_repo.go b/internal/repository/artist_repo.go new file mode 100644 index 0000000..3a25f45 --- /dev/null +++ b/internal/repository/artist_repo.go @@ -0,0 +1,85 @@ +package repository + +import ( + "butterfliu/internal/model" + "database/sql" +) + +type ArtistRepository struct { + db *sql.DB +} + +func NewArtistRepository(db *sql.DB) *ArtistRepository { + return &ArtistRepository{db: db} +} + +func (r *ArtistRepository) Get(id int) (model.Artist, error) { + row := r.db.QueryRow("SELECT id, name FROM artists WHERE id = ?", id) + var artist model.Artist + if err := row.Scan(&artist.ID, &artist.Name); err != nil { + return model.Artist{}, err + } + return artist, nil +} + +func (r *ArtistRepository) GetByName(name string) (model.Artist, error) { + row := r.db.QueryRow("SELECT id, name FROM artists WHERE name = ?", name) + var artist model.Artist + if err := row.Scan(&artist.ID, &artist.Name); err != nil { + return model.Artist{}, err + } + return artist, nil +} + +func (r *ArtistRepository) Create(name string) (model.Artist, error) { + result, err := r.db.Exec("INSERT INTO artists (name) VALUES (?)", name) + if err != nil { + return model.Artist{}, err + } + + id, err := result.LastInsertId() + if err != nil { + return model.Artist{}, err + } + + return model.Artist{ + ID: int(id), + Name: name, + }, nil +} + +func (r *ArtistRepository) GetAll() ([]model.Artist, error) { + rows, err := r.db.Query("SELECT id, name FROM artists") + if err != nil { + return nil, err + } + defer rows.Close() + + artists := []model.Artist{} + for rows.Next() { + var artist model.Artist + if err := rows.Scan(&artist.ID, &artist.Name); err != nil { + return nil, err + } + artists = append(artists, artist) + } + return artists, nil +} + +func (r *ArtistRepository) 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 +} diff --git a/internal/repository/library.go b/internal/repository/library.go index 2126643..d4b9af5 100644 --- a/internal/repository/library.go +++ b/internal/repository/library.go @@ -5,11 +5,6 @@ import ( "database/sql" ) -// SongDetail is a DTO for API responses with joined artist/album names. -// Kept here temporarily for backward compatibility with service layer. -// Consider moving to model package in future refactoring. -type SongDetail = model.SongDetail - type LibraryRepository struct { db *sql.DB } @@ -19,7 +14,7 @@ func NewLibraryRepository(db *sql.DB) *LibraryRepository { } func (r *LibraryRepository) GetAll() ([]model.Library, error) { - rows, err := r.db.Query("SELECT id, name, path, created_at,updated_at FROM libraries") + rows, err := r.db.Query("SELECT id, name, path, created_at, updated_at FROM libraries") if err != nil { return nil, err } @@ -111,329 +106,3 @@ func (r *LibraryRepository) Delete(id int) error { return tx.Commit() } - -func (r *LibraryRepository) GetSongsByLibraryWithDetails(libraryID 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 mf.library_id = ? - ORDER BY s.title - `, libraryID) - 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) 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, - COALESCE(file_size, 0), COALESCE(format, ''), - COALESCE(bit_rate, 0), COALESCE(sample_rate, 0), - COALESCE(created_at, '1970-01-01T00:00:00Z'), - COALESCE(updated_at, '1970-01-01T00:00:00Z') - FROM media_files WHERE path = ? - `) - var mediaFile model.MediaFile - if err := row.Scan( - &mediaFile.ID, &mediaFile.Path, &mediaFile.LibraryID, - &mediaFile.FileSize, &mediaFile.Format, - &mediaFile.BitRate, &mediaFile.SampleRate, - &mediaFile.CreatedAt, &mediaFile.UpdatedAt, - ); err != nil { - return model.MediaFile{}, err - } - return mediaFile, nil -} - -func (r *LibraryRepository) CreateMediaFile(path string, libraryID int) (model.MediaFile, error) { - result, err := r.db.Exec("INSERT INTO media_files (path, library_id) VALUES (?, ?)", path, libraryID) - if err != nil { - return model.MediaFile{}, err - } - - id, err := result.LastInsertId() - if err != nil { - return model.MediaFile{}, err - } - - return model.MediaFile{ - ID: int(id), - Path: path, - LibraryID: libraryID, - }, nil -} - -func (r *LibraryRepository) GetArtistByName(name string) (model.Artist, error) { - row := r.db.QueryRow("SELECT id, name FROM artists WHERE name = ?", name) - var artist model.Artist - if err := row.Scan(&artist.ID, &artist.Name); err != nil { - return model.Artist{}, err - } - return artist, nil -} - -func (r *LibraryRepository) CreateArtist(name string) (model.Artist, error) { - result, err := r.db.Exec("INSERT INTO artists (name) VALUES (?)", name) - if err != nil { - return model.Artist{}, err - } - - id, err := result.LastInsertId() - if err != nil { - return model.Artist{}, err - } - - return model.Artist{ - ID: int(id), - Name: name, - }, nil -} - -func (r *LibraryRepository) GetAlbumByTitleAndArtist(title string, artistID int) (model.Album, error) { - row := r.db.QueryRow(` - SELECT id, title, artist_id, COALESCE(cover, ''), COALESCE(year, 0) - FROM albums WHERE title = ? AND artist_id = ? - `) - var album model.Album - if err := row.Scan(&album.ID, &album.Title, &album.ArtistID, &album.Cover, &album.Year); err != nil { - return model.Album{}, err - } - return album, nil -} - -func (r *LibraryRepository) CreateAlbum(title string, artistID int) (model.Album, error) { - result, err := r.db.Exec("INSERT INTO albums (title, artist_id) VALUES (?, ?)", title, artistID) - if err != nil { - return model.Album{}, err - } - - id, err := result.LastInsertId() - if err != nil { - return model.Album{}, err - } - - return model.Album{ - ID: int(id), - Title: title, - ArtistID: artistID, - }, nil -} - -func (r *LibraryRepository) CreateSong(title string, artistID, albumID, duration, mediaFileID int) (model.Song, error) { - result, err := r.db.Exec( - "INSERT INTO songs (title, artist_id, album_id, duration, media_file_id) VALUES (?, ?, ?, ?, ?)", - title, artistID, albumID, duration, mediaFileID, - ) - if err != nil { - return model.Song{}, err - } - - id, err := result.LastInsertId() - if err != nil { - return model.Song{}, err - } - - return model.Song{ - ID: int(id), - Title: title, - ArtistID: artistID, - AlbumID: albumID, - Duration: duration, - MediaFileID: mediaFileID, - }, nil -} - -func (r *LibraryRepository) GetArtists() ([]model.Artist, error) { - rows, err := r.db.Query("SELECT id, name FROM artists") - if err != nil { - return nil, err - } - defer rows.Close() - - artists := []model.Artist{} - for rows.Next() { - var artist model.Artist - if err := rows.Scan(&artist.ID, &artist.Name); err != nil { - return nil, err - } - artists = append(artists, artist) - } - return artists, nil -} - -func (r *LibraryRepository) GetArtist(id int) (model.Artist, error) { - row := r.db.QueryRow("SELECT id, name FROM artists WHERE id = ?", id) - - var artist model.Artist - if err := row.Scan(&artist.ID, &artist.Name); err != nil { - return model.Artist{}, err - } - - return artist, nil -} - -func (r *LibraryRepository) GetAlbums() ([]model.Album, error) { - rows, err := r.db.Query("SELECT id, title, artist_id FROM albums") - 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) 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) - - var album model.Album - if err := row.Scan(&album.ID, &album.Title, &album.ArtistID); err != nil { - return model.Album{}, err - } - 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/repository/media_repo.go b/internal/repository/media_repo.go index 2bc1f01..3d2eac3 100644 --- a/internal/repository/media_repo.go +++ b/internal/repository/media_repo.go @@ -23,3 +23,120 @@ func (r *MediaRepository) Get(id int) (model.MediaFile, error) { } return m, nil } + +func (r *MediaRepository) GetByPath(path string) (model.MediaFile, error) { + row := r.db.QueryRow(` + SELECT id, path, library_id, + COALESCE(file_size, 0), COALESCE(format, ''), + COALESCE(bit_rate, 0), COALESCE(sample_rate, 0), + COALESCE(created_at, '1970-01-01T00:00:00Z'), + COALESCE(updated_at, '1970-01-01T00:00:00Z') + FROM media_files WHERE path = ? + `) + var mediaFile model.MediaFile + if err := row.Scan( + &mediaFile.ID, &mediaFile.Path, &mediaFile.LibraryID, + &mediaFile.FileSize, &mediaFile.Format, + &mediaFile.BitRate, &mediaFile.SampleRate, + &mediaFile.CreatedAt, &mediaFile.UpdatedAt, + ); err != nil { + return model.MediaFile{}, err + } + return mediaFile, nil +} + +func (r *MediaRepository) Create(path string, libraryID int) (model.MediaFile, error) { + result, err := r.db.Exec("INSERT INTO media_files (path, library_id) VALUES (?, ?)", path, libraryID) + if err != nil { + return model.MediaFile{}, err + } + + id, err := result.LastInsertId() + if err != nil { + return model.MediaFile{}, err + } + + return model.MediaFile{ + ID: int(id), + Path: path, + LibraryID: libraryID, + }, nil +} + +func (r *MediaRepository) GetSongsByLibraryWithDetails(libraryID int) ([]model.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 mf.library_id = ? + ORDER BY s.title + `, libraryID) + if err != nil { + return nil, err + } + defer rows.Close() + + songs := []model.SongDetail{} + for rows.Next() { + var song model.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 *MediaRepository) GetSongsByArtistWithDetails(artistID int) ([]model.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 := []model.SongDetail{} + for rows.Next() { + var song model.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 *MediaRepository) GetSongsByAlbumWithDetails(albumID int) ([]model.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 := []model.SongDetail{} + for rows.Next() { + var song model.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 +} diff --git a/internal/repository/song_repo.go b/internal/repository/song_repo.go index d0fa205..8f636c7 100644 --- a/internal/repository/song_repo.go +++ b/internal/repository/song_repo.go @@ -38,7 +38,7 @@ func (r *SongRepository) GetAll() ([]model.Song, error) { return songs, nil } -func (r *SongRepository) GetAllWithDetails() ([]SongDetail, error) { +func (r *SongRepository) GetAllWithDetails() ([]model.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 @@ -52,9 +52,9 @@ func (r *SongRepository) GetAllWithDetails() ([]SongDetail, error) { } defer rows.Close() - songs := []SongDetail{} + songs := []model.SongDetail{} for rows.Next() { - var song SongDetail + var song model.SongDetail if err := rows.Scan(&song.ID, &song.Title, &song.Artist, &song.Album, &song.Duration, &song.Path); err != nil { return nil, err } @@ -94,3 +94,27 @@ func (r *SongRepository) Get(id int) (model.Song, error) { } return song, nil } + +func (r *SongRepository) Create(title string, artistID, albumID, duration, mediaFileID int) (model.Song, error) { + result, err := r.db.Exec( + "INSERT INTO songs (title, artist_id, album_id, duration, media_file_id) VALUES (?, ?, ?, ?, ?)", + title, artistID, albumID, duration, mediaFileID, + ) + if err != nil { + return model.Song{}, err + } + + id, err := result.LastInsertId() + if err != nil { + return model.Song{}, err + } + + return model.Song{ + ID: int(id), + Title: title, + ArtistID: artistID, + AlbumID: albumID, + Duration: duration, + MediaFileID: mediaFileID, + }, nil +} diff --git a/internal/service/library.go b/internal/service/library.go index 363088f..c6e6cd9 100644 --- a/internal/service/library.go +++ b/internal/service/library.go @@ -23,19 +23,35 @@ type ScanReport struct { } type LibraryService struct { - repo *repository.LibraryRepository + libRepo *repository.LibraryRepository + artistRepo *repository.ArtistRepository + albumRepo *repository.AlbumRepository + songRepo *repository.SongRepository + mediaRepo *repository.MediaRepository } -func NewLibraryService(repo *repository.LibraryRepository) *LibraryService { - return &LibraryService{repo: repo} +func NewLibraryService( + libRepo *repository.LibraryRepository, + artistRepo *repository.ArtistRepository, + albumRepo *repository.AlbumRepository, + songRepo *repository.SongRepository, + mediaRepo *repository.MediaRepository, +) *LibraryService { + return &LibraryService{ + libRepo: libRepo, + artistRepo: artistRepo, + albumRepo: albumRepo, + songRepo: songRepo, + mediaRepo: mediaRepo, + } } func (s *LibraryService) GetAll() ([]model.Library, error) { - return s.repo.GetAll() + return s.libRepo.GetAll() } func (s *LibraryService) GetByID(id int) (model.Library, error) { - return s.repo.GetByID(id) + return s.libRepo.GetByID(id) } func (s *LibraryService) Create(name, path string) (model.Library, error) { @@ -45,57 +61,53 @@ func (s *LibraryService) Create(name, path string) (model.Library, error) { if path = strings.TrimSpace(path); path == "" { return model.Library{}, errors.New("library path cannot be empty") } - return s.repo.Create(name, path) + return s.libRepo.Create(name, path) } func (s *LibraryService) UpdateName(id int, name string) error { if name = strings.TrimSpace(name); name == "" { return errors.New("library name cannot be empty") } - return s.repo.UpdateName(id, name) + return s.libRepo.UpdateName(id, name) } func (s *LibraryService) UpdatePath(id int, path string) error { if path = strings.TrimSpace(path); path == "" { return errors.New("library path cannot be empty") } - return s.repo.UpdatePath(id, path) + return s.libRepo.UpdatePath(id, path) } func (s *LibraryService) Delete(id int) error { - return s.repo.Delete(id) + return s.libRepo.Delete(id) } -func (s *LibraryService) GetSongs(id int) ([]repository.SongDetail, error) { - return s.repo.GetSongsByLibraryWithDetails(id) +func (s *LibraryService) GetSongs(id int) ([]model.SongDetail, error) { + return s.mediaRepo.GetSongsByLibraryWithDetails(id) } -func (s *LibraryService) GetSongsByArtist(id int) ([]repository.SongDetail, error) { - return s.repo.GetSongsByArtistWithDetails(id) +func (s *LibraryService) GetSongsByArtist(id int) ([]model.SongDetail, error) { + return s.mediaRepo.GetSongsByArtistWithDetails(id) } -func (s *LibraryService) GetSongsByAlbum(id int) ([]repository.SongDetail, error) { - return s.repo.GetSongsByAlbumWithDetails(id) -} - -func (s *LibraryService) GetSongIDsByAlbum(id int) ([]repository.SongDetail, error) { - return s.repo.GetSongsByAlbumWithDetails(id) +func (s *LibraryService) GetSongsByAlbum(id int) ([]model.SongDetail, error) { + return s.mediaRepo.GetSongsByAlbumWithDetails(id) } func (s *LibraryService) GetArtists() ([]model.Artist, error) { - return s.repo.GetArtists() + return s.artistRepo.GetAll() } func (s *LibraryService) GetArtist(id int) (model.ArtistDetail, error) { - artist, err := s.repo.GetArtist(id) + artist, err := s.artistRepo.Get(id) if err != nil { return model.ArtistDetail{}, err } - albums, err := s.repo.GetAlbumIDsByArtist(id) + albums, err := s.albumRepo.GetIDsByArtist(id) if err != nil { return model.ArtistDetail{}, err } - songs, err := s.repo.GetSongIDsByArtist(id) + songs, err := s.artistRepo.GetSongIDsByArtist(id) if err != nil { return model.ArtistDetail{}, err } @@ -108,21 +120,21 @@ func (s *LibraryService) GetArtist(id int) (model.ArtistDetail, error) { } func (s *LibraryService) GetAlbums() ([]model.Album, error) { - return s.repo.GetAlbums() + return s.albumRepo.GetAll() } func (s *LibraryService) GetAlbumsByArtistWithDetail(artistID int) ([]model.AlbumDetail, error) { - albums, err := s.repo.GetAlbumsByArtist(artistID) + albums, err := s.albumRepo.GetByArtist(artistID) if err != nil { return nil, err } details := []model.AlbumDetail{} for _, a := range albums { - songs, err := s.repo.GetSongIDsByAlbum(a.ID) + songs, err := s.albumRepo.GetSongIDs(a.ID) if err != nil { break } - artist, err := s.repo.GetArtist(artistID) + artist, err := s.artistRepo.Get(artistID) if err != nil { break } @@ -137,15 +149,15 @@ func (s *LibraryService) GetAlbumsByArtistWithDetail(artistID int) ([]model.Albu } func (s *LibraryService) GetAlbum(id int) (model.AlbumDetail, error) { - album, err := s.repo.GetAlbum(id) + album, err := s.albumRepo.Get(id) if err != nil { return model.AlbumDetail{}, err } - songs, err := s.repo.GetSongIDsByAlbum(id) + songs, err := s.albumRepo.GetSongIDs(id) if err != nil { return model.AlbumDetail{}, err } - artist, err := s.repo.GetArtist(album.ArtistID) + artist, err := s.artistRepo.Get(album.ArtistID) if err != nil { return model.AlbumDetail{}, err } @@ -158,16 +170,19 @@ func (s *LibraryService) GetAlbum(id int) (model.AlbumDetail, error) { } func (s *LibraryService) GetAlbumCover(id int) (string, error) { - songs, err := s.repo.GetSongIDsByAlbum(id) + songs, err := s.albumRepo.GetSongIDs(id) if err != nil { return "", err } + if len(songs) == 0 { + return "", errors.New("no songs found for album") + } conf := config.LoadConfig() return path.Join(conf.GetCachePath("cover"), strconv.Itoa(songs[0])+".jpg"), nil } func (s *LibraryService) Scan(id int) (*ScanReport, error) { - lib, err := s.repo.GetByID(id) + lib, err := s.libRepo.GetByID(id) if err != nil { return nil, fmt.Errorf("library %d not found: %w", id, err) } @@ -207,7 +222,7 @@ func (s *LibraryService) addScannedSong(song scanner.ScannedSong, libraryID int, return fmt.Errorf("album: %w", err) } - if _, err := s.repo.CreateSong(song.Title, artist.ID, album.ID, song.Duration, mediaFile.ID); err != nil { + if _, err := s.songRepo.Create(song.Title, artist.ID, album.ID, song.Duration, mediaFile.ID); err != nil { return fmt.Errorf("song: %w", err) } @@ -216,25 +231,25 @@ func (s *LibraryService) addScannedSong(song scanner.ScannedSong, libraryID int, } func (s *LibraryService) getOrCreateMediaFile(path string, libraryID int) (model.MediaFile, error) { - mf, err := s.repo.GetMediaFileByPath(path) + mf, err := s.mediaRepo.GetByPath(path) if err == nil { return mf, nil } - return s.repo.CreateMediaFile(path, libraryID) + return s.mediaRepo.Create(path, libraryID) } func (s *LibraryService) getOrCreateArtist(name string) (model.Artist, error) { - a, err := s.repo.GetArtistByName(name) + a, err := s.artistRepo.GetByName(name) if err == nil { return a, nil } - return s.repo.CreateArtist(name) + return s.artistRepo.Create(name) } func (s *LibraryService) getOrCreateAlbum(title string, artistID int) (model.Album, error) { - al, err := s.repo.GetAlbumByTitleAndArtist(title, artistID) + al, err := s.albumRepo.GetByTitleAndArtist(title, artistID) if err == nil { return al, nil } - return s.repo.CreateAlbum(title, artistID) + return s.albumRepo.Create(title, artistID) } diff --git a/internal/service/song_svc.go b/internal/service/song_svc.go index 63e5e0f..7128524 100644 --- a/internal/service/song_svc.go +++ b/internal/service/song_svc.go @@ -21,11 +21,11 @@ func NewSongService(songRepo *repository.SongRepository, mediaRepo *repository.M } } -func (s *SongService) GetAllWithDetails() ([]repository.SongDetail, error) { +func (s *SongService) GetAllWithDetails() ([]model.SongDetail, error) { return s.songRepo.GetAllWithDetails() } -func (s *SongService) GetByIDWithDetails(id int) (repository.SongDetail, error) { +func (s *SongService) GetByIDWithDetails(id int) (model.SongDetail, error) { return s.songRepo.GetWithDetails(id) } diff --git a/main.go b/main.go index 11f8934..1b3315e 100644 --- a/main.go +++ b/main.go @@ -23,9 +23,11 @@ func main() { r.Use(middleware.Logger) libraryRepo := repository.NewLibraryRepository(GetDB()) + artistRepo := repository.NewArtistRepository(GetDB()) + albumRepo := repository.NewAlbumRepository(GetDB()) songRepo := repository.NewSongRepository(GetDB()) mediaRepo := repository.NewMediaRepository(GetDB()) - libraryService := service.NewLibraryService(libraryRepo) + libraryService := service.NewLibraryService(libraryRepo, artistRepo, albumRepo, songRepo, mediaRepo) songService := service.NewSongService(songRepo, mediaRepo) libraryController := controller.NewLibraryController(libraryService) songController := controller.NewSongController(songService)