- Document all exported types, functions, methods, and constants across 52 files - Add package-level doc comments to client, models, utils, and ynison packages - Document HTTP method and endpoint path for each API client method - Document model struct fields and DeJSON/DeList/ToJSON/ToMap methods - Fix duplicate package doc comment in internal/models/base.go Co-Authored-By: Claude Code <noreply@anthropic.com>
409 lines
12 KiB
Go
409 lines
12 KiB
Go
// Package models provides data models for the Yandex Music API.
|
|
package models
|
|
|
|
import (
|
|
"encoding/json"
|
|
)
|
|
|
|
// Playlist represents a playlist from the Yandex Music API.
|
|
type Playlist struct {
|
|
BaseModel
|
|
Kind int `json:"kind"`
|
|
Title string `json:"title"`
|
|
Description string `json:"description"`
|
|
CoverURI string `json:"cover_uri"`
|
|
Created string `json:"created"`
|
|
Modified string `json:"modified"`
|
|
TrackCount int `json:"track_count"`
|
|
DurationMs int `json:"duration_ms"`
|
|
Availability *Availability `json:"availability"`
|
|
Owner *User `json:"owner"`
|
|
Tracks []Track `json:"tracks"`
|
|
LikesCount int `json:"likes_count"`
|
|
IsPublic bool `json:"is_public"`
|
|
Revision int `json:"revision"`
|
|
UUID string `json:"uuid"`
|
|
Tags []string `json:"tags"`
|
|
SimilarPlaylists []Playlist `json:"similar_playlists"`
|
|
// Additional fields
|
|
AccessType string `json:"access_type"`
|
|
Available bool `json:"available"`
|
|
ContentWarning string `json:"content_warning"`
|
|
Genre string `json:"genre"`
|
|
Image []Image `json:"image"`
|
|
OwnerUID int64 `json:"owner_uid"`
|
|
Shared bool `json:"shared"`
|
|
SnapshotID string `json:"snapshot_id"`
|
|
Trailer *TrailerInfo `json:"trailer"`
|
|
}
|
|
|
|
// DeJSON deserializes a Playlist from JSON data.
|
|
func (p *Playlist) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|
var raw map[string]json.RawMessage
|
|
if err := json.Unmarshal(data, &raw); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
playlist := &Playlist{BaseModel: *NewBaseModel(c)}
|
|
|
|
// Simple fields
|
|
if v, ok := raw["kind"]; ok {
|
|
json.Unmarshal(v, &playlist.Kind)
|
|
}
|
|
if v, ok := raw["title"]; ok {
|
|
json.Unmarshal(v, &playlist.Title)
|
|
}
|
|
if v, ok := raw["description"]; ok {
|
|
json.Unmarshal(v, &playlist.Description)
|
|
}
|
|
if v, ok := raw["cover_uri"]; ok {
|
|
json.Unmarshal(v, &playlist.CoverURI)
|
|
}
|
|
if v, ok := raw["created"]; ok {
|
|
json.Unmarshal(v, &playlist.Created)
|
|
}
|
|
if v, ok := raw["modified"]; ok {
|
|
json.Unmarshal(v, &playlist.Modified)
|
|
}
|
|
if v, ok := raw["track_count"]; ok {
|
|
json.Unmarshal(v, &playlist.TrackCount)
|
|
}
|
|
if v, ok := raw["duration_ms"]; ok {
|
|
json.Unmarshal(v, &playlist.DurationMs)
|
|
}
|
|
if v, ok := raw["likes_count"]; ok {
|
|
json.Unmarshal(v, &playlist.LikesCount)
|
|
}
|
|
if v, ok := raw["is_public"]; ok {
|
|
json.Unmarshal(v, &playlist.IsPublic)
|
|
}
|
|
if v, ok := raw["revision"]; ok {
|
|
json.Unmarshal(v, &playlist.Revision)
|
|
}
|
|
if v, ok := raw["uuid"]; ok {
|
|
json.Unmarshal(v, &playlist.UUID)
|
|
}
|
|
if v, ok := raw["tags"]; ok {
|
|
json.Unmarshal(v, &playlist.Tags)
|
|
}
|
|
if v, ok := raw["access_type"]; ok {
|
|
json.Unmarshal(v, &playlist.AccessType)
|
|
}
|
|
if v, ok := raw["available"]; ok {
|
|
json.Unmarshal(v, &playlist.Available)
|
|
}
|
|
if v, ok := raw["content_warning"]; ok {
|
|
json.Unmarshal(v, &playlist.ContentWarning)
|
|
}
|
|
if v, ok := raw["genre"]; ok {
|
|
json.Unmarshal(v, &playlist.Genre)
|
|
}
|
|
if v, ok := raw["owner_uid"]; ok {
|
|
json.Unmarshal(v, &playlist.OwnerUID)
|
|
}
|
|
if v, ok := raw["shared"]; ok {
|
|
json.Unmarshal(v, &playlist.Shared)
|
|
}
|
|
if v, ok := raw["snapshot_id"]; ok {
|
|
json.Unmarshal(v, &playlist.SnapshotID)
|
|
}
|
|
|
|
// Nested objects
|
|
if v, ok := raw["availability"]; ok {
|
|
var avail Availability
|
|
json.Unmarshal(v, &avail)
|
|
playlist.Availability = &avail
|
|
}
|
|
if v, ok := raw["owner"]; ok {
|
|
var user User
|
|
json.Unmarshal(v, &user)
|
|
playlist.Owner = &user
|
|
}
|
|
if v, ok := raw["tracks"]; ok {
|
|
var tracks []Track
|
|
json.Unmarshal(v, &tracks)
|
|
playlist.Tracks = tracks
|
|
}
|
|
if v, ok := raw["similar_playlists"]; ok {
|
|
var similar []Playlist
|
|
json.Unmarshal(v, &similar)
|
|
playlist.SimilarPlaylists = similar
|
|
}
|
|
if v, ok := raw["image"]; ok {
|
|
var images []Image
|
|
json.Unmarshal(v, &images)
|
|
playlist.Image = images
|
|
}
|
|
if v, ok := raw["trailer"]; ok {
|
|
var trailer TrailerInfo
|
|
json.Unmarshal(v, &trailer)
|
|
playlist.Trailer = &trailer
|
|
}
|
|
|
|
return playlist, nil
|
|
}
|
|
|
|
// DeList deserializes a list of Playlists from JSON data.
|
|
func (p *Playlist) 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 {
|
|
playlist := &Playlist{BaseModel: *NewBaseModel(c)}
|
|
if err := json.Unmarshal(item, playlist); err != nil {
|
|
continue
|
|
}
|
|
result = append(result, playlist)
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// User represents a user (playlist owner) from the Yandex Music API.
|
|
type User struct {
|
|
BaseModel
|
|
UID int64 `json:"uid"`
|
|
Login string `json:"login"`
|
|
DisplayName string `json:"display_name"`
|
|
CoverURI string `json:"cover_uri"`
|
|
Sex string `json:"sex"`
|
|
PublicPlaylists int `json:"public_playlists"`
|
|
FollowersCount int `json:"followers_count"`
|
|
FollowingsCount int `json:"followings_count"`
|
|
HasPlaylists bool `json:"has_playlists"`
|
|
Available bool `json:"available"`
|
|
// Additional fields
|
|
Description string `json:"description"`
|
|
IsVerified bool `json:"is_verified"`
|
|
City string `json:"city"`
|
|
Country string `json:"country"`
|
|
Birthday string `json:"birthday"`
|
|
RegistrationDate string `json:"registration_date"`
|
|
Settings *UserSettings `json:"settings"`
|
|
Counters *UserCounters `json:"counters"`
|
|
}
|
|
|
|
// DeJSON deserializes a User from JSON data.
|
|
func (u *User) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|
var raw map[string]json.RawMessage
|
|
if err := json.Unmarshal(data, &raw); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
user := &User{BaseModel: *NewBaseModel(c)}
|
|
|
|
if v, ok := raw["uid"]; ok {
|
|
json.Unmarshal(v, &user.UID)
|
|
}
|
|
if v, ok := raw["login"]; ok {
|
|
json.Unmarshal(v, &user.Login)
|
|
}
|
|
if v, ok := raw["display_name"]; ok {
|
|
json.Unmarshal(v, &user.DisplayName)
|
|
}
|
|
if v, ok := raw["cover_uri"]; ok {
|
|
json.Unmarshal(v, &user.CoverURI)
|
|
}
|
|
if v, ok := raw["sex"]; ok {
|
|
json.Unmarshal(v, &user.Sex)
|
|
}
|
|
if v, ok := raw["public_playlists"]; ok {
|
|
json.Unmarshal(v, &user.PublicPlaylists)
|
|
}
|
|
if v, ok := raw["followers_count"]; ok {
|
|
json.Unmarshal(v, &user.FollowersCount)
|
|
}
|
|
if v, ok := raw["followings_count"]; ok {
|
|
json.Unmarshal(v, &user.FollowingsCount)
|
|
}
|
|
if v, ok := raw["has_playlists"]; ok {
|
|
json.Unmarshal(v, &user.HasPlaylists)
|
|
}
|
|
if v, ok := raw["available"]; ok {
|
|
json.Unmarshal(v, &user.Available)
|
|
}
|
|
if v, ok := raw["description"]; ok {
|
|
json.Unmarshal(v, &user.Description)
|
|
}
|
|
if v, ok := raw["is_verified"]; ok {
|
|
json.Unmarshal(v, &user.IsVerified)
|
|
}
|
|
if v, ok := raw["city"]; ok {
|
|
json.Unmarshal(v, &user.City)
|
|
}
|
|
if v, ok := raw["country"]; ok {
|
|
json.Unmarshal(v, &user.Country)
|
|
}
|
|
if v, ok := raw["birthday"]; ok {
|
|
json.Unmarshal(v, &user.Birthday)
|
|
}
|
|
if v, ok := raw["registration_date"]; ok {
|
|
json.Unmarshal(v, &user.RegistrationDate)
|
|
}
|
|
if v, ok := raw["settings"]; ok {
|
|
var settings UserSettings
|
|
json.Unmarshal(v, &settings)
|
|
user.Settings = &settings
|
|
}
|
|
if v, ok := raw["counters"]; ok {
|
|
var counters UserCounters
|
|
json.Unmarshal(v, &counters)
|
|
user.Counters = &counters
|
|
}
|
|
|
|
return user, nil
|
|
}
|
|
|
|
// DeList deserializes a list of Users from JSON data.
|
|
func (u *User) 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 {
|
|
user := &User{BaseModel: *NewBaseModel(c)}
|
|
if err := json.Unmarshal(item, user); err != nil {
|
|
continue
|
|
}
|
|
result = append(result, user)
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// UserSettings represents user settings from /account/settings.
|
|
type UserSettings struct {
|
|
BaseModel
|
|
UID int64 `json:"uid"`
|
|
LastFMScrobblingEnabled bool `json:"last_fm_scrobbling_enabled"`
|
|
ShuffleEnabled bool `json:"shuffle_enabled"`
|
|
VolumePercents int `json:"volume_percents"`
|
|
Modified string `json:"modified"`
|
|
FacebookScrobblingEnabled bool `json:"facebook_scrobbling_enabled"`
|
|
AddNewTrackOnPlaylistTop bool `json:"add_new_track_on_playlist_top"`
|
|
UserMusicVisibility string `json:"user_music_visibility"`
|
|
UserSocialVisibility string `json:"user_social_visibility"`
|
|
RBTDisabled bool `json:"rbt_disabled"`
|
|
Theme string `json:"theme"`
|
|
PromosDisabled bool `json:"promos_disabled"`
|
|
AutoPlayRadio bool `json:"auto_play_radio"`
|
|
SyncQueueEnabled bool `json:"sync_queue_enabled"`
|
|
AdsDisabled *bool `json:"ads_disabled,omitempty"`
|
|
DiskEnabled *bool `json:"disk_enabled,omitempty"`
|
|
ShowDiskTracksInLibrary *bool `json:"show_disk_tracks_in_library,omitempty"`
|
|
}
|
|
|
|
// DeJSON deserializes UserSettings from JSON data.
|
|
func (u *UserSettings) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|
var raw map[string]json.RawMessage
|
|
if err := json.Unmarshal(data, &raw); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
settings := &UserSettings{BaseModel: *NewBaseModel(c)}
|
|
|
|
if v, ok := raw["uid"]; ok {
|
|
json.Unmarshal(v, &settings.UID)
|
|
}
|
|
if v, ok := raw["last_fm_scrobbling_enabled"]; ok {
|
|
json.Unmarshal(v, &settings.LastFMScrobblingEnabled)
|
|
}
|
|
if v, ok := raw["shuffle_enabled"]; ok {
|
|
json.Unmarshal(v, &settings.ShuffleEnabled)
|
|
}
|
|
if v, ok := raw["volume_percents"]; ok {
|
|
json.Unmarshal(v, &settings.VolumePercents)
|
|
}
|
|
if v, ok := raw["modified"]; ok {
|
|
json.Unmarshal(v, &settings.Modified)
|
|
}
|
|
if v, ok := raw["facebook_scrobbling_enabled"]; ok {
|
|
json.Unmarshal(v, &settings.FacebookScrobblingEnabled)
|
|
}
|
|
if v, ok := raw["add_new_track_on_playlist_top"]; ok {
|
|
json.Unmarshal(v, &settings.AddNewTrackOnPlaylistTop)
|
|
}
|
|
if v, ok := raw["user_music_visibility"]; ok {
|
|
json.Unmarshal(v, &settings.UserMusicVisibility)
|
|
}
|
|
if v, ok := raw["user_social_visibility"]; ok {
|
|
json.Unmarshal(v, &settings.UserSocialVisibility)
|
|
}
|
|
if v, ok := raw["rbt_disabled"]; ok {
|
|
json.Unmarshal(v, &settings.RBTDisabled)
|
|
}
|
|
if v, ok := raw["theme"]; ok {
|
|
json.Unmarshal(v, &settings.Theme)
|
|
}
|
|
if v, ok := raw["promos_disabled"]; ok {
|
|
json.Unmarshal(v, &settings.PromosDisabled)
|
|
}
|
|
if v, ok := raw["auto_play_radio"]; ok {
|
|
json.Unmarshal(v, &settings.AutoPlayRadio)
|
|
}
|
|
if v, ok := raw["sync_queue_enabled"]; ok {
|
|
json.Unmarshal(v, &settings.SyncQueueEnabled)
|
|
}
|
|
if v, ok := raw["ads_disabled"]; ok {
|
|
var val bool
|
|
json.Unmarshal(v, &val)
|
|
settings.AdsDisabled = &val
|
|
}
|
|
if v, ok := raw["disk_enabled"]; ok {
|
|
var val bool
|
|
json.Unmarshal(v, &val)
|
|
settings.DiskEnabled = &val
|
|
}
|
|
if v, ok := raw["show_disk_tracks_in_library"]; ok {
|
|
var val bool
|
|
json.Unmarshal(v, &val)
|
|
settings.ShowDiskTracksInLibrary = &val
|
|
}
|
|
|
|
return settings, nil
|
|
}
|
|
|
|
// DeList deserializes a list of UserSettings from JSON data.
|
|
func (u *UserSettings) 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 {
|
|
settings := &UserSettings{BaseModel: *NewBaseModel(c)}
|
|
if err := json.Unmarshal(item, settings); err != nil {
|
|
continue
|
|
}
|
|
result = append(result, settings)
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// UserCounters represents user counters.
|
|
type UserCounters struct {
|
|
Tracks int `json:"tracks"`
|
|
Albums int `json:"albums"`
|
|
Playlists int `json:"playlists"`
|
|
Followers int `json:"followers"`
|
|
Followings int `json:"followings"`
|
|
Likes int `json:"likes"`
|
|
}
|
|
|
|
// Image represents an image with multiple sizes.
|
|
type Image struct {
|
|
URI string `json:"uri"`
|
|
Type string `json:"type"`
|
|
Width int `json:"width"`
|
|
Height int `json:"height"`
|
|
Size int64 `json:"size"`
|
|
Extension string `json:"extension"`
|
|
}
|
|
|
|
// Re-export types from other files for convenience
|
|
// Availability, TrailerInfo are defined in album.go
|