Fix R128 and remaining ID fields to accept both JSON types

- Track.R128 and TrackShort.R128: float64 → JSONR128 (accepts both JSON number and object)
- All remaining primary ID fields: string → JSONID (accepts both JSON string and number)
  Fixed in: account, artist, clip, concert, feed, label, landing, metatag,
  music_history, pin, queue, radio, search, settings, supplement
This commit is contained in:
Mrixs committed 2026-10-18 11:01:26 +03:00
1 parent d0173f795d
commit dbb823ade3
18 files changed
+75 -44

No files matched your search

+1 -1
View File
@@ -112,7 +112,7 @@ func (a *AccountSettings) DeList(data []byte, c ClientInterface) ([]Model, error
// Subscription represents subscription info. // Subscription represents subscription info.
type Subscription struct { type Subscription struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Type string `json:"type"` Type string `json:"type"`
Status string `json:"status"` Status string `json:"status"`
StartDate string `json:"start_date"` StartDate string `json:"start_date"`
+4 -4
View File
@@ -8,7 +8,7 @@ import (
// Artist represents a full artist from the Yandex Music API. // Artist represents a full artist from the Yandex Music API.
type Artist struct { type Artist struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Name string `json:"name"` Name string `json:"name"`
CoverURI string `json:"cover_uri"` CoverURI string `json:"cover_uri"`
Genres []string `json:"genres"` Genres []string `json:"genres"`
@@ -210,7 +210,7 @@ type ArtistDonations struct {
// DonationItem represents a donation item. // DonationItem represents a donation item.
type DonationItem struct { type DonationItem struct {
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
Amount int `json:"amount"` Amount int `json:"amount"`
@@ -222,7 +222,7 @@ type DonationItem struct {
// ConcertShort represents a concert (minimal for artist). // ConcertShort represents a concert (minimal for artist).
type ConcertShort struct { type ConcertShort struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Date string `json:"date"` Date string `json:"date"`
Venue string `json:"venue"` Venue string `json:"venue"`
@@ -298,7 +298,7 @@ func (c *ConcertShort) DeList(data []byte, client ClientInterface) ([]Model, err
// ClipShort represents a clip (minimal for artist). // ClipShort represents a clip (minimal for artist).
type ClipShort struct { type ClipShort struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Duration int `json:"duration"` Duration int `json:"duration"`
CoverURI string `json:"cover_uri"` CoverURI string `json:"cover_uri"`
+31
View File
@@ -110,3 +110,34 @@ func (id *JSONID) UnmarshalJSON(data []byte) error {
func (id JSONID) String() string { func (id JSONID) String() string {
return string(id) return string(id)
} }
// JSONR128 is a flexible R128 loudness normalization value that accepts both JSON numbers and objects.
// The Yandex Music API sometimes returns r128 as a number (e.g., -23.5) and sometimes
// as an object (e.g., {"value": -23.5}). JSONR128 accepts both and stores as float64.
type JSONR128 float64
// UnmarshalJSON implements json.Unmarshaler, accepting both JSON numbers and objects.
func (r *JSONR128) UnmarshalJSON(data []byte) error {
// Try float64 first
var f float64
if err := json.Unmarshal(data, &f); err == nil {
*r = JSONR128(f)
return nil
}
// Try object with "value" key
var obj struct {
Value float64 `json:"value"`
}
if err := json.Unmarshal(data, &obj); err == nil {
*r = JSONR128(obj.Value)
return nil
}
// Default to 0 if neither format works
*r = 0
return nil
}
// Float64 returns the R128 value as a float64.
func (r JSONR128) Float64() float64 {
return float64(r)
}
+3 -3
View File
@@ -8,7 +8,7 @@ import (
// Clip represents a clip (short video) from the Yandex Music API. // Clip represents a clip (short video) from the Yandex Music API.
type Clip struct { type Clip struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Duration int `json:"duration"` Duration int `json:"duration"`
CoverURI string `json:"cover_uri"` CoverURI string `json:"cover_uri"`
@@ -132,7 +132,7 @@ type ArtistClipItem struct {
// Shot represents a shot (short video). // Shot represents a shot (short video).
type Shot struct { type Shot struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
Duration int `json:"duration"` Duration int `json:"duration"`
@@ -258,7 +258,7 @@ type ShotEvent struct {
// ShotType represents a shot type. // ShotType represents a shot type.
type ShotType struct { type ShotType struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description"` Description string `json:"description"`
Icon string `json:"icon"` Icon string `json:"icon"`
+5 -5
View File
@@ -8,7 +8,7 @@ import (
// Concert represents a concert from the Yandex Music API. // Concert represents a concert from the Yandex Music API.
type Concert struct { type Concert struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
Date string `json:"date"` Date string `json:"date"`
@@ -133,7 +133,7 @@ func (c *Concert) DeList(data []byte, client ClientInterface) ([]Model, error) {
// ConcertVenue represents a concert venue. // ConcertVenue represents a concert venue.
type ConcertVenue struct { type ConcertVenue struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Address string `json:"address"` Address string `json:"address"`
City string `json:"city"` City string `json:"city"`
@@ -145,7 +145,7 @@ type ConcertVenue struct {
// ConcertLocation represents a concert location. // ConcertLocation represents a concert location.
type ConcertLocation struct { type ConcertLocation struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Name string `json:"name"` Name string `json:"name"`
City string `json:"city"` City string `json:"city"`
Country string `json:"country"` Country string `json:"country"`
@@ -214,7 +214,7 @@ type ConcertMinPrice struct {
// ConcertTabConfig represents concert tab config. // ConcertTabConfig represents concert tab config.
type ConcertTabConfig struct { type ConcertTabConfig struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Type string `json:"type"` Type string `json:"type"`
Active bool `json:"active"` Active bool `json:"active"`
@@ -237,7 +237,7 @@ type ConcertSkeleton struct {
// ConcertSkeletonBlock represents a concert skeleton block. // ConcertSkeletonBlock represents a concert skeleton block.
type ConcertSkeletonBlock struct { type ConcertSkeletonBlock struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Type string `json:"type"` Type string `json:"type"`
Title string `json:"title"` Title string `json:"title"`
Data json.RawMessage `json:"data"` Data json.RawMessage `json:"data"`
+3 -3
View File
@@ -122,7 +122,7 @@ func (d *Day) DeList(data []byte, c ClientInterface) ([]Model, error) {
// DayBlock represents a block in a day. // DayBlock represents a block in a day.
type DayBlock struct { type DayBlock struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Type string `json:"type"` Type string `json:"type"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
@@ -141,7 +141,7 @@ type DayBlockData struct {
// GeneratedPlaylist represents a generated playlist. // GeneratedPlaylist represents a generated playlist.
type GeneratedPlaylist struct { type GeneratedPlaylist struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
CoverURI string `json:"cover_uri"` CoverURI string `json:"cover_uri"`
@@ -261,7 +261,7 @@ type TrackWithAds struct {
// Ad represents an ad. // Ad represents an ad.
type Ad struct { type Ad struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Type string `json:"type"` Type string `json:"type"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
+1 -1
View File
@@ -8,7 +8,7 @@ import (
// Label represents a label from the Yandex Music API. // Label represents a label from the Yandex Music API.
type Label struct { type Label struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Name string `json:"name"` Name string `json:"name"`
CoverURI string `json:"cover_uri"` CoverURI string `json:"cover_uri"`
Description string `json:"description"` Description string `json:"description"`
+2 -2
View File
@@ -8,7 +8,7 @@ import (
// Landing represents a landing page from the Yandex Music API. // Landing represents a landing page from the Yandex Music API.
type Landing struct { type Landing struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
CoverURI string `json:"cover_uri"` CoverURI string `json:"cover_uri"`
@@ -75,7 +75,7 @@ func (l *Landing) DeList(data []byte, c ClientInterface) ([]Model, error) {
// LandingBlock represents a block in a landing. // LandingBlock represents a block in a landing.
type LandingBlock struct { type LandingBlock struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Type string `json:"type"` Type string `json:"type"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
+6 -6
View File
@@ -8,7 +8,7 @@ import (
// Metatag represents a metatag from the Yandex Music API. // Metatag represents a metatag from the Yandex Music API.
type Metatag struct { type Metatag struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
Image string `json:"image"` Image string `json:"image"`
@@ -81,7 +81,7 @@ type MetatagTree struct {
// MetatagLeaf represents a metatag leaf. // MetatagLeaf represents a metatag leaf.
type MetatagLeaf struct { type MetatagLeaf struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
Image string `json:"image"` Image string `json:"image"`
@@ -139,7 +139,7 @@ type MetatagArtistEntry struct {
// Genre represents a genre from the Yandex Music API. // Genre represents a genre from the Yandex Music API.
type Genre struct { type Genre struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
Image string `json:"image"` Image string `json:"image"`
@@ -205,7 +205,7 @@ func (g *Genre) DeList(data []byte, client ClientInterface) ([]Model, error) {
// Chart represents a chart from the Yandex Music API. // Chart represents a chart from the Yandex Music API.
type Chart struct { type Chart struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
CoverURI string `json:"cover_uri"` CoverURI string `json:"cover_uri"`
@@ -286,7 +286,7 @@ type ChartItem struct {
// ChartInfoMenu represents a chart info menu. // ChartInfoMenu represents a chart info menu.
type ChartInfoMenu struct { type ChartInfoMenu struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
Items []ChartInfoMenuItem `json:"items"` Items []ChartInfoMenuItem `json:"items"`
@@ -295,7 +295,7 @@ type ChartInfoMenu struct {
// ChartInfoMenuItem represents a chart info menu item. // ChartInfoMenuItem represents a chart info menu item.
type ChartInfoMenuItem struct { type ChartInfoMenuItem struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
Action string `json:"action"` Action string `json:"action"`
+4 -4
View File
@@ -68,7 +68,7 @@ func (mh *MusicHistory) DeList(data []byte, client ClientInterface) ([]Model, er
// MusicHistoryTab represents a music history tab. // MusicHistoryTab represents a music history tab.
type MusicHistoryTab struct { type MusicHistoryTab struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
Icon string `json:"icon"` Icon string `json:"icon"`
@@ -79,7 +79,7 @@ type MusicHistoryTab struct {
// MusicHistoryGroup represents a music history group. // MusicHistoryGroup represents a music history group.
type MusicHistoryGroup struct { type MusicHistoryGroup struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
Items []MusicHistoryItem `json:"items"` Items []MusicHistoryItem `json:"items"`
@@ -89,7 +89,7 @@ type MusicHistoryGroup struct {
// MusicHistoryItem represents a music history item. // MusicHistoryItem represents a music history item.
type MusicHistoryItem struct { type MusicHistoryItem struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Type string `json:"type"` // "track", "album", "artist", "playlist" Type string `json:"type"` // "track", "album", "artist", "playlist"
Track *Track `json:"track"` Track *Track `json:"track"`
Album *Album `json:"album"` Album *Album `json:"album"`
@@ -116,7 +116,7 @@ type MusicHistoryItemData struct {
// MusicHistoryItemID represents music history item ID. // MusicHistoryItemID represents music history item ID.
type MusicHistoryItemID struct { type MusicHistoryItemID struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Type string `json:"type"` Type string `json:"type"`
} }
+2 -2
View File
@@ -8,7 +8,7 @@ import (
// Pin represents a pin from the Yandex Music API. // Pin represents a pin from the Yandex Music API.
type Pin struct { type Pin struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
Image string `json:"image"` Image string `json:"image"`
@@ -130,7 +130,7 @@ type Presaves struct {
// Presave represents a presave. // Presave represents a presave.
type Presave struct { type Presave struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
Image string `json:"image"` Image string `json:"image"`
+2 -2
View File
@@ -8,7 +8,7 @@ import (
// Queue represents a playback queue from the Yandex Music API. // Queue represents a playback queue from the Yandex Music API.
type Queue struct { type Queue struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
TrackIDs []string `json:"track_ids"` TrackIDs []string `json:"track_ids"`
CurrentIndex int `json:"current_index"` CurrentIndex int `json:"current_index"`
QueueType string `json:"queue_type"` QueueType string `json:"queue_type"`
@@ -162,7 +162,7 @@ func (qi *QueueItem) DeList(data []byte, c ClientInterface) ([]Model, error) {
// PlayContext represents a play context. // PlayContext represents a play context.
type PlayContext struct { type PlayContext struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Type string `json:"type"` // "playlist", "album", "artist", "radio", "search" Type string `json:"type"` // "playlist", "album", "artist", "radio", "search"
SourceID string `json:"source_id"` SourceID string `json:"source_id"`
SourceKind string `json:"source_kind"` SourceKind string `json:"source_kind"`
+2 -2
View File
@@ -8,7 +8,7 @@ import (
// RadioStation represents a radio station from the Yandex Music API. // RadioStation represents a radio station from the Yandex Music API.
type RadioStation struct { type RadioStation struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
CoverURI string `json:"cover_uri"` CoverURI string `json:"cover_uri"`
@@ -122,7 +122,7 @@ func (s *StationTracksResult) DeList(data []byte, client ClientInterface) ([]Mod
// RotorStation represents a rotor (generative) station. // RotorStation represents a rotor (generative) station.
type RotorStation struct { type RotorStation struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
CoverURI string `json:"cover_uri"` CoverURI string `json:"cover_uri"`
+3 -3
View File
@@ -49,7 +49,7 @@ type SearchUsersResult struct {
// SearchBanner represents a search banner. // SearchBanner represents a search banner.
type SearchBanner struct { type SearchBanner struct {
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
Image string `json:"image"` Image string `json:"image"`
@@ -60,7 +60,7 @@ type SearchBanner struct {
// Tag represents a search tag. // Tag represents a search tag.
type Tag struct { type Tag struct {
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
Count int `json:"count"` Count int `json:"count"`
@@ -70,7 +70,7 @@ type Tag struct {
// Video represents a video (minimal). // Video represents a video (minimal).
type Video struct { type Video struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Duration int `json:"duration"` Duration int `json:"duration"`
CoverURI string `json:"cover_uri"` CoverURI string `json:"cover_uri"`
+2 -2
View File
@@ -54,7 +54,7 @@ func (e *Experiments) DeList(data []byte, client ClientInterface) ([]Model, erro
// ExperimentDetail represents experiment details. // ExperimentDetail represents experiment details.
type ExperimentDetail struct { type ExperimentDetail struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description"` Description string `json:"description"`
Status string `json:"status"` Status string `json:"status"`
@@ -240,7 +240,7 @@ func (p *PermissionAlerts) DeList(data []byte, client ClientInterface) ([]Model,
// PermissionAlert represents a permission alert. // PermissionAlert represents a permission alert.
type PermissionAlert struct { type PermissionAlert struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Type string `json:"type"` Type string `json:"type"`
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
+1 -1
View File
@@ -333,7 +333,7 @@ func (vs *VideoSupplement) DeList(data []byte, c ClientInterface) ([]Model, erro
// Supplement represents a track supplement. // Supplement represents a track supplement.
type Supplement struct { type Supplement struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Lyrics *LyricsInfo `json:"lyrics"` Lyrics *LyricsInfo `json:"lyrics"`
Videos []VideoSupplement `json:"videos"` Videos []VideoSupplement `json:"videos"`
RadioIsAvailable bool `json:"radio_is_available"` RadioIsAvailable bool `json:"radio_is_available"`
+1 -1
View File
@@ -20,7 +20,7 @@ type Track struct {
Explicit bool `json:"explicit"` Explicit bool `json:"explicit"`
Available bool `json:"available"` Available bool `json:"available"`
AvailableForPremiumUsers bool `json:"available_for_premium_users"` AvailableForPremiumUsers bool `json:"available_for_premium_users"`
R128 float64 `json:"r128"` R128 JSONR128 `json:"r128"`
TrackSharingFlag string `json:"track_sharing_flag"` TrackSharingFlag string `json:"track_sharing_flag"`
Major *Major `json:"major"` Major *Major `json:"major"`
Lyrics *TrackLyricsInfo `json:"lyrics"` Lyrics *TrackLyricsInfo `json:"lyrics"`
+2 -2
View File
@@ -8,7 +8,7 @@ import (
// TrackShort represents a lightweight track used in lists. // TrackShort represents a lightweight track used in lists.
type TrackShort struct { type TrackShort struct {
BaseModel BaseModel
ID string `json:"id"` ID JSONID `json:"id"`
Title string `json:"title"` Title string `json:"title"`
DurationMs int `json:"duration_ms"` DurationMs int `json:"duration_ms"`
StorageID string `json:"storage_id"` StorageID string `json:"storage_id"`
@@ -20,7 +20,7 @@ type TrackShort struct {
Explicit bool `json:"explicit"` Explicit bool `json:"explicit"`
Available bool `json:"available"` Available bool `json:"available"`
AvailableForPremiumUsers bool `json:"available_for_premium_users"` AvailableForPremiumUsers bool `json:"available_for_premium_users"`
R128 float64 `json:"r128"` R128 JSONR128 `json:"r128"`
TrackSharingFlag string `json:"track_sharing_flag"` TrackSharingFlag string `json:"track_sharing_flag"`
Major *Major `json:"major"` Major *Major `json:"major"`
Lyrics *SupplementLyrics `json:"lyrics"` Lyrics *SupplementLyrics `json:"lyrics"`