Initial commit
This commit is contained in:
commit
02a6dabcfb
62 files changed
+15751
No files matched your search
@@ -0,0 +1,315 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// AccountSettings represents account settings
|
||||
type AccountSettings struct {
|
||||
BaseModel
|
||||
Language string `json:"language"`
|
||||
Region string `json:"region"`
|
||||
Email string `json:"email"`
|
||||
Phone string `json:"phone"`
|
||||
Notifications bool `json:"notifications"`
|
||||
AutoPlay bool `json:"auto_play"`
|
||||
HighQuality bool `json:"high_quality"`
|
||||
CacheSize int `json:"cache_size"`
|
||||
DownloadQuality string `json:"download_quality"`
|
||||
ExplicitContent bool `json:"explicit_content"`
|
||||
NormalizeVolume bool `json:"normalize_volume"`
|
||||
Crossfade bool `json:"crossfade"`
|
||||
GaplessPlayback bool `json:"gapless_playback"`
|
||||
ShowLyrics bool `json:"show_lyrics"`
|
||||
ShowCredits bool `json:"show_credits"`
|
||||
AutoDownload bool `json:"auto_download"`
|
||||
DownloadOnWifiOnly bool `json:"download_on_wifi_only"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes AccountSettings from JSON
|
||||
func (a *AccountSettings) 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 := &AccountSettings{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["language"]; ok {
|
||||
json.Unmarshal(v, &settings.Language)
|
||||
}
|
||||
if v, ok := raw["region"]; ok {
|
||||
json.Unmarshal(v, &settings.Region)
|
||||
}
|
||||
if v, ok := raw["email"]; ok {
|
||||
json.Unmarshal(v, &settings.Email)
|
||||
}
|
||||
if v, ok := raw["phone"]; ok {
|
||||
json.Unmarshal(v, &settings.Phone)
|
||||
}
|
||||
if v, ok := raw["notifications"]; ok {
|
||||
json.Unmarshal(v, &settings.Notifications)
|
||||
}
|
||||
if v, ok := raw["auto_play"]; ok {
|
||||
json.Unmarshal(v, &settings.AutoPlay)
|
||||
}
|
||||
if v, ok := raw["high_quality"]; ok {
|
||||
json.Unmarshal(v, &settings.HighQuality)
|
||||
}
|
||||
if v, ok := raw["cache_size"]; ok {
|
||||
json.Unmarshal(v, &settings.CacheSize)
|
||||
}
|
||||
if v, ok := raw["download_quality"]; ok {
|
||||
json.Unmarshal(v, &settings.DownloadQuality)
|
||||
}
|
||||
if v, ok := raw["explicit_content"]; ok {
|
||||
json.Unmarshal(v, &settings.ExplicitContent)
|
||||
}
|
||||
if v, ok := raw["normalize_volume"]; ok {
|
||||
json.Unmarshal(v, &settings.NormalizeVolume)
|
||||
}
|
||||
if v, ok := raw["crossfade"]; ok {
|
||||
json.Unmarshal(v, &settings.Crossfade)
|
||||
}
|
||||
if v, ok := raw["gapless_playback"]; ok {
|
||||
json.Unmarshal(v, &settings.GaplessPlayback)
|
||||
}
|
||||
if v, ok := raw["show_lyrics"]; ok {
|
||||
json.Unmarshal(v, &settings.ShowLyrics)
|
||||
}
|
||||
if v, ok := raw["show_credits"]; ok {
|
||||
json.Unmarshal(v, &settings.ShowCredits)
|
||||
}
|
||||
if v, ok := raw["auto_download"]; ok {
|
||||
json.Unmarshal(v, &settings.AutoDownload)
|
||||
}
|
||||
if v, ok := raw["download_on_wifi_only"]; ok {
|
||||
json.Unmarshal(v, &settings.DownloadOnWifiOnly)
|
||||
}
|
||||
|
||||
return settings, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of AccountSettings
|
||||
func (a *AccountSettings) 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 := &AccountSettings{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, settings); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, settings)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Subscription represents subscription info
|
||||
type Subscription struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Status string `json:"status"`
|
||||
StartDate string `json:"start_date"`
|
||||
EndDate string `json:"end_date"`
|
||||
AutoRenew bool `json:"auto_renew"`
|
||||
PaymentMethod string `json:"payment_method"`
|
||||
Price int `json:"price"`
|
||||
Currency string `json:"currency"`
|
||||
Features []string `json:"features"`
|
||||
CanCancel bool `json:"can_cancel"`
|
||||
CanUpgrade bool `json:"can_upgrade"`
|
||||
TrialAvailable bool `json:"trial_available"`
|
||||
TrialUsed bool `json:"trial_used"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes Subscription from JSON
|
||||
func (s *Subscription) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sub := &Subscription{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &sub.ID)
|
||||
}
|
||||
if v, ok := raw["type"]; ok {
|
||||
json.Unmarshal(v, &sub.Type)
|
||||
}
|
||||
if v, ok := raw["status"]; ok {
|
||||
json.Unmarshal(v, &sub.Status)
|
||||
}
|
||||
if v, ok := raw["start_date"]; ok {
|
||||
json.Unmarshal(v, &sub.StartDate)
|
||||
}
|
||||
if v, ok := raw["end_date"]; ok {
|
||||
json.Unmarshal(v, &sub.EndDate)
|
||||
}
|
||||
if v, ok := raw["auto_renew"]; ok {
|
||||
json.Unmarshal(v, &sub.AutoRenew)
|
||||
}
|
||||
if v, ok := raw["payment_method"]; ok {
|
||||
json.Unmarshal(v, &sub.PaymentMethod)
|
||||
}
|
||||
if v, ok := raw["price"]; ok {
|
||||
json.Unmarshal(v, &sub.Price)
|
||||
}
|
||||
if v, ok := raw["currency"]; ok {
|
||||
json.Unmarshal(v, &sub.Currency)
|
||||
}
|
||||
if v, ok := raw["features"]; ok {
|
||||
json.Unmarshal(v, &sub.Features)
|
||||
}
|
||||
if v, ok := raw["can_cancel"]; ok {
|
||||
json.Unmarshal(v, &sub.CanCancel)
|
||||
}
|
||||
if v, ok := raw["can_upgrade"]; ok {
|
||||
json.Unmarshal(v, &sub.CanUpgrade)
|
||||
}
|
||||
if v, ok := raw["trial_available"]; ok {
|
||||
json.Unmarshal(v, &sub.TrialAvailable)
|
||||
}
|
||||
if v, ok := raw["trial_used"]; ok {
|
||||
json.Unmarshal(v, &sub.TrialUsed)
|
||||
}
|
||||
|
||||
return sub, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of Subscriptions
|
||||
func (s *Subscription) 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 {
|
||||
sub := &Subscription{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, sub); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, sub)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// PlusInfo represents Plus subscription info (from /account/plus or account status)
|
||||
type PlusInfo struct {
|
||||
BaseModel
|
||||
HasPlus bool `json:"has_plus"`
|
||||
IsTutorialCompleted bool `json:"is_tutorial_completed"`
|
||||
Migrated *bool `json:"migrated,omitempty"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes PlusInfo from JSON
|
||||
func (p *PlusInfo) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
plus := &PlusInfo{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["has_plus"]; ok {
|
||||
json.Unmarshal(v, &plus.HasPlus)
|
||||
}
|
||||
if v, ok := raw["is_tutorial_completed"]; ok {
|
||||
json.Unmarshal(v, &plus.IsTutorialCompleted)
|
||||
}
|
||||
if v, ok := raw["migrated"]; ok {
|
||||
var val bool
|
||||
json.Unmarshal(v, &val)
|
||||
plus.Migrated = &val
|
||||
}
|
||||
|
||||
return plus, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of PlusInfo
|
||||
func (p *PlusInfo) 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 {
|
||||
plus := &PlusInfo{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, plus); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, plus)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// PromoCodeStatus represents promo code status
|
||||
type PromoCodeStatus struct {
|
||||
BaseModel
|
||||
Code string `json:"code"`
|
||||
Status string `json:"status"`
|
||||
Description string `json:"description"`
|
||||
Discount int `json:"discount"`
|
||||
Months int `json:"months"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
Activated bool `json:"activated"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes PromoCodeStatus from JSON
|
||||
func (p *PromoCodeStatus) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
promo := &PromoCodeStatus{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["code"]; ok {
|
||||
json.Unmarshal(v, &promo.Code)
|
||||
}
|
||||
if v, ok := raw["status"]; ok {
|
||||
json.Unmarshal(v, &promo.Status)
|
||||
}
|
||||
if v, ok := raw["description"]; ok {
|
||||
json.Unmarshal(v, &promo.Description)
|
||||
}
|
||||
if v, ok := raw["discount"]; ok {
|
||||
json.Unmarshal(v, &promo.Discount)
|
||||
}
|
||||
if v, ok := raw["months"]; ok {
|
||||
json.Unmarshal(v, &promo.Months)
|
||||
}
|
||||
if v, ok := raw["expires_at"]; ok {
|
||||
json.Unmarshal(v, &promo.ExpiresAt)
|
||||
}
|
||||
if v, ok := raw["activated"]; ok {
|
||||
json.Unmarshal(v, &promo.Activated)
|
||||
}
|
||||
|
||||
return promo, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of PromoCodeStatus
|
||||
func (p *PromoCodeStatus) 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 {
|
||||
promo := &PromoCodeStatus{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, promo); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, promo)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Album represents a full album
|
||||
type Album struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
CoverURI string `json:"cover_uri"`
|
||||
Genre string `json:"genre"`
|
||||
Year int `json:"year"`
|
||||
TrackCount int `json:"track_count"`
|
||||
Available bool `json:"available"`
|
||||
ReleaseDate string `json:"release_date"`
|
||||
Artists []Artist `json:"artists"`
|
||||
Labels []Label `json:"labels"`
|
||||
Volumes [][]Track `json:"volumes"`
|
||||
Description string `json:"description"`
|
||||
Meta *AlbumMeta `json:"meta"`
|
||||
Best *Best `json:"best"`
|
||||
// Additional fields
|
||||
Region string `json:"region"`
|
||||
AvailableForPremiumUsers bool `json:"available_for_premium_users"`
|
||||
AvailableForPremiumUsersOnly bool `json:"available_for_premium_users_only"`
|
||||
ContentWarning string `json:"content_warning"`
|
||||
Label string `json:"label"`
|
||||
CatalogNumber string `json:"catalog_number"`
|
||||
Options []string `json:"options"`
|
||||
TrackPositions []TrackPosition `json:"track_positions"`
|
||||
SimilarAlbums []Album `json:"similar_albums"`
|
||||
Trailer *TrailerInfo `json:"trailer"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes an Album from JSON
|
||||
func (a *Album) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
album := &Album{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
// Simple fields
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &album.ID)
|
||||
}
|
||||
if v, ok := raw["title"]; ok {
|
||||
json.Unmarshal(v, &album.Title)
|
||||
}
|
||||
if v, ok := raw["cover_uri"]; ok {
|
||||
json.Unmarshal(v, &album.CoverURI)
|
||||
}
|
||||
if v, ok := raw["genre"]; ok {
|
||||
json.Unmarshal(v, &album.Genre)
|
||||
}
|
||||
if v, ok := raw["year"]; ok {
|
||||
json.Unmarshal(v, &album.Year)
|
||||
}
|
||||
if v, ok := raw["track_count"]; ok {
|
||||
json.Unmarshal(v, &album.TrackCount)
|
||||
}
|
||||
if v, ok := raw["available"]; ok {
|
||||
json.Unmarshal(v, &album.Available)
|
||||
}
|
||||
if v, ok := raw["release_date"]; ok {
|
||||
json.Unmarshal(v, &album.ReleaseDate)
|
||||
}
|
||||
if v, ok := raw["description"]; ok {
|
||||
json.Unmarshal(v, &album.Description)
|
||||
}
|
||||
if v, ok := raw["region"]; ok {
|
||||
json.Unmarshal(v, &album.Region)
|
||||
}
|
||||
if v, ok := raw["available_for_premium_users"]; ok {
|
||||
json.Unmarshal(v, &album.AvailableForPremiumUsers)
|
||||
}
|
||||
if v, ok := raw["available_for_premium_users_only"]; ok {
|
||||
json.Unmarshal(v, &album.AvailableForPremiumUsersOnly)
|
||||
}
|
||||
if v, ok := raw["content_warning"]; ok {
|
||||
json.Unmarshal(v, &album.ContentWarning)
|
||||
}
|
||||
if v, ok := raw["label"]; ok {
|
||||
json.Unmarshal(v, &album.Label)
|
||||
}
|
||||
if v, ok := raw["catalog_number"]; ok {
|
||||
json.Unmarshal(v, &album.CatalogNumber)
|
||||
}
|
||||
if v, ok := raw["options"]; ok {
|
||||
json.Unmarshal(v, &album.Options)
|
||||
}
|
||||
|
||||
// Nested objects
|
||||
if v, ok := raw["artists"]; ok {
|
||||
var artists []Artist
|
||||
json.Unmarshal(v, &artists)
|
||||
album.Artists = artists
|
||||
}
|
||||
if v, ok := raw["labels"]; ok {
|
||||
var labels []Label
|
||||
json.Unmarshal(v, &labels)
|
||||
album.Labels = labels
|
||||
}
|
||||
if v, ok := raw["volumes"]; ok {
|
||||
var volumes [][]Track
|
||||
json.Unmarshal(v, &volumes)
|
||||
album.Volumes = volumes
|
||||
}
|
||||
if v, ok := raw["meta"]; ok {
|
||||
var meta AlbumMeta
|
||||
json.Unmarshal(v, &meta)
|
||||
album.Meta = &meta
|
||||
}
|
||||
if v, ok := raw["best"]; ok {
|
||||
var best Best
|
||||
json.Unmarshal(v, &best)
|
||||
album.Best = &best
|
||||
}
|
||||
if v, ok := raw["track_positions"]; ok {
|
||||
var positions []TrackPosition
|
||||
json.Unmarshal(v, &positions)
|
||||
album.TrackPositions = positions
|
||||
}
|
||||
if v, ok := raw["similar_albums"]; ok {
|
||||
var similar []Album
|
||||
json.Unmarshal(v, &similar)
|
||||
album.SimilarAlbums = similar
|
||||
}
|
||||
if v, ok := raw["trailer"]; ok {
|
||||
var trailer TrailerInfo
|
||||
json.Unmarshal(v, &trailer)
|
||||
album.Trailer = &trailer
|
||||
}
|
||||
|
||||
return album, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of Albums
|
||||
func (a *Album) 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 {
|
||||
album := &Album{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, album); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, album)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// AlbumMeta represents album metadata
|
||||
type AlbumMeta struct {
|
||||
BaseModel
|
||||
Availability *Availability `json:"availability"`
|
||||
Upsell *Upsell `json:"upsell"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes an AlbumMeta from JSON
|
||||
func (am *AlbumMeta) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
meta := &AlbumMeta{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["availability"]; ok {
|
||||
var avail Availability
|
||||
json.Unmarshal(v, &avail)
|
||||
meta.Availability = &avail
|
||||
}
|
||||
if v, ok := raw["upsell"]; ok {
|
||||
var upsell Upsell
|
||||
json.Unmarshal(v, &upsell)
|
||||
meta.Upsell = &upsell
|
||||
}
|
||||
|
||||
return meta, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of AlbumMeta
|
||||
func (am *AlbumMeta) 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 {
|
||||
meta := &AlbumMeta{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, meta); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, meta)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Availability represents availability info
|
||||
type Availability struct {
|
||||
AvailableForPremiumUsers bool `json:"available_for_premium_users"`
|
||||
Territories []string `json:"territories"`
|
||||
}
|
||||
|
||||
// Upsell represents upsell info
|
||||
type Upsell struct {
|
||||
Type string `json:"type"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
// Best represents best tracks info
|
||||
type Best struct {
|
||||
Tracks []Track `json:"tracks"`
|
||||
}
|
||||
|
||||
// TrailerInfo represents album/track trailer info
|
||||
type TrailerInfo struct {
|
||||
BaseModel
|
||||
PreviewURI string `json:"preview_uri"`
|
||||
TrackID string `json:"track_id"`
|
||||
AlbumID string `json:"album_id"`
|
||||
Duration int `json:"duration"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a TrailerInfo from JSON
|
||||
func (ti *TrailerInfo) 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 := &TrailerInfo{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["preview_uri"]; ok {
|
||||
json.Unmarshal(v, &trailer.PreviewURI)
|
||||
}
|
||||
if v, ok := raw["track_id"]; ok {
|
||||
json.Unmarshal(v, &trailer.TrackID)
|
||||
}
|
||||
if v, ok := raw["album_id"]; ok {
|
||||
json.Unmarshal(v, &trailer.AlbumID)
|
||||
}
|
||||
if v, ok := raw["duration"]; ok {
|
||||
json.Unmarshal(v, &trailer.Duration)
|
||||
}
|
||||
|
||||
return trailer, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of TrailerInfo
|
||||
func (ti *TrailerInfo) 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 := &TrailerInfo{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, trailer); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, trailer)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@@ -0,0 +1,357 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAlbum_DeJSON(t *testing.T) {
|
||||
client := newMockClient()
|
||||
data := []byte(`{
|
||||
"id": "123",
|
||||
"title": "Test Album",
|
||||
"cover_uri": "https://example.com/cover.jpg",
|
||||
"genre": "rock",
|
||||
"year": 2023,
|
||||
"track_count": 10,
|
||||
"available": true,
|
||||
"release_date": "2023-01-15",
|
||||
"description": "Test album description",
|
||||
"region": "RU",
|
||||
"available_for_premium_users": true,
|
||||
"available_for_premium_users_only": false,
|
||||
"content_warning": "explicit",
|
||||
"label": "Test Label",
|
||||
"catalog_number": "CAT-123",
|
||||
"options": ["option1", "option2"],
|
||||
"artists": [{"id": "1", "name": "Artist 1", "cover_uri": "https://example.com/artist.jpg"}],
|
||||
"labels": [{"id": "label1", "name": "Label 1"}],
|
||||
"volumes": [[{"id": "t1", "title": "Track 1", "duration_ms": 180000}]],
|
||||
"meta": {"availability": {"available_for_premium_users": true, "territories": ["RU", "US"]}},
|
||||
"best": {"tracks": [{"id": "bt1", "title": "Best Track", "duration_ms": 200000}]},
|
||||
"track_positions": [{"revision": 1, "timestamp": "2023-01-01T00:00:00Z", "position": 1, "from_cache": false}],
|
||||
"similar_albums": [{"id": "sim1", "title": "Similar Album", "cover_uri": "https://example.com/sim.jpg", "year": 2022}],
|
||||
"trailer": {"preview_uri": "https://example.com/preview.mp3", "track_id": "t1", "album_id": "123", "duration": 30}
|
||||
}`)
|
||||
|
||||
album := &Album{BaseModel: *NewBaseModel(client)}
|
||||
result, err := album.DeJSON(data, client)
|
||||
if err != nil {
|
||||
t.Fatalf("DeJSON failed: %v", err)
|
||||
}
|
||||
|
||||
resultAlbum := result.(*Album)
|
||||
if resultAlbum.ID != "123" {
|
||||
t.Errorf("Expected ID '123', got '%s'", resultAlbum.ID)
|
||||
}
|
||||
if resultAlbum.Title != "Test Album" {
|
||||
t.Errorf("Expected Title 'Test Album', got '%s'", resultAlbum.Title)
|
||||
}
|
||||
if resultAlbum.CoverURI != "https://example.com/cover.jpg" {
|
||||
t.Errorf("Expected CoverURI 'https://example.com/cover.jpg', got '%s'", resultAlbum.CoverURI)
|
||||
}
|
||||
if resultAlbum.Genre != "rock" {
|
||||
t.Errorf("Expected Genre 'rock', got '%s'", resultAlbum.Genre)
|
||||
}
|
||||
if resultAlbum.Year != 2023 {
|
||||
t.Errorf("Expected Year 2023, got %d", resultAlbum.Year)
|
||||
}
|
||||
if resultAlbum.TrackCount != 10 {
|
||||
t.Errorf("Expected TrackCount 10, got %d", resultAlbum.TrackCount)
|
||||
}
|
||||
if !resultAlbum.Available {
|
||||
t.Errorf("Expected Available true, got false")
|
||||
}
|
||||
if resultAlbum.ReleaseDate != "2023-01-15" {
|
||||
t.Errorf("Expected ReleaseDate '2023-01-15', got '%s'", resultAlbum.ReleaseDate)
|
||||
}
|
||||
if resultAlbum.Description != "Test album description" {
|
||||
t.Errorf("Expected Description 'Test album description', got '%s'", resultAlbum.Description)
|
||||
}
|
||||
if resultAlbum.Region != "RU" {
|
||||
t.Errorf("Expected Region 'RU', got '%s'", resultAlbum.Region)
|
||||
}
|
||||
if !resultAlbum.AvailableForPremiumUsers {
|
||||
t.Errorf("Expected AvailableForPremiumUsers true, got false")
|
||||
}
|
||||
if resultAlbum.AvailableForPremiumUsersOnly {
|
||||
t.Errorf("Expected AvailableForPremiumUsersOnly false, got true")
|
||||
}
|
||||
if resultAlbum.ContentWarning != "explicit" {
|
||||
t.Errorf("Expected ContentWarning 'explicit', got '%s'", resultAlbum.ContentWarning)
|
||||
}
|
||||
if resultAlbum.Label != "Test Label" {
|
||||
t.Errorf("Expected Label 'Test Label', got '%s'", resultAlbum.Label)
|
||||
}
|
||||
if resultAlbum.CatalogNumber != "CAT-123" {
|
||||
t.Errorf("Expected CatalogNumber 'CAT-123', got '%s'", resultAlbum.CatalogNumber)
|
||||
}
|
||||
if len(resultAlbum.Options) != 2 {
|
||||
t.Errorf("Expected 2 options, got %d", len(resultAlbum.Options))
|
||||
}
|
||||
|
||||
// Test nested artists
|
||||
if len(resultAlbum.Artists) != 1 {
|
||||
t.Errorf("Expected 1 artist, got %d", len(resultAlbum.Artists))
|
||||
}
|
||||
if resultAlbum.Artists[0].Name != "Artist 1" {
|
||||
t.Errorf("Expected artist name 'Artist 1', got '%s'", resultAlbum.Artists[0].Name)
|
||||
}
|
||||
|
||||
// Test nested labels
|
||||
if len(resultAlbum.Labels) != 1 {
|
||||
t.Errorf("Expected 1 label, got %d", len(resultAlbum.Labels))
|
||||
}
|
||||
if resultAlbum.Labels[0].Name != "Label 1" {
|
||||
t.Errorf("Expected label name 'Label 1', got '%s'", resultAlbum.Labels[0].Name)
|
||||
}
|
||||
|
||||
// Test volumes
|
||||
if len(resultAlbum.Volumes) != 1 {
|
||||
t.Errorf("Expected 1 volume, got %d", len(resultAlbum.Volumes))
|
||||
}
|
||||
if len(resultAlbum.Volumes[0]) != 1 {
|
||||
t.Errorf("Expected 1 track in volume, got %d", len(resultAlbum.Volumes[0]))
|
||||
}
|
||||
if resultAlbum.Volumes[0][0].Title != "Track 1" {
|
||||
t.Errorf("Expected track title 'Track 1', got '%s'", resultAlbum.Volumes[0][0].Title)
|
||||
}
|
||||
|
||||
// Test meta
|
||||
if resultAlbum.Meta == nil {
|
||||
t.Fatal("Expected Meta to be non-nil")
|
||||
}
|
||||
if resultAlbum.Meta.Availability == nil {
|
||||
t.Fatal("Expected Availability to be non-nil")
|
||||
}
|
||||
if !resultAlbum.Meta.Availability.AvailableForPremiumUsers {
|
||||
t.Errorf("Expected AvailableForPremiumUsers true in meta")
|
||||
}
|
||||
if len(resultAlbum.Meta.Availability.Territories) != 2 {
|
||||
t.Errorf("Expected 2 territories, got %d", len(resultAlbum.Meta.Availability.Territories))
|
||||
}
|
||||
|
||||
// Test best
|
||||
if resultAlbum.Best == nil {
|
||||
t.Fatal("Expected Best to be non-nil")
|
||||
}
|
||||
if len(resultAlbum.Best.Tracks) != 1 {
|
||||
t.Errorf("Expected 1 best track, got %d", len(resultAlbum.Best.Tracks))
|
||||
}
|
||||
if resultAlbum.Best.Tracks[0].Title != "Best Track" {
|
||||
t.Errorf("Expected best track title 'Best Track', got '%s'", resultAlbum.Best.Tracks[0].Title)
|
||||
}
|
||||
|
||||
// Test track positions
|
||||
if len(resultAlbum.TrackPositions) != 1 {
|
||||
t.Errorf("Expected 1 track position, got %d", len(resultAlbum.TrackPositions))
|
||||
}
|
||||
if resultAlbum.TrackPositions[0].Position != 1 {
|
||||
t.Errorf("Expected position 1, got %d", resultAlbum.TrackPositions[0].Position)
|
||||
}
|
||||
if resultAlbum.TrackPositions[0].Revision != 1 {
|
||||
t.Errorf("Expected revision 1, got %d", resultAlbum.TrackPositions[0].Revision)
|
||||
}
|
||||
|
||||
// Test similar albums
|
||||
if len(resultAlbum.SimilarAlbums) != 1 {
|
||||
t.Errorf("Expected 1 similar album, got %d", len(resultAlbum.SimilarAlbums))
|
||||
}
|
||||
if resultAlbum.SimilarAlbums[0].Title != "Similar Album" {
|
||||
t.Errorf("Expected similar album title 'Similar Album', got '%s'", resultAlbum.SimilarAlbums[0].Title)
|
||||
}
|
||||
|
||||
// Test trailer
|
||||
if resultAlbum.Trailer == nil {
|
||||
t.Fatal("Expected Trailer to be non-nil")
|
||||
}
|
||||
if resultAlbum.Trailer.PreviewURI != "https://example.com/preview.mp3" {
|
||||
t.Errorf("Expected PreviewURI 'https://example.com/preview.mp3', got '%s'", resultAlbum.Trailer.PreviewURI)
|
||||
}
|
||||
if resultAlbum.Trailer.TrackID != "t1" {
|
||||
t.Errorf("Expected TrackID 't1', got '%s'", resultAlbum.Trailer.TrackID)
|
||||
}
|
||||
if resultAlbum.Trailer.AlbumID != "123" {
|
||||
t.Errorf("Expected AlbumID '123', got '%s'", resultAlbum.Trailer.AlbumID)
|
||||
}
|
||||
if resultAlbum.Trailer.Duration != 30 {
|
||||
t.Errorf("Expected Duration 30, got %d", resultAlbum.Trailer.Duration)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlbum_DeJSON_Minimal(t *testing.T) {
|
||||
client := newMockClient()
|
||||
data := []byte(`{
|
||||
"id": "minimal",
|
||||
"title": "Minimal Album"
|
||||
}`)
|
||||
|
||||
album := &Album{BaseModel: *NewBaseModel(client)}
|
||||
result, err := album.DeJSON(data, client)
|
||||
if err != nil {
|
||||
t.Fatalf("DeJSON failed: %v", err)
|
||||
}
|
||||
|
||||
resultAlbum := result.(*Album)
|
||||
if resultAlbum.ID != "minimal" {
|
||||
t.Errorf("Expected ID 'minimal', got '%s'", resultAlbum.ID)
|
||||
}
|
||||
if resultAlbum.Title != "Minimal Album" {
|
||||
t.Errorf("Expected Title 'Minimal Album', got '%s'", resultAlbum.Title)
|
||||
}
|
||||
// Other fields should be zero values
|
||||
if resultAlbum.Year != 0 {
|
||||
t.Errorf("Expected Year 0, got %d", resultAlbum.Year)
|
||||
}
|
||||
if resultAlbum.Available {
|
||||
t.Errorf("Expected Available false, got true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlbum_DeList(t *testing.T) {
|
||||
client := newMockClient()
|
||||
data := []byte(`[
|
||||
{"id": "1", "title": "Album 1", "year": 2022, "track_count": 5, "available": true},
|
||||
{"id": "2", "title": "Album 2", "year": 2023, "track_count": 8, "available": true},
|
||||
{"id": "3", "title": "Album 3", "year": 2021, "track_count": 12, "available": false}
|
||||
]`)
|
||||
|
||||
album := &Album{BaseModel: *NewBaseModel(client)}
|
||||
result, err := album.DeList(data, client)
|
||||
if err != nil {
|
||||
t.Fatalf("DeList failed: %v", err)
|
||||
}
|
||||
|
||||
if len(result) != 3 {
|
||||
t.Errorf("Expected 3 albums, got %d", len(result))
|
||||
}
|
||||
|
||||
albums := make([]*Album, len(result))
|
||||
for i, a := range result {
|
||||
albums[i] = a.(*Album)
|
||||
}
|
||||
|
||||
if albums[0].ID != "1" || albums[0].Title != "Album 1" || albums[0].Year != 2022 {
|
||||
t.Errorf("Album 1 mismatch: %+v", albums[0])
|
||||
}
|
||||
if albums[1].ID != "2" || albums[1].Title != "Album 2" || albums[1].Year != 2023 {
|
||||
t.Errorf("Album 2 mismatch: %+v", albums[1])
|
||||
}
|
||||
if albums[2].ID != "3" || albums[2].Title != "Album 3" || albums[2].Year != 2021 {
|
||||
t.Errorf("Album 3 mismatch: %+v", albums[2])
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlbum_DeList_Empty(t *testing.T) {
|
||||
client := newMockClient()
|
||||
data := []byte(`[]`)
|
||||
|
||||
album := &Album{BaseModel: *NewBaseModel(client)}
|
||||
result, err := album.DeList(data, client)
|
||||
if err != nil {
|
||||
t.Fatalf("DeList failed: %v", err)
|
||||
}
|
||||
|
||||
if len(result) != 0 {
|
||||
t.Errorf("Expected 0 albums, got %d", len(result))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlbumMeta_DeJSON(t *testing.T) {
|
||||
client := newMockClient()
|
||||
data := []byte(`{
|
||||
"availability": {"available_for_premium_users": true, "territories": ["RU", "US", "EU"]},
|
||||
"upsell": {"type": "premium", "description": "Upgrade to premium for full access"}
|
||||
}`)
|
||||
|
||||
meta := &AlbumMeta{BaseModel: *NewBaseModel(client)}
|
||||
result, err := meta.DeJSON(data, client)
|
||||
if err != nil {
|
||||
t.Fatalf("DeJSON failed: %v", err)
|
||||
}
|
||||
|
||||
resultMeta := result.(*AlbumMeta)
|
||||
if resultMeta.Availability == nil {
|
||||
t.Fatal("Expected Availability to be non-nil")
|
||||
}
|
||||
if !resultMeta.Availability.AvailableForPremiumUsers {
|
||||
t.Errorf("Expected AvailableForPremiumUsers true")
|
||||
}
|
||||
if len(resultMeta.Availability.Territories) != 3 {
|
||||
t.Errorf("Expected 3 territories, got %d", len(resultMeta.Availability.Territories))
|
||||
}
|
||||
if resultMeta.Upsell == nil {
|
||||
t.Fatal("Expected Upsell to be non-nil")
|
||||
}
|
||||
if resultMeta.Upsell.Type != "premium" {
|
||||
t.Errorf("Expected Upsell Type 'premium', got '%s'", resultMeta.Upsell.Type)
|
||||
}
|
||||
if resultMeta.Upsell.Description != "Upgrade to premium for full access" {
|
||||
t.Errorf("Expected Upsell Description 'Upgrade to premium for full access', got '%s'", resultMeta.Upsell.Description)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlbumMeta_DeList(t *testing.T) {
|
||||
client := newMockClient()
|
||||
data := []byte(`[
|
||||
{"availability": {"available_for_premium_users": true}},
|
||||
{"availability": {"available_for_premium_users": false}}
|
||||
]`)
|
||||
|
||||
meta := &AlbumMeta{BaseModel: *NewBaseModel(client)}
|
||||
result, err := meta.DeList(data, client)
|
||||
if err != nil {
|
||||
t.Fatalf("DeList failed: %v", err)
|
||||
}
|
||||
|
||||
if len(result) != 2 {
|
||||
t.Errorf("Expected 2 meta objects, got %d", len(result))
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrailerInfo_DeJSON(t *testing.T) {
|
||||
client := newMockClient()
|
||||
data := []byte(`{
|
||||
"preview_uri": "https://example.com/preview.mp3",
|
||||
"track_id": "track123",
|
||||
"album_id": "album456",
|
||||
"duration": 45
|
||||
}`)
|
||||
|
||||
trailer := &TrailerInfo{BaseModel: *NewBaseModel(client)}
|
||||
result, err := trailer.DeJSON(data, client)
|
||||
if err != nil {
|
||||
t.Fatalf("DeJSON failed: %v", err)
|
||||
}
|
||||
|
||||
resultTrailer := result.(*TrailerInfo)
|
||||
if resultTrailer.PreviewURI != "https://example.com/preview.mp3" {
|
||||
t.Errorf("Expected PreviewURI 'https://example.com/preview.mp3', got '%s'", resultTrailer.PreviewURI)
|
||||
}
|
||||
if resultTrailer.TrackID != "track123" {
|
||||
t.Errorf("Expected TrackID 'track123', got '%s'", resultTrailer.TrackID)
|
||||
}
|
||||
if resultTrailer.AlbumID != "album456" {
|
||||
t.Errorf("Expected AlbumID 'album456', got '%s'", resultTrailer.AlbumID)
|
||||
}
|
||||
if resultTrailer.Duration != 45 {
|
||||
t.Errorf("Expected Duration 45, got %d", resultTrailer.Duration)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrailerInfo_DeList(t *testing.T) {
|
||||
client := newMockClient()
|
||||
data := []byte(`[
|
||||
{"preview_uri": "https://example.com/preview1.mp3", "track_id": "t1", "album_id": "a1", "duration": 30},
|
||||
{"preview_uri": "https://example.com/preview2.mp3", "track_id": "t2", "album_id": "a2", "duration": 45}
|
||||
]`)
|
||||
|
||||
trailer := &TrailerInfo{BaseModel: *NewBaseModel(client)}
|
||||
result, err := trailer.DeList(data, client)
|
||||
if err != nil {
|
||||
t.Fatalf("DeList failed: %v", err)
|
||||
}
|
||||
|
||||
if len(result) != 2 {
|
||||
t.Errorf("Expected 2 trailers, got %d", len(result))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,367 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Artist represents a full artist
|
||||
type Artist struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
CoverURI string `json:"cover_uri"`
|
||||
Genres []string `json:"genres"`
|
||||
Tracks int `json:"tracks"`
|
||||
Albums int `json:"albums"`
|
||||
Link string `json:"link"`
|
||||
Available bool `json:"available"`
|
||||
Description string `json:"description"`
|
||||
Composer bool `json:"composer"`
|
||||
Various bool `json:"various"`
|
||||
Decomposed []Artist `json:"decomposed"`
|
||||
Ratings *Ratings `json:"ratings"`
|
||||
Counts *Counts `json:"counts"`
|
||||
SocialLinks []SocialLink `json:"social_links"`
|
||||
// Additional fields
|
||||
IDForFrom string `json:"id_for_from"`
|
||||
Cover *Cover `json:"cover"`
|
||||
BriefInfo *ArtistBriefInfo `json:"brief_info"`
|
||||
Donations *ArtistDonations `json:"donations"`
|
||||
Concerts []Concert `json:"concerts"`
|
||||
Clips []Clip `json:"clips"`
|
||||
Similar []Artist `json:"similar"`
|
||||
AlbumsData []Album `json:"albums_data"`
|
||||
TracksData []Track `json:"tracks_data"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes an Artist from JSON
|
||||
func (a *Artist) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
artist := &Artist{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
// Simple fields
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &artist.ID)
|
||||
}
|
||||
if v, ok := raw["name"]; ok {
|
||||
json.Unmarshal(v, &artist.Name)
|
||||
}
|
||||
if v, ok := raw["cover_uri"]; ok {
|
||||
json.Unmarshal(v, &artist.CoverURI)
|
||||
}
|
||||
if v, ok := raw["genres"]; ok {
|
||||
json.Unmarshal(v, &artist.Genres)
|
||||
}
|
||||
if v, ok := raw["tracks"]; ok {
|
||||
json.Unmarshal(v, &artist.Tracks)
|
||||
}
|
||||
if v, ok := raw["albums"]; ok {
|
||||
json.Unmarshal(v, &artist.Albums)
|
||||
}
|
||||
if v, ok := raw["link"]; ok {
|
||||
json.Unmarshal(v, &artist.Link)
|
||||
}
|
||||
if v, ok := raw["available"]; ok {
|
||||
json.Unmarshal(v, &artist.Available)
|
||||
}
|
||||
if v, ok := raw["description"]; ok {
|
||||
json.Unmarshal(v, &artist.Description)
|
||||
}
|
||||
if v, ok := raw["composer"]; ok {
|
||||
json.Unmarshal(v, &artist.Composer)
|
||||
}
|
||||
if v, ok := raw["various"]; ok {
|
||||
json.Unmarshal(v, &artist.Various)
|
||||
}
|
||||
if v, ok := raw["id_for_from"]; ok {
|
||||
json.Unmarshal(v, &artist.IDForFrom)
|
||||
}
|
||||
|
||||
// Nested objects
|
||||
if v, ok := raw["decomposed"]; ok {
|
||||
var decomposed []Artist
|
||||
json.Unmarshal(v, &decomposed)
|
||||
artist.Decomposed = decomposed
|
||||
}
|
||||
if v, ok := raw["ratings"]; ok {
|
||||
var ratings Ratings
|
||||
json.Unmarshal(v, &ratings)
|
||||
artist.Ratings = &ratings
|
||||
}
|
||||
if v, ok := raw["counts"]; ok {
|
||||
var counts Counts
|
||||
json.Unmarshal(v, &counts)
|
||||
artist.Counts = &counts
|
||||
}
|
||||
if v, ok := raw["social_links"]; ok {
|
||||
var links []SocialLink
|
||||
json.Unmarshal(v, &links)
|
||||
artist.SocialLinks = links
|
||||
}
|
||||
if v, ok := raw["cover"]; ok {
|
||||
var cover Cover
|
||||
json.Unmarshal(v, &cover)
|
||||
artist.Cover = &cover
|
||||
}
|
||||
if v, ok := raw["brief_info"]; ok {
|
||||
var brief ArtistBriefInfo
|
||||
json.Unmarshal(v, &brief)
|
||||
artist.BriefInfo = &brief
|
||||
}
|
||||
if v, ok := raw["donations"]; ok {
|
||||
var donations ArtistDonations
|
||||
json.Unmarshal(v, &donations)
|
||||
artist.Donations = &donations
|
||||
}
|
||||
if v, ok := raw["concerts"]; ok {
|
||||
var concerts []Concert
|
||||
json.Unmarshal(v, &concerts)
|
||||
artist.Concerts = concerts
|
||||
}
|
||||
if v, ok := raw["clips"]; ok {
|
||||
var clips []Clip
|
||||
json.Unmarshal(v, &clips)
|
||||
artist.Clips = clips
|
||||
}
|
||||
if v, ok := raw["similar"]; ok {
|
||||
var similar []Artist
|
||||
json.Unmarshal(v, &similar)
|
||||
artist.Similar = similar
|
||||
}
|
||||
if v, ok := raw["albums"]; ok {
|
||||
var albums []Album
|
||||
json.Unmarshal(v, &albums)
|
||||
artist.AlbumsData = albums
|
||||
}
|
||||
if v, ok := raw["tracks"]; ok {
|
||||
var tracks []Track
|
||||
json.Unmarshal(v, &tracks)
|
||||
artist.TracksData = tracks
|
||||
}
|
||||
|
||||
return artist, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of Artists
|
||||
func (a *Artist) 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 {
|
||||
artist := &Artist{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, artist); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, artist)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Ratings represents artist ratings
|
||||
type Ratings struct {
|
||||
Rating float64 `json:"rating"`
|
||||
Votes int `json:"votes"`
|
||||
}
|
||||
|
||||
// Counts represents artist counts
|
||||
type Counts struct {
|
||||
Tracks int `json:"tracks"`
|
||||
Albums int `json:"albums"`
|
||||
Folders int `json:"folders"`
|
||||
}
|
||||
|
||||
// SocialLink represents a social media link
|
||||
type SocialLink struct {
|
||||
URL string `json:"url"`
|
||||
Title string `json:"title"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// Cover represents cover image info
|
||||
type Cover struct {
|
||||
URI string `json:"uri"`
|
||||
Type string `json:"type"`
|
||||
Prefix string `json:"prefix"`
|
||||
Pattern string `json:"pattern"`
|
||||
Background string `json:"background"`
|
||||
}
|
||||
|
||||
// ArtistBriefInfo represents brief artist info
|
||||
type ArtistBriefInfo struct {
|
||||
Description string `json:"description"`
|
||||
Available bool `json:"available"`
|
||||
}
|
||||
|
||||
// ArtistDonations represents artist donations info
|
||||
type ArtistDonations struct {
|
||||
Items []DonationItem `json:"items"`
|
||||
Total int `json:"total"`
|
||||
Goal int `json:"goal"`
|
||||
Raised int `json:"raised"`
|
||||
}
|
||||
|
||||
// DonationItem represents a donation item
|
||||
type DonationItem struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Amount int `json:"amount"`
|
||||
Goal int `json:"goal"`
|
||||
Raised int `json:"raised"`
|
||||
Currency string `json:"currency"`
|
||||
}
|
||||
|
||||
// ConcertShort represents a concert (minimal for artist)
|
||||
type ConcertShort struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Date string `json:"date"`
|
||||
Venue string `json:"venue"`
|
||||
Location string `json:"location"`
|
||||
TicketURI string `json:"ticket_uri"`
|
||||
ImageURI string `json:"image_uri"`
|
||||
MinPrice int `json:"min_price"`
|
||||
MaxPrice int `json:"max_price"`
|
||||
Available bool `json:"available"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a ConcertShort from JSON
|
||||
func (c *ConcertShort) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
concert := &ConcertShort{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &concert.ID)
|
||||
}
|
||||
if v, ok := raw["title"]; ok {
|
||||
json.Unmarshal(v, &concert.Title)
|
||||
}
|
||||
if v, ok := raw["date"]; ok {
|
||||
json.Unmarshal(v, &concert.Date)
|
||||
}
|
||||
if v, ok := raw["venue"]; ok {
|
||||
json.Unmarshal(v, &concert.Venue)
|
||||
}
|
||||
if v, ok := raw["location"]; ok {
|
||||
json.Unmarshal(v, &concert.Location)
|
||||
}
|
||||
if v, ok := raw["ticket_uri"]; ok {
|
||||
json.Unmarshal(v, &concert.TicketURI)
|
||||
}
|
||||
if v, ok := raw["image_uri"]; ok {
|
||||
json.Unmarshal(v, &concert.ImageURI)
|
||||
}
|
||||
if v, ok := raw["min_price"]; ok {
|
||||
json.Unmarshal(v, &concert.MinPrice)
|
||||
}
|
||||
if v, ok := raw["max_price"]; ok {
|
||||
json.Unmarshal(v, &concert.MaxPrice)
|
||||
}
|
||||
if v, ok := raw["available"]; ok {
|
||||
json.Unmarshal(v, &concert.Available)
|
||||
}
|
||||
|
||||
return concert, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of ConcertShort
|
||||
func (c *ConcertShort) DeList(data []byte, client 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 {
|
||||
concert := &ConcertShort{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, concert); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, concert)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ClipShort represents a clip (minimal for artist)
|
||||
type ClipShort struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Duration int `json:"duration"`
|
||||
CoverURI string `json:"cover_uri"`
|
||||
PreviewURI string `json:"preview_uri"`
|
||||
Available bool `json:"available"`
|
||||
Views int `json:"views"`
|
||||
Likes int `json:"likes"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a ClipShort from JSON
|
||||
func (c *ClipShort) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
clip := &ClipShort{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &clip.ID)
|
||||
}
|
||||
if v, ok := raw["title"]; ok {
|
||||
json.Unmarshal(v, &clip.Title)
|
||||
}
|
||||
if v, ok := raw["duration"]; ok {
|
||||
json.Unmarshal(v, &clip.Duration)
|
||||
}
|
||||
if v, ok := raw["cover_uri"]; ok {
|
||||
json.Unmarshal(v, &clip.CoverURI)
|
||||
}
|
||||
if v, ok := raw["preview_uri"]; ok {
|
||||
json.Unmarshal(v, &clip.PreviewURI)
|
||||
}
|
||||
if v, ok := raw["available"]; ok {
|
||||
json.Unmarshal(v, &clip.Available)
|
||||
}
|
||||
if v, ok := raw["views"]; ok {
|
||||
json.Unmarshal(v, &clip.Views)
|
||||
}
|
||||
if v, ok := raw["likes"]; ok {
|
||||
json.Unmarshal(v, &clip.Likes)
|
||||
}
|
||||
if v, ok := raw["created_at"]; ok {
|
||||
json.Unmarshal(v, &clip.CreatedAt)
|
||||
}
|
||||
|
||||
return clip, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of ClipShort
|
||||
func (c *ClipShort) DeList(data []byte, client 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 {
|
||||
clip := &ClipShort{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, clip); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, clip)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/utils"
|
||||
)
|
||||
|
||||
// Model is the base interface for all models
|
||||
type Model interface {
|
||||
// DeJSON deserializes from JSON
|
||||
DeJSON(data []byte, c ClientInterface) (Model, error)
|
||||
// DeList deserializes a list of models
|
||||
DeList(data []byte, c ClientInterface) ([]Model, error)
|
||||
// ToJSON serializes to JSON
|
||||
ToJSON() ([]byte, error)
|
||||
// ToMap converts to map
|
||||
ToMap() (map[string]any, error)
|
||||
}
|
||||
|
||||
// BaseModel provides common functionality for models
|
||||
type BaseModel struct {
|
||||
Client ClientInterface `json:"-"`
|
||||
}
|
||||
|
||||
// NewBaseModel creates a new BaseModel
|
||||
func NewBaseModel(c ClientInterface) *BaseModel {
|
||||
return &BaseModel{Client: c}
|
||||
}
|
||||
|
||||
// DeJSON implements Model.DeJSON for basic models
|
||||
func (b *BaseModel) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
// This should be overridden by concrete types
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// DeList implements Model.DeList for basic models
|
||||
func (b *BaseModel) 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 range rawList {
|
||||
// This should be overridden by concrete types
|
||||
result = append(result, nil)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ToJSON serializes the model to JSON
|
||||
func (b *BaseModel) ToJSON() ([]byte, error) {
|
||||
return utils.Marshal(b)
|
||||
}
|
||||
|
||||
// ToMap converts the model to a map
|
||||
func (b *BaseModel) ToMap() (map[string]any, error) {
|
||||
data, err := b.ToJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result map[string]any
|
||||
if err := json.Unmarshal(data, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// SetClient sets the client on the model
|
||||
func (b *BaseModel) SetClient(c ClientInterface) {
|
||||
b.Client = c
|
||||
}
|
||||
|
||||
// GetClient returns the client
|
||||
func (b *BaseModel) GetClient() ClientInterface {
|
||||
return b.Client
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// ClientInterface defines the minimal client interface needed by models
|
||||
type ClientInterface interface {
|
||||
GetRequest() RequestInterface
|
||||
}
|
||||
|
||||
// RequestInterface defines the minimal request interface needed by models
|
||||
type RequestInterface interface {
|
||||
Get(ctx context.Context, path string, params map[string]string, result any) error
|
||||
Post(ctx context.Context, path string, body any, result any) error
|
||||
Put(ctx context.Context, path string, body any, result any) error
|
||||
Delete(ctx context.Context, path string, body any, result any) error
|
||||
Download(ctx context.Context, url string) ([]byte, error)
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Clip represents a clip (short video)
|
||||
type Clip struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Duration int `json:"duration"`
|
||||
CoverURI string `json:"cover_uri"`
|
||||
PreviewURI string `json:"preview_uri"`
|
||||
Available bool `json:"available"`
|
||||
Views int `json:"views"`
|
||||
Likes int `json:"likes"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
Artist *Artist `json:"artist"`
|
||||
Track *Track `json:"track"`
|
||||
Playlist *Playlist `json:"playlist"`
|
||||
ClipType string `json:"clip_type"`
|
||||
IsVertical bool `json:"is_vertical"`
|
||||
AspectRatio string `json:"aspect_ratio"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a Clip from JSON
|
||||
func (c *Clip) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
clip := &Clip{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &clip.ID)
|
||||
}
|
||||
if v, ok := raw["title"]; ok {
|
||||
json.Unmarshal(v, &clip.Title)
|
||||
}
|
||||
if v, ok := raw["duration"]; ok {
|
||||
json.Unmarshal(v, &clip.Duration)
|
||||
}
|
||||
if v, ok := raw["cover_uri"]; ok {
|
||||
json.Unmarshal(v, &clip.CoverURI)
|
||||
}
|
||||
if v, ok := raw["preview_uri"]; ok {
|
||||
json.Unmarshal(v, &clip.PreviewURI)
|
||||
}
|
||||
if v, ok := raw["available"]; ok {
|
||||
json.Unmarshal(v, &clip.Available)
|
||||
}
|
||||
if v, ok := raw["views"]; ok {
|
||||
json.Unmarshal(v, &clip.Views)
|
||||
}
|
||||
if v, ok := raw["likes"]; ok {
|
||||
json.Unmarshal(v, &clip.Likes)
|
||||
}
|
||||
if v, ok := raw["created_at"]; ok {
|
||||
json.Unmarshal(v, &clip.CreatedAt)
|
||||
}
|
||||
if v, ok := raw["clip_type"]; ok {
|
||||
json.Unmarshal(v, &clip.ClipType)
|
||||
}
|
||||
if v, ok := raw["is_vertical"]; ok {
|
||||
json.Unmarshal(v, &clip.IsVertical)
|
||||
}
|
||||
if v, ok := raw["aspect_ratio"]; ok {
|
||||
json.Unmarshal(v, &clip.AspectRatio)
|
||||
}
|
||||
|
||||
if v, ok := raw["artist"]; ok {
|
||||
var artist Artist
|
||||
json.Unmarshal(v, &artist)
|
||||
clip.Artist = &artist
|
||||
}
|
||||
if v, ok := raw["track"]; ok {
|
||||
var track Track
|
||||
json.Unmarshal(v, &track)
|
||||
clip.Track = &track
|
||||
}
|
||||
if v, ok := raw["playlist"]; ok {
|
||||
var playlist Playlist
|
||||
json.Unmarshal(v, &playlist)
|
||||
clip.Playlist = &playlist
|
||||
}
|
||||
|
||||
return clip, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of Clips
|
||||
func (c *Clip) DeList(data []byte, client 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 {
|
||||
clip := &Clip{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, clip); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, clip)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ClipsWillLike represents clips the user might like
|
||||
type ClipsWillLike struct {
|
||||
BaseModel
|
||||
Clips []Clip `json:"clips"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
// ArtistClipData represents artist clip data
|
||||
type ArtistClipData struct {
|
||||
BaseModel
|
||||
Clips []Clip `json:"clips"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
// ArtistClipItem represents an artist clip item
|
||||
type ArtistClipItem struct {
|
||||
BaseModel
|
||||
Clip *Clip `json:"clip"`
|
||||
Index int `json:"index"`
|
||||
}
|
||||
|
||||
// Shot represents a shot (short video)
|
||||
type Shot struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Duration int `json:"duration"`
|
||||
CoverURI string `json:"cover_uri"`
|
||||
PreviewURI string `json:"preview_uri"`
|
||||
Available bool `json:"available"`
|
||||
Views int `json:"views"`
|
||||
Likes int `json:"likes"`
|
||||
Comments int `json:"comments"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
Author *User `json:"author"`
|
||||
Track *Track `json:"track"`
|
||||
ShotType string `json:"shot_type"`
|
||||
Tags []string `json:"tags"`
|
||||
IsVertical bool `json:"is_vertical"`
|
||||
AspectRatio string `json:"aspect_ratio"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a Shot from JSON
|
||||
func (s *Shot) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
shot := &Shot{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &shot.ID)
|
||||
}
|
||||
if v, ok := raw["title"]; ok {
|
||||
json.Unmarshal(v, &shot.Title)
|
||||
}
|
||||
if v, ok := raw["description"]; ok {
|
||||
json.Unmarshal(v, &shot.Description)
|
||||
}
|
||||
if v, ok := raw["duration"]; ok {
|
||||
json.Unmarshal(v, &shot.Duration)
|
||||
}
|
||||
if v, ok := raw["cover_uri"]; ok {
|
||||
json.Unmarshal(v, &shot.CoverURI)
|
||||
}
|
||||
if v, ok := raw["preview_uri"]; ok {
|
||||
json.Unmarshal(v, &shot.PreviewURI)
|
||||
}
|
||||
if v, ok := raw["available"]; ok {
|
||||
json.Unmarshal(v, &shot.Available)
|
||||
}
|
||||
if v, ok := raw["views"]; ok {
|
||||
json.Unmarshal(v, &shot.Views)
|
||||
}
|
||||
if v, ok := raw["likes"]; ok {
|
||||
json.Unmarshal(v, &shot.Likes)
|
||||
}
|
||||
if v, ok := raw["comments"]; ok {
|
||||
json.Unmarshal(v, &shot.Comments)
|
||||
}
|
||||
if v, ok := raw["created_at"]; ok {
|
||||
json.Unmarshal(v, &shot.CreatedAt)
|
||||
}
|
||||
if v, ok := raw["shot_type"]; ok {
|
||||
json.Unmarshal(v, &shot.ShotType)
|
||||
}
|
||||
if v, ok := raw["tags"]; ok {
|
||||
json.Unmarshal(v, &shot.Tags)
|
||||
}
|
||||
if v, ok := raw["is_vertical"]; ok {
|
||||
json.Unmarshal(v, &shot.IsVertical)
|
||||
}
|
||||
if v, ok := raw["aspect_ratio"]; ok {
|
||||
json.Unmarshal(v, &shot.AspectRatio)
|
||||
}
|
||||
|
||||
if v, ok := raw["author"]; ok {
|
||||
var user User
|
||||
json.Unmarshal(v, &user)
|
||||
shot.Author = &user
|
||||
}
|
||||
if v, ok := raw["track"]; ok {
|
||||
var track Track
|
||||
json.Unmarshal(v, &track)
|
||||
shot.Track = &track
|
||||
}
|
||||
|
||||
return shot, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of Shots
|
||||
func (s *Shot) DeList(data []byte, client 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 {
|
||||
shot := &Shot{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, shot); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, shot)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ShotData represents shot data
|
||||
type ShotData struct {
|
||||
BaseModel
|
||||
Shots []Shot `json:"shots"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
// ShotEvent represents a shot event
|
||||
type ShotEvent struct {
|
||||
BaseModel
|
||||
EventID string `json:"event_id"`
|
||||
EventType string `json:"event_type"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
ShotID string `json:"shot_id"`
|
||||
Action string `json:"action"`
|
||||
}
|
||||
|
||||
// ShotType represents a shot type
|
||||
type ShotType struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Icon string `json:"icon"`
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Concert represents a concert
|
||||
type Concert struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Date string `json:"date"`
|
||||
Time string `json:"time"`
|
||||
Venue *ConcertVenue `json:"venue"`
|
||||
Location *ConcertLocation `json:"location"`
|
||||
MinPrice int `json:"min_price"`
|
||||
MaxPrice int `json:"max_price"`
|
||||
Currency string `json:"currency"`
|
||||
TicketURI string `json:"ticket_uri"`
|
||||
ImageURI string `json:"image_uri"`
|
||||
Available bool `json:"available"`
|
||||
SoldOut bool `json:"sold_out"`
|
||||
Artists []Artist `json:"artists"`
|
||||
Genres []string `json:"genres"`
|
||||
Cashback *ConcertCashback `json:"cashback"`
|
||||
Tabs []ConcertTabConfig `json:"tabs"`
|
||||
Skeleton *ConcertSkeleton `json:"skeleton"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a Concert from JSON
|
||||
func (c *Concert) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
concert := &Concert{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &concert.ID)
|
||||
}
|
||||
if v, ok := raw["title"]; ok {
|
||||
json.Unmarshal(v, &concert.Title)
|
||||
}
|
||||
if v, ok := raw["description"]; ok {
|
||||
json.Unmarshal(v, &concert.Description)
|
||||
}
|
||||
if v, ok := raw["date"]; ok {
|
||||
json.Unmarshal(v, &concert.Date)
|
||||
}
|
||||
if v, ok := raw["time"]; ok {
|
||||
json.Unmarshal(v, &concert.Time)
|
||||
}
|
||||
if v, ok := raw["min_price"]; ok {
|
||||
json.Unmarshal(v, &concert.MinPrice)
|
||||
}
|
||||
if v, ok := raw["max_price"]; ok {
|
||||
json.Unmarshal(v, &concert.MaxPrice)
|
||||
}
|
||||
if v, ok := raw["currency"]; ok {
|
||||
json.Unmarshal(v, &concert.Currency)
|
||||
}
|
||||
if v, ok := raw["ticket_uri"]; ok {
|
||||
json.Unmarshal(v, &concert.TicketURI)
|
||||
}
|
||||
if v, ok := raw["image_uri"]; ok {
|
||||
json.Unmarshal(v, &concert.ImageURI)
|
||||
}
|
||||
if v, ok := raw["available"]; ok {
|
||||
json.Unmarshal(v, &concert.Available)
|
||||
}
|
||||
if v, ok := raw["sold_out"]; ok {
|
||||
json.Unmarshal(v, &concert.SoldOut)
|
||||
}
|
||||
if v, ok := raw["genres"]; ok {
|
||||
json.Unmarshal(v, &concert.Genres)
|
||||
}
|
||||
|
||||
if v, ok := raw["venue"]; ok {
|
||||
var venue ConcertVenue
|
||||
json.Unmarshal(v, &venue)
|
||||
concert.Venue = &venue
|
||||
}
|
||||
if v, ok := raw["location"]; ok {
|
||||
var location ConcertLocation
|
||||
json.Unmarshal(v, &location)
|
||||
concert.Location = &location
|
||||
}
|
||||
if v, ok := raw["artists"]; ok {
|
||||
var artists []Artist
|
||||
json.Unmarshal(v, &artists)
|
||||
concert.Artists = artists
|
||||
}
|
||||
if v, ok := raw["cashback"]; ok {
|
||||
var cashback ConcertCashback
|
||||
json.Unmarshal(v, &cashback)
|
||||
concert.Cashback = &cashback
|
||||
}
|
||||
if v, ok := raw["tabs"]; ok {
|
||||
var tabs []ConcertTabConfig
|
||||
json.Unmarshal(v, &tabs)
|
||||
concert.Tabs = tabs
|
||||
}
|
||||
if v, ok := raw["skeleton"]; ok {
|
||||
var skeleton ConcertSkeleton
|
||||
json.Unmarshal(v, &skeleton)
|
||||
concert.Skeleton = &skeleton
|
||||
}
|
||||
|
||||
return concert, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of Concerts
|
||||
func (c *Concert) DeList(data []byte, client 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 {
|
||||
concert := &Concert{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, concert); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, concert)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ConcertVenue represents a concert venue
|
||||
type ConcertVenue struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Address string `json:"address"`
|
||||
City string `json:"city"`
|
||||
Country string `json:"country"`
|
||||
Capacity int `json:"capacity"`
|
||||
ImageURI string `json:"image_uri"`
|
||||
}
|
||||
|
||||
// ConcertLocation represents a concert location
|
||||
type ConcertLocation struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
City string `json:"city"`
|
||||
Country string `json:"country"`
|
||||
Timezone string `json:"timezone"`
|
||||
Venues []ConcertVenue `json:"venues"`
|
||||
}
|
||||
|
||||
// ConcertLocations represents concert locations
|
||||
type ConcertLocations struct {
|
||||
BaseModel
|
||||
Locations []ConcertLocation `json:"locations"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// ConcertFeed represents a concert feed
|
||||
type ConcertFeed struct {
|
||||
BaseModel
|
||||
Concerts []Concert `json:"concerts"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// ConcertInfo represents concert info
|
||||
type ConcertInfo struct {
|
||||
BaseModel
|
||||
Concert *Concert `json:"concert"`
|
||||
Related []Concert `json:"related"`
|
||||
}
|
||||
|
||||
// ConcertEventInfo represents concert event info
|
||||
type ConcertEventInfo struct {
|
||||
BaseModel
|
||||
EventID string `json:"event_id"`
|
||||
EventType string `json:"event_type"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
}
|
||||
|
||||
// ConcertDescription represents concert description
|
||||
type ConcertDescription struct {
|
||||
BaseModel
|
||||
Text string `json:"text"`
|
||||
HTML string `json:"html"`
|
||||
ShortText string `json:"short_text"`
|
||||
}
|
||||
|
||||
// ConcertCashback represents concert cashback
|
||||
type ConcertCashback struct {
|
||||
BaseModel
|
||||
Amount int `json:"amount"`
|
||||
Currency string `json:"currency"`
|
||||
Percent int `json:"percent"`
|
||||
Expires string `json:"expires"`
|
||||
}
|
||||
|
||||
// ConcertMinPrice represents concert min price
|
||||
type ConcertMinPrice struct {
|
||||
BaseModel
|
||||
Price int `json:"price"`
|
||||
Currency string `json:"currency"`
|
||||
}
|
||||
|
||||
// ConcertTabConfig represents concert tab config
|
||||
type ConcertTabConfig struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Type string `json:"type"`
|
||||
Active bool `json:"active"`
|
||||
Range *ConcertTabRange `json:"range"`
|
||||
}
|
||||
|
||||
// ConcertTabRange represents concert tab range
|
||||
type ConcertTabRange struct {
|
||||
BaseModel
|
||||
From string `json:"from"`
|
||||
To string `json:"to"`
|
||||
}
|
||||
|
||||
// ConcertSkeleton represents concert skeleton
|
||||
type ConcertSkeleton struct {
|
||||
BaseModel
|
||||
Blocks []ConcertSkeletonBlock `json:"blocks"`
|
||||
}
|
||||
|
||||
// ConcertSkeletonBlock represents a concert skeleton block
|
||||
type ConcertSkeletonBlock struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Title string `json:"title"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Credits represents track credits
|
||||
type Credits struct {
|
||||
BaseModel
|
||||
Items []Credit `json:"items"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes Credits from JSON
|
||||
func (c *Credits) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
credits := &Credits{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["items"]; ok {
|
||||
var items []Credit
|
||||
json.Unmarshal(v, &items)
|
||||
credits.Items = items
|
||||
}
|
||||
if v, ok := raw["total"]; ok {
|
||||
json.Unmarshal(v, &credits.Total)
|
||||
}
|
||||
|
||||
return credits, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of Credits
|
||||
func (c *Credits) DeList(data []byte, client 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 {
|
||||
credits := &Credits{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, credits); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, credits)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Credit represents a credit
|
||||
type Credit struct {
|
||||
BaseModel
|
||||
Role string `json:"role"`
|
||||
Name string `json:"name"`
|
||||
ArtistID string `json:"artist_id"`
|
||||
ArtistName string `json:"artist_name"`
|
||||
IsMain bool `json:"is_main"`
|
||||
TrackID string `json:"track_id"`
|
||||
AlbumID string `json:"album_id"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a Credit from JSON
|
||||
func (c *Credit) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
credit := &Credit{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["role"]; ok {
|
||||
json.Unmarshal(v, &credit.Role)
|
||||
}
|
||||
if v, ok := raw["name"]; ok {
|
||||
json.Unmarshal(v, &credit.Name)
|
||||
}
|
||||
if v, ok := raw["artist_id"]; ok {
|
||||
json.Unmarshal(v, &credit.ArtistID)
|
||||
}
|
||||
if v, ok := raw["artist_name"]; ok {
|
||||
json.Unmarshal(v, &credit.ArtistName)
|
||||
}
|
||||
if v, ok := raw["is_main"]; ok {
|
||||
json.Unmarshal(v, &credit.IsMain)
|
||||
}
|
||||
if v, ok := raw["track_id"]; ok {
|
||||
json.Unmarshal(v, &credit.TrackID)
|
||||
}
|
||||
if v, ok := raw["album_id"]; ok {
|
||||
json.Unmarshal(v, &credit.AlbumID)
|
||||
}
|
||||
|
||||
return credit, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of Credits
|
||||
func (c *Credit) DeList(data []byte, client 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 {
|
||||
credit := &Credit{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, credit); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, credit)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// LicenceTextPart represents a licence text part
|
||||
type LicenceTextPart struct {
|
||||
BaseModel
|
||||
Text string `json:"text"`
|
||||
Language string `json:"language"`
|
||||
URL string `json:"url"`
|
||||
Title string `json:"title"`
|
||||
IsMain bool `json:"is_main"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a LicenceTextPart from JSON
|
||||
func (ltp *LicenceTextPart) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
part := &LicenceTextPart{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["text"]; ok {
|
||||
json.Unmarshal(v, &part.Text)
|
||||
}
|
||||
if v, ok := raw["language"]; ok {
|
||||
json.Unmarshal(v, &part.Language)
|
||||
}
|
||||
if v, ok := raw["url"]; ok {
|
||||
json.Unmarshal(v, &part.URL)
|
||||
}
|
||||
if v, ok := raw["title"]; ok {
|
||||
json.Unmarshal(v, &part.Title)
|
||||
}
|
||||
if v, ok := raw["is_main"]; ok {
|
||||
json.Unmarshal(v, &part.IsMain)
|
||||
}
|
||||
|
||||
return part, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of LicenceTextPart
|
||||
func (ltp *LicenceTextPart) DeList(data []byte, client 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 {
|
||||
part := &LicenceTextPart{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, part); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, part)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Feed represents the main feed
|
||||
type Feed struct {
|
||||
BaseModel
|
||||
Days []Day `json:"days"`
|
||||
GeneratedPlaylists []GeneratedPlaylist `json:"generated_playlists"`
|
||||
PlayContexts []PlayContext `json:"play_contexts"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a Feed from JSON
|
||||
func (f *Feed) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
feed := &Feed{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["days"]; ok {
|
||||
var days []Day
|
||||
json.Unmarshal(v, &days)
|
||||
feed.Days = days
|
||||
}
|
||||
if v, ok := raw["generated_playlists"]; ok {
|
||||
var playlists []GeneratedPlaylist
|
||||
json.Unmarshal(v, &playlists)
|
||||
feed.GeneratedPlaylists = playlists
|
||||
}
|
||||
if v, ok := raw["play_contexts"]; ok {
|
||||
var contexts []PlayContext
|
||||
json.Unmarshal(v, &contexts)
|
||||
feed.PlayContexts = contexts
|
||||
}
|
||||
|
||||
return feed, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of Feeds
|
||||
func (f *Feed) 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 {
|
||||
feed := &Feed{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, feed); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, feed)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Day represents a day in the feed
|
||||
type Day struct {
|
||||
BaseModel
|
||||
Date string `json:"date"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Blocks []DayBlock `json:"blocks"`
|
||||
GeneratedPlaylists []GeneratedPlaylist `json:"generated_playlists"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a Day from JSON
|
||||
func (d *Day) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
day := &Day{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["date"]; ok {
|
||||
json.Unmarshal(v, &day.Date)
|
||||
}
|
||||
if v, ok := raw["title"]; ok {
|
||||
json.Unmarshal(v, &day.Title)
|
||||
}
|
||||
if v, ok := raw["description"]; ok {
|
||||
json.Unmarshal(v, &day.Description)
|
||||
}
|
||||
if v, ok := raw["blocks"]; ok {
|
||||
var blocks []DayBlock
|
||||
json.Unmarshal(v, &blocks)
|
||||
day.Blocks = blocks
|
||||
}
|
||||
if v, ok := raw["generated_playlists"]; ok {
|
||||
var playlists []GeneratedPlaylist
|
||||
json.Unmarshal(v, &playlists)
|
||||
day.GeneratedPlaylists = playlists
|
||||
}
|
||||
|
||||
return day, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of Days
|
||||
func (d *Day) 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 {
|
||||
day := &Day{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, day); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, day)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// DayBlock represents a block in a day
|
||||
type DayBlock struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Data *DayBlockData `json:"data"`
|
||||
}
|
||||
|
||||
// DayBlockData represents data in a day block
|
||||
type DayBlockData struct {
|
||||
Tracks []Track `json:"tracks"`
|
||||
Playlists []Playlist `json:"playlists"`
|
||||
Albums []Album `json:"albums"`
|
||||
Artists []Artist `json:"artists"`
|
||||
GeneratedPlaylist *GeneratedPlaylist `json:"generated_playlist"`
|
||||
}
|
||||
|
||||
// GeneratedPlaylist represents a generated playlist
|
||||
type GeneratedPlaylist struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
CoverURI string `json:"cover_uri"`
|
||||
TrackCount int `json:"track_count"`
|
||||
DurationMs int `json:"duration_ms"`
|
||||
Kind int `json:"kind"`
|
||||
Revision int `json:"revision"`
|
||||
Type string `json:"type"`
|
||||
Available bool `json:"available"`
|
||||
Tracks []Track `json:"tracks"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a GeneratedPlaylist from JSON
|
||||
func (gp *GeneratedPlaylist) 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 := &GeneratedPlaylist{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &playlist.ID)
|
||||
}
|
||||
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["track_count"]; ok {
|
||||
json.Unmarshal(v, &playlist.TrackCount)
|
||||
}
|
||||
if v, ok := raw["duration_ms"]; ok {
|
||||
json.Unmarshal(v, &playlist.DurationMs)
|
||||
}
|
||||
if v, ok := raw["kind"]; ok {
|
||||
json.Unmarshal(v, &playlist.Kind)
|
||||
}
|
||||
if v, ok := raw["revision"]; ok {
|
||||
json.Unmarshal(v, &playlist.Revision)
|
||||
}
|
||||
if v, ok := raw["type"]; ok {
|
||||
json.Unmarshal(v, &playlist.Type)
|
||||
}
|
||||
if v, ok := raw["available"]; ok {
|
||||
json.Unmarshal(v, &playlist.Available)
|
||||
}
|
||||
if v, ok := raw["tracks"]; ok {
|
||||
var tracks []Track
|
||||
json.Unmarshal(v, &tracks)
|
||||
playlist.Tracks = tracks
|
||||
}
|
||||
|
||||
return playlist, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of GeneratedPlaylists
|
||||
func (gp *GeneratedPlaylist) 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 := &GeneratedPlaylist{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, playlist); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, playlist)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Event represents a feed event
|
||||
type Event struct {
|
||||
BaseModel
|
||||
Timestamp string `json:"timestamp"`
|
||||
Type string `json:"type"`
|
||||
TrackID string `json:"track_id"`
|
||||
AlbumID string `json:"album_id"`
|
||||
ArtistID string `json:"artist_id"`
|
||||
PlaylistID string `json:"playlist_id"`
|
||||
Action string `json:"action"`
|
||||
}
|
||||
|
||||
// AlbumEvent represents an album event
|
||||
type AlbumEvent struct {
|
||||
BaseModel
|
||||
Album *Album `json:"album"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
Type string `json:"type"`
|
||||
Action string `json:"action"`
|
||||
}
|
||||
|
||||
// ArtistEvent represents an artist event
|
||||
type ArtistEvent struct {
|
||||
BaseModel
|
||||
Artist *Artist `json:"artist"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
Type string `json:"type"`
|
||||
Action string `json:"action"`
|
||||
}
|
||||
|
||||
// TrackWithAds represents a track with ads
|
||||
type TrackWithAds struct {
|
||||
BaseModel
|
||||
Track *Track `json:"track"`
|
||||
Ads []Ad `json:"ads"`
|
||||
AdParams *AdParams `json:"ad_params"`
|
||||
}
|
||||
|
||||
// Ad represents an ad
|
||||
type Ad struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Image string `json:"image"`
|
||||
URL string `json:"url"`
|
||||
Duration int `json:"duration"`
|
||||
}
|
||||
|
||||
// AdParams represents ad parameters
|
||||
type AdParams struct {
|
||||
BaseModel
|
||||
Frequency int `json:"frequency"`
|
||||
MaxPerDay int `json:"max_per_day"`
|
||||
Targeting string `json:"targeting"`
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Label represents a label
|
||||
type Label struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
CoverURI string `json:"cover_uri"`
|
||||
Description string `json:"description"`
|
||||
Website string `json:"website"`
|
||||
SocialLinks []SocialLink `json:"social_links"`
|
||||
Available bool `json:"available"`
|
||||
Owner *User `json:"owner"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a Label from JSON
|
||||
func (l *Label) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label := &Label{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &label.ID)
|
||||
}
|
||||
if v, ok := raw["name"]; ok {
|
||||
json.Unmarshal(v, &label.Name)
|
||||
}
|
||||
if v, ok := raw["cover_uri"]; ok {
|
||||
json.Unmarshal(v, &label.CoverURI)
|
||||
}
|
||||
if v, ok := raw["description"]; ok {
|
||||
json.Unmarshal(v, &label.Description)
|
||||
}
|
||||
if v, ok := raw["website"]; ok {
|
||||
json.Unmarshal(v, &label.Website)
|
||||
}
|
||||
if v, ok := raw["available"]; ok {
|
||||
json.Unmarshal(v, &label.Available)
|
||||
}
|
||||
if v, ok := raw["social_links"]; ok {
|
||||
var links []SocialLink
|
||||
json.Unmarshal(v, &links)
|
||||
label.SocialLinks = links
|
||||
}
|
||||
if v, ok := raw["owner"]; ok {
|
||||
var user User
|
||||
json.Unmarshal(v, &user)
|
||||
label.Owner = &user
|
||||
}
|
||||
|
||||
return label, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of Labels
|
||||
func (l *Label) DeList(data []byte, client 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 {
|
||||
label := &Label{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, label); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, label)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// LabelAlbums represents label albums
|
||||
type LabelAlbums struct {
|
||||
BaseModel
|
||||
Albums []Album `json:"albums"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// LabelArtists represents label artists
|
||||
type LabelArtists struct {
|
||||
BaseModel
|
||||
Artists []Artist `json:"artists"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Landing represents a landing page
|
||||
type Landing struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
CoverURI string `json:"cover_uri"`
|
||||
Type string `json:"type"`
|
||||
Blocks []LandingBlock `json:"blocks"`
|
||||
Available bool `json:"available"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a Landing from JSON
|
||||
func (l *Landing) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
landing := &Landing{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &landing.ID)
|
||||
}
|
||||
if v, ok := raw["title"]; ok {
|
||||
json.Unmarshal(v, &landing.Title)
|
||||
}
|
||||
if v, ok := raw["description"]; ok {
|
||||
json.Unmarshal(v, &landing.Description)
|
||||
}
|
||||
if v, ok := raw["cover_uri"]; ok {
|
||||
json.Unmarshal(v, &landing.CoverURI)
|
||||
}
|
||||
if v, ok := raw["type"]; ok {
|
||||
json.Unmarshal(v, &landing.Type)
|
||||
}
|
||||
if v, ok := raw["available"]; ok {
|
||||
json.Unmarshal(v, &landing.Available)
|
||||
}
|
||||
|
||||
if v, ok := raw["blocks"]; ok {
|
||||
var blocks []LandingBlock
|
||||
json.Unmarshal(v, &blocks)
|
||||
landing.Blocks = blocks
|
||||
}
|
||||
|
||||
return landing, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of Landings
|
||||
func (l *Landing) 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 {
|
||||
landing := &Landing{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, landing); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, landing)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// LandingBlock represents a block in a landing
|
||||
type LandingBlock struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Data *LandingBlockData `json:"data"`
|
||||
}
|
||||
|
||||
// LandingBlockData represents data in a landing block
|
||||
type LandingBlockData struct {
|
||||
Tracks []Track `json:"tracks"`
|
||||
Playlists []Playlist `json:"playlists"`
|
||||
Albums []Album `json:"albums"`
|
||||
Artists []Artist `json:"artists"`
|
||||
GeneratedPlaylist *GeneratedPlaylist `json:"generated_playlist"`
|
||||
}
|
||||
|
||||
// LandingList represents a list of landings
|
||||
type LandingList struct {
|
||||
BaseModel
|
||||
Landings []Landing `json:"landings"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a LandingList from JSON
|
||||
func (ll *LandingList) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
list := &LandingList{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["landings"]; ok {
|
||||
var landings []Landing
|
||||
json.Unmarshal(v, &landings)
|
||||
list.Landings = landings
|
||||
}
|
||||
if v, ok := raw["total"]; ok {
|
||||
json.Unmarshal(v, &list.Total)
|
||||
}
|
||||
if v, ok := raw["page"]; ok {
|
||||
json.Unmarshal(v, &list.Page)
|
||||
}
|
||||
if v, ok := raw["page_size"]; ok {
|
||||
json.Unmarshal(v, &list.PageSize)
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of LandingLists
|
||||
func (ll *LandingList) 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 {
|
||||
list := &LandingList{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, list); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, list)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Metatag represents a metatag
|
||||
type Metatag struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Image string `json:"image"`
|
||||
Type string `json:"type"`
|
||||
Position int `json:"position"`
|
||||
Children []Metatag `json:"children"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a Metatag from JSON
|
||||
func (m *Metatag) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
metatag := &Metatag{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &metatag.ID)
|
||||
}
|
||||
if v, ok := raw["title"]; ok {
|
||||
json.Unmarshal(v, &metatag.Title)
|
||||
}
|
||||
if v, ok := raw["description"]; ok {
|
||||
json.Unmarshal(v, &metatag.Description)
|
||||
}
|
||||
if v, ok := raw["image"]; ok {
|
||||
json.Unmarshal(v, &metatag.Image)
|
||||
}
|
||||
if v, ok := raw["type"]; ok {
|
||||
json.Unmarshal(v, &metatag.Type)
|
||||
}
|
||||
if v, ok := raw["position"]; ok {
|
||||
json.Unmarshal(v, &metatag.Position)
|
||||
}
|
||||
if v, ok := raw["children"]; ok {
|
||||
var children []Metatag
|
||||
json.Unmarshal(v, &children)
|
||||
metatag.Children = children
|
||||
}
|
||||
|
||||
return metatag, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of Metatags
|
||||
func (m *Metatag) DeList(data []byte, client 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 {
|
||||
metatag := &Metatag{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, metatag); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, metatag)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// MetatagTree represents a metatag tree
|
||||
type MetatagTree struct {
|
||||
BaseModel
|
||||
Root *Metatag `json:"root"`
|
||||
Leaves []Metatag `json:"leaves"`
|
||||
}
|
||||
|
||||
// MetatagLeaf represents a metatag leaf
|
||||
type MetatagLeaf struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Image string `json:"image"`
|
||||
Type string `json:"type"`
|
||||
Position int `json:"position"`
|
||||
}
|
||||
|
||||
// MetatagArtists represents metatag artists
|
||||
type MetatagArtists struct {
|
||||
BaseModel
|
||||
Artists []Artist `json:"artists"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// MetatagAlbums represents metatag albums
|
||||
type MetatagAlbums struct {
|
||||
BaseModel
|
||||
Albums []Album `json:"albums"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// MetatagPlaylists represents metatag playlists
|
||||
type MetatagPlaylists struct {
|
||||
BaseModel
|
||||
Playlists []Playlist `json:"playlists"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// MetatagTitle represents a metatag title
|
||||
type MetatagTitle struct {
|
||||
BaseModel
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
// MetatagSortByValue represents metatag sort by value
|
||||
type MetatagSortByValue struct {
|
||||
BaseModel
|
||||
Value string `json:"value"`
|
||||
Label string `json:"label"`
|
||||
}
|
||||
|
||||
// MetatagArtistEntry represents a metatag artist entry
|
||||
type MetatagArtistEntry struct {
|
||||
BaseModel
|
||||
Artist *Artist `json:"artist"`
|
||||
Score float64 `json:"score"`
|
||||
}
|
||||
|
||||
// Genre represents a genre
|
||||
type Genre struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Image string `json:"image"`
|
||||
Position int `json:"position"`
|
||||
ParentID string `json:"parent_id"`
|
||||
Children []Genre `json:"children"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a Genre from JSON
|
||||
func (g *Genre) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
genre := &Genre{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &genre.ID)
|
||||
}
|
||||
if v, ok := raw["title"]; ok {
|
||||
json.Unmarshal(v, &genre.Title)
|
||||
}
|
||||
if v, ok := raw["description"]; ok {
|
||||
json.Unmarshal(v, &genre.Description)
|
||||
}
|
||||
if v, ok := raw["image"]; ok {
|
||||
json.Unmarshal(v, &genre.Image)
|
||||
}
|
||||
if v, ok := raw["position"]; ok {
|
||||
json.Unmarshal(v, &genre.Position)
|
||||
}
|
||||
if v, ok := raw["parent_id"]; ok {
|
||||
json.Unmarshal(v, &genre.ParentID)
|
||||
}
|
||||
if v, ok := raw["children"]; ok {
|
||||
var children []Genre
|
||||
json.Unmarshal(v, &children)
|
||||
genre.Children = children
|
||||
}
|
||||
|
||||
return genre, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of Genres
|
||||
func (g *Genre) DeList(data []byte, client 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 {
|
||||
genre := &Genre{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, genre); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, genre)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Chart represents a chart
|
||||
type Chart struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
CoverURI string `json:"cover_uri"`
|
||||
Type string `json:"type"`
|
||||
Items []ChartItem `json:"items"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a Chart from JSON
|
||||
func (c *Chart) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
chart := &Chart{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &chart.ID)
|
||||
}
|
||||
if v, ok := raw["title"]; ok {
|
||||
json.Unmarshal(v, &chart.Title)
|
||||
}
|
||||
if v, ok := raw["description"]; ok {
|
||||
json.Unmarshal(v, &chart.Description)
|
||||
}
|
||||
if v, ok := raw["cover_uri"]; ok {
|
||||
json.Unmarshal(v, &chart.CoverURI)
|
||||
}
|
||||
if v, ok := raw["type"]; ok {
|
||||
json.Unmarshal(v, &chart.Type)
|
||||
}
|
||||
if v, ok := raw["items"]; ok {
|
||||
var items []ChartItem
|
||||
json.Unmarshal(v, &items)
|
||||
chart.Items = items
|
||||
}
|
||||
|
||||
return chart, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of Charts
|
||||
func (c *Chart) DeList(data []byte, client 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 {
|
||||
chart := &Chart{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, chart); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, chart)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ChartInfo represents chart info
|
||||
type ChartInfo struct {
|
||||
BaseModel
|
||||
Chart *Chart `json:"chart"`
|
||||
Menu []ChartInfoMenu `json:"menu"`
|
||||
}
|
||||
|
||||
// ChartItem represents a chart item
|
||||
type ChartItem struct {
|
||||
BaseModel
|
||||
Position int `json:"position"`
|
||||
Track *Track `json:"track"`
|
||||
Artist *Artist `json:"artist"`
|
||||
Album *Album `json:"album"`
|
||||
Playlist *Playlist `json:"playlist"`
|
||||
Score float64 `json:"score"`
|
||||
Trend string `json:"trend"`
|
||||
}
|
||||
|
||||
// ChartInfoMenu represents a chart info menu
|
||||
type ChartInfoMenu struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Items []ChartInfoMenuItem `json:"items"`
|
||||
}
|
||||
|
||||
// ChartInfoMenuItem represents a chart info menu item
|
||||
type ChartInfoMenuItem struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Action string `json:"action"`
|
||||
}
|
||||
|
||||
// ChartItems represents chart items response
|
||||
type ChartItems struct {
|
||||
BaseModel
|
||||
Items []ChartItem `json:"items"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// MusicHistory represents music history
|
||||
type MusicHistory struct {
|
||||
BaseModel
|
||||
Tabs []MusicHistoryTab `json:"tabs"`
|
||||
Groups []MusicHistoryGroup `json:"groups"`
|
||||
Items []MusicHistoryItem `json:"items"`
|
||||
Context *MusicHistoryContextFullModel `json:"context"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a MusicHistory from JSON
|
||||
func (mh *MusicHistory) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
history := &MusicHistory{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["tabs"]; ok {
|
||||
var tabs []MusicHistoryTab
|
||||
json.Unmarshal(v, &tabs)
|
||||
history.Tabs = tabs
|
||||
}
|
||||
if v, ok := raw["groups"]; ok {
|
||||
var groups []MusicHistoryGroup
|
||||
json.Unmarshal(v, &groups)
|
||||
history.Groups = groups
|
||||
}
|
||||
if v, ok := raw["items"]; ok {
|
||||
var items []MusicHistoryItem
|
||||
json.Unmarshal(v, &items)
|
||||
history.Items = items
|
||||
}
|
||||
if v, ok := raw["context"]; ok {
|
||||
var context MusicHistoryContextFullModel
|
||||
json.Unmarshal(v, &context)
|
||||
history.Context = &context
|
||||
}
|
||||
|
||||
return history, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of MusicHistory
|
||||
func (mh *MusicHistory) DeList(data []byte, client 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 {
|
||||
history := &MusicHistory{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, history); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, history)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// MusicHistoryTab represents a music history tab
|
||||
type MusicHistoryTab struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Icon string `json:"icon"`
|
||||
Active bool `json:"active"`
|
||||
Position int `json:"position"`
|
||||
}
|
||||
|
||||
// MusicHistoryGroup represents a music history group
|
||||
type MusicHistoryGroup struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Items []MusicHistoryItem `json:"items"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
// MusicHistoryItem represents a music history item
|
||||
type MusicHistoryItem struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"` // "track", "album", "artist", "playlist"
|
||||
Track *Track `json:"track"`
|
||||
Album *Album `json:"album"`
|
||||
Artist *Artist `json:"artist"`
|
||||
Playlist *Playlist `json:"playlist"`
|
||||
PlayedAt string `json:"played_at"`
|
||||
PlayCount int `json:"play_count"`
|
||||
Duration int `json:"duration"`
|
||||
Context *MusicHistoryItemData `json:"context"`
|
||||
}
|
||||
|
||||
// MusicHistoryItemData represents music history item data
|
||||
type MusicHistoryItemData struct {
|
||||
BaseModel
|
||||
Source string `json:"source"`
|
||||
SourceID string `json:"source_id"`
|
||||
SourceType string `json:"source_type"`
|
||||
PlayContext *PlayContext `json:"play_context"`
|
||||
Position int `json:"position"`
|
||||
Duration int `json:"duration"`
|
||||
Progress float64 `json:"progress"`
|
||||
}
|
||||
|
||||
// MusicHistoryItemID represents music history item ID
|
||||
type MusicHistoryItemID struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// MusicHistoryItems represents music history items
|
||||
type MusicHistoryItems struct {
|
||||
BaseModel
|
||||
Items []MusicHistoryItem `json:"items"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// MusicHistoryContextFullModel represents music history context full model
|
||||
type MusicHistoryContextFullModel struct {
|
||||
BaseModel
|
||||
DeviceID string `json:"device_id"`
|
||||
SessionID string `json:"session_id"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
ClientInfo string `json:"client_info"`
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Pin represents a pin
|
||||
type Pin struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Image string `json:"image"`
|
||||
Type string `json:"type"` // "track", "album", "artist", "playlist"
|
||||
Track *Track `json:"track"`
|
||||
Album *Album `json:"album"`
|
||||
Artist *Artist `json:"artist"`
|
||||
Playlist *Playlist `json:"playlist"`
|
||||
Position int `json:"position"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
Active bool `json:"active"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a Pin from JSON
|
||||
func (p *Pin) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pin := &Pin{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &pin.ID)
|
||||
}
|
||||
if v, ok := raw["title"]; ok {
|
||||
json.Unmarshal(v, &pin.Title)
|
||||
}
|
||||
if v, ok := raw["description"]; ok {
|
||||
json.Unmarshal(v, &pin.Description)
|
||||
}
|
||||
if v, ok := raw["image"]; ok {
|
||||
json.Unmarshal(v, &pin.Image)
|
||||
}
|
||||
if v, ok := raw["type"]; ok {
|
||||
json.Unmarshal(v, &pin.Type)
|
||||
}
|
||||
if v, ok := raw["position"]; ok {
|
||||
json.Unmarshal(v, &pin.Position)
|
||||
}
|
||||
if v, ok := raw["created_at"]; ok {
|
||||
json.Unmarshal(v, &pin.CreatedAt)
|
||||
}
|
||||
if v, ok := raw["expires_at"]; ok {
|
||||
json.Unmarshal(v, &pin.ExpiresAt)
|
||||
}
|
||||
if v, ok := raw["active"]; ok {
|
||||
json.Unmarshal(v, &pin.Active)
|
||||
}
|
||||
|
||||
if v, ok := raw["track"]; ok {
|
||||
var track Track
|
||||
json.Unmarshal(v, &track)
|
||||
pin.Track = &track
|
||||
}
|
||||
if v, ok := raw["album"]; ok {
|
||||
var album Album
|
||||
json.Unmarshal(v, &album)
|
||||
pin.Album = &album
|
||||
}
|
||||
if v, ok := raw["artist"]; ok {
|
||||
var artist Artist
|
||||
json.Unmarshal(v, &artist)
|
||||
pin.Artist = &artist
|
||||
}
|
||||
if v, ok := raw["playlist"]; ok {
|
||||
var playlist Playlist
|
||||
json.Unmarshal(v, &playlist)
|
||||
pin.Playlist = &playlist
|
||||
}
|
||||
|
||||
return pin, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of Pins
|
||||
func (p *Pin) DeList(data []byte, client 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 {
|
||||
pin := &Pin{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, pin); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, pin)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// PinData represents pin data
|
||||
type PinData struct {
|
||||
BaseModel
|
||||
Pins []Pin `json:"pins"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
// PinsList represents a list of pins
|
||||
type PinsList struct {
|
||||
BaseModel
|
||||
Pins []Pin `json:"pins"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// Presaves represents presaves
|
||||
type Presaves struct {
|
||||
BaseModel
|
||||
Presaves []Presave `json:"presaves"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// Presave represents a presave
|
||||
type Presave struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Image string `json:"image"`
|
||||
ReleaseDate string `json:"release_date"`
|
||||
Track *Track `json:"track"`
|
||||
Album *Album `json:"album"`
|
||||
Artist *Artist `json:"artist"`
|
||||
Status string `json:"status"` // "pending", "released", "cancelled"
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a Presave from JSON
|
||||
func (p *Presave) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
presave := &Presave{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &presave.ID)
|
||||
}
|
||||
if v, ok := raw["title"]; ok {
|
||||
json.Unmarshal(v, &presave.Title)
|
||||
}
|
||||
if v, ok := raw["description"]; ok {
|
||||
json.Unmarshal(v, &presave.Description)
|
||||
}
|
||||
if v, ok := raw["image"]; ok {
|
||||
json.Unmarshal(v, &presave.Image)
|
||||
}
|
||||
if v, ok := raw["release_date"]; ok {
|
||||
json.Unmarshal(v, &presave.ReleaseDate)
|
||||
}
|
||||
if v, ok := raw["status"]; ok {
|
||||
json.Unmarshal(v, &presave.Status)
|
||||
}
|
||||
if v, ok := raw["created_at"]; ok {
|
||||
json.Unmarshal(v, &presave.CreatedAt)
|
||||
}
|
||||
if v, ok := raw["updated_at"]; ok {
|
||||
json.Unmarshal(v, &presave.UpdatedAt)
|
||||
}
|
||||
|
||||
if v, ok := raw["track"]; ok {
|
||||
var track Track
|
||||
json.Unmarshal(v, &track)
|
||||
presave.Track = &track
|
||||
}
|
||||
if v, ok := raw["album"]; ok {
|
||||
var album Album
|
||||
json.Unmarshal(v, &album)
|
||||
presave.Album = &album
|
||||
}
|
||||
if v, ok := raw["artist"]; ok {
|
||||
var artist Artist
|
||||
json.Unmarshal(v, &artist)
|
||||
presave.Artist = &artist
|
||||
}
|
||||
|
||||
return presave, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of Presaves
|
||||
func (p *Presave) DeList(data []byte, client 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 {
|
||||
presave := &Presave{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, presave); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, presave)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@@ -0,0 +1,407 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Playlist represents a playlist
|
||||
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
|
||||
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
|
||||
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)
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
@@ -0,0 +1,292 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Queue represents a playback queue
|
||||
type Queue struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
TrackIDs []string `json:"track_ids"`
|
||||
CurrentIndex int `json:"current_index"`
|
||||
QueueType string `json:"queue_type"`
|
||||
RepeatMode string `json:"repeat_mode"`
|
||||
Shuffle bool `json:"shuffle"`
|
||||
Device string `json:"device"`
|
||||
Items []QueueItem `json:"items"`
|
||||
Context *PlayContext `json:"context"`
|
||||
AvailableTracks int `json:"available_tracks"`
|
||||
TotalDuration int `json:"total_duration_ms"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a Queue from JSON
|
||||
func (q *Queue) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
queue := &Queue{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &queue.ID)
|
||||
}
|
||||
if v, ok := raw["track_ids"]; ok {
|
||||
json.Unmarshal(v, &queue.TrackIDs)
|
||||
}
|
||||
if v, ok := raw["current_index"]; ok {
|
||||
json.Unmarshal(v, &queue.CurrentIndex)
|
||||
}
|
||||
if v, ok := raw["queue_type"]; ok {
|
||||
json.Unmarshal(v, &queue.QueueType)
|
||||
}
|
||||
if v, ok := raw["repeat_mode"]; ok {
|
||||
json.Unmarshal(v, &queue.RepeatMode)
|
||||
}
|
||||
if v, ok := raw["shuffle"]; ok {
|
||||
json.Unmarshal(v, &queue.Shuffle)
|
||||
}
|
||||
if v, ok := raw["device"]; ok {
|
||||
json.Unmarshal(v, &queue.Device)
|
||||
}
|
||||
if v, ok := raw["available_tracks"]; ok {
|
||||
json.Unmarshal(v, &queue.AvailableTracks)
|
||||
}
|
||||
if v, ok := raw["total_duration_ms"]; ok {
|
||||
json.Unmarshal(v, &queue.TotalDuration)
|
||||
}
|
||||
|
||||
if v, ok := raw["items"]; ok {
|
||||
var items []QueueItem
|
||||
json.Unmarshal(v, &items)
|
||||
queue.Items = items
|
||||
}
|
||||
if v, ok := raw["context"]; ok {
|
||||
var ctx PlayContext
|
||||
json.Unmarshal(v, &ctx)
|
||||
queue.Context = &ctx
|
||||
}
|
||||
|
||||
return queue, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of Queues
|
||||
func (q *Queue) 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 {
|
||||
queue := &Queue{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, queue); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, queue)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// QueueItem represents a queue item
|
||||
type QueueItem struct {
|
||||
BaseModel
|
||||
TrackID string `json:"track_id"`
|
||||
Track *Track `json:"track"`
|
||||
Position int `json:"position"`
|
||||
AddedAt string `json:"added_at"`
|
||||
AddedBy string `json:"added_by"`
|
||||
Playable bool `json:"playable"`
|
||||
PlayContext *PlayContext `json:"play_context"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a QueueItem from JSON
|
||||
func (qi *QueueItem) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
item := &QueueItem{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["track_id"]; ok {
|
||||
json.Unmarshal(v, &item.TrackID)
|
||||
}
|
||||
if v, ok := raw["position"]; ok {
|
||||
json.Unmarshal(v, &item.Position)
|
||||
}
|
||||
if v, ok := raw["added_at"]; ok {
|
||||
json.Unmarshal(v, &item.AddedAt)
|
||||
}
|
||||
if v, ok := raw["added_by"]; ok {
|
||||
json.Unmarshal(v, &item.AddedBy)
|
||||
}
|
||||
if v, ok := raw["playable"]; ok {
|
||||
json.Unmarshal(v, &item.Playable)
|
||||
}
|
||||
|
||||
if v, ok := raw["track"]; ok {
|
||||
var track Track
|
||||
json.Unmarshal(v, &track)
|
||||
item.Track = &track
|
||||
}
|
||||
if v, ok := raw["play_context"]; ok {
|
||||
var ctx PlayContext
|
||||
json.Unmarshal(v, &ctx)
|
||||
item.PlayContext = &ctx
|
||||
}
|
||||
|
||||
return item, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of QueueItems
|
||||
func (qi *QueueItem) 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 {
|
||||
qi := &QueueItem{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, qi); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, qi)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// PlayContext represents a play context
|
||||
type PlayContext struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"` // "playlist", "album", "artist", "radio", "search"
|
||||
SourceID string `json:"source_id"`
|
||||
SourceKind string `json:"source_kind"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
CoverURI string `json:"cover_uri"`
|
||||
TrackCount int `json:"track_count"`
|
||||
Owner *User `json:"owner"`
|
||||
Available bool `json:"available"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a PlayContext from JSON
|
||||
func (pc *PlayContext) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx := &PlayContext{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &ctx.ID)
|
||||
}
|
||||
if v, ok := raw["type"]; ok {
|
||||
json.Unmarshal(v, &ctx.Type)
|
||||
}
|
||||
if v, ok := raw["source_id"]; ok {
|
||||
json.Unmarshal(v, &ctx.SourceID)
|
||||
}
|
||||
if v, ok := raw["source_kind"]; ok {
|
||||
json.Unmarshal(v, &ctx.SourceKind)
|
||||
}
|
||||
if v, ok := raw["title"]; ok {
|
||||
json.Unmarshal(v, &ctx.Title)
|
||||
}
|
||||
if v, ok := raw["description"]; ok {
|
||||
json.Unmarshal(v, &ctx.Description)
|
||||
}
|
||||
if v, ok := raw["cover_uri"]; ok {
|
||||
json.Unmarshal(v, &ctx.CoverURI)
|
||||
}
|
||||
if v, ok := raw["track_count"]; ok {
|
||||
json.Unmarshal(v, &ctx.TrackCount)
|
||||
}
|
||||
if v, ok := raw["available"]; ok {
|
||||
json.Unmarshal(v, &ctx.Available)
|
||||
}
|
||||
|
||||
if v, ok := raw["owner"]; ok {
|
||||
var user User
|
||||
json.Unmarshal(v, &user)
|
||||
ctx.Owner = &user
|
||||
}
|
||||
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of PlayContexts
|
||||
func (pc *PlayContext) 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 {
|
||||
ctx := &PlayContext{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, ctx); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, ctx)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// PlayContextsData represents play contexts data
|
||||
type PlayContextsData struct {
|
||||
BaseModel
|
||||
Contexts []PlayContext `json:"contexts"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes PlayContextsData from JSON
|
||||
func (pcd *PlayContextsData) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := &PlayContextsData{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["contexts"]; ok {
|
||||
var contexts []PlayContext
|
||||
json.Unmarshal(v, &contexts)
|
||||
result.Contexts = contexts
|
||||
}
|
||||
if v, ok := raw["total"]; ok {
|
||||
json.Unmarshal(v, &result.Total)
|
||||
}
|
||||
if v, ok := raw["page"]; ok {
|
||||
json.Unmarshal(v, &result.Page)
|
||||
}
|
||||
if v, ok := raw["page_size"]; ok {
|
||||
json.Unmarshal(v, &result.PageSize)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of PlayContextsData
|
||||
func (pcd *PlayContextsData) 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 {
|
||||
d := &PlayContextsData{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, d); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, d)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@@ -0,0 +1,328 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// RadioStation represents a radio station
|
||||
type RadioStation struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
CoverURI string `json:"cover_uri"`
|
||||
Genre string `json:"genre"`
|
||||
Available bool `json:"available"`
|
||||
IsPersonal bool `json:"is_personal"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a RadioStation from JSON
|
||||
func (r *RadioStation) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
station := &RadioStation{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &station.ID)
|
||||
}
|
||||
if v, ok := raw["title"]; ok {
|
||||
json.Unmarshal(v, &station.Title)
|
||||
}
|
||||
if v, ok := raw["description"]; ok {
|
||||
json.Unmarshal(v, &station.Description)
|
||||
}
|
||||
if v, ok := raw["cover_uri"]; ok {
|
||||
json.Unmarshal(v, &station.CoverURI)
|
||||
}
|
||||
if v, ok := raw["genre"]; ok {
|
||||
json.Unmarshal(v, &station.Genre)
|
||||
}
|
||||
if v, ok := raw["available"]; ok {
|
||||
json.Unmarshal(v, &station.Available)
|
||||
}
|
||||
if v, ok := raw["is_personal"]; ok {
|
||||
json.Unmarshal(v, &station.IsPersonal)
|
||||
}
|
||||
|
||||
return station, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of RadioStations
|
||||
func (r *RadioStation) DeList(data []byte, client 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 {
|
||||
station := &RadioStation{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, station); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, station)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// StationTracksResult represents station tracks result
|
||||
type StationTracksResult struct {
|
||||
BaseModel
|
||||
Tracks []Track `json:"tracks"`
|
||||
Total int `json:"total"`
|
||||
Sequence string `json:"sequence"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes StationTracksResult from JSON
|
||||
func (s *StationTracksResult) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := &StationTracksResult{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["tracks"]; ok {
|
||||
var tracks []Track
|
||||
json.Unmarshal(v, &tracks)
|
||||
result.Tracks = tracks
|
||||
}
|
||||
if v, ok := raw["total"]; ok {
|
||||
json.Unmarshal(v, &result.Total)
|
||||
}
|
||||
if v, ok := raw["sequence"]; ok {
|
||||
json.Unmarshal(v, &result.Sequence)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of StationTracksResult
|
||||
func (s *StationTracksResult) DeList(data []byte, client 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 {
|
||||
r := &StationTracksResult{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, r); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, r)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// RotorStation represents a rotor (generative) station
|
||||
type RotorStation struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
CoverURI string `json:"cover_uri"`
|
||||
Genre string `json:"genre"`
|
||||
StationType string `json:"station_type"`
|
||||
Available bool `json:"available"`
|
||||
Settings *RotorSettings `json:"settings"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a RotorStation from JSON
|
||||
func (r *RotorStation) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
station := &RotorStation{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &station.ID)
|
||||
}
|
||||
if v, ok := raw["title"]; ok {
|
||||
json.Unmarshal(v, &station.Title)
|
||||
}
|
||||
if v, ok := raw["description"]; ok {
|
||||
json.Unmarshal(v, &station.Description)
|
||||
}
|
||||
if v, ok := raw["cover_uri"]; ok {
|
||||
json.Unmarshal(v, &station.CoverURI)
|
||||
}
|
||||
if v, ok := raw["genre"]; ok {
|
||||
json.Unmarshal(v, &station.Genre)
|
||||
}
|
||||
if v, ok := raw["station_type"]; ok {
|
||||
json.Unmarshal(v, &station.StationType)
|
||||
}
|
||||
if v, ok := raw["available"]; ok {
|
||||
json.Unmarshal(v, &station.Available)
|
||||
}
|
||||
if v, ok := raw["settings"]; ok {
|
||||
var settings RotorSettings
|
||||
json.Unmarshal(v, &settings)
|
||||
station.Settings = &settings
|
||||
}
|
||||
|
||||
return station, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of RotorStations
|
||||
func (r *RotorStation) DeList(data []byte, client 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 {
|
||||
station := &RotorStation{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, station); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, station)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// RotorSettings represents rotor station settings
|
||||
type RotorSettings struct {
|
||||
BaseModel
|
||||
Diversity float64 `json:"diversity"`
|
||||
Energy float64 `json:"energy"`
|
||||
Acousticness float64 `json:"acousticness"`
|
||||
Instrumentalness float64 `json:"instrumentalness"`
|
||||
Live float64 `json:"live"`
|
||||
Speechiness float64 `json:"speechiness"`
|
||||
Tempo float64 `json:"tempo"`
|
||||
Valence float64 `json:"valence"`
|
||||
}
|
||||
|
||||
// RotorStationTracksResult represents rotor station tracks result
|
||||
type RotorStationTracksResult struct {
|
||||
BaseModel
|
||||
Tracks []Track `json:"tracks"`
|
||||
Total int `json:"total"`
|
||||
Sequence string `json:"sequence"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes RotorStationTracksResult from JSON
|
||||
func (r *RotorStationTracksResult) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := &RotorStationTracksResult{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["tracks"]; ok {
|
||||
var tracks []Track
|
||||
json.Unmarshal(v, &tracks)
|
||||
result.Tracks = tracks
|
||||
}
|
||||
if v, ok := raw["total"]; ok {
|
||||
json.Unmarshal(v, &result.Total)
|
||||
}
|
||||
if v, ok := raw["sequence"]; ok {
|
||||
json.Unmarshal(v, &result.Sequence)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of RotorStationTracksResult
|
||||
func (r *RotorStationTracksResult) DeList(data []byte, client 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 {
|
||||
r := &RotorStationTracksResult{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, r); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, r)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// RotorSession represents a rotor session
|
||||
type RotorSession struct {
|
||||
BaseModel
|
||||
SessionID string `json:"session_id"`
|
||||
StationID string `json:"station_id"`
|
||||
Tracks []Track `json:"tracks"`
|
||||
BatchID string `json:"batch_id"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a RotorSession from JSON
|
||||
func (r *RotorSession) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
session := &RotorSession{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["session_id"]; ok {
|
||||
json.Unmarshal(v, &session.SessionID)
|
||||
}
|
||||
if v, ok := raw["station_id"]; ok {
|
||||
json.Unmarshal(v, &session.StationID)
|
||||
}
|
||||
if v, ok := raw["tracks"]; ok {
|
||||
var tracks []Track
|
||||
json.Unmarshal(v, &tracks)
|
||||
session.Tracks = tracks
|
||||
}
|
||||
if v, ok := raw["batch_id"]; ok {
|
||||
json.Unmarshal(v, &session.BatchID)
|
||||
}
|
||||
if v, ok := raw["expires_at"]; ok {
|
||||
json.Unmarshal(v, &session.ExpiresAt)
|
||||
}
|
||||
if v, ok := raw["created_at"]; ok {
|
||||
json.Unmarshal(v, &session.CreatedAt)
|
||||
}
|
||||
|
||||
return session, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of RotorSessions
|
||||
func (r *RotorSession) DeList(data []byte, client 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 {
|
||||
session := &RotorSession{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, session); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, session)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// SessionFeedback represents session feedback
|
||||
type SessionFeedback struct {
|
||||
BaseModel
|
||||
TrackID string `json:"track_id"`
|
||||
Feedback string `json:"feedback"` // "like", "dislike", "skip"
|
||||
Timestamp string `json:"timestamp"`
|
||||
}
|
||||
|
||||
// SessionFeedbacks represents multiple session feedbacks
|
||||
type SessionFeedbacks struct {
|
||||
BaseModel
|
||||
Feedbacks []SessionFeedback `json:"feedbacks"`
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package models
|
||||
|
||||
// SearchResult represents search results
|
||||
type SearchResult struct {
|
||||
Tracks *SearchTracksResult `json:"tracks"`
|
||||
Albums *SearchAlbumsResult `json:"albums"`
|
||||
Artists *SearchArtistsResult `json:"artists"`
|
||||
Playlists *SearchPlaylistsResult `json:"playlists"`
|
||||
Videos *SearchVideosResult `json:"videos"`
|
||||
Users *SearchUsersResult `json:"users"`
|
||||
}
|
||||
|
||||
// SearchTracksResult represents track search results
|
||||
type SearchTracksResult struct {
|
||||
Total int `json:"total"`
|
||||
Results []Track `json:"results"`
|
||||
}
|
||||
|
||||
// SearchAlbumsResult represents album search results
|
||||
type SearchAlbumsResult struct {
|
||||
Total int `json:"total"`
|
||||
Results []Album `json:"results"`
|
||||
}
|
||||
|
||||
// SearchArtistsResult represents artist search results
|
||||
type SearchArtistsResult struct {
|
||||
Total int `json:"total"`
|
||||
Results []Artist `json:"results"`
|
||||
}
|
||||
|
||||
// SearchPlaylistsResult represents playlist search results
|
||||
type SearchPlaylistsResult struct {
|
||||
Total int `json:"total"`
|
||||
Results []Playlist `json:"results"`
|
||||
}
|
||||
|
||||
// SearchVideosResult represents video search results
|
||||
type SearchVideosResult struct {
|
||||
Total int `json:"total"`
|
||||
Results []Video `json:"results"`
|
||||
}
|
||||
|
||||
// SearchUsersResult represents user search results
|
||||
type SearchUsersResult struct {
|
||||
Total int `json:"total"`
|
||||
Results []User `json:"results"`
|
||||
}
|
||||
|
||||
// SearchBanner represents a search banner
|
||||
type SearchBanner struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Image string `json:"image"`
|
||||
URL string `json:"url"`
|
||||
Action string `json:"action"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// Tag represents a search tag
|
||||
type Tag struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Count int `json:"count"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// Video represents a video (minimal)
|
||||
type Video struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Duration int `json:"duration"`
|
||||
CoverURI string `json:"cover_uri"`
|
||||
PreviewURI string `json:"preview_uri"`
|
||||
Available bool `json:"available"`
|
||||
Views int `json:"views"`
|
||||
Likes int `json:"likes"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
Owner *User `json:"owner"`
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Experiments represents experiments
|
||||
type Experiments struct {
|
||||
BaseModel
|
||||
Experiments []ExperimentDetail `json:"experiments"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes Experiments from JSON
|
||||
func (e *Experiments) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
experiments := &Experiments{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["experiments"]; ok {
|
||||
var items []ExperimentDetail
|
||||
json.Unmarshal(v, &items)
|
||||
experiments.Experiments = items
|
||||
}
|
||||
if v, ok := raw["total"]; ok {
|
||||
json.Unmarshal(v, &experiments.Total)
|
||||
}
|
||||
|
||||
return experiments, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of Experiments
|
||||
func (e *Experiments) DeList(data []byte, client 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 {
|
||||
e := &Experiments{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, e); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, e)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ExperimentDetail represents experiment details
|
||||
type ExperimentDetail struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Status string `json:"status"`
|
||||
Variant string `json:"variant"`
|
||||
StartDate string `json:"start_date"`
|
||||
EndDate string `json:"end_date"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes ExperimentDetail from JSON
|
||||
func (e *ExperimentDetail) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
detail := &ExperimentDetail{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &detail.ID)
|
||||
}
|
||||
if v, ok := raw["name"]; ok {
|
||||
json.Unmarshal(v, &detail.Name)
|
||||
}
|
||||
if v, ok := raw["description"]; ok {
|
||||
json.Unmarshal(v, &detail.Description)
|
||||
}
|
||||
if v, ok := raw["status"]; ok {
|
||||
json.Unmarshal(v, &detail.Status)
|
||||
}
|
||||
if v, ok := raw["variant"]; ok {
|
||||
json.Unmarshal(v, &detail.Variant)
|
||||
}
|
||||
if v, ok := raw["start_date"]; ok {
|
||||
json.Unmarshal(v, &detail.StartDate)
|
||||
}
|
||||
if v, ok := raw["end_date"]; ok {
|
||||
json.Unmarshal(v, &detail.EndDate)
|
||||
}
|
||||
|
||||
return detail, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of ExperimentDetails
|
||||
func (e *ExperimentDetail) DeList(data []byte, client 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 {
|
||||
detail := &ExperimentDetail{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, detail); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, detail)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Permissions represents user permissions
|
||||
type Permissions struct {
|
||||
BaseModel
|
||||
CanPlay bool `json:"can_play"`
|
||||
CanDownload bool `json:"can_download"`
|
||||
CanLike bool `json:"can_like"`
|
||||
CanCreatePlaylist bool `json:"can_create_playlist"`
|
||||
CanSubscribe bool `json:"can_subscribe"`
|
||||
CanUsePlus bool `json:"can_use_plus"`
|
||||
CanUseRadio bool `json:"can_use_radio"`
|
||||
CanUseYnison bool `json:"can_use_ynison"`
|
||||
CanUseHighQuality bool `json:"can_use_high_quality"`
|
||||
CanUseLossless bool `json:"can_use_lossless"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes Permissions from JSON
|
||||
func (p *Permissions) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
perms := &Permissions{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["can_play"]; ok {
|
||||
json.Unmarshal(v, &perms.CanPlay)
|
||||
}
|
||||
if v, ok := raw["can_download"]; ok {
|
||||
json.Unmarshal(v, &perms.CanDownload)
|
||||
}
|
||||
if v, ok := raw["can_like"]; ok {
|
||||
json.Unmarshal(v, &perms.CanLike)
|
||||
}
|
||||
if v, ok := raw["can_create_playlist"]; ok {
|
||||
json.Unmarshal(v, &perms.CanCreatePlaylist)
|
||||
}
|
||||
if v, ok := raw["can_subscribe"]; ok {
|
||||
json.Unmarshal(v, &perms.CanSubscribe)
|
||||
}
|
||||
if v, ok := raw["can_use_plus"]; ok {
|
||||
json.Unmarshal(v, &perms.CanUsePlus)
|
||||
}
|
||||
if v, ok := raw["can_use_radio"]; ok {
|
||||
json.Unmarshal(v, &perms.CanUseRadio)
|
||||
}
|
||||
if v, ok := raw["can_use_ynison"]; ok {
|
||||
json.Unmarshal(v, &perms.CanUseYnison)
|
||||
}
|
||||
if v, ok := raw["can_use_high_quality"]; ok {
|
||||
json.Unmarshal(v, &perms.CanUseHighQuality)
|
||||
}
|
||||
if v, ok := raw["can_use_lossless"]; ok {
|
||||
json.Unmarshal(v, &perms.CanUseLossless)
|
||||
}
|
||||
|
||||
return perms, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of Permissions
|
||||
func (p *Permissions) DeList(data []byte, client 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 {
|
||||
perms := &Permissions{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, perms); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, perms)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// PermissionAlerts represents permission alerts
|
||||
type PermissionAlerts struct {
|
||||
BaseModel
|
||||
Alerts []PermissionAlert `json:"alerts"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes PermissionAlerts from JSON
|
||||
func (p *PermissionAlerts) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
alerts := &PermissionAlerts{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["alerts"]; ok {
|
||||
var items []PermissionAlert
|
||||
json.Unmarshal(v, &items)
|
||||
alerts.Alerts = items
|
||||
}
|
||||
if v, ok := raw["total"]; ok {
|
||||
json.Unmarshal(v, &alerts.Total)
|
||||
}
|
||||
|
||||
return alerts, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of PermissionAlerts
|
||||
func (p *PermissionAlerts) DeList(data []byte, client 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 {
|
||||
alerts := &PermissionAlerts{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, alerts); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, alerts)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// PermissionAlert represents a permission alert
|
||||
type PermissionAlert struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Action string `json:"action"`
|
||||
IsRead bool `json:"is_read"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes PermissionAlert from JSON
|
||||
func (p *PermissionAlert) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
alert := &PermissionAlert{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &alert.ID)
|
||||
}
|
||||
if v, ok := raw["type"]; ok {
|
||||
json.Unmarshal(v, &alert.Type)
|
||||
}
|
||||
if v, ok := raw["title"]; ok {
|
||||
json.Unmarshal(v, &alert.Title)
|
||||
}
|
||||
if v, ok := raw["description"]; ok {
|
||||
json.Unmarshal(v, &alert.Description)
|
||||
}
|
||||
if v, ok := raw["action"]; ok {
|
||||
json.Unmarshal(v, &alert.Action)
|
||||
}
|
||||
if v, ok := raw["is_read"]; ok {
|
||||
json.Unmarshal(v, &alert.IsRead)
|
||||
}
|
||||
if v, ok := raw["created_at"]; ok {
|
||||
json.Unmarshal(v, &alert.CreatedAt)
|
||||
}
|
||||
|
||||
return alert, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of PermissionAlerts
|
||||
func (p *PermissionAlert) DeList(data []byte, client 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 {
|
||||
alert := &PermissionAlert{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, alert); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, alert)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ContentRestrictions represents content restrictions
|
||||
type ContentRestrictions struct {
|
||||
BaseModel
|
||||
HasExplicitContent bool `json:"has_explicit_content"`
|
||||
RestrictedRegions []string `json:"restricted_regions"`
|
||||
AgeRating int `json:"age_rating"`
|
||||
BlockedTracks []string `json:"blocked_tracks"`
|
||||
BlockedAlbums []string `json:"blocked_albums"`
|
||||
BlockedArtists []string `json:"blocked_artists"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes ContentRestrictions from JSON
|
||||
func (c *ContentRestrictions) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
restrictions := &ContentRestrictions{BaseModel: *NewBaseModel(client)}
|
||||
|
||||
if v, ok := raw["has_explicit_content"]; ok {
|
||||
json.Unmarshal(v, &restrictions.HasExplicitContent)
|
||||
}
|
||||
if v, ok := raw["restricted_regions"]; ok {
|
||||
json.Unmarshal(v, &restrictions.RestrictedRegions)
|
||||
}
|
||||
if v, ok := raw["age_rating"]; ok {
|
||||
json.Unmarshal(v, &restrictions.AgeRating)
|
||||
}
|
||||
if v, ok := raw["blocked_tracks"]; ok {
|
||||
json.Unmarshal(v, &restrictions.BlockedTracks)
|
||||
}
|
||||
if v, ok := raw["blocked_albums"]; ok {
|
||||
json.Unmarshal(v, &restrictions.BlockedAlbums)
|
||||
}
|
||||
if v, ok := raw["blocked_artists"]; ok {
|
||||
json.Unmarshal(v, &restrictions.BlockedArtists)
|
||||
}
|
||||
|
||||
return restrictions, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of ContentRestrictions
|
||||
func (c *ContentRestrictions) DeList(data []byte, client 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 {
|
||||
restrictions := &ContentRestrictions{BaseModel: *NewBaseModel(client)}
|
||||
if err := json.Unmarshal(item, restrictions); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, restrictions)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@@ -0,0 +1,395 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// LyricsMajor represents a lyrics provider (e.g., Genius, Musixmatch)
|
||||
type LyricsMajor struct {
|
||||
BaseModel
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
PrettyName string `json:"pretty_name"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes LyricsMajor from JSON
|
||||
func (lm *LyricsMajor) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
major := &LyricsMajor{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &major.ID)
|
||||
}
|
||||
if v, ok := raw["name"]; ok {
|
||||
json.Unmarshal(v, &major.Name)
|
||||
}
|
||||
if v, ok := raw["pretty_name"]; ok {
|
||||
json.Unmarshal(v, &major.PrettyName)
|
||||
}
|
||||
|
||||
return major, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of LyricsMajor
|
||||
func (lm *LyricsMajor) 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 {
|
||||
major := &LyricsMajor{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, major); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, major)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// TrackLyrics represents lyrics information from /tracks/{id}/lyrics endpoint
|
||||
type TrackLyrics struct {
|
||||
BaseModel
|
||||
DownloadURL string `json:"download_url"`
|
||||
LyricID int `json:"lyric_id"`
|
||||
ExternalLyricID string `json:"external_lyric_id"`
|
||||
Writers []string `json:"writers"`
|
||||
Major *LyricsMajor `json:"major"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes TrackLyrics from JSON
|
||||
func (tl *TrackLyrics) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lyrics := &TrackLyrics{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["download_url"]; ok {
|
||||
json.Unmarshal(v, &lyrics.DownloadURL)
|
||||
}
|
||||
if v, ok := raw["lyric_id"]; ok {
|
||||
json.Unmarshal(v, &lyrics.LyricID)
|
||||
}
|
||||
if v, ok := raw["external_lyric_id"]; ok {
|
||||
json.Unmarshal(v, &lyrics.ExternalLyricID)
|
||||
}
|
||||
if v, ok := raw["writers"]; ok {
|
||||
json.Unmarshal(v, &lyrics.Writers)
|
||||
}
|
||||
if v, ok := raw["major"]; ok {
|
||||
var major LyricsMajor
|
||||
json.Unmarshal(v, &major)
|
||||
lyrics.Major = &major
|
||||
}
|
||||
|
||||
return lyrics, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of TrackLyrics
|
||||
func (tl *TrackLyrics) 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 {
|
||||
lyrics := &TrackLyrics{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, lyrics); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, lyrics)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// SupplementLyrics represents the actual lyrics content (from supplement)
|
||||
type SupplementLyrics struct {
|
||||
BaseModel
|
||||
ID int `json:"id"`
|
||||
Text string `json:"lyrics"` // First lines of lyrics
|
||||
FullLyrics string `json:"full_lyrics"` // Full lyrics text
|
||||
HasRights bool `json:"has_rights"`
|
||||
ShowTranslation bool `json:"show_translation"`
|
||||
TextLanguage string `json:"text_language"`
|
||||
URL string `json:"url"`
|
||||
Major *LyricsMajor `json:"major"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes SupplementLyrics from JSON
|
||||
func (l *SupplementLyrics) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lyrics := &SupplementLyrics{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &lyrics.ID)
|
||||
}
|
||||
if v, ok := raw["lyrics"]; ok {
|
||||
json.Unmarshal(v, &lyrics.Text)
|
||||
}
|
||||
if v, ok := raw["full_lyrics"]; ok {
|
||||
json.Unmarshal(v, &lyrics.FullLyrics)
|
||||
}
|
||||
if v, ok := raw["has_rights"]; ok {
|
||||
json.Unmarshal(v, &lyrics.HasRights)
|
||||
}
|
||||
if v, ok := raw["show_translation"]; ok {
|
||||
json.Unmarshal(v, &lyrics.ShowTranslation)
|
||||
}
|
||||
if v, ok := raw["text_language"]; ok {
|
||||
json.Unmarshal(v, &lyrics.TextLanguage)
|
||||
}
|
||||
if v, ok := raw["url"]; ok {
|
||||
json.Unmarshal(v, &lyrics.URL)
|
||||
}
|
||||
if v, ok := raw["major"]; ok {
|
||||
var major LyricsMajor
|
||||
json.Unmarshal(v, &major)
|
||||
lyrics.Major = &major
|
||||
}
|
||||
|
||||
return lyrics, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of SupplementLyrics
|
||||
func (l *SupplementLyrics) 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 {
|
||||
lyrics := &SupplementLyrics{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, lyrics); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, lyrics)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// LyricsInfo represents lyrics availability information
|
||||
type LyricsInfo struct {
|
||||
BaseModel
|
||||
TrackID string `json:"track_id"`
|
||||
Lyrics *SupplementLyrics `json:"lyrics"`
|
||||
Text string `json:"text"`
|
||||
Language string `json:"language"`
|
||||
HasText bool `json:"has_text"`
|
||||
HasSync bool `json:"has_sync"`
|
||||
SyncType string `json:"sync_type"`
|
||||
Major *LyricsMajor `json:"major"`
|
||||
Available bool `json:"available"`
|
||||
HasAvailableSyncLyrics bool `json:"has_available_sync_lyrics"`
|
||||
HasAvailableTextLyrics bool `json:"has_available_text_lyrics"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes LyricsInfo from JSON
|
||||
func (li *LyricsInfo) 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 := &LyricsInfo{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["track_id"]; ok {
|
||||
json.Unmarshal(v, &info.TrackID)
|
||||
}
|
||||
if v, ok := raw["text"]; ok {
|
||||
json.Unmarshal(v, &info.Text)
|
||||
}
|
||||
if v, ok := raw["language"]; ok {
|
||||
json.Unmarshal(v, &info.Language)
|
||||
}
|
||||
if v, ok := raw["has_text"]; ok {
|
||||
json.Unmarshal(v, &info.HasText)
|
||||
}
|
||||
if v, ok := raw["has_sync"]; ok {
|
||||
json.Unmarshal(v, &info.HasSync)
|
||||
}
|
||||
if v, ok := raw["sync_type"]; ok {
|
||||
json.Unmarshal(v, &info.SyncType)
|
||||
}
|
||||
if v, ok := raw["available"]; ok {
|
||||
json.Unmarshal(v, &info.Available)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
if v, ok := raw["lyrics"]; ok {
|
||||
var lyrics SupplementLyrics
|
||||
json.Unmarshal(v, &lyrics)
|
||||
info.Lyrics = &lyrics
|
||||
}
|
||||
if v, ok := raw["major"]; ok {
|
||||
var major LyricsMajor
|
||||
json.Unmarshal(v, &major)
|
||||
info.Major = &major
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of LyricsInfo
|
||||
func (li *LyricsInfo) 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 := &LyricsInfo{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, info); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, info)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// VideoSupplement represents a video supplement (from supplement endpoint)
|
||||
type VideoSupplement struct {
|
||||
BaseModel
|
||||
Cover string `json:"cover"`
|
||||
Provider string `json:"provider"`
|
||||
Title string `json:"title"`
|
||||
ProviderVideoID string `json:"provider_video_id"`
|
||||
URL string `json:"url"`
|
||||
EmbedURL string `json:"embed_url"`
|
||||
Embed string `json:"embed"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes VideoSupplement from JSON
|
||||
func (vs *VideoSupplement) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
supp := &VideoSupplement{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["cover"]; ok {
|
||||
json.Unmarshal(v, &supp.Cover)
|
||||
}
|
||||
if v, ok := raw["provider"]; ok {
|
||||
json.Unmarshal(v, &supp.Provider)
|
||||
}
|
||||
if v, ok := raw["title"]; ok {
|
||||
json.Unmarshal(v, &supp.Title)
|
||||
}
|
||||
if v, ok := raw["provider_video_id"]; ok {
|
||||
json.Unmarshal(v, &supp.ProviderVideoID)
|
||||
}
|
||||
if v, ok := raw["url"]; ok {
|
||||
json.Unmarshal(v, &supp.URL)
|
||||
}
|
||||
if v, ok := raw["embed_url"]; ok {
|
||||
json.Unmarshal(v, &supp.EmbedURL)
|
||||
}
|
||||
if v, ok := raw["embed"]; ok {
|
||||
json.Unmarshal(v, &supp.Embed)
|
||||
}
|
||||
|
||||
return supp, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of VideoSupplements
|
||||
func (vs *VideoSupplement) 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 {
|
||||
supp := &VideoSupplement{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, supp); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, supp)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Supplement represents a track supplement
|
||||
type Supplement struct {
|
||||
BaseModel
|
||||
ID string `json:"id"`
|
||||
Lyrics *LyricsInfo `json:"lyrics"`
|
||||
Videos []VideoSupplement `json:"videos"`
|
||||
RadioIsAvailable bool `json:"radio_is_available"`
|
||||
Description string `json:"description"`
|
||||
Available bool `json:"available"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes Supplement from JSON
|
||||
func (s *Supplement) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
supp := &Supplement{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["id"]; ok {
|
||||
json.Unmarshal(v, &supp.ID)
|
||||
}
|
||||
if v, ok := raw["radio_is_available"]; ok {
|
||||
json.Unmarshal(v, &supp.RadioIsAvailable)
|
||||
}
|
||||
if v, ok := raw["description"]; ok {
|
||||
json.Unmarshal(v, &supp.Description)
|
||||
}
|
||||
if v, ok := raw["available"]; ok {
|
||||
json.Unmarshal(v, &supp.Available)
|
||||
}
|
||||
|
||||
if v, ok := raw["lyrics"]; ok {
|
||||
var lyrics LyricsInfo
|
||||
json.Unmarshal(v, &lyrics)
|
||||
supp.Lyrics = &lyrics
|
||||
}
|
||||
if v, ok := raw["videos"]; ok {
|
||||
var videos []VideoSupplement
|
||||
json.Unmarshal(v, &videos)
|
||||
supp.Videos = videos
|
||||
}
|
||||
|
||||
return supp, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of Supplements
|
||||
func (s *Supplement) 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 {
|
||||
supp := &Supplement{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, supp); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, supp)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Track represents a full track
|
||||
type Track struct {
|
||||
BaseModel
|
||||
ID string `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
|
||||
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
|
||||
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
|
||||
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 info
|
||||
type Major struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
// TrackLyricsInfo represents minimal lyrics info for a track
|
||||
type TrackLyricsInfo struct {
|
||||
ID string `json:"id"`
|
||||
Text string `json:"text"`
|
||||
Major *Major `json:"major"`
|
||||
Available bool `json:"available"`
|
||||
HasText bool `json:"has_text"`
|
||||
}
|
||||
|
||||
// DownloadInfo represents file download info
|
||||
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"`
|
||||
}
|
||||
@@ -0,0 +1,342 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// TrackShort represents a lightweight track (used in lists)
|
||||
type TrackShort struct {
|
||||
BaseModel
|
||||
ID string `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 *SupplementLyrics `json:"lyrics"`
|
||||
SimilarTracks []TrackShort `json:"similar_tracks"`
|
||||
DownloadInfo []DownloadInfo `json:"download_info"`
|
||||
// Additional fields from track_short.py
|
||||
Position *TrackPosition `json:"position"`
|
||||
AvailableAsRingtone bool `json:"available_as_ringtone"`
|
||||
RingtoneID string `json:"ringtone_id"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a TrackShort from JSON
|
||||
func (t *TrackShort) 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 := &TrackShort{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)
|
||||
}
|
||||
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"]; ok {
|
||||
var lyrics SupplementLyrics
|
||||
if err := json.Unmarshal(v, &lyrics); err == nil {
|
||||
track.Lyrics = &lyrics
|
||||
}
|
||||
}
|
||||
if v, ok := raw["similar_tracks"]; ok {
|
||||
var similar []TrackShort
|
||||
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 TrackShort
|
||||
func (t *TrackShort) 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 := &TrackShort{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, track); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, track)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// TracksList represents a list of tracks with metadata
|
||||
type TracksList struct {
|
||||
BaseModel
|
||||
Tracks []TrackShort `json:"tracks"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
Pager *Pager `json:"pager"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a TracksList from JSON
|
||||
func (t *TracksList) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
list := &TracksList{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["tracks"]; ok {
|
||||
var tracks []TrackShort
|
||||
if err := json.Unmarshal(v, &tracks); err == nil {
|
||||
list.Tracks = tracks
|
||||
}
|
||||
}
|
||||
if v, ok := raw["total"]; ok {
|
||||
json.Unmarshal(v, &list.Total)
|
||||
}
|
||||
if v, ok := raw["page"]; ok {
|
||||
json.Unmarshal(v, &list.Page)
|
||||
}
|
||||
if v, ok := raw["page_size"]; ok {
|
||||
json.Unmarshal(v, &list.PageSize)
|
||||
}
|
||||
if v, ok := raw["pager"]; ok {
|
||||
var pager Pager
|
||||
if err := json.Unmarshal(v, &pager); err == nil {
|
||||
list.Pager = &pager
|
||||
}
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of TracksList
|
||||
func (t *TracksList) 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 {
|
||||
list := &TracksList{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, list); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, list)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Pager represents pagination info
|
||||
type Pager struct {
|
||||
BaseModel
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
Pages int `json:"pages"`
|
||||
PerPage int `json:"per_page"`
|
||||
PrevPage *int `json:"prev_page"`
|
||||
NextPage *int `json:"next_page"`
|
||||
HasPrev bool `json:"has_prev"`
|
||||
HasNext bool `json:"has_next"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a Pager from JSON
|
||||
func (p *Pager) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pager := &Pager{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["total"]; ok {
|
||||
json.Unmarshal(v, &pager.Total)
|
||||
}
|
||||
if v, ok := raw["page"]; ok {
|
||||
json.Unmarshal(v, &pager.Page)
|
||||
}
|
||||
if v, ok := raw["page_size"]; ok {
|
||||
json.Unmarshal(v, &pager.PageSize)
|
||||
}
|
||||
if v, ok := raw["pages"]; ok {
|
||||
json.Unmarshal(v, &pager.Pages)
|
||||
}
|
||||
if v, ok := raw["per_page"]; ok {
|
||||
json.Unmarshal(v, &pager.PerPage)
|
||||
}
|
||||
if v, ok := raw["prev_page"]; ok {
|
||||
var prev int
|
||||
if err := json.Unmarshal(v, &prev); err == nil {
|
||||
pager.PrevPage = &prev
|
||||
}
|
||||
}
|
||||
if v, ok := raw["next_page"]; ok {
|
||||
var next int
|
||||
if err := json.Unmarshal(v, &next); err == nil {
|
||||
pager.NextPage = &next
|
||||
}
|
||||
}
|
||||
if v, ok := raw["has_prev"]; ok {
|
||||
json.Unmarshal(v, &pager.HasPrev)
|
||||
}
|
||||
if v, ok := raw["has_next"]; ok {
|
||||
json.Unmarshal(v, &pager.HasNext)
|
||||
}
|
||||
|
||||
return pager, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of Pager
|
||||
func (p *Pager) 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 {
|
||||
pager := &Pager{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, pager); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, pager)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// TrackPosition represents track position in a playlist/queue
|
||||
type TrackPosition struct {
|
||||
BaseModel
|
||||
Revision int `json:"revision"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
Position int `json:"position"`
|
||||
FromCache bool `json:"from_cache"`
|
||||
}
|
||||
|
||||
// DeJSON deserializes a TrackPosition from JSON
|
||||
func (tp *TrackPosition) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pos := &TrackPosition{BaseModel: *NewBaseModel(c)}
|
||||
|
||||
if v, ok := raw["revision"]; ok {
|
||||
json.Unmarshal(v, &pos.Revision)
|
||||
}
|
||||
if v, ok := raw["timestamp"]; ok {
|
||||
json.Unmarshal(v, &pos.Timestamp)
|
||||
}
|
||||
if v, ok := raw["position"]; ok {
|
||||
json.Unmarshal(v, &pos.Position)
|
||||
}
|
||||
if v, ok := raw["from_cache"]; ok {
|
||||
json.Unmarshal(v, &pos.FromCache)
|
||||
}
|
||||
|
||||
return pos, nil
|
||||
}
|
||||
|
||||
// DeList deserializes a list of TrackPosition
|
||||
func (tp *TrackPosition) 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 {
|
||||
pos := &TrackPosition{BaseModel: *NewBaseModel(c)}
|
||||
if err := json.Unmarshal(item, pos); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, pos)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// mockRequest implements RequestInterface for testing
|
||||
type mockRequest struct{}
|
||||
|
||||
func (m *mockRequest) Get(ctx context.Context, path string, params map[string]string, result any) error {
|
||||
return nil
|
||||
}
|
||||
func (m *mockRequest) Post(ctx context.Context, path string, body any, result any) error {
|
||||
return nil
|
||||
}
|
||||
func (m *mockRequest) Put(ctx context.Context, path string, body any, result any) error {
|
||||
return nil
|
||||
}
|
||||
func (m *mockRequest) Delete(ctx context.Context, path string, body any, result any) error {
|
||||
return nil
|
||||
}
|
||||
func (m *mockRequest) Download(ctx context.Context, url string) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// mockClient implements ClientInterface for testing
|
||||
type mockClient struct {
|
||||
request *mockRequest
|
||||
}
|
||||
|
||||
func (m *mockClient) GetRequest() RequestInterface {
|
||||
return m.request
|
||||
}
|
||||
|
||||
func newMockClient() *mockClient {
|
||||
return &mockClient{request: &mockRequest{}}
|
||||
}
|
||||
|
||||
func TestTrack_DeJSON(t *testing.T) {
|
||||
client := newMockClient()
|
||||
data := []byte(`{
|
||||
"id": "123",
|
||||
"title": "Test Track",
|
||||
"duration_ms": 180000,
|
||||
"storage_id": "456",
|
||||
"cover_uri": "https://example.com/cover.jpg",
|
||||
"genre": "rock",
|
||||
"version": "album",
|
||||
"explicit": false,
|
||||
"available": true,
|
||||
"available_for_premium_users": true,
|
||||
"r128": -12.5,
|
||||
"track_sharing_flag": "allowed",
|
||||
"artists": [{"id": "1", "name": "Artist 1", "cover_uri": "https://example.com/artist.jpg"}],
|
||||
"albums": [{"id": "789", "title": "Test Album", "cover_uri": "https://example.com/album.jpg", "year": 2023}],
|
||||
"major": {"id": "major1", "name": "Major Label", "description": "Big label"},
|
||||
"lyrics": {"id": "lyr1", "text": "Test lyrics", "available": true, "has_text": true}
|
||||
}`)
|
||||
|
||||
track := &Track{BaseModel: *NewBaseModel(client)}
|
||||
result, err := track.DeJSON(data, client)
|
||||
if err != nil {
|
||||
t.Fatalf("DeJSON failed: %v", err)
|
||||
}
|
||||
|
||||
resultTrack := result.(*Track)
|
||||
if resultTrack.ID != "123" {
|
||||
t.Errorf("Expected ID '123', got '%s'", resultTrack.ID)
|
||||
}
|
||||
if resultTrack.Title != "Test Track" {
|
||||
t.Errorf("Expected Title 'Test Track', got '%s'", resultTrack.Title)
|
||||
}
|
||||
if resultTrack.DurationMs != 180000 {
|
||||
t.Errorf("Expected DurationMs 180000, got %d", resultTrack.DurationMs)
|
||||
}
|
||||
if len(resultTrack.Artists) != 1 {
|
||||
t.Errorf("Expected 1 artist, got %d", len(resultTrack.Artists))
|
||||
}
|
||||
if resultTrack.Major == nil || resultTrack.Major.Name != "Major Label" {
|
||||
t.Errorf("Expected Major 'Major Label'")
|
||||
}
|
||||
if resultTrack.Lyrics == nil || resultTrack.Lyrics.Text != "Test lyrics" {
|
||||
t.Errorf("Expected Lyrics 'Test lyrics'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrack_DeList(t *testing.T) {
|
||||
client := newMockClient()
|
||||
data := []byte(`[
|
||||
{"id": "1", "title": "Track 1", "duration_ms": 100000},
|
||||
{"id": "2", "title": "Track 2", "duration_ms": 200000}
|
||||
]`)
|
||||
|
||||
track := &Track{BaseModel: *NewBaseModel(client)}
|
||||
result, err := track.DeList(data, client)
|
||||
if err != nil {
|
||||
t.Fatalf("DeList failed: %v", err)
|
||||
}
|
||||
|
||||
if len(result) != 2 {
|
||||
t.Errorf("Expected 2 tracks, got %d", len(result))
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrack_GetDownloadInfo(t *testing.T) {
|
||||
client := newMockClient()
|
||||
track := &Track{
|
||||
BaseModel: *NewBaseModel(client),
|
||||
DownloadInfo: []DownloadInfo{
|
||||
{Quality: "mp3", Codec: "mp3", Bitrate: 320, Size: 5000000, URL: "https://example.com/track.mp3"},
|
||||
{Quality: "flac", Codec: "flac", Bitrate: 1411, Size: 25000000, URL: "https://example.com/track.flac"},
|
||||
},
|
||||
}
|
||||
|
||||
info := track.GetDownloadInfo("mp3")
|
||||
if info == nil {
|
||||
t.Fatal("Expected mp3 download info")
|
||||
}
|
||||
if info.Bitrate != 320 {
|
||||
t.Errorf("Expected bitrate 320, got %d", info.Bitrate)
|
||||
}
|
||||
|
||||
info = track.GetDownloadInfo("flac")
|
||||
if info == nil {
|
||||
t.Fatal("Expected flac download info")
|
||||
}
|
||||
if info.Bitrate != 1411 {
|
||||
t.Errorf("Expected bitrate 1411, got %d", info.Bitrate)
|
||||
}
|
||||
|
||||
info = track.GetDownloadInfo("ogg")
|
||||
if info != nil {
|
||||
t.Errorf("Expected nil for ogg, got %v", info)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user