Files
pipu-music/services/api/internal/library/artist_images.go
T
mrleo1nid 82bf015283
ci / module boundaries / boundaries (push) Successful in 6s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 2m1s
ci / ts / ts (packages + web) (push) Failing after 5m13s
ci / api / api (push) Successful in 41s
ci / db / db (push) Failing after 1m33s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 2m25s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 2m19s
Import missing artist portraits from uploaded album folders
2026-10-30 10:46:07 +03:00

75 lines
2.1 KiB
Go

package library
import (
"context"
"crypto/sha256"
"encoding/hex"
"errors"
"os"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
)
type artistImageStore interface {
ArtistWithoutImageForFile(context.Context, uuid.UUID) (uuid.UUID, error)
SetArtistImageIfMissing(context.Context, uuid.UUID, string) error
}
type imageRenderer interface {
StoreImage(context.Context, []byte) (string, error)
}
// ArtistImages applies approved portraits to the album artist, never guests.
type ArtistImages struct {
store artistImageStore
images imageRenderer
}
func NewArtistImages(store *Store, covers *Covers) *ArtistImages {
return &ArtistImages{store: store, images: covers}
}
func (a *ArtistImages) ApplyArtistImage(ctx context.Context, file uuid.UUID, data []byte) error {
id, err := a.store.ArtistWithoutImageForFile(ctx, file)
if errors.Is(err, ErrNotFound) {
return nil
}
if err != nil {
return err
}
key, err := a.images.StoreImage(ctx, data)
if err != nil {
return err
}
return a.store.SetArtistImageIfMissing(ctx, id, key)
}
func (c *Covers) StoreImage(ctx context.Context, data []byte) (string, error) {
if err := os.MkdirAll(c.Dir, 0o755); err != nil {
return "", err
}
sum := sha256.Sum256(data)
key := hex.EncodeToString(sum[:8])
_, err := c.render(ctx, data, key)
return key, err
}
func (st *Store) ArtistWithoutImageForFile(ctx context.Context, file uuid.UUID) (uuid.UUID, error) {
var id uuid.UUID
err := st.pool.QueryRow(ctx, `SELECT a.id FROM media_files f JOIN tracks t ON t.id=f.track_id
JOIN albums al ON al.id=t.album_id JOIN artists a ON a.id=al.album_artist_id
WHERE f.id=$1 AND a.image_path IS NULL AND a.genius_image_url IS NULL`, file).Scan(&id)
if errors.Is(err, pgx.ErrNoRows) {
return id, ErrNotFound
}
return id, err
}
func (st *Store) SetArtistImageIfMissing(ctx context.Context, id uuid.UUID, key string) error {
// Another import or Genius may have supplied a portrait during rendering.
_, err := st.pool.Exec(ctx, `UPDATE artists SET image_path=$2 WHERE id=$1
AND image_path IS NULL AND genius_image_url IS NULL`, id, key)
return err
}