优化Service
All checks were successful
Go CI / test-and-build (push) Successful in 11s

This commit is contained in:
2026-04-06 16:37:27 +08:00
parent 3aa8057648
commit a067e8d17c
3 changed files with 95 additions and 51 deletions

View File

@@ -3,9 +3,21 @@ package service
import (
"butterfliu/internal/repository"
"butterfliu/internal/scanner"
"errors"
"fmt"
"log"
"path/filepath"
"strings"
)
// ScanReport holds the result of a library scan.
type ScanReport struct {
TotalFiles int
Added int
Skipped int
FailedFiles []string
}
type LibraryService struct {
repo *repository.LibraryRepository
}
@@ -23,14 +35,26 @@ func (s *LibraryService) GetByID(id int) (repository.Library, error) {
}
func (s *LibraryService) Create(name, path string) (repository.Library, error) {
if name = strings.TrimSpace(name); name == "" {
return repository.Library{}, errors.New("library name cannot be empty")
}
if path = strings.TrimSpace(path); path == "" {
return repository.Library{}, errors.New("library path cannot be empty")
}
return s.repo.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)
}
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)
}
@@ -50,53 +74,75 @@ func (s *LibraryService) GetAlbums() ([]repository.Album, error) {
return s.repo.GetAlbums()
}
func (s *LibraryService) Scan(id int) error {
func (s *LibraryService) Scan(id int) (*ScanReport, error) {
lib, err := s.repo.GetByID(id)
if err != nil {
return err
return nil, fmt.Errorf("library %d not found: %w", id, err)
}
scannedSongs, err := scanner.ScanDirectory(lib.Path)
if err != nil {
return err
return nil, fmt.Errorf("scan directory %s: %w", lib.Path, err)
}
log.Println("Scanned songs:", len(scannedSongs))
report := &ScanReport{TotalFiles: len(scannedSongs)}
for _, song := range scannedSongs {
mediaFile, err := s.repo.GetMediaFileByPath(song.Path)
if err != nil {
mediaFile, err = s.repo.CreateMediaFile(song.Path, id)
if err != nil {
log.Println("Error adding media file:", song.Path, err)
continue
}
}
artist, err := s.repo.GetArtistByName(song.Artist)
if err != nil {
artist, err = s.repo.CreateArtist(song.Artist)
if err != nil {
log.Println("Error adding artist:", song.Artist, err)
continue
}
}
album, err := s.repo.GetAlbumByTitleAndArtist(song.Album, artist.ID)
if err != nil {
album, err = s.repo.CreateAlbum(song.Album, artist.ID)
if err != nil {
log.Println("Error adding album:", err)
continue
}
}
_, err = s.repo.CreateSong(song.Title, artist.ID, album.ID, song.Duration, mediaFile.ID)
if err != nil {
log.Printf("Song already exists or error adding: %s - %v", song.Title, err)
continue
if err := s.addScannedSong(song, lib.ID, report); err != nil {
log.Printf("Failed to add %s: %v", filepath.Base(song.Path), err)
report.FailedFiles = append(report.FailedFiles, song.Path)
}
}
log.Printf("Scan complete for library %d: %+v", id, report)
return report, nil
}
// addScannedSong upserts a scanned song and its related artist, album, and media file.
func (s *LibraryService) addScannedSong(song scanner.ScannedSong, libraryID int, report *ScanReport) error {
mediaFile, err := s.getOrCreateMediaFile(song.Path, libraryID)
if err != nil {
return fmt.Errorf("media file: %w", err)
}
artist, err := s.getOrCreateArtist(song.Artist)
if err != nil {
return fmt.Errorf("artist: %w", err)
}
album, err := s.getOrCreateAlbum(song.Album, artist.ID)
if err != nil {
return fmt.Errorf("album: %w", err)
}
if _, err := s.repo.CreateSong(song.Title, artist.ID, album.ID, song.Duration, mediaFile.ID); err != nil {
return fmt.Errorf("song: %w", err)
}
report.Added++
return nil
}
func (s *LibraryService) getOrCreateMediaFile(path string, libraryID int) (repository.MediaFile, error) {
mf, err := s.repo.GetMediaFileByPath(path)
if err == nil {
return mf, nil
}
return s.repo.CreateMediaFile(path, libraryID)
}
func (s *LibraryService) getOrCreateArtist(name string) (repository.Artist, error) {
a, err := s.repo.GetArtistByName(name)
if err == nil {
return a, nil
}
return s.repo.CreateArtist(name)
}
func (s *LibraryService) getOrCreateAlbum(title string, artistID int) (repository.Album, error) {
al, err := s.repo.GetAlbumByTitleAndArtist(title, artistID)
if err == nil {
return al, nil
}
return s.repo.CreateAlbum(title, artistID)
}