Files
yandex-music-api-go/internal/models/artist.go
T
Mrixs a9be10b5e5 Fix remaining type mismatches vs Python reference
- RotorSettings: Diversity float64→string, Energy float64→int, add Mood int and MoodEnergy string
- Ratings: Rating float64→int, add Week int and Day int
- MetatagArtistEntry: Remove Score float64 (not in Python), add PopularTracks []Track
- MusicHistoryItemData: Remove Progress float64 (not in Python)
2026-10-18 12:57:21 +03:00

538 lines
14 KiB
Go

// Package models provides data models for the Yandex Music API.
package models
import (
"encoding/json"
)
// Artist represents a full artist from the Yandex Music API.
type Artist struct {
BaseModel
ID JSONID `json:"id"`
Name string `json:"name"`
CoverURI string `json:"cover_uri"`
Genres []string `json:"genres"`
Tracks int `json:"tracks"`
Albums int `json:"albums"`
Available bool `json:"available"`
Composer bool `json:"composer"`
Various bool `json:"various"`
Decomposed []Decomposed `json:"decomposed"`
Ratings *Ratings `json:"ratings"`
Counts *Counts `json:"counts"`
Links []Link `json:"social_links"`
Description *Description `json:"description"`
// Additional fields
IDForFrom string `json:"id_for_from"`
Cover *Cover `json:"cover"`
BriefInfo *ArtistBriefInfo `json:"brief_info"`
DonationInfo *ArtistDonationInfo `json:"donation_info"`
Concerts []Concert `json:"concerts"`
Clips []Clip `json:"clips"`
Similar []Artist `json:"similar"`
AlbumsData []Album `json:"albums_data"`
TracksData []Track `json:"tracks_data"`
}
// DeJSON deserializes an Artist from JSON data.
func (a *Artist) DeJSON(data []byte, c ClientInterface) (Model, error) {
var raw map[string]json.RawMessage
if err := json.Unmarshal(data, &raw); err != nil {
return nil, err
}
artist := &Artist{BaseModel: *NewBaseModel(c)}
// Simple fields
if v, ok := raw["id"]; ok {
json.Unmarshal(v, &artist.ID)
}
if v, ok := raw["name"]; ok {
json.Unmarshal(v, &artist.Name)
}
if v, ok := raw["cover_uri"]; ok {
json.Unmarshal(v, &artist.CoverURI)
}
if v, ok := raw["genres"]; ok {
json.Unmarshal(v, &artist.Genres)
}
if v, ok := raw["tracks"]; ok {
json.Unmarshal(v, &artist.Tracks)
}
if v, ok := raw["albums"]; ok {
json.Unmarshal(v, &artist.Albums)
}
if v, ok := raw["available"]; ok {
json.Unmarshal(v, &artist.Available)
}
if v, ok := raw["composer"]; ok {
json.Unmarshal(v, &artist.Composer)
}
if v, ok := raw["various"]; ok {
json.Unmarshal(v, &artist.Various)
}
if v, ok := raw["id_for_from"]; ok {
json.Unmarshal(v, &artist.IDForFrom)
}
// Nested objects
if v, ok := raw["decomposed"]; ok {
var decomposed []Decomposed
if err := json.Unmarshal(v, &decomposed); err == nil {
artist.Decomposed = decomposed
}
}
if v, ok := raw["ratings"]; ok {
var ratings Ratings
json.Unmarshal(v, &ratings)
artist.Ratings = &ratings
}
if v, ok := raw["counts"]; ok {
var counts Counts
json.Unmarshal(v, &counts)
artist.Counts = &counts
}
if v, ok := raw["social_links"]; ok {
var links []Link
if err := json.Unmarshal(v, &links); err == nil {
artist.Links = links
}
}
if v, ok := raw["cover"]; ok {
var cover Cover
json.Unmarshal(v, &cover)
artist.Cover = &cover
}
if v, ok := raw["brief_info"]; ok {
var brief ArtistBriefInfo
json.Unmarshal(v, &brief)
artist.BriefInfo = &brief
}
if v, ok := raw["donation_info"]; ok {
var donation ArtistDonationInfo
json.Unmarshal(v, &donation)
artist.DonationInfo = &donation
}
if v, ok := raw["concerts"]; ok {
var concerts []Concert
json.Unmarshal(v, &concerts)
artist.Concerts = concerts
}
if v, ok := raw["clips"]; ok {
var clips []Clip
json.Unmarshal(v, &clips)
artist.Clips = clips
}
if v, ok := raw["similar"]; ok {
var similar []Artist
json.Unmarshal(v, &similar)
artist.Similar = similar
}
if v, ok := raw["albums"]; ok {
var albums []Album
json.Unmarshal(v, &albums)
artist.AlbumsData = albums
}
if v, ok := raw["tracks"]; ok {
var tracks []Track
json.Unmarshal(v, &tracks)
artist.TracksData = tracks
}
return artist, nil
}
// DeList deserializes a list of Artists from JSON data.
func (a *Artist) DeList(data []byte, c ClientInterface) ([]Model, error) {
var rawList []json.RawMessage
if err := json.Unmarshal(data, &rawList); err != nil {
return nil, err
}
result := make([]Model, 0, len(rawList))
for _, item := range rawList {
artist := &Artist{BaseModel: *NewBaseModel(c)}
if err := json.Unmarshal(item, artist); err != nil {
continue
}
result = append(result, artist)
}
return result, nil
}
// Ratings represents artist ratings.
type Ratings struct {
Rating int `json:"rating"`
Votes int `json:"votes"`
Week int `json:"week"`
Day int `json:"day"`
}
// Counts represents artist counts.
type Counts struct {
Tracks int `json:"tracks"`
Albums int `json:"albums"`
Folders int `json:"folders"`
}
// SocialLink represents a social media link.
type SocialLink struct {
URL string `json:"url"`
Title string `json:"title"`
Type string `json:"type"`
}
// Cover represents cover image info.
type Cover struct {
URI string `json:"uri"`
Type string `json:"type"`
Prefix string `json:"prefix"`
Pattern string `json:"pattern"`
Background string `json:"background"`
}
// ArtistBriefInfo represents brief artist info.
type ArtistBriefInfo struct {
Description string `json:"description"`
Available bool `json:"available"`
}
// ArtistDonations represents artist donations info.
type ArtistDonations struct {
Items []DonationItem `json:"items"`
Total int `json:"total"`
Goal int `json:"goal"`
Raised int `json:"raised"`
}
// DonationItem represents a donation item.
type DonationItem struct {
ID JSONID `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
Amount int `json:"amount"`
Goal int `json:"goal"`
Raised int `json:"raised"`
Currency string `json:"currency"`
}
// Decomposed represents a decomposed artist that can be either a string or an Artist object.
type Decomposed struct {
Artist *Artist `json:"-"`
Str string `json:"-"`
IsStr bool `json:"-"`
}
// UnmarshalJSON implements json.Unmarshaler, accepting both string and Artist object.
func (d *Decomposed) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err == nil {
d.Str = s
d.IsStr = true
return nil
}
var artist Artist
if err := json.Unmarshal(data, &artist); err != nil {
return err
}
d.Artist = &artist
d.IsStr = false
return nil
}
// MarshalJSON implements json.Marshaler.
func (d Decomposed) MarshalJSON() ([]byte, error) {
if d.IsStr {
return json.Marshal(d.Str)
}
return json.Marshal(d.Artist)
}
// Link represents a link to an artist's official page or social network.
type Link struct {
BaseModel
Title string `json:"title"`
Href string `json:"href"`
Type string `json:"type"`
SocialNetwork string `json:"social_network"`
}
// DeJSON deserializes Link from JSON data.
func (l *Link) DeJSON(data []byte, c ClientInterface) (Model, error) {
var raw map[string]json.RawMessage
if err := json.Unmarshal(data, &raw); err != nil {
return nil, err
}
link := &Link{BaseModel: *NewBaseModel(c)}
if v, ok := raw["title"]; ok {
json.Unmarshal(v, &link.Title)
}
if v, ok := raw["href"]; ok {
json.Unmarshal(v, &link.Href)
}
if v, ok := raw["type"]; ok {
json.Unmarshal(v, &link.Type)
}
if v, ok := raw["social_network"]; ok {
json.Unmarshal(v, &link.SocialNetwork)
}
return link, nil
}
// DeList deserializes a list of Links from JSON data.
func (l *Link) DeList(data []byte, c ClientInterface) ([]Model, error) {
var rawList []json.RawMessage
if err := json.Unmarshal(data, &rawList); err != nil {
return nil, err
}
result := make([]Model, 0, len(rawList))
for _, item := range rawList {
link := &Link{BaseModel: *NewBaseModel(c)}
if err := json.Unmarshal(item, link); err != nil {
continue
}
result = append(result, link)
}
return result, nil
}
// Description represents artist description.
type Description struct {
BaseModel
Text string `json:"text"`
URI string `json:"uri"`
}
// DeJSON deserializes Description from JSON data.
func (d *Description) DeJSON(data []byte, c ClientInterface) (Model, error) {
var raw map[string]json.RawMessage
if err := json.Unmarshal(data, &raw); err != nil {
return nil, err
}
desc := &Description{BaseModel: *NewBaseModel(c)}
if v, ok := raw["text"]; ok {
json.Unmarshal(v, &desc.Text)
}
if v, ok := raw["uri"]; ok {
json.Unmarshal(v, &desc.URI)
}
return desc, nil
}
// DeList deserializes a list of Descriptions from JSON data.
func (d *Description) DeList(data []byte, c ClientInterface) ([]Model, error) {
var rawList []json.RawMessage
if err := json.Unmarshal(data, &rawList); err != nil {
return nil, err
}
result := make([]Model, 0, len(rawList))
for _, item := range rawList {
desc := &Description{BaseModel: *NewBaseModel(c)}
if err := json.Unmarshal(item, desc); err != nil {
continue
}
result = append(result, desc)
}
return result, nil
}
// ArtistDonationInfo represents artist donation info.
type ArtistDonationInfo struct {
BaseModel
Title string `json:"title"`
URL string `json:"url"`
}
// DeJSON deserializes ArtistDonationInfo from JSON data.
func (adi *ArtistDonationInfo) DeJSON(data []byte, c ClientInterface) (Model, error) {
var raw map[string]json.RawMessage
if err := json.Unmarshal(data, &raw); err != nil {
return nil, err
}
info := &ArtistDonationInfo{BaseModel: *NewBaseModel(c)}
if v, ok := raw["title"]; ok {
json.Unmarshal(v, &info.Title)
}
if v, ok := raw["url"]; ok {
json.Unmarshal(v, &info.URL)
}
return info, nil
}
// DeList deserializes a list of ArtistDonationInfo from JSON data.
func (adi *ArtistDonationInfo) DeList(data []byte, c ClientInterface) ([]Model, error) {
var rawList []json.RawMessage
if err := json.Unmarshal(data, &rawList); err != nil {
return nil, err
}
result := make([]Model, 0, len(rawList))
for _, item := range rawList {
info := &ArtistDonationInfo{BaseModel: *NewBaseModel(c)}
if err := json.Unmarshal(item, info); err != nil {
continue
}
result = append(result, info)
}
return result, nil
}
// ConcertShort represents a concert (minimal for artist).
type ConcertShort struct {
BaseModel
ID JSONID `json:"id"`
Title string `json:"title"`
Date string `json:"date"`
Venue string `json:"venue"`
Location string `json:"location"`
TicketURI string `json:"ticket_uri"`
ImageURI string `json:"image_uri"`
MinPrice int `json:"min_price"`
MaxPrice int `json:"max_price"`
Available bool `json:"available"`
}
// DeJSON deserializes a ConcertShort from JSON data.
func (c *ConcertShort) DeJSON(data []byte, client ClientInterface) (Model, error) {
var raw map[string]json.RawMessage
if err := json.Unmarshal(data, &raw); err != nil {
return nil, err
}
concert := &ConcertShort{BaseModel: *NewBaseModel(client)}
if v, ok := raw["id"]; ok {
json.Unmarshal(v, &concert.ID)
}
if v, ok := raw["title"]; ok {
json.Unmarshal(v, &concert.Title)
}
if v, ok := raw["date"]; ok {
json.Unmarshal(v, &concert.Date)
}
if v, ok := raw["venue"]; ok {
json.Unmarshal(v, &concert.Venue)
}
if v, ok := raw["location"]; ok {
json.Unmarshal(v, &concert.Location)
}
if v, ok := raw["ticket_uri"]; ok {
json.Unmarshal(v, &concert.TicketURI)
}
if v, ok := raw["image_uri"]; ok {
json.Unmarshal(v, &concert.ImageURI)
}
if v, ok := raw["min_price"]; ok {
json.Unmarshal(v, &concert.MinPrice)
}
if v, ok := raw["max_price"]; ok {
json.Unmarshal(v, &concert.MaxPrice)
}
if v, ok := raw["available"]; ok {
json.Unmarshal(v, &concert.Available)
}
return concert, nil
}
// DeList deserializes a list of ConcertShort from JSON data.
func (c *ConcertShort) DeList(data []byte, client ClientInterface) ([]Model, error) {
var rawList []json.RawMessage
if err := json.Unmarshal(data, &rawList); err != nil {
return nil, err
}
result := make([]Model, 0, len(rawList))
for _, item := range rawList {
concert := &ConcertShort{BaseModel: *NewBaseModel(client)}
if err := json.Unmarshal(item, concert); err != nil {
continue
}
result = append(result, concert)
}
return result, nil
}
// ClipShort represents a clip (minimal for artist).
type ClipShort struct {
BaseModel
ID JSONID `json:"id"`
Title string `json:"title"`
Duration int `json:"duration"`
CoverURI string `json:"cover_uri"`
PreviewURI string `json:"preview_uri"`
Available bool `json:"available"`
Views int `json:"views"`
Likes int `json:"likes"`
CreatedAt string `json:"created_at"`
}
// DeJSON deserializes a ClipShort from JSON data.
func (c *ClipShort) DeJSON(data []byte, client ClientInterface) (Model, error) {
var raw map[string]json.RawMessage
if err := json.Unmarshal(data, &raw); err != nil {
return nil, err
}
clip := &ClipShort{BaseModel: *NewBaseModel(client)}
if v, ok := raw["id"]; ok {
json.Unmarshal(v, &clip.ID)
}
if v, ok := raw["title"]; ok {
json.Unmarshal(v, &clip.Title)
}
if v, ok := raw["duration"]; ok {
json.Unmarshal(v, &clip.Duration)
}
if v, ok := raw["cover_uri"]; ok {
json.Unmarshal(v, &clip.CoverURI)
}
if v, ok := raw["preview_uri"]; ok {
json.Unmarshal(v, &clip.PreviewURI)
}
if v, ok := raw["available"]; ok {
json.Unmarshal(v, &clip.Available)
}
if v, ok := raw["views"]; ok {
json.Unmarshal(v, &clip.Views)
}
if v, ok := raw["likes"]; ok {
json.Unmarshal(v, &clip.Likes)
}
if v, ok := raw["created_at"]; ok {
json.Unmarshal(v, &clip.CreatedAt)
}
return clip, nil
}
// DeList deserializes a list of ClipShort from JSON data.
func (c *ClipShort) DeList(data []byte, client ClientInterface) ([]Model, error) {
var rawList []json.RawMessage
if err := json.Unmarshal(data, &rawList); err != nil {
return nil, err
}
result := make([]Model, 0, len(rawList))
for _, item := range rawList {
clip := &ClipShort{BaseModel: *NewBaseModel(client)}
if err := json.Unmarshal(item, clip); err != nil {
continue
}
result = append(result, clip)
}
return result, nil
}