mirror of
https://github.com/gabehf/Koito.git
synced 2026-03-07 21:48:18 -08:00
fix: improve subsonic image searching (#164)
This commit is contained in:
parent
1a8099e902
commit
56ac73d12b
3 changed files with 53 additions and 12 deletions
|
|
@ -363,8 +363,9 @@ func FetchMissingAlbumImages(ctx context.Context, store db.DB) error {
|
||||||
|
|
||||||
var imgid uuid.UUID
|
var imgid uuid.UUID
|
||||||
imgUrl, imgErr := images.GetAlbumImage(ctx, images.AlbumImageOpts{
|
imgUrl, imgErr := images.GetAlbumImage(ctx, images.AlbumImageOpts{
|
||||||
Artists: utils.FlattenSimpleArtistNames(album.Artists),
|
Artists: utils.FlattenSimpleArtistNames(album.Artists),
|
||||||
Album: album.Title,
|
Album: album.Title,
|
||||||
|
ReleaseMbzID: album.MbzID,
|
||||||
})
|
})
|
||||||
if imgErr == nil && imgUrl != "" {
|
if imgErr == nil && imgUrl != "" {
|
||||||
imgid = uuid.New()
|
imgid = uuid.New()
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ var imgsrc ImageSource
|
||||||
|
|
||||||
type ArtistImageOpts struct {
|
type ArtistImageOpts struct {
|
||||||
Aliases []string
|
Aliases []string
|
||||||
|
MBID *uuid.UUID
|
||||||
}
|
}
|
||||||
|
|
||||||
type AlbumImageOpts struct {
|
type AlbumImageOpts struct {
|
||||||
|
|
@ -66,7 +67,7 @@ func Shutdown() {
|
||||||
func GetArtistImage(ctx context.Context, opts ArtistImageOpts) (string, error) {
|
func GetArtistImage(ctx context.Context, opts ArtistImageOpts) (string, error) {
|
||||||
l := logger.FromContext(ctx)
|
l := logger.FromContext(ctx)
|
||||||
if imgsrc.subsonicEnabled {
|
if imgsrc.subsonicEnabled {
|
||||||
img, err := imgsrc.subsonicC.GetArtistImage(ctx, opts.Aliases[0])
|
img, err := imgsrc.subsonicC.GetArtistImage(ctx, opts.MBID, opts.Aliases[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Debug().Err(err).Msg("GetArtistImage: Could not find artist image from Subsonic")
|
l.Debug().Err(err).Msg("GetArtistImage: Could not find artist image from Subsonic")
|
||||||
} else if img != "" {
|
} else if img != "" {
|
||||||
|
|
@ -92,7 +93,7 @@ func GetArtistImage(ctx context.Context, opts ArtistImageOpts) (string, error) {
|
||||||
func GetAlbumImage(ctx context.Context, opts AlbumImageOpts) (string, error) {
|
func GetAlbumImage(ctx context.Context, opts AlbumImageOpts) (string, error) {
|
||||||
l := logger.FromContext(ctx)
|
l := logger.FromContext(ctx)
|
||||||
if imgsrc.subsonicEnabled {
|
if imgsrc.subsonicEnabled {
|
||||||
img, err := imgsrc.subsonicC.GetAlbumImage(ctx, opts.Artists[0], opts.Album)
|
img, err := imgsrc.subsonicC.GetAlbumImage(ctx, opts.ReleaseMbzID, opts.Artists[0], opts.Album)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Debug().Err(err).Msg("GetAlbumImage: Could not find artist image from Subsonic")
|
l.Debug().Err(err).Msg("GetAlbumImage: Could not find artist image from Subsonic")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/gabehf/koito/internal/cfg"
|
"github.com/gabehf/koito/internal/cfg"
|
||||||
"github.com/gabehf/koito/internal/logger"
|
"github.com/gabehf/koito/internal/logger"
|
||||||
"github.com/gabehf/koito/queue"
|
"github.com/gabehf/koito/queue"
|
||||||
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SubsonicClient struct {
|
type SubsonicClient struct {
|
||||||
|
|
@ -26,6 +27,8 @@ type SubsonicAlbumResponse struct {
|
||||||
SearchResult3 struct {
|
SearchResult3 struct {
|
||||||
Album []struct {
|
Album []struct {
|
||||||
CoverArt string `json:"coverArt"`
|
CoverArt string `json:"coverArt"`
|
||||||
|
Artist string `json:"artist"`
|
||||||
|
MBID string `json:"musicBrainzId"`
|
||||||
} `json:"album"`
|
} `json:"album"`
|
||||||
} `json:"searchResult3"`
|
} `json:"searchResult3"`
|
||||||
} `json:"subsonic-response"`
|
} `json:"subsonic-response"`
|
||||||
|
|
@ -43,7 +46,7 @@ type SubsonicArtistResponse struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
subsonicAlbumSearchFmtStr = "/rest/search3?%s&f=json&query=%s&v=1.13.0&c=koito&artistCount=0&songCount=0&albumCount=1"
|
subsonicAlbumSearchFmtStr = "/rest/search3?%s&f=json&query=%s&v=1.13.0&c=koito&artistCount=0&songCount=0&albumCount=10"
|
||||||
subsonicArtistSearchFmtStr = "/rest/search3?%s&f=json&query=%s&v=1.13.0&c=koito&artistCount=1&songCount=0&albumCount=0"
|
subsonicArtistSearchFmtStr = "/rest/search3?%s&f=json&query=%s&v=1.13.0&c=koito&artistCount=1&songCount=0&albumCount=0"
|
||||||
subsonicCoverArtFmtStr = "/rest/getCoverArt?%s&id=%s&v=1.13.0&c=koito"
|
subsonicCoverArtFmtStr = "/rest/getCoverArt?%s&id=%s&v=1.13.0&c=koito"
|
||||||
)
|
)
|
||||||
|
|
@ -106,25 +109,61 @@ func (c *SubsonicClient) getEntity(ctx context.Context, endpoint string, result
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SubsonicClient) GetAlbumImage(ctx context.Context, artist, album string) (string, error) {
|
func (c *SubsonicClient) GetAlbumImage(ctx context.Context, mbid *uuid.UUID, artist, album string) (string, error) {
|
||||||
l := logger.FromContext(ctx)
|
l := logger.FromContext(ctx)
|
||||||
resp := new(SubsonicAlbumResponse)
|
resp := new(SubsonicAlbumResponse)
|
||||||
l.Debug().Msgf("Finding album image for %s from artist %s", album, artist)
|
l.Debug().Msgf("Finding album image for %s from artist %s", album, artist)
|
||||||
err := c.getEntity(ctx, fmt.Sprintf(subsonicAlbumSearchFmtStr, c.authParams, url.QueryEscape(artist+" "+album)), resp)
|
// first try mbid search
|
||||||
|
if mbid != nil {
|
||||||
|
l.Debug().Str("mbid", mbid.String()).Msg("Searching album image by MBID")
|
||||||
|
err := c.getEntity(ctx, fmt.Sprintf(subsonicAlbumSearchFmtStr, c.authParams, url.QueryEscape(mbid.String())), resp)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("GetAlbumImage: %v", err)
|
||||||
|
}
|
||||||
|
l.Debug().Any("subsonic_response", resp).Msg("")
|
||||||
|
if len(resp.SubsonicResponse.SearchResult3.Album) >= 1 {
|
||||||
|
return cfg.SubsonicUrl() + fmt.Sprintf(subsonicCoverArtFmtStr, c.authParams, url.QueryEscape(resp.SubsonicResponse.SearchResult3.Album[0].CoverArt)), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// else do artist match
|
||||||
|
l.Debug().Str("title", album).Str("artist", artist).Msg("Searching album image by title and artist")
|
||||||
|
err := c.getEntity(ctx, fmt.Sprintf(subsonicAlbumSearchFmtStr, c.authParams, url.QueryEscape(album)), resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("GetAlbumImage: %v", err)
|
return "", fmt.Errorf("GetAlbumImage: %v", err)
|
||||||
}
|
}
|
||||||
l.Debug().Any("subsonic_response", resp).Send()
|
l.Debug().Any("subsonic_response", resp).Msg("")
|
||||||
if len(resp.SubsonicResponse.SearchResult3.Album) < 1 || resp.SubsonicResponse.SearchResult3.Album[0].CoverArt == "" {
|
if len(resp.SubsonicResponse.SearchResult3.Album) < 1 {
|
||||||
return "", fmt.Errorf("GetAlbumImage: failed to get album art")
|
return "", fmt.Errorf("GetAlbumImage: failed to get album art from subsonic")
|
||||||
}
|
}
|
||||||
return cfg.SubsonicUrl() + fmt.Sprintf(subsonicCoverArtFmtStr, c.authParams, url.QueryEscape(resp.SubsonicResponse.SearchResult3.Album[0].CoverArt)), nil
|
for _, album := range resp.SubsonicResponse.SearchResult3.Album {
|
||||||
|
if album.Artist == artist {
|
||||||
|
return cfg.SubsonicUrl() + fmt.Sprintf(subsonicCoverArtFmtStr, c.authParams, url.QueryEscape(resp.SubsonicResponse.SearchResult3.Album[0].CoverArt)), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("GetAlbumImage: failed to get album art from subsonic")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SubsonicClient) GetArtistImage(ctx context.Context, artist string) (string, error) {
|
func (c *SubsonicClient) GetArtistImage(ctx context.Context, mbid *uuid.UUID, artist string) (string, error) {
|
||||||
l := logger.FromContext(ctx)
|
l := logger.FromContext(ctx)
|
||||||
resp := new(SubsonicArtistResponse)
|
resp := new(SubsonicArtistResponse)
|
||||||
l.Debug().Msgf("Finding artist image for %s", artist)
|
l.Debug().Msgf("Finding artist image for %s", artist)
|
||||||
|
// first try mbid search
|
||||||
|
if mbid != nil {
|
||||||
|
l.Debug().Str("mbid", mbid.String()).Msg("Searching artist image by MBID")
|
||||||
|
err := c.getEntity(ctx, fmt.Sprintf(subsonicArtistSearchFmtStr, c.authParams, url.QueryEscape(mbid.String())), resp)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("GetArtistImage: %v", err)
|
||||||
|
}
|
||||||
|
l.Debug().Any("subsonic_response", resp).Msg("")
|
||||||
|
if len(resp.SubsonicResponse.SearchResult3.Artist) < 1 || resp.SubsonicResponse.SearchResult3.Artist[0].ArtistImageUrl == "" {
|
||||||
|
return "", fmt.Errorf("GetArtistImage: failed to get artist art")
|
||||||
|
}
|
||||||
|
// Subsonic seems to have a tendency to return an artist image even though the url is a 404
|
||||||
|
if err = ValidateImageURL(resp.SubsonicResponse.SearchResult3.Artist[0].ArtistImageUrl); err != nil {
|
||||||
|
return "", fmt.Errorf("GetArtistImage: failed to get validate image url")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l.Debug().Str("artist", artist).Msg("Searching artist image by name")
|
||||||
err := c.getEntity(ctx, fmt.Sprintf(subsonicArtistSearchFmtStr, c.authParams, url.QueryEscape(artist)), resp)
|
err := c.getEntity(ctx, fmt.Sprintf(subsonicArtistSearchFmtStr, c.authParams, url.QueryEscape(artist)), resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("GetArtistImage: %v", err)
|
return "", fmt.Errorf("GetArtistImage: %v", err)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue