Files
Dongho Kim c251f174ed
Some checks failed
Pipeline: Test, Lint, Build / Get version info (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test JS code (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint i18n files (push) Has been cancelled
Pipeline: Test, Lint, Build / Check Docker configuration (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v5) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v6) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v7) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to GHCR (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to Docker Hub (push) Has been cancelled
Pipeline: Test, Lint, Build / Cleanup digest artifacts (push) Has been cancelled
Pipeline: Test, Lint, Build / Build Windows installers (push) Has been cancelled
Pipeline: Test, Lint, Build / Package/Release (push) Has been cancelled
Pipeline: Test, Lint, Build / Upload Linux PKG (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled
POEditor import / update-translations (push) Has been cancelled
update
2025-12-08 16:16:23 +01:00

152 lines
3.9 KiB
Go

//go:build wasip1
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/navidrome/navidrome/plugins/api"
"github.com/navidrome/navidrome/plugins/host/http"
)
type CoverArtArchiveAgent struct{}
var ErrNotFound = api.ErrNotFound
type caaImage struct {
Image string `json:"image"`
Front bool `json:"front"`
Types []string `json:"types"`
Thumbnails map[string]string `json:"thumbnails"`
}
var client = http.NewHttpService()
func (CoverArtArchiveAgent) GetAlbumImages(ctx context.Context, req *api.AlbumImagesRequest) (*api.AlbumImagesResponse, error) {
if req.Mbid == "" {
return nil, ErrNotFound
}
url := "https://coverartarchive.org/release/" + req.Mbid
resp, err := client.Get(ctx, &http.HttpRequest{Url: url, TimeoutMs: 5000})
if err != nil || resp.Status != 200 {
log.Printf("[CAA] Error getting album images from CoverArtArchive (status: %d): %v", resp.Status, err)
return nil, ErrNotFound
}
images, err := extractFrontImages(resp.Body)
if err != nil || len(images) == 0 {
return nil, ErrNotFound
}
return &api.AlbumImagesResponse{Images: images}, nil
}
func extractFrontImages(body []byte) ([]*api.ExternalImage, error) {
var data struct {
Images []caaImage `json:"images"`
}
if err := json.Unmarshal(body, &data); err != nil {
return nil, err
}
img := findFrontImage(data.Images)
if img == nil {
return nil, ErrNotFound
}
return buildImageList(img), nil
}
func findFrontImage(images []caaImage) *caaImage {
for i, img := range images {
if img.Front {
return &images[i]
}
}
for i, img := range images {
for _, t := range img.Types {
if t == "Front" {
return &images[i]
}
}
}
if len(images) > 0 {
return &images[0]
}
return nil
}
func buildImageList(img *caaImage) []*api.ExternalImage {
var images []*api.ExternalImage
// First, try numeric sizes only
for sizeStr, url := range img.Thumbnails {
if url == "" {
continue
}
size := 0
if _, err := fmt.Sscanf(sizeStr, "%d", &size); err == nil {
images = append(images, &api.ExternalImage{Url: url, Size: int32(size)})
}
}
// If no numeric sizes, fallback to large/small
if len(images) == 0 {
for sizeStr, url := range img.Thumbnails {
if url == "" {
continue
}
var size int
switch sizeStr {
case "large":
size = 500
case "small":
size = 250
default:
continue
}
images = append(images, &api.ExternalImage{Url: url, Size: int32(size)})
}
}
if len(images) == 0 && img.Image != "" {
images = append(images, &api.ExternalImage{Url: img.Image, Size: 0})
}
return images
}
func (CoverArtArchiveAgent) GetAlbumInfo(ctx context.Context, req *api.AlbumInfoRequest) (*api.AlbumInfoResponse, error) {
return nil, api.ErrNotImplemented
}
func (CoverArtArchiveAgent) GetArtistMBID(ctx context.Context, req *api.ArtistMBIDRequest) (*api.ArtistMBIDResponse, error) {
return nil, api.ErrNotImplemented
}
func (CoverArtArchiveAgent) GetArtistURL(ctx context.Context, req *api.ArtistURLRequest) (*api.ArtistURLResponse, error) {
return nil, api.ErrNotImplemented
}
func (CoverArtArchiveAgent) GetArtistBiography(ctx context.Context, req *api.ArtistBiographyRequest) (*api.ArtistBiographyResponse, error) {
return nil, api.ErrNotImplemented
}
func (CoverArtArchiveAgent) GetSimilarArtists(ctx context.Context, req *api.ArtistSimilarRequest) (*api.ArtistSimilarResponse, error) {
return nil, api.ErrNotImplemented
}
func (CoverArtArchiveAgent) GetArtistImages(ctx context.Context, req *api.ArtistImageRequest) (*api.ArtistImageResponse, error) {
return nil, api.ErrNotImplemented
}
func (CoverArtArchiveAgent) GetArtistTopSongs(ctx context.Context, req *api.ArtistTopSongsRequest) (*api.ArtistTopSongsResponse, error) {
return nil, api.ErrNotImplemented
}
func main() {}
func init() {
// Configure logging: No timestamps, no source file/line
log.SetFlags(0)
log.SetPrefix("[CAA] ")
api.RegisterMetadataAgent(CoverArtArchiveAgent{})
}