feat: allow multi valued tag modes to be configurable
This commit is contained in:
@@ -30,32 +30,32 @@ var (
|
||||
)
|
||||
|
||||
type Scanner struct {
|
||||
db *db.DB
|
||||
musicDirs []string
|
||||
genreSplit string
|
||||
tagger tags.Reader
|
||||
excludePattern *regexp.Regexp
|
||||
scanning *int32
|
||||
watcher *fsnotify.Watcher
|
||||
watchMap map[string]string // maps watched dirs back to root music dir
|
||||
watchDone chan bool
|
||||
db *db.DB
|
||||
musicDirs []string
|
||||
multiValueSettings map[Tag]MultiValueSetting
|
||||
tagger tags.Reader
|
||||
excludePattern *regexp.Regexp
|
||||
scanning *int32
|
||||
watcher *fsnotify.Watcher
|
||||
watchMap map[string]string // maps watched dirs back to root music dir
|
||||
watchDone chan bool
|
||||
}
|
||||
|
||||
func New(musicDirs []string, db *db.DB, genreSplit string, tagger tags.Reader, excludePattern string) *Scanner {
|
||||
func New(musicDirs []string, db *db.DB, multiValueSettings map[Tag]MultiValueSetting, tagger tags.Reader, excludePattern string) *Scanner {
|
||||
var excludePatternRegExp *regexp.Regexp
|
||||
if excludePattern != "" {
|
||||
excludePatternRegExp = regexp.MustCompile(excludePattern)
|
||||
}
|
||||
|
||||
return &Scanner{
|
||||
db: db,
|
||||
musicDirs: musicDirs,
|
||||
genreSplit: genreSplit,
|
||||
tagger: tagger,
|
||||
excludePattern: excludePatternRegExp,
|
||||
scanning: new(int32),
|
||||
watchMap: make(map[string]string),
|
||||
watchDone: make(chan bool),
|
||||
db: db,
|
||||
musicDirs: musicDirs,
|
||||
multiValueSettings: multiValueSettings,
|
||||
tagger: tagger,
|
||||
excludePattern: excludePatternRegExp,
|
||||
scanning: new(int32),
|
||||
watchMap: make(map[string]string),
|
||||
watchDone: make(chan bool),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,7 +353,7 @@ func (s *Scanner) populateTrackAndAlbumArtists(tx *db.DB, c *Context, i int, alb
|
||||
return fmt.Errorf("%v: %w", err, ErrReadingTags)
|
||||
}
|
||||
|
||||
genreNames := strings.Split(tags.MustGenre(trags), s.genreSplit)
|
||||
genreNames := parseMulti(trags, s.multiValueSettings[Genre], tags.MustGenres, tags.MustGenre)
|
||||
genreIDs, err := populateGenres(tx, genreNames)
|
||||
if err != nil {
|
||||
return fmt.Errorf("populate genres: %w", err)
|
||||
@@ -361,9 +361,9 @@ func (s *Scanner) populateTrackAndAlbumArtists(tx *db.DB, c *Context, i int, alb
|
||||
|
||||
// metadata for the album table comes only from the the first track's tags
|
||||
if i == 0 {
|
||||
albumArtists := tags.MustAlbumArtists(trags)
|
||||
albumArtistNames := parseMulti(trags, s.multiValueSettings[AlbumArtist], tags.MustAlbumArtists, tags.MustAlbumArtist)
|
||||
var albumArtistIDs []int
|
||||
for _, albumArtistName := range albumArtists {
|
||||
for _, albumArtistName := range albumArtistNames {
|
||||
albumArtist, err := populateArtist(tx, albumArtistName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("populate album artist: %w", err)
|
||||
@@ -669,3 +669,39 @@ func (c *Context) TracksMissing() int { return len(c.tracksMissing) }
|
||||
func (c *Context) AlbumsMissing() int { return len(c.albumsMissing) }
|
||||
func (c *Context) ArtistsMissing() int { return c.artistsMissing }
|
||||
func (c *Context) GenresMissing() int { return c.genresMissing }
|
||||
|
||||
type MultiValueMode uint8
|
||||
|
||||
const (
|
||||
None MultiValueMode = iota
|
||||
Delim
|
||||
Multi
|
||||
)
|
||||
|
||||
type Tag uint8
|
||||
|
||||
const (
|
||||
Genre Tag = iota
|
||||
AlbumArtist
|
||||
)
|
||||
|
||||
type MultiValueSetting struct {
|
||||
Mode MultiValueMode
|
||||
Delim string
|
||||
}
|
||||
|
||||
func parseMulti(parser tags.Parser, setting MultiValueSetting, getMulti func(tags.Parser) []string, get func(tags.Parser) string) []string {
|
||||
var parts []string
|
||||
switch setting.Mode {
|
||||
case Multi:
|
||||
parts = getMulti(parser)
|
||||
case Delim:
|
||||
parts = strings.Split(get(parser), setting.Delim)
|
||||
default:
|
||||
parts = []string{get(parser)}
|
||||
}
|
||||
for i := range parts {
|
||||
parts[i] = strings.TrimSpace(parts[i])
|
||||
}
|
||||
return parts
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ func (t *Tagger) AlbumArtist() string { return first(find(t.raw, "albumartist
|
||||
func (t *Tagger) AlbumArtists() []string { return find(t.raw, "albumartists", "album_artists") }
|
||||
func (t *Tagger) AlbumBrainzID() string { return first(find(t.raw, "musicbrainz_albumid")) } // musicbrainz release ID
|
||||
func (t *Tagger) Genre() string { return first(find(t.raw, "genre")) }
|
||||
func (t *Tagger) Genres() []string { return find(t.raw, "genres") }
|
||||
|
||||
func (t *Tagger) TrackNumber() int {
|
||||
return intSep("/" /* eg. 5/12 */, first(find(t.raw, "tracknumber")))
|
||||
@@ -56,6 +57,7 @@ type Parser interface {
|
||||
AlbumArtists() []string
|
||||
AlbumBrainzID() string
|
||||
Genre() string
|
||||
Genres() []string
|
||||
TrackNumber() int
|
||||
DiscNumber() int
|
||||
Length() int
|
||||
@@ -127,17 +129,18 @@ func MustArtist(p Parser) string {
|
||||
return "Unknown Artist"
|
||||
}
|
||||
|
||||
func MustAlbumArtist(p Parser) string {
|
||||
if r := p.AlbumArtist(); r != "" {
|
||||
return r
|
||||
}
|
||||
return MustArtist(p)
|
||||
}
|
||||
|
||||
func MustAlbumArtists(p Parser) []string {
|
||||
if r := p.AlbumArtists(); len(r) > 0 {
|
||||
return r
|
||||
}
|
||||
if r := p.AlbumArtist(); r != "" {
|
||||
return []string{r}
|
||||
}
|
||||
if r := p.Artist(); r != "" {
|
||||
return []string{r}
|
||||
}
|
||||
return []string{"Unknown Artist"}
|
||||
return []string{MustAlbumArtist(p)}
|
||||
}
|
||||
|
||||
func MustGenre(p Parser) string {
|
||||
@@ -146,3 +149,10 @@ func MustGenre(p Parser) string {
|
||||
}
|
||||
return "Unknown Genre"
|
||||
}
|
||||
|
||||
func MustGenres(p Parser) []string {
|
||||
if r := p.Genres(); len(r) > 0 {
|
||||
return r
|
||||
}
|
||||
return []string{MustGenre(p)}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user