feat(subsonic): make it easier to add more tag reading backends
related https://github.com/sentriz/gonic/issues/379 related https://github.com/sentriz/gonic/issues/324 related https://github.com/sentriz/gonic/issues/244
This commit is contained in:
@@ -15,7 +15,7 @@ import (
|
||||
"github.com/mattn/go-sqlite3"
|
||||
"go.senan.xyz/gonic/db"
|
||||
"go.senan.xyz/gonic/scanner"
|
||||
"go.senan.xyz/gonic/scanner/tags"
|
||||
"go.senan.xyz/gonic/scanner/tags/tagcommon"
|
||||
)
|
||||
|
||||
var ErrPathNotFound = errors.New("path not found")
|
||||
@@ -69,7 +69,7 @@ func newMockFS(tb testing.TB, dirs []string, excludePattern string) *MockFS {
|
||||
scanner.AlbumArtist: {Mode: scanner.Multi},
|
||||
}
|
||||
|
||||
tagReader := &tagReader{paths: map[string]*tagReaderResult{}}
|
||||
tagReader := &tagReader{paths: map[string]*TagInfo{}}
|
||||
scanner := scanner.New(absDirs, dbc, multiValueSettings, tagReader, excludePattern)
|
||||
|
||||
return &MockFS{
|
||||
@@ -81,11 +81,13 @@ func newMockFS(tb testing.TB, dirs []string, excludePattern string) *MockFS {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MockFS) DB() *db.DB { return m.db }
|
||||
func (m *MockFS) TmpDir() string { return m.dir }
|
||||
func (m *MockFS) TagReader() tags.Reader { return m.tagReader }
|
||||
func (m *MockFS) DB() *db.DB { return m.db }
|
||||
func (m *MockFS) TmpDir() string { return m.dir }
|
||||
func (m *MockFS) TagReader() tagcommon.Reader { return m.tagReader }
|
||||
|
||||
func (m *MockFS) ScanAndClean() *scanner.Context {
|
||||
m.t.Helper()
|
||||
|
||||
ctx, err := m.scanner.ScanAndClean(scanner.ScanOptions{})
|
||||
if err != nil {
|
||||
m.t.Fatalf("error scan and cleaning: %v", err)
|
||||
@@ -94,6 +96,8 @@ func (m *MockFS) ScanAndClean() *scanner.Context {
|
||||
}
|
||||
|
||||
func (m *MockFS) ScanAndCleanErr() (*scanner.Context, error) {
|
||||
m.t.Helper()
|
||||
|
||||
return m.scanner.ScanAndClean(scanner.ScanOptions{})
|
||||
}
|
||||
|
||||
@@ -126,12 +130,11 @@ func (m *MockFS) addItems(prefix string, onlyGlob string, covers bool) {
|
||||
}
|
||||
|
||||
m.AddTrack(path)
|
||||
m.SetTags(path, func(tags *Tags) error {
|
||||
m.SetTags(path, func(tags *TagInfo) {
|
||||
tags.RawArtist = fmt.Sprintf("artist-%d", ar)
|
||||
tags.RawAlbumArtist = fmt.Sprintf("artist-%d", ar)
|
||||
tags.RawAlbum = fmt.Sprintf("album-%d", al)
|
||||
tags.RawTitle = fmt.Sprintf("title-%d", tr)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
if covers {
|
||||
@@ -180,10 +183,9 @@ func (m *MockFS) SetRealAudio(path string, length int, audioPath string) {
|
||||
if err := os.Symlink(filepath.Join(wd, audioPath), abspath); err != nil {
|
||||
m.t.Fatalf("symlink: %v", err)
|
||||
}
|
||||
m.SetTags(path, func(tags *Tags) error {
|
||||
m.SetTags(path, func(tags *TagInfo) {
|
||||
tags.RawLength = length
|
||||
tags.RawBitrate = 0
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -288,18 +290,15 @@ func (m *MockFS) AddCover(path string) {
|
||||
defer f.Close()
|
||||
}
|
||||
|
||||
func (m *MockFS) SetTags(path string, cb func(*Tags) error) {
|
||||
abspath := filepath.Join(m.dir, path)
|
||||
if err := os.Chtimes(abspath, time.Time{}, time.Now()); err != nil {
|
||||
func (m *MockFS) SetTags(path string, cb func(*TagInfo)) {
|
||||
absPath := filepath.Join(m.dir, path)
|
||||
if err := os.Chtimes(absPath, time.Time{}, time.Now()); err != nil {
|
||||
m.t.Fatalf("touch track: %v", err)
|
||||
}
|
||||
r := m.tagReader
|
||||
if _, ok := r.paths[abspath]; !ok {
|
||||
r.paths[abspath] = &tagReaderResult{tags: &Tags{}}
|
||||
}
|
||||
if err := cb(r.paths[abspath].tags); err != nil {
|
||||
r.paths[abspath].err = err
|
||||
if _, ok := m.tagReader.paths[absPath]; !ok {
|
||||
m.tagReader.paths[absPath] = &TagInfo{}
|
||||
}
|
||||
cb(m.tagReader.paths[absPath])
|
||||
}
|
||||
|
||||
func (m *MockFS) DumpDB(suffix ...string) {
|
||||
@@ -353,54 +352,54 @@ func (m *MockFS) DumpDB(suffix ...string) {
|
||||
m.t.Error(destPath)
|
||||
}
|
||||
|
||||
type tagReaderResult struct {
|
||||
tags *Tags
|
||||
err error
|
||||
}
|
||||
|
||||
type tagReader struct {
|
||||
paths map[string]*tagReaderResult
|
||||
paths map[string]*TagInfo
|
||||
}
|
||||
|
||||
func (m *tagReader) Read(abspath string) (tags.Parser, error) {
|
||||
p, ok := m.paths[abspath]
|
||||
func (m *tagReader) CanRead(absPath string) bool {
|
||||
stat, _ := os.Stat(absPath)
|
||||
return stat.Mode().IsRegular()
|
||||
}
|
||||
|
||||
func (m *tagReader) Read(absPath string) (tagcommon.Info, error) {
|
||||
p, ok := m.paths[absPath]
|
||||
if !ok {
|
||||
return nil, ErrPathNotFound
|
||||
}
|
||||
return p.tags, p.err
|
||||
if p.Error != nil {
|
||||
return nil, p.Error
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
var _ tags.Reader = (*tagReader)(nil)
|
||||
|
||||
type Tags struct {
|
||||
type TagInfo struct {
|
||||
RawTitle string
|
||||
RawArtist string
|
||||
RawAlbum string
|
||||
RawAlbumArtist string
|
||||
RawAlbumArtists []string
|
||||
RawGenre string
|
||||
|
||||
RawBitrate int
|
||||
RawLength int
|
||||
RawBitrate int
|
||||
RawLength int
|
||||
Error error
|
||||
}
|
||||
|
||||
func (m *Tags) Title() string { return m.RawTitle }
|
||||
func (m *Tags) BrainzID() string { return "" }
|
||||
func (m *Tags) Artist() string { return m.RawArtist }
|
||||
func (m *Tags) Album() string { return m.RawAlbum }
|
||||
func (m *Tags) AlbumArtist() string { return m.RawAlbumArtist }
|
||||
func (m *Tags) AlbumArtists() []string { return m.RawAlbumArtists }
|
||||
func (m *Tags) AlbumBrainzID() string { return "" }
|
||||
func (m *Tags) Genre() string { return m.RawGenre }
|
||||
func (m *Tags) Genres() []string { return []string{m.RawGenre} }
|
||||
func (m *Tags) TrackNumber() int { return 1 }
|
||||
func (m *Tags) DiscNumber() int { return 1 }
|
||||
func (m *Tags) Year() int { return 2021 }
|
||||
func (i *TagInfo) Title() string { return i.RawTitle }
|
||||
func (i *TagInfo) BrainzID() string { return "" }
|
||||
func (i *TagInfo) Artist() string { return i.RawArtist }
|
||||
func (i *TagInfo) Album() string { return i.RawAlbum }
|
||||
func (i *TagInfo) AlbumArtist() string { return i.RawAlbumArtist }
|
||||
func (i *TagInfo) AlbumArtists() []string { return i.RawAlbumArtists }
|
||||
func (i *TagInfo) AlbumBrainzID() string { return "" }
|
||||
func (i *TagInfo) Genre() string { return i.RawGenre }
|
||||
func (i *TagInfo) Genres() []string { return []string{i.RawGenre} }
|
||||
func (i *TagInfo) TrackNumber() int { return 1 }
|
||||
func (i *TagInfo) DiscNumber() int { return 1 }
|
||||
func (i *TagInfo) Year() int { return 2021 }
|
||||
func (i *TagInfo) Length() int { return firstInt(100, i.RawLength) }
|
||||
func (i *TagInfo) Bitrate() int { return firstInt(100, i.RawBitrate) }
|
||||
|
||||
func (m *Tags) Length() int { return firstInt(100, m.RawLength) }
|
||||
func (m *Tags) Bitrate() int { return firstInt(100, m.RawBitrate) }
|
||||
|
||||
var _ tags.Parser = (*Tags)(nil)
|
||||
var _ tagcommon.Reader = (*tagReader)(nil)
|
||||
|
||||
func firstInt(or int, ints ...int) int {
|
||||
for _, int := range ints {
|
||||
|
||||
Reference in New Issue
Block a user