Better way to match top songs from external sources (Last.fm)

This commit is contained in:
Deluan 2021-10-23 20:19:15 -04:00
parent 31c598de07
commit cc1659aa73
4 changed files with 69 additions and 1 deletions

View File

@ -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

View File

@ -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
}

View File

@ -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"`

View File

@ -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)