@@ -512,3 +512,64 @@ func (c *Controller) ServeGetSimilarSongs(r *http.Request) *spec.Response {
|
|||||||
}
|
}
|
||||||
return sub
|
return sub
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Controller) ServeGetSimilarSongsTwo(r *http.Request) *spec.Response {
|
||||||
|
params := r.Context().Value(CtxParams).(params.Params)
|
||||||
|
count := params.GetOrInt("count", 10)
|
||||||
|
id, err := params.GetID("id")
|
||||||
|
if err != nil || id.Type != specid.Artist {
|
||||||
|
return spec.NewError(10, "please provide an artist `id` parameter")
|
||||||
|
}
|
||||||
|
|
||||||
|
apiKey, _ := c.DB.GetSetting("lastfm_api_key")
|
||||||
|
if apiKey == "" {
|
||||||
|
return spec.NewResponse()
|
||||||
|
}
|
||||||
|
|
||||||
|
var artist db.Artist
|
||||||
|
err = c.DB.
|
||||||
|
Where("id=?", id.Value).
|
||||||
|
First(&artist).
|
||||||
|
Error
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return spec.NewError(0, "artist with id `%s` not found", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
similarArtists, err := lastfm.ArtistGetSimilar(apiKey, artist.Name)
|
||||||
|
if err != nil {
|
||||||
|
return spec.NewError(0, "fetching artist similar artists: %v", err)
|
||||||
|
}
|
||||||
|
if len(similarArtists.Artists) == 0 {
|
||||||
|
return spec.NewError(0, "no similar artist found for: %v", artist.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
artistNames := make([]string, len(similarArtists.Artists))
|
||||||
|
for i, similarArtist := range similarArtists.Artists {
|
||||||
|
artistNames[i] = similarArtist.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
var tracks []*db.Track
|
||||||
|
err = c.DB.
|
||||||
|
Preload("Album").
|
||||||
|
Joins("JOIN artists on tracks.artist_id=artists.id").
|
||||||
|
Where("artists.name IN (?)", artistNames).
|
||||||
|
Order(gorm.Expr("random()")).
|
||||||
|
Limit(count).
|
||||||
|
Find(&tracks).
|
||||||
|
Error
|
||||||
|
if err != nil {
|
||||||
|
return spec.NewError(0, "error finding tracks: %v", err)
|
||||||
|
}
|
||||||
|
if len(tracks) == 0 {
|
||||||
|
return spec.NewError(70, "no similar song could be match with collection in database: %v", artist.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
sub := spec.NewResponse()
|
||||||
|
sub.SimilarSongsTwo = &spec.SimilarSongsTwo{
|
||||||
|
Tracks: make([]*spec.TrackChild, len(tracks)),
|
||||||
|
}
|
||||||
|
for i, track := range tracks {
|
||||||
|
sub.SimilarSongsTwo.Tracks[i] = spec.NewTrackByTags(track, track.Album)
|
||||||
|
}
|
||||||
|
return sub
|
||||||
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ type Response struct {
|
|||||||
StarredTwo *StarredTwo `xml:"starred2" json:"starred2,omitempty"`
|
StarredTwo *StarredTwo `xml:"starred2" json:"starred2,omitempty"`
|
||||||
TopSongs *TopSongs `xml:"topSongs" json:"topSongs,omitempty"`
|
TopSongs *TopSongs `xml:"topSongs" json:"topSongs,omitempty"`
|
||||||
SimilarSongs *SimilarSongs `xml:"similarSongs" json:"similarSongs,omitempty"`
|
SimilarSongs *SimilarSongs `xml:"similarSongs" json:"similarSongs,omitempty"`
|
||||||
|
SimilarSongsTwo *SimilarSongsTwo `xml:"similarSongs2" json:"similarSongs2,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewResponse() *Response {
|
func NewResponse() *Response {
|
||||||
@@ -362,3 +363,7 @@ type TopSongs struct {
|
|||||||
type SimilarSongs struct {
|
type SimilarSongs struct {
|
||||||
Tracks []*TrackChild `xml:"song,omitempty" json:"song,omitempty"`
|
Tracks []*TrackChild `xml:"song,omitempty" json:"song,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SimilarSongsTwo struct {
|
||||||
|
Tracks []*TrackChild `xml:"song,omitempty" json:"song,omitempty"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ type LastFM struct {
|
|||||||
Artist Artist `xml:"artist"`
|
Artist Artist `xml:"artist"`
|
||||||
TopTracks TopTracks `xml:"toptracks"`
|
TopTracks TopTracks `xml:"toptracks"`
|
||||||
SimilarTracks SimilarTracks `xml:"similartracks"`
|
SimilarTracks SimilarTracks `xml:"similartracks"`
|
||||||
|
SimilarArtists SimilarArtists `xml:"similarartists"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Session struct {
|
type Session struct {
|
||||||
@@ -45,6 +46,18 @@ type Error struct {
|
|||||||
Value string `xml:",chardata"`
|
Value string `xml:",chardata"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SimilarArtist struct {
|
||||||
|
XMLName xml.Name `xml:"artist"`
|
||||||
|
Name string `xml:"name"`
|
||||||
|
MBID string `xml:"mbid"`
|
||||||
|
URL string `xml:"url"`
|
||||||
|
Image []struct {
|
||||||
|
Text string `xml:",chardata"`
|
||||||
|
Size string `xml:"size,attr"`
|
||||||
|
} `xml:"image"`
|
||||||
|
Streamable string `xml:"streamable"`
|
||||||
|
}
|
||||||
|
|
||||||
type Artist struct {
|
type Artist struct {
|
||||||
XMLName xml.Name `xml:"artist"`
|
XMLName xml.Name `xml:"artist"`
|
||||||
Name string `xml:"name"`
|
Name string `xml:"name"`
|
||||||
@@ -92,6 +105,12 @@ type SimilarTracks struct {
|
|||||||
Tracks []Track `xml:"track"`
|
Tracks []Track `xml:"track"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SimilarArtists struct {
|
||||||
|
XMLName xml.Name `xml:"similarartists"`
|
||||||
|
Artist string `xml:"artist,attr"`
|
||||||
|
Artists []Artist `xml:"artist"`
|
||||||
|
}
|
||||||
|
|
||||||
type Track struct {
|
type Track struct {
|
||||||
Rank int `xml:"rank,attr"`
|
Rank int `xml:"rank,attr"`
|
||||||
Tracks []Track `xml:"track"`
|
Tracks []Track `xml:"track"`
|
||||||
@@ -178,6 +197,19 @@ func TrackGetSimilarTracks(apiKey string, artistName, trackName string) (Similar
|
|||||||
}
|
}
|
||||||
return resp.SimilarTracks, nil
|
return resp.SimilarTracks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ArtistGetSimilar(apiKey string, artistName string) (SimilarArtists, error) {
|
||||||
|
params := url.Values{}
|
||||||
|
params.Add("method", "artist.getSimilar")
|
||||||
|
params.Add("api_key", apiKey)
|
||||||
|
params.Add("artist", artistName)
|
||||||
|
resp, err := makeRequest("GET", params)
|
||||||
|
if err != nil {
|
||||||
|
return SimilarArtists{}, fmt.Errorf("making similar artists GET: %w", err)
|
||||||
|
}
|
||||||
|
return resp.SimilarArtists, nil
|
||||||
|
}
|
||||||
|
|
||||||
func GetSession(apiKey, secret, token string) (string, error) {
|
func GetSession(apiKey, secret, token string) (string, error) {
|
||||||
params := url.Values{}
|
params := url.Values{}
|
||||||
params.Add("method", "auth.getSession")
|
params.Add("method", "auth.getSession")
|
||||||
|
|||||||
@@ -219,6 +219,7 @@ func setupSubsonic(r *mux.Router, ctrl *ctrlsubsonic.Controller) {
|
|||||||
r.Handle("/deleteBookmark{_:(?:\\.view)?}", ctrl.H(ctrl.ServeDeleteBookmark))
|
r.Handle("/deleteBookmark{_:(?:\\.view)?}", ctrl.H(ctrl.ServeDeleteBookmark))
|
||||||
r.Handle("/getTopSongs{_:(?:\\.view)?}", ctrl.H(ctrl.ServeGetTopSongs))
|
r.Handle("/getTopSongs{_:(?:\\.view)?}", ctrl.H(ctrl.ServeGetTopSongs))
|
||||||
r.Handle("/getSimilarSongs{_:(?:\\.view)?}", ctrl.H(ctrl.ServeGetSimilarSongs))
|
r.Handle("/getSimilarSongs{_:(?:\\.view)?}", ctrl.H(ctrl.ServeGetSimilarSongs))
|
||||||
|
r.Handle("/getSimilarSongs2{_:(?:\\.view)?}", ctrl.H(ctrl.ServeGetSimilarSongsTwo))
|
||||||
|
|
||||||
// raw
|
// raw
|
||||||
r.Handle("/download{_:(?:\\.view)?}", ctrl.HR(ctrl.ServeDownload))
|
r.Handle("/download{_:(?:\\.view)?}", ctrl.HR(ctrl.ServeDownload))
|
||||||
|
|||||||
Reference in New Issue
Block a user