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
+4 -1
View File
@@ -8,6 +8,7 @@ import (
"time" "time"
"github.com/Masterminds/squirrel" "github.com/Masterminds/squirrel"
"github.com/kennygrant/sanitize"
"github.com/microcosm-cc/bluemonday" "github.com/microcosm-cc/bluemonday"
"github.com/navidrome/navidrome/consts" "github.com/navidrome/navidrome/consts"
"github.com/navidrome/navidrome/core/agents" "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 { if err == nil && len(mfs) > 0 {
return &mfs[0], nil return &mfs[0], nil
} }
return e.findMatchingTrack(ctx, "", artistID, title)
} }
mfs, err := e.ds.MediaFile(ctx).GetAll(model.QueryOptions{ mfs, err := e.ds.MediaFile(ctx).GetAll(model.QueryOptions{
Filters: squirrel.And{ Filters: squirrel.And{
@@ -249,9 +251,10 @@ func (e *externalMetadata) findMatchingTrack(ctx context.Context, mbid string, a
squirrel.Eq{"artist_id": artistID}, squirrel.Eq{"artist_id": artistID},
squirrel.Eq{"album_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", Sort: "starred desc, rating desc, year asc",
Max: 1,
}) })
if err != nil || len(mfs) == 0 { if err != nil || len(mfs) == 0 {
return nil, model.ErrNotFound return nil, model.ErrNotFound
@@ -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
}
+1
View File
@@ -35,6 +35,7 @@ type MediaFile struct {
SortAlbumName string `structs:"sort_album_name" json:"sortAlbumName,omitempty"` SortAlbumName string `structs:"sort_album_name" json:"sortAlbumName,omitempty"`
SortArtistName string `structs:"sort_artist_name" json:"sortArtistName,omitempty"` SortArtistName string `structs:"sort_artist_name" json:"sortArtistName,omitempty"`
SortAlbumArtistName string `structs:"sort_album_artist_name" json:"sortAlbumArtistName,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"` OrderAlbumName string `structs:"order_album_name" json:"orderAlbumName"`
OrderArtistName string `structs:"order_artist_name" json:"orderArtistName"` OrderArtistName string `structs:"order_artist_name" json:"orderArtistName"`
OrderAlbumArtistName string `structs:"order_album_artist_name" json:"orderAlbumArtistName"` OrderAlbumArtistName string `structs:"order_album_artist_name" json:"orderAlbumArtistName"`
+2
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 { func (s mediaFileMapper) toMediaFile(md metadata.Tags) model.MediaFile {
mf := &model.MediaFile{} mf := &model.MediaFile{}
mf.ID = s.trackID(md) mf.ID = s.trackID(md)
@@ -59,6 +60,7 @@ func (s mediaFileMapper) toMediaFile(md metadata.Tags) model.MediaFile {
mf.SortAlbumName = md.SortAlbum() mf.SortAlbumName = md.SortAlbum()
mf.SortArtistName = md.SortArtist() mf.SortArtistName = md.SortArtist()
mf.SortAlbumArtistName = md.SortAlbumArtist() mf.SortAlbumArtistName = md.SortAlbumArtist()
mf.OrderTitle = strings.TrimSpace(sanitize.Accents(mf.Title))
mf.OrderAlbumName = sanitizeFieldForSorting(mf.Album) mf.OrderAlbumName = sanitizeFieldForSorting(mf.Album)
mf.OrderArtistName = sanitizeFieldForSorting(mf.Artist) mf.OrderArtistName = sanitizeFieldForSorting(mf.Artist)
mf.OrderAlbumArtistName = sanitizeFieldForSorting(mf.AlbumArtist) mf.OrderAlbumArtistName = sanitizeFieldForSorting(mf.AlbumArtist)