Files
yandex-music-api-go/internal/models/track.go
T
MrixsandClaude Code 5535d2a941 Fix ID fields to accept both JSON strings and numbers
The Yandex Music API returns IDs as both JSON strings and numbers depending
on the endpoint. Added JSONID custom type in internal/models/base.go that
implements json.Unmarshaler to accept both formats and store as string.

Changed ID fields from string to JSONID:
- Track.ID, Major.ID, TrackLyricsInfo.ID (track.go)
- Album.ID, TrailerInfo.TrackID, TrailerInfo.AlbumID (album.go)

Updated example to convert JSONID to string when passing to client methods.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-18 10:21:58 +03:00

175 lines
5.0 KiB
Go

// 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"`
DurationMs int `json:"duration_ms"`
StorageID string `json:"storage_id"`
CoverURI string `json:"cover_uri"`
Artists []Artist `json:"artists"`
Albums []Album `json:"albums"`
Genre string `json:"genre"`
Version string `json:"version"`
Explicit bool `json:"explicit"`
Available bool `json:"available"`
AvailableForPremiumUsers bool `json:"available_for_premium_users"`
R128 float64 `json:"r128"`
TrackSharingFlag string `json:"track_sharing_flag"`
Major *Major `json:"major"`
Lyrics *TrackLyricsInfo `json:"lyrics"`
SimilarTracks []Track `json:"similar_tracks"`
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_id"]; ok {
json.Unmarshal(v, &track.StorageID)
}
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)
}
// 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"]; ok {
var lyrics TrackLyricsInfo
if err := json.Unmarshal(v, &lyrics); err == nil {
track.Lyrics = &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
}
}
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
}
// Note: Artist and Album types are defined in their respective files
// These are imported automatically since they're in the same package
// 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 minimal lyrics info for a track.
type TrackLyricsInfo struct {
ID JSONID `json:"id"`
Text string `json:"text"`
Major *Major `json:"major"`
Available bool `json:"available"`
HasText bool `json:"has_text"`
}
// 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"`
}