diff --git a/core/external_metadata.go b/core/external_metadata.go index 8ab6e4055..9ae9c6779 100644 --- a/core/external_metadata.go +++ b/core/external_metadata.go @@ -8,6 +8,7 @@ import ( "time" "github.com/Masterminds/squirrel" + "github.com/kennygrant/sanitize" "github.com/microcosm-cc/bluemonday" "github.com/navidrome/navidrome/consts" "github.com/navidrome/navidrome/core/agents" @@ -242,6 +243,7 @@ func (e *externalMetadata) findMatchingTrack(ctx context.Context, mbid string, a if err == nil && len(mfs) > 0 { return &mfs[0], nil } + return e.findMatchingTrack(ctx, "", artistID, title) } mfs, err := e.ds.MediaFile(ctx).GetAll(model.QueryOptions{ Filters: squirrel.And{ @@ -249,9 +251,10 @@ func (e *externalMetadata) findMatchingTrack(ctx context.Context, mbid string, a squirrel.Eq{"artist_id": artistID}, squirrel.Eq{"album_artist_id": artistID}, }, - squirrel.Like{"title": title}, + squirrel.Like{"order_title": strings.TrimSpace(sanitize.Accents(title))}, }, Sort: "starred desc, rating desc, year asc", + Max: 1, }) if err != nil || len(mfs) == 0 { return nil, model.ErrNotFound diff --git a/db/migration/20211023184825_add_order_title_to_media_file.go b/db/migration/20211023184825_add_order_title_to_media_file.go new file mode 100644 index 000000000..012ab76d4 --- /dev/null +++ b/db/migration/20211023184825_add_order_title_to_media_file.go @@ -0,0 +1,62 @@ +package migrations + +import ( + "database/sql" + "strings" + + "github.com/kennygrant/sanitize" + "github.com/navidrome/navidrome/log" + + "github.com/pressly/goose" +) + +func init() { + goose.AddMigration(upAddOrderTitleToMediaFile, downAddOrderTitleToMediaFile) +} + +func upAddOrderTitleToMediaFile(tx *sql.Tx) error { + _, err := tx.Exec(` +alter table main.media_file + add order_title varchar null collate NOCASE; +create index if not exists media_file_order_title + on media_file (order_title); +`) + if err != nil { + return err + } + + return upAddOrderTitleToMediaFile_populateOrderTitle(tx) +} + +//goland:noinspection GoSnakeCaseUsage +func upAddOrderTitleToMediaFile_populateOrderTitle(tx *sql.Tx) error { + rows, err := tx.Query(`select id, title from media_file`) + if err != nil { + return err + } + defer rows.Close() + + stmt, err := tx.Prepare("update media_file set order_title = ? where id = ?") + if err != nil { + return err + } + + var id, title string + for rows.Next() { + err = rows.Scan(&id, &title) + if err != nil { + return err + } + + orderTitle := strings.TrimSpace(sanitize.Accents(title)) + _, err = stmt.Exec(orderTitle, id) + if err != nil { + log.Error("Error setting media_file's order_title", "title", title, "id", id, err) + } + } + return rows.Err() +} + +func downAddOrderTitleToMediaFile(tx *sql.Tx) error { + return nil +} diff --git a/model/mediafile.go b/model/mediafile.go index 41e0ed265..27e91797c 100644 --- a/model/mediafile.go +++ b/model/mediafile.go @@ -35,6 +35,7 @@ type MediaFile struct { SortAlbumName string `structs:"sort_album_name" json:"sortAlbumName,omitempty"` SortArtistName string `structs:"sort_artist_name" json:"sortArtistName,omitempty"` SortAlbumArtistName string `structs:"sort_album_artist_name" json:"sortAlbumArtistName,omitempty"` + OrderTitle string `structs:"order_title" json:"orderTitle,omitempty"` OrderAlbumName string `structs:"order_album_name" json:"orderAlbumName"` OrderArtistName string `structs:"order_artist_name" json:"orderArtistName"` OrderAlbumArtistName string `structs:"order_album_artist_name" json:"orderAlbumArtistName"` diff --git a/scanner/mapping.go b/scanner/mapping.go index 500f2d194..2930b0eea 100644 --- a/scanner/mapping.go +++ b/scanner/mapping.go @@ -31,6 +31,7 @@ func newMediaFileMapper(rootFolder string, genres model.GenreRepository) *mediaF } } +// TODO Move most of these mapping functions to setters in the model.MediaFile func (s mediaFileMapper) toMediaFile(md metadata.Tags) model.MediaFile { mf := &model.MediaFile{} mf.ID = s.trackID(md) @@ -59,6 +60,7 @@ func (s mediaFileMapper) toMediaFile(md metadata.Tags) model.MediaFile { mf.SortAlbumName = md.SortAlbum() mf.SortArtistName = md.SortArtist() mf.SortAlbumArtistName = md.SortAlbumArtist() + mf.OrderTitle = strings.TrimSpace(sanitize.Accents(mf.Title)) mf.OrderAlbumName = sanitizeFieldForSorting(mf.Album) mf.OrderArtistName = sanitizeFieldForSorting(mf.Artist) mf.OrderAlbumArtistName = sanitizeFieldForSorting(mf.AlbumArtist)