🏡 index : quine-global/quintodrome.git

package agents

import (
	"context"

	"github.com/Masterminds/squirrel"
	"github.com/navidrome/navidrome/model"
	"github.com/navidrome/navidrome/persistence"
	"github.com/navidrome/navidrome/utils/slice"
)

const LocalAgentName = "local"

type localAgent struct {
	ds model.DataStore
}

func localsConstructor(ds model.DataStore) Interface {
	return &localAgent{ds}
}

func (p *localAgent) AgentName() string {
	return LocalAgentName
}

func (p *localAgent) GetArtistTopSongs(ctx context.Context, id, artistName, mbid string, count int) ([]Song, error) {
	top, err := p.ds.MediaFile().GetAll(ctx, model.QueryOptions{
		Sort:  "playCount",
		Order: "desc",
		Max:   count,
		Filters: squirrel.And{
			squirrel.Eq{"artist_id": id},
			squirrel.Or{
				squirrel.Eq{"starred": true},
				squirrel.Eq{"rating": 5},
			},
		},
	})
	if err != nil {
		return nil, err
	}
	return songsFrom(top), nil
}

func (p *localAgent) GetSimilarSongsByTrack(ctx context.Context, id, name, artist, mbid string, count int) ([]Song, error) {
	seed, err := p.ds.MediaFile().Get(ctx, id)
	if err != nil {
		return nil, err
	}
	// Tag ids derive from (name, value), so the seed's genre ids need no extra query.
	genreIDs := slice.Map(seed.Tags.Flatten(model.TagGenre), func(t model.Tag) string { return t.ID })
	if len(genreIDs) == 0 {
		return nil, nil
	}
	// Ask for extra so we can drop the seed itself and still fill the count.
	candidates, err := p.ds.MediaFile().GetRandom(ctx, model.QueryOptions{
		Filters: squirrel.And{
			persistence.SongGenres.ByID(genreIDs),
			squirrel.Eq{"missing": false},
		},
		Max: count + 1,
	})
	if err != nil {
		return nil, err
	}
	filtered := make(model.MediaFiles, 0, len(candidates))
	for _, s := range candidates {
		if s.ID == id {
			continue
		}
		filtered = append(filtered, s)
		if len(filtered) >= count {
			break
		}
	}
	return songsFrom(filtered), nil
}

func songsFrom(mfs model.MediaFiles) []Song {
	if len(mfs) == 0 {
		return nil
	}

	return slice.Map(mfs, func(mf model.MediaFile) Song {
		return Song{ID: mf.ID, Name: mf.Title}
	})
}

func init() {
	Register(LocalAgentName, localsConstructor)
}