diff --git a/db/migration/20201110205344_add_comments_and_lyrics.go b/db/migration/20201110205344_add_comments_and_lyrics.go new file mode 100644 index 000000000..1bd8e4ad7 --- /dev/null +++ b/db/migration/20201110205344_add_comments_and_lyrics.go @@ -0,0 +1,32 @@ +package migration + +import ( + "database/sql" + + "github.com/pressly/goose" +) + +func init() { + goose.AddMigration(Up20201110205344, Down20201110205344) +} + +func Up20201110205344(tx *sql.Tx) error { + _, err := tx.Exec(` +alter table media_file + add comment varchar; +alter table media_file + add lyrics varchar; + +alter table album + add comment varchar; +`) + if err != nil { + return err + } + notice(tx, "A full rescan will be performed to import comments and lyrics") + return forceFullRescan(tx) +} + +func Down20201110205344(tx *sql.Tx) error { + return nil +} diff --git a/model/album.go b/model/album.go index cbb10f11f..8a712b901 100644 --- a/model/album.go +++ b/model/album.go @@ -16,6 +16,7 @@ type Album struct { MaxYear int `json:"maxYear"` MinYear int `json:"minYear"` Compilation bool `json:"compilation"` + Comment string `json:"comment"` SongCount int `json:"songCount"` Duration float32 `json:"duration"` Genre string `json:"genre"` diff --git a/model/mediafile.go b/model/mediafile.go index ce1e26a05..f54a778e2 100644 --- a/model/mediafile.go +++ b/model/mediafile.go @@ -37,6 +37,8 @@ type MediaFile struct { OrderArtistName string `json:"orderArtistName"` OrderAlbumArtistName string `json:"orderAlbumArtistName"` Compilation bool `json:"compilation"` + Comment string `json:"comment"` + Lyrics string `json:"lyrics"` CatalogNum string `json:"catalogNum"` MbzTrackID string `json:"mbzTrackId" orm:"column(mbz_track_id)"` MbzAlbumID string `json:"mbzAlbumId" orm:"column(mbz_album_id)"` diff --git a/persistence/album_repository.go b/persistence/album_repository.go index 8c758ef07..5268049b0 100644 --- a/persistence/album_repository.go +++ b/persistence/album_repository.go @@ -155,12 +155,14 @@ func (r *albumRepository) refresh(ids ...string) error { SongArtists string Years string DiscSubtitles string + Comments string Path string } var albums []refreshAlbum + const zwsp = string('\u200b') sel := Select(`f.album_id as id, f.album as name, f.artist, f.album_artist, f.artist_id, f.album_artist_id, f.sort_album_name, f.sort_artist_name, f.sort_album_artist_name, - f.order_album_name, f.order_album_artist_name, f.path, + f.order_album_name, f.order_album_artist_name, f.path, group_concat(f.comment, "` + zwsp + `") as comments, group_concat(f.mbz_album_id, ' ') as mbz_album_id, f.mbz_album_artist_id, f.mbz_album_type, f.mbz_album_comment, f.catalog_num, f.compilation, f.genre, max(f.year) as max_year, sum(f.duration) as duration, count(f.id) as song_count, a.id as current_id, @@ -212,6 +214,7 @@ func (r *albumRepository) refresh(ids ...string) error { } al.MinYear = getMinYear(al.Years) al.MbzAlbumID = getMbzId(r.ctx, al.MbzAlbumID, r.tableName, al.Name) + al.Comment = getComment(al.Comments, zwsp) al.UpdatedAt = time.Now() if al.CurrentId != "" { toUpdate++ @@ -235,6 +238,17 @@ func (r *albumRepository) refresh(ids ...string) error { return err } +// Return the first non empty comment, if any +func getComment(comments string, separator string) string { + cs := strings.Split(comments, separator) + for _, c := range cs { + if c != "" { + return c + } + } + return "" +} + func getMinYear(years string) int { ys := strings.Fields(years) sort.Strings(ys) diff --git a/persistence/album_repository_test.go b/persistence/album_repository_test.go index 3f8c3c616..8b700a0e1 100644 --- a/persistence/album_repository_test.go +++ b/persistence/album_repository_test.go @@ -91,6 +91,16 @@ var _ = Describe("AlbumRepository", func() { }) }) + Describe("getComment", func() { + const zwsp = string('\u200b') + It("returns empty string if there are no comments", func() { + Expect(getComment("", "")).To(Equal("")) + }) + It("returns first occurrence of non-empty comment", func() { + Expect(getComment(zwsp+zwsp+"first"+zwsp+"second", zwsp)).To(Equal("first")) + }) + }) + Describe("getCoverFromPath", func() { testFolder, _ := ioutil.TempDir("", "album_persistence_tests") if err := os.MkdirAll(testFolder, 0777); err != nil { diff --git a/scanner/mapping.go b/scanner/mapping.go index 27142fe61..b6723c5dc 100644 --- a/scanner/mapping.go +++ b/scanner/mapping.go @@ -59,6 +59,8 @@ func (s *mediaFileMapper) toMediaFile(md metadata.Metadata) model.MediaFile { mf.MbzAlbumArtistID = md.MbzAlbumArtistID() mf.MbzAlbumType = md.MbzAlbumType() mf.MbzAlbumComment = md.MbzAlbumComment() + mf.Comment = md.Comment() + mf.Lyrics = md.Lyrics() // TODO Get Creation time. https://github.com/djherbis/times ? mf.CreatedAt = md.ModificationTime() diff --git a/scanner/metadata/metadata.go b/scanner/metadata/metadata.go index 2bd6883a2..bae0d940e 100644 --- a/scanner/metadata/metadata.go +++ b/scanner/metadata/metadata.go @@ -51,6 +51,7 @@ type Metadata interface { DiscSubtitle() string HasPicture() bool Comment() string + Lyrics() string Compilation() bool CatalogNum() string MbzTrackID() string @@ -89,6 +90,7 @@ func (m *baseMetadata) Composer() string { return m.getTag("composer", "t func (m *baseMetadata) Genre() string { return m.getTag("genre") } func (m *baseMetadata) Year() int { return m.parseYear("date") } func (m *baseMetadata) Comment() string { return m.getTag("comment") } +func (m *baseMetadata) Lyrics() string { return m.getTag("lyrics", "lyrics-eng") } func (m *baseMetadata) Compilation() bool { return m.parseBool("tcmp", "compilation") } func (m *baseMetadata) TrackNumber() (int, int) { return m.parseTuple("track", "tracknumber") } func (m *baseMetadata) DiscNumber() (int, int) { return m.parseTuple("disc", "discnumber") }