// Package models provides data models for the Yandex Music API. package models import ( "encoding/json" ) // Track represents a full track from the Yandex Music API. type Track struct { BaseModel ID JSONID `json:"id"` Title string `json:"title"` Available bool `json:"available"` Artists []Artist `json:"artists"` Albums []Album `json:"albums"` AvailableForPremiumUsers bool `json:"available_for_premium_users"` LyricsAvailable bool `json:"lyrics_available"` Best bool `json:"best"` RealID JSONID `json:"real_id"` OgImage string `json:"og_image"` Type string `json:"type"` CoverURI string `json:"cover_uri"` Major *Major `json:"major"` DurationMs int `json:"duration_ms"` StorageDir string `json:"storage_dir"` FileSize int64 `json:"file_size"` Genre string `json:"genre"` AvailableAsRingtone bool `json:"available_as_ringtone"` RingtoneID string `json:"ringtone_id"` SimilarTracks []Track `json:"similar_tracks"` Position *TrackPosition `json:"position"` Substituted *Track `json:"substituted"` MatchedTrack *Track `json:"matched_track"` Normalization *Normalization `json:"normalization"` Error string `json:"error"` CanPublish bool `json:"can_publish"` State string `json:"state"` DesiredVisibility string `json:"desired_visibility"` Filename string `json:"filename"` UserInfo *User `json:"user_info"` MetaData *MetaData `json:"meta_data"` Regions []string `json:"regions"` AvailableAsRbt bool `json:"available_as_rbt"` ContentWarning string `json:"content_warning"` Explicit bool `json:"explicit"` PreviewDurationMs int `json:"preview_duration_ms"` AvailableFullWithoutPermission bool `json:"available_full_without_permission"` Version string `json:"version"` RememberPosition bool `json:"remember_position"` BackgroundVideoURI string `json:"background_video_uri"` ShortDescription string `json:"short_description"` IsSuitableForChildren bool `json:"is_suitable_for_children"` TrackSource string `json:"track_source"` AvailableForOptions []string `json:"available_for_options"` R128 *R128 `json:"r128"` LyricsInfo *TrackLyricsInfo `json:"lyrics_info"` TrackSharingFlag string `json:"track_sharing_flag"` DerivedColors *CoverDerivedColors `json:"derived_colors"` Fade *Fade `json:"fade"` SmartPreviewParams *SmartPreviewParams `json:"smart_preview_params"` SpecialAudioResources []string `json:"special_audio_resources"` Disclaimers []string `json:"disclaimers"` BackgroundVideoID string `json:"background_video_id"` PlayerID string `json:"player_id"` MixFade *Fade `json:"mix_fade"` Chart *Chart `json:"chart"` ClipIDs []int `json:"clip_ids"` Isrc string `json:"isrc"` UgcArtistName string `json:"ugc_artist_name"` PodcastEpisodeType string `json:"podcast_episode_type"` PubDate string `json:"pub_date"` DownloadInfo []DownloadInfo `json:"download_info"` } // DeJSON deserializes a Track from JSON data. func (t *Track) DeJSON(data []byte, c ClientInterface) (Model, error) { var raw map[string]json.RawMessage if err := json.Unmarshal(data, &raw); err != nil { return nil, err } track := &Track{BaseModel: *NewBaseModel(c)} // Simple fields if v, ok := raw["id"]; ok { json.Unmarshal(v, &track.ID) } if v, ok := raw["title"]; ok { json.Unmarshal(v, &track.Title) } if v, ok := raw["duration_ms"]; ok { json.Unmarshal(v, &track.DurationMs) } if v, ok := raw["storage_dir"]; ok { json.Unmarshal(v, &track.StorageDir) } if v, ok := raw["cover_uri"]; ok { json.Unmarshal(v, &track.CoverURI) } if v, ok := raw["genre"]; ok { json.Unmarshal(v, &track.Genre) } if v, ok := raw["version"]; ok { json.Unmarshal(v, &track.Version) } if v, ok := raw["explicit"]; ok { json.Unmarshal(v, &track.Explicit) } if v, ok := raw["available"]; ok { json.Unmarshal(v, &track.Available) } if v, ok := raw["available_for_premium_users"]; ok { json.Unmarshal(v, &track.AvailableForPremiumUsers) } if v, ok := raw["r128"]; ok { json.Unmarshal(v, &track.R128) } if v, ok := raw["track_sharing_flag"]; ok { json.Unmarshal(v, &track.TrackSharingFlag) } if v, ok := raw["available_as_ringtone"]; ok { json.Unmarshal(v, &track.AvailableAsRingtone) } if v, ok := raw["ringtone_id"]; ok { json.Unmarshal(v, &track.RingtoneID) } // Nested objects if v, ok := raw["artists"]; ok { var artists []Artist if err := json.Unmarshal(v, &artists); err == nil { track.Artists = artists } } if v, ok := raw["albums"]; ok { var albums []Album if err := json.Unmarshal(v, &albums); err == nil { track.Albums = albums } } if v, ok := raw["major"]; ok { var major Major if err := json.Unmarshal(v, &major); err == nil { track.Major = &major } } if v, ok := raw["lyrics_info"]; ok { var lyrics TrackLyricsInfo if err := json.Unmarshal(v, &lyrics); err == nil { track.LyricsInfo = &lyrics } } if v, ok := raw["similar_tracks"]; ok { var similar []Track if err := json.Unmarshal(v, &similar); err == nil { track.SimilarTracks = similar } } if v, ok := raw["download_info"]; ok { var downloadInfo []DownloadInfo if err := json.Unmarshal(v, &downloadInfo); err == nil { track.DownloadInfo = downloadInfo } } if v, ok := raw["position"]; ok { var pos TrackPosition if err := json.Unmarshal(v, &pos); err == nil { track.Position = &pos } } return track, nil } // DeList deserializes a list of Tracks from JSON data. func (t *Track) 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 { track := &Track{BaseModel: *NewBaseModel(c)} if err := json.Unmarshal(item, track); err != nil { continue } result = append(result, track) } return result, nil } // GetDownloadInfo returns download info for a specific quality, or nil if not found. func (t *Track) GetDownloadInfo(quality string) *DownloadInfo { for _, info := range t.DownloadInfo { if info.Quality == quality { return &info } } return nil } // Major represents major label info for a track. type Major struct { ID JSONID `json:"id"` Name string `json:"name"` Description string `json:"description"` } // TrackLyricsInfo represents lyrics availability info for a track. type TrackLyricsInfo struct { BaseModel HasAvailableSyncLyrics bool `json:"has_available_sync_lyrics"` HasAvailableTextLyrics bool `json:"has_available_text_lyrics"` } // DeJSON deserializes TrackLyricsInfo from JSON data. func (tli *TrackLyricsInfo) 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 := &TrackLyricsInfo{BaseModel: *NewBaseModel(c)} if v, ok := raw["has_available_sync_lyrics"]; ok { json.Unmarshal(v, &info.HasAvailableSyncLyrics) } if v, ok := raw["has_available_text_lyrics"]; ok { json.Unmarshal(v, &info.HasAvailableTextLyrics) } return info, nil } // DeList deserializes a list of TrackLyricsInfo from JSON data. func (tli *TrackLyricsInfo) 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 := &TrackLyricsInfo{BaseModel: *NewBaseModel(c)} if err := json.Unmarshal(item, info); err != nil { continue } result = append(result, info) } return result, nil } // DownloadInfo represents file download info for a track. type DownloadInfo struct { Quality string `json:"quality"` Codec string `json:"codec"` Bitrate int `json:"bitrate"` Size int64 `json:"size"` URL string `json:"url"` DirectLink bool `json:"direct_link"` DownloadInfoURL string `json:"download_info_url"` DirectLinkURL string `json:"-"` // Computed signed download URL } // Normalization represents track normalization values. type Normalization struct { BaseModel Gain float64 `json:"gain"` Peak int `json:"peak"` } // MetaData represents track metadata. type MetaData struct { BaseModel Album string `json:"album"` Volume int `json:"volume"` Year int `json:"year"` Number int `json:"number"` Genre string `json:"genre"` Lyricist string `json:"lyricist"` Version string `json:"version"` Composer string `json:"composer"` } // Fade represents fade parameters for a track. type Fade struct { BaseModel InStart float64 `json:"in_start"` InStop float64 `json:"in_stop"` OutStart float64 `json:"out_start"` OutStop float64 `json:"out_stop"` } // SmartPreviewParams represents smart preview parameters. type SmartPreviewParams struct { BaseModel DurationMs int `json:"duration_ms"` Fade *Fade `json:"fade"` } // CoverDerivedColors represents derived colors from cover art. type CoverDerivedColors struct { BaseModel Average string `json:"average"` WaveText string `json:"wave_text"` MiniPlayer string `json:"mini_player"` Accent string `json:"accent"` } // CustomWave represents a custom wave for playlists. type CustomWave struct { BaseModel Title string `json:"title"` AnimationURL string `json:"animation_url"` Position string `json:"position"` Header string `json:"header"` BackgroundImageURL string `json:"background_image_url"` SquareAgentAnimation string `json:"square_agent_animation"` } // TrackId represents a track ID reference. type TrackId struct { BaseModel ID JSONID `json:"id"` TrackID JSONID `json:"track_id"` AlbumID JSONID `json:"album_id"` From string `json:"from"` } // DeJSON deserializes a TrackId from JSON data. func (ti *TrackId) DeJSON(data []byte, c ClientInterface) (Model, error) { var raw map[string]json.RawMessage if err := json.Unmarshal(data, &raw); err != nil { return nil, err } tid := &TrackId{BaseModel: *NewBaseModel(c)} if v, ok := raw["id"]; ok { json.Unmarshal(v, &tid.ID) } if v, ok := raw["track_id"]; ok { json.Unmarshal(v, &tid.TrackID) } if v, ok := raw["album_id"]; ok { json.Unmarshal(v, &tid.AlbumID) } if v, ok := raw["from"]; ok { json.Unmarshal(v, &tid.From) } return tid, nil } // DeList deserializes a list of TrackId from JSON data. func (ti *TrackId) 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 { tid := &TrackId{BaseModel: *NewBaseModel(c)} if err := json.Unmarshal(item, tid); err != nil { continue } result = append(result, tid) } return result, nil } // TrackFullInfo represents full track info. type TrackFullInfo struct { BaseModel Track *Track `json:"track"` SimilarTracks []Track `json:"similar_tracks"` AlsoInAlbums []Track `json:"also_in_albums"` Aliases []string `json:"aliases"` Artists []Artist `json:"artists"` } // DeJSON deserializes a TrackFullInfo from JSON data. func (tfi *TrackFullInfo) 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 := &TrackFullInfo{BaseModel: *NewBaseModel(c)} if v, ok := raw["track"]; ok { var track Track if err := json.Unmarshal(v, &track); err == nil { info.Track = &track } } if v, ok := raw["similar_tracks"]; ok { var tracks []Track if err := json.Unmarshal(v, &tracks); err == nil { info.SimilarTracks = tracks } } if v, ok := raw["also_in_albums"]; ok { var tracks []Track if err := json.Unmarshal(v, &tracks); err == nil { info.AlsoInAlbums = tracks } } if v, ok := raw["aliases"]; ok { json.Unmarshal(v, &info.Aliases) } if v, ok := raw["artists"]; ok { var artists []Artist if err := json.Unmarshal(v, &artists); err == nil { info.Artists = artists } } return info, nil } // DeList deserializes a list of TrackFullInfo from JSON data. func (tfi *TrackFullInfo) 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 := &TrackFullInfo{BaseModel: *NewBaseModel(c)} if err := json.Unmarshal(item, info); err != nil { continue } result = append(result, info) } return result, nil } // SimilarTracks represents similar tracks. type SimilarTracks struct { BaseModel Track *Track `json:"track"` SimilarTracks []Track `json:"similar_tracks"` } // DeJSON deserializes SimilarTracks from JSON data. func (st *SimilarTracks) DeJSON(data []byte, c ClientInterface) (Model, error) { var raw map[string]json.RawMessage if err := json.Unmarshal(data, &raw); err != nil { return nil, err } similar := &SimilarTracks{BaseModel: *NewBaseModel(c)} if v, ok := raw["track"]; ok { var track Track if err := json.Unmarshal(v, &track); err == nil { similar.Track = &track } } if v, ok := raw["similar_tracks"]; ok { var tracks []Track if err := json.Unmarshal(v, &tracks); err == nil { similar.SimilarTracks = tracks } } return similar, nil } // DeList deserializes a list of SimilarTracks from JSON data. func (st *SimilarTracks) 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 { similar := &SimilarTracks{BaseModel: *NewBaseModel(c)} if err := json.Unmarshal(item, similar); err != nil { continue } result = append(result, similar) } return result, nil } // TrackTrailer represents track trailer info. type TrackTrailer struct { BaseModel Title string `json:"title"` Track *Track `json:"track"` } // DeJSON deserializes a TrackTrailer from JSON data. func (tt *TrackTrailer) DeJSON(data []byte, c ClientInterface) (Model, error) { var raw map[string]json.RawMessage if err := json.Unmarshal(data, &raw); err != nil { return nil, err } trailer := &TrackTrailer{BaseModel: *NewBaseModel(c)} if v, ok := raw["title"]; ok { json.Unmarshal(v, &trailer.Title) } if v, ok := raw["track"]; ok { var track Track if err := json.Unmarshal(v, &track); err == nil { trailer.Track = &track } } return trailer, nil } // DeList deserializes a list of TrackTrailer from JSON data. func (tt *TrackTrailer) 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 { trailer := &TrackTrailer{BaseModel: *NewBaseModel(c)} if err := json.Unmarshal(item, trailer); err != nil { continue } result = append(result, trailer) } return result, nil }