changed genre scanning to parse multiple genres, updated db to accommodate.
This commit is contained in:
@@ -43,6 +43,7 @@ type entityCache struct {
|
||||
artists map[string]sqlcgen.Artist
|
||||
releaseGroups map[string]sqlcgen.ReleaseGroup
|
||||
coverArt map[string]sqlcgen.CoverArt
|
||||
genres map[string]sqlcgen.Genre
|
||||
// linkedCredits tracks artist-credit-artist links already created
|
||||
// so we skip the duplicate INSERT. Key is "artistID:creditID".
|
||||
linkedCredits map[string]struct{}
|
||||
@@ -54,6 +55,7 @@ func newEntityCache() *entityCache {
|
||||
artists: make(map[string]sqlcgen.Artist),
|
||||
releaseGroups: make(map[string]sqlcgen.ReleaseGroup),
|
||||
coverArt: make(map[string]sqlcgen.CoverArt),
|
||||
genres: make(map[string]sqlcgen.Genre),
|
||||
linkedCredits: make(map[string]struct{}),
|
||||
}
|
||||
}
|
||||
@@ -856,7 +858,10 @@ func (l *Library) processMetadata(
|
||||
)
|
||||
}
|
||||
|
||||
// 6. Link recording to release group.
|
||||
// 6. Link recording to genres.
|
||||
l.linkRecordingGenres(q, cache, tags.Genre, recording.ID)
|
||||
|
||||
// 7. Link recording to release group.
|
||||
if releaseGroupID.Valid {
|
||||
_, err = q.CreateReleaseGroupRecording(
|
||||
l.ctx,
|
||||
@@ -990,6 +995,67 @@ func (l *Library) cachedLinkArtist(
|
||||
cache.linkedCredits[linkKey] = struct{}{}
|
||||
}
|
||||
|
||||
// cachedUpsertGenre returns the genre for the given name, using
|
||||
// the cache when possible.
|
||||
func (l *Library) cachedUpsertGenre(
|
||||
q *sqlcgen.Queries,
|
||||
cache *entityCache,
|
||||
name string,
|
||||
) (sqlcgen.Genre, error) {
|
||||
if cached, ok := cache.genres[name]; ok {
|
||||
return cached, nil
|
||||
}
|
||||
|
||||
genre, err := q.UpsertGenre(l.ctx, name)
|
||||
if err != nil {
|
||||
return sqlcgen.Genre{}, err
|
||||
}
|
||||
|
||||
cache.genres[name] = genre
|
||||
|
||||
return genre, nil
|
||||
}
|
||||
|
||||
// linkRecordingGenres parses the raw genre string, upserts each
|
||||
// individual genre, and creates the recording-genre associations.
|
||||
func (l *Library) linkRecordingGenres(
|
||||
q *sqlcgen.Queries,
|
||||
cache *entityCache,
|
||||
rawGenre string,
|
||||
recordingID int64,
|
||||
) {
|
||||
genres := metadata.ParseGenres(rawGenre)
|
||||
|
||||
for _, name := range genres {
|
||||
genre, err := l.cachedUpsertGenre(q, cache, name)
|
||||
if err != nil {
|
||||
l.logger.Warn(
|
||||
"could not upsert genre",
|
||||
"genre", name,
|
||||
"err", err,
|
||||
)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
err = q.CreateRecordingGenre(
|
||||
l.ctx,
|
||||
sqlcgen.CreateRecordingGenreParams{
|
||||
RecordingID: recordingID,
|
||||
GenreID: genre.ID,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
l.logger.Warn(
|
||||
"could not link recording to genre",
|
||||
"genre", name,
|
||||
"recordingID", recordingID,
|
||||
"err", err,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// resolveAlbumArtistCredit returns the album artist credit ID.
|
||||
// When the AlbumArtist tag is absent or matches the track artist,
|
||||
// the track artist credit is reused.
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Sentinel errors for library queries.
|
||||
@@ -22,12 +23,26 @@ type Track struct {
|
||||
TrackNumber int64
|
||||
DiscNumber int64
|
||||
Album string
|
||||
Genre string
|
||||
Genre []string
|
||||
Year int64
|
||||
Composer string
|
||||
FileType string
|
||||
}
|
||||
|
||||
// genreDelimiter is the separator used by GROUP_CONCAT in the
|
||||
// GetAllTracksWithFullMetadata query.
|
||||
const genreDelimiter = "||"
|
||||
|
||||
// splitGenres splits a GROUP_CONCAT genre string into individual
|
||||
// genre names. An empty string returns nil.
|
||||
func splitGenres(concatenated string) []string {
|
||||
if concatenated == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return strings.Split(concatenated, genreDelimiter)
|
||||
}
|
||||
|
||||
// Album represents an album for the cover grid display.
|
||||
type Album struct {
|
||||
ID int64
|
||||
@@ -75,7 +90,7 @@ func (l *Library) GetAllTracks() ([]Track, error) {
|
||||
TrackNumber: row.TrackNumber.Int64,
|
||||
DiscNumber: row.DiscNumber.Int64,
|
||||
Album: row.Album,
|
||||
Genre: row.Genre,
|
||||
Genre: splitGenres(row.Genre),
|
||||
Year: row.Year,
|
||||
Composer: row.Composer,
|
||||
FileType: row.FileType,
|
||||
|
||||
@@ -102,6 +102,12 @@ func (l *Library) clearLibraryTables() error {
|
||||
)
|
||||
}
|
||||
|
||||
if err := txq.DeleteAllRecordingGenres(l.ctx); err != nil {
|
||||
return fmt.Errorf(
|
||||
"could not clear recording genres: %w", err,
|
||||
)
|
||||
}
|
||||
|
||||
if err := txq.DeleteAllReleaseGroupRecordings(l.ctx); err != nil {
|
||||
return fmt.Errorf(
|
||||
"could not clear release group recordings: %w", err,
|
||||
@@ -152,6 +158,12 @@ func (l *Library) clearLibraryTables() error {
|
||||
)
|
||||
}
|
||||
|
||||
if err := txq.DeleteAllGenres(l.ctx); err != nil {
|
||||
return fmt.Errorf(
|
||||
"could not clear genres: %w", err,
|
||||
)
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return fmt.Errorf(
|
||||
"could not commit library clear transaction: %w", err,
|
||||
|
||||
Reference in New Issue
Block a user