Fix Track model to match Python reference

- R128: changed from JSONR128 float64 to R128 struct with i, tp, important_secs fields
  (Python R128 is an object, not a number)
- StorageID -> StorageDir with json tag storage_dir (Python API uses storage_dir)
- Lyrics: replaced TrackLyricsInfo with Lyrics (from supplement/lyrics.py) and
  TrackLyricsInfo (from track/lyrics_info.py with has_available_sync_lyrics,
  has_available_text_lyrics fields)
- Track.Lyrics field now maps to lyrics_info JSON key with TrackLyricsInfo type
This commit is contained in:
Mrixs committed 2026-10-18 12:34:58 +03:00
1 parent ad83d84531
commit 6312c24b0f
5 files changed
+192 -52

No files matched your search

+53 -17
View File
@@ -111,33 +111,69 @@ func (id JSONID) String() string {
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
// R128 represents EBU R 128 loudness normalization parameters.
// The Yandex Music API returns this either as a number (e.g., -23.5) or as an object
// with fields i, tp, important_secs.
type R128 struct {
BaseModel
I float64 `json:"i"`
Tp float64 `json:"tp"`
ImportantSecs int `json:"important_secs"`
}
// UnmarshalJSON implements json.Unmarshaler, accepting both JSON numbers and objects.
func (r *JSONR128) UnmarshalJSON(data []byte) error {
// Try float64 first
func (r *R128) UnmarshalJSON(data []byte) error {
// Try float64 first (API sometimes returns just a number)
var f float64
if err := json.Unmarshal(data, &f); err == nil {
*r = JSONR128(f)
r.I = f
r.Tp = 0
r.ImportantSecs = 0
return nil
}
// Try object with "value" key
// Try object with fields i, tp, important_secs
var obj struct {
Value float64 `json:"value"`
I float64 `json:"i"`
Tp float64 `json:"tp"`
ImportantSecs int `json:"important_secs"`
}
if err := json.Unmarshal(data, &obj); err == nil {
*r = JSONR128(obj.Value)
return nil
if err := json.Unmarshal(data, &obj); err != nil {
return err
}
// Default to 0 if neither format works
*r = 0
r.I = obj.I
r.Tp = obj.Tp
r.ImportantSecs = obj.ImportantSecs
return nil
}
// Float64 returns the R128 value as a float64.
func (r JSONR128) Float64() float64 {
return float64(r)
// Float64 returns the integrated loudness (i) value as a float64.
func (r R128) Float64() float64 {
return r.I
}
// DeJSON deserializes an R128 from JSON data.
func (r *R128) DeJSON(data []byte, c ClientInterface) (Model, error) {
r128 := &R128{BaseModel: *NewBaseModel(c)}
if err := r128.UnmarshalJSON(data); err != nil {
return nil, err
}
return r128, nil
}
// DeList deserializes a list of R128 from JSON data.
func (r *R128) 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 {
r128 := &R128{BaseModel: *NewBaseModel(c)}
if err := r128.UnmarshalJSON(item); err != nil {
continue
}
result = append(result, r128)
}
return result, nil
}