Compare commits
18
Commits
02a6dabcfb
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dbf9a46bb2 | ||
|
|
73775a8526 | ||
|
|
49920d8908 | ||
|
|
9d3bcc4a9b | ||
|
|
463e0bcd1a | ||
|
|
bc026d82b4 | ||
|
|
a9be10b5e5 | ||
|
|
577c4a418c | ||
|
|
277a3e6924 | ||
|
|
6312c24b0f | ||
|
|
ad83d84531 | ||
|
|
dbb823ade3 | ||
|
|
d0173f795d | ||
|
|
5535d2a941 | ||
|
|
0456ca0665 | ||
|
|
7a68ad86cb | ||
|
|
5786f0df1e | ||
|
|
70c2a5cd01 |
No files matched your search
@@ -0,0 +1 @@
|
|||||||
|
.serena/
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
This is a Go port of the [yandex-music-api](https://github.com/MarshalX/yandex-music-api) Python library. The original Python library is in `yandex-music-api-python/` and serves as the reference implementation.
|
||||||
|
|
||||||
|
The Python library provides:
|
||||||
|
- **Sync and async HTTP clients** for Yandex Music API
|
||||||
|
- **Ynison protocol support** for player synchronization across devices
|
||||||
|
- **Radio sessions** (My Wave, generative stations)
|
||||||
|
- **High-level wrapper objects** (Track, Album, Artist, Playlist, etc.)
|
||||||
|
- **Schema mismatch handling** for API evolution
|
||||||
|
- **Multiple JSON backend support** (orjson, pydantic-core, ujson, stdlib json)
|
||||||
|
|
||||||
|
## Python Library Architecture (Reference)
|
||||||
|
|
||||||
|
### Core Structure
|
||||||
|
```
|
||||||
|
yandex_music/
|
||||||
|
├── client.py # Sync Client (main entry point)
|
||||||
|
├── client_async.py # Async ClientAsync
|
||||||
|
├── _client_base.py # Shared base class with common attributes
|
||||||
|
├── base.py # YandexMusicObject base model with de_json/de_list
|
||||||
|
├── exceptions.py # Custom exceptions
|
||||||
|
├── utils/
|
||||||
|
│ ├── request.py # Sync HTTP request handling
|
||||||
|
│ ├── request_async.py # Async HTTP request handling
|
||||||
|
│ ├── json_backend.py # Pluggable JSON backends
|
||||||
|
│ └── schema_mismatch.py # Schema mismatch reporting
|
||||||
|
├── _client/ # Generated sync method mixins (20+ files)
|
||||||
|
├── _client_async/ # Generated async method mixins
|
||||||
|
├── track/, album/, artist/, playlist/, etc. # Model packages
|
||||||
|
├── ynison/ # Ynison protocol (WebSocket)
|
||||||
|
│ ├── client.py # Sync Ynison client
|
||||||
|
│ ├── client_async.py # Async Ynison client
|
||||||
|
│ └── models/ # Protobuf-generated models
|
||||||
|
└── supplement/ # Lyrics, video supplements
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key Patterns
|
||||||
|
- **Mixin-based Client**: `Client` inherits from 20+ mixins (AccountMixin, AlbumsMixin, TracksMixin, etc.)
|
||||||
|
- **Model deserialization**: Each model has `de_json(data, client)` and `de_list(list_data, client)` classmethods
|
||||||
|
- **Request signing**: Requests to `api.music.yandex.net` are signed with a custom algorithm
|
||||||
|
- **Device auth**: OAuth Device Flow for token acquisition
|
||||||
|
- **Generated code**: Sync/async clients and models are partially code-generated from OpenAPI spec
|
||||||
|
|
||||||
|
## Go Project Structure (Target)
|
||||||
|
|
||||||
|
```
|
||||||
|
yandex-music-api-go/
|
||||||
|
├── go.mod
|
||||||
|
├── go.sum
|
||||||
|
├── cmd/
|
||||||
|
│ └── examples/ # Example applications
|
||||||
|
├── internal/
|
||||||
|
│ ├── client/ # Core HTTP client
|
||||||
|
│ │ ├── client.go # Main Client struct
|
||||||
|
│ │ ├── request.go # Request building/signing
|
||||||
|
│ │ └── auth.go # Device auth, token handling
|
||||||
|
│ ├── models/ # Data models (Track, Album, Artist, etc.)
|
||||||
|
│ │ ├── base.go # BaseModel interface
|
||||||
|
│ │ ├── track.go
|
||||||
|
│ │ ├── album.go
|
||||||
|
│ │ └── ...
|
||||||
|
│ ├── ynison/ # Ynison WebSocket client
|
||||||
|
│ │ ├── client.go
|
||||||
|
│ │ └── proto/ # Protobuf-generated Go code
|
||||||
|
│ └── utils/
|
||||||
|
│ ├── json.go # JSON handling
|
||||||
|
│ └── schema.go # Schema mismatch handling
|
||||||
|
├── yandexmusic/ # Public API package (re-exports)
|
||||||
|
│ ├── client.go # Public Client interface
|
||||||
|
│ └── models.go # Public model types
|
||||||
|
└── tests/ # Integration tests
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development Commands
|
||||||
|
|
||||||
|
### Go Toolchain
|
||||||
|
```bash
|
||||||
|
# Initialize module (run once)
|
||||||
|
go mod init github.com/your-org/yandex-music-api-go
|
||||||
|
|
||||||
|
# Download dependencies
|
||||||
|
go mod tidy
|
||||||
|
|
||||||
|
# Build
|
||||||
|
go build ./...
|
||||||
|
|
||||||
|
# Run tests
|
||||||
|
go test ./...
|
||||||
|
|
||||||
|
# Run tests with coverage
|
||||||
|
go test -cover ./...
|
||||||
|
|
||||||
|
# Run single test
|
||||||
|
go test -v -run TestName ./path/to/package
|
||||||
|
|
||||||
|
# Lint (requires golangci-lint)
|
||||||
|
golangci-lint run
|
||||||
|
|
||||||
|
# Format
|
||||||
|
go fmt ./...
|
||||||
|
|
||||||
|
# Vet
|
||||||
|
go vet ./...
|
||||||
|
|
||||||
|
# Generate code (if using code generation)
|
||||||
|
go generate ./...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Protobuf (for Ynison)
|
||||||
|
```bash
|
||||||
|
# Install protoc and plugins
|
||||||
|
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
|
||||||
|
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
|
||||||
|
go install github.com/bufbuild/buf/cmd/buf@latest # optional, for buf.yaml workflow
|
||||||
|
|
||||||
|
# Generate from .proto files
|
||||||
|
protoc --go_out=. --go_opt=paths=source_relative \
|
||||||
|
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
|
||||||
|
internal/ynison/proto/*.proto
|
||||||
|
|
||||||
|
# Or with buf
|
||||||
|
buf generate
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key Implementation Notes
|
||||||
|
|
||||||
|
### Request Signing
|
||||||
|
The Python library signs requests with a custom algorithm. Port this exactly from `yandex_music/utils/request.py`:
|
||||||
|
- Request parameters are sorted and concatenated
|
||||||
|
- Signed with a secret key
|
||||||
|
- Signature added as `sign` parameter
|
||||||
|
|
||||||
|
### JSON Handling
|
||||||
|
Go's standard `encoding/json` is fast enough. No need for multiple backends. Use `json.RawMessage` for flexible fields.
|
||||||
|
|
||||||
|
### Schema Mismatch Handling
|
||||||
|
Port the Python `SchemaMismatch` logic:
|
||||||
|
- Track unknown fields in API responses
|
||||||
|
- Configurable: ignore, warn, or strict (error)
|
||||||
|
- Callback support for custom handling (e.g., Sentry)
|
||||||
|
|
||||||
|
### Ynison Protocol
|
||||||
|
- Uses WebSocket with protobuf messages
|
||||||
|
- Python uses `betterproto` for protobuf; Go uses standard `protobuf` module
|
||||||
|
- Port the message types from `yandex_music/ynison/models/`
|
||||||
|
|
||||||
|
### Model Structure
|
||||||
|
Follow Python patterns:
|
||||||
|
```go
|
||||||
|
// Base interface for all models
|
||||||
|
type Model interface {
|
||||||
|
// DeJSON deserializes from JSON
|
||||||
|
DeJSON(data []byte, client *Client) (Model, error)
|
||||||
|
// DeList deserializes a list
|
||||||
|
DeList(data []byte, client *Client) ([]Model, error)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Client Design
|
||||||
|
- Single `Client` struct with methods (not mixins - Go doesn't have them)
|
||||||
|
- Group methods by feature using separate files: `client_tracks.go`, `client_albums.go`, etc.
|
||||||
|
- Support both sync and async (context-based) patterns
|
||||||
|
|
||||||
|
## Testing Strategy
|
||||||
|
- Unit tests for models (de/serialization)
|
||||||
|
- Integration tests against mock server (use `httptest`)
|
||||||
|
- Test schema mismatch handling
|
||||||
|
- Test request signing
|
||||||
|
|
||||||
|
## License
|
||||||
|
LGPL-3.0-only (same as Python library)
|
||||||
|
|
||||||
|
## References
|
||||||
|
- Python library: `yandex-music-api-python/`
|
||||||
|
- OpenAPI spec: https://ym.marshal.dev/api/openapi.json
|
||||||
|
- Documentation: https://ym.marshal.dev/
|
||||||
|
- Telegram: https://t.me/yandex_music_api
|
||||||
@@ -57,7 +57,7 @@ func main() {
|
|||||||
// Example: Get track by ID (if we have results)
|
// Example: Get track by ID (if we have results)
|
||||||
if len(tracks) > 0 {
|
if len(tracks) > 0 {
|
||||||
fmt.Println("\n--- Getting track details ---")
|
fmt.Println("\n--- Getting track details ---")
|
||||||
track, err := client.GetTrack(ctx, tracks[0].ID)
|
track, err := client.GetTrack(ctx, string(tracks[0].ID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Get track failed: %v", err)
|
log.Printf("Get track failed: %v", err)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Package client provides methods for interacting with Yandex Music API endpoints.
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -6,7 +7,7 @@ import (
|
|||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetAccountSettings gets account settings (current user's settings from /account/settings)
|
// GetAccountSettings gets account settings (current user's settings from /account/settings).
|
||||||
func (c *Client) GetAccountSettings(ctx context.Context) (*models.UserSettings, error) {
|
func (c *Client) GetAccountSettings(ctx context.Context) (*models.UserSettings, error) {
|
||||||
var result models.UserSettings
|
var result models.UserSettings
|
||||||
if err := c.request.Get(ctx, "/account/settings", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/account/settings", nil, &result); err != nil {
|
||||||
@@ -15,7 +16,7 @@ func (c *Client) GetAccountSettings(ctx context.Context) (*models.UserSettings,
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateAccountSettings updates account settings
|
// UpdateAccountSettings updates account settings (PUT /account/settings).
|
||||||
func (c *Client) UpdateAccountSettings(ctx context.Context, settings *models.AccountSettings) (*models.AccountSettings, error) {
|
func (c *Client) UpdateAccountSettings(ctx context.Context, settings *models.AccountSettings) (*models.AccountSettings, error) {
|
||||||
var result models.AccountSettings
|
var result models.AccountSettings
|
||||||
if err := c.request.Put(ctx, "/account/settings", settings, &result); err != nil {
|
if err := c.request.Put(ctx, "/account/settings", settings, &result); err != nil {
|
||||||
@@ -24,7 +25,7 @@ func (c *Client) UpdateAccountSettings(ctx context.Context, settings *models.Acc
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSubscription gets user subscription info
|
// GetSubscription gets user subscription info (GET /account/subscription).
|
||||||
func (c *Client) GetSubscription(ctx context.Context) (*models.Subscription, error) {
|
func (c *Client) GetSubscription(ctx context.Context) (*models.Subscription, error) {
|
||||||
var result models.Subscription
|
var result models.Subscription
|
||||||
if err := c.request.Get(ctx, "/account/subscription", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/account/subscription", nil, &result); err != nil {
|
||||||
@@ -33,7 +34,7 @@ func (c *Client) GetSubscription(ctx context.Context) (*models.Subscription, err
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPlusInfo gets Plus subscription info
|
// GetPlusInfo gets Plus subscription info (GET /account/plus).
|
||||||
func (c *Client) GetPlusInfo(ctx context.Context) (*models.PlusInfo, error) {
|
func (c *Client) GetPlusInfo(ctx context.Context) (*models.PlusInfo, error) {
|
||||||
var result models.PlusInfo
|
var result models.PlusInfo
|
||||||
if err := c.request.Get(ctx, "/account/plus", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/account/plus", nil, &result); err != nil {
|
||||||
@@ -42,7 +43,7 @@ func (c *Client) GetPlusInfo(ctx context.Context) (*models.PlusInfo, error) {
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPromoCodeStatus gets promo code status
|
// GetPromoCodeStatus gets promo code status (GET /promo-code-status).
|
||||||
func (c *Client) GetPromoCodeStatus(ctx context.Context, code string) (*models.PromoCodeStatus, error) {
|
func (c *Client) GetPromoCodeStatus(ctx context.Context, code string) (*models.PromoCodeStatus, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"code": code,
|
"code": code,
|
||||||
@@ -54,7 +55,7 @@ func (c *Client) GetPromoCodeStatus(ctx context.Context, code string) (*models.P
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ActivatePromoCode activates a promo code
|
// ActivatePromoCode activates a promo code (POST /promo-code/activate).
|
||||||
func (c *Client) ActivatePromoCode(ctx context.Context, code string) (*models.PromoCodeStatus, error) {
|
func (c *Client) ActivatePromoCode(ctx context.Context, code string) (*models.PromoCodeStatus, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"code": code,
|
"code": code,
|
||||||
@@ -66,7 +67,7 @@ func (c *Client) ActivatePromoCode(ctx context.Context, code string) (*models.Pr
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserSettings gets user settings
|
// GetUserSettings gets user settings for a specific user (GET /user/settings).
|
||||||
func (c *Client) GetUserSettings(ctx context.Context, userID string) (*models.UserSettings, error) {
|
func (c *Client) GetUserSettings(ctx context.Context, userID string) (*models.UserSettings, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"user_id": userID,
|
"user_id": userID,
|
||||||
@@ -78,7 +79,8 @@ func (c *Client) GetUserSettings(ctx context.Context, userID string) (*models.Us
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAccountStatus fetches account status
|
// GetAccountStatus fetches account status (GET /account/status).
|
||||||
|
// It returns the account status including account info and Plus subscription status.
|
||||||
func (c *Client) GetAccountStatus(ctx context.Context) (*Status, error) {
|
func (c *Client) GetAccountStatus(ctx context.Context) (*Status, error) {
|
||||||
var result Status
|
var result Status
|
||||||
if err := c.request.Get(ctx, "/account/status", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/account/status", nil, &result); err != nil {
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
|
// Package client provides methods for interacting with Yandex Music API endpoints.
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/utils"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetAlbums gets albums by IDs
|
// GetAlbums gets albums by their IDs (GET /tracks?album-ids=...).
|
||||||
|
// Returns a slice of Album pointers, or nil if no IDs are provided.
|
||||||
func (c *Client) GetAlbums(ctx context.Context, albumIDs []string) ([]*models.Album, error) {
|
func (c *Client) GetAlbums(ctx context.Context, albumIDs []string) ([]*models.Album, error) {
|
||||||
if len(albumIDs) == 0 {
|
if len(albumIDs) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -30,7 +33,8 @@ func (c *Client) GetAlbums(ctx context.Context, albumIDs []string) ([]*models.Al
|
|||||||
return albums, nil
|
return albums, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAlbum gets a single album by ID
|
// GetAlbum gets a single album by ID using GetAlbums.
|
||||||
|
// Returns an error if no album is found with the given ID.
|
||||||
func (c *Client) GetAlbum(ctx context.Context, albumID string) (*models.Album, error) {
|
func (c *Client) GetAlbum(ctx context.Context, albumID string) (*models.Album, error) {
|
||||||
albums, err := c.GetAlbums(ctx, []string{albumID})
|
albums, err := c.GetAlbums(ctx, []string{albumID})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -42,7 +46,8 @@ func (c *Client) GetAlbum(ctx context.Context, albumID string) (*models.Album, e
|
|||||||
return albums[0], nil
|
return albums[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAlbumsWithTracks gets albums with tracks expanded
|
// GetAlbumsWithTracks gets albums with tracks expanded (GET /tracks?with-tracks=true).
|
||||||
|
// Returns a slice of Album pointers with their tracks populated.
|
||||||
func (c *Client) GetAlbumsWithTracks(ctx context.Context, albumIDs []string) ([]*models.Album, error) {
|
func (c *Client) GetAlbumsWithTracks(ctx context.Context, albumIDs []string) ([]*models.Album, error) {
|
||||||
if len(albumIDs) == 0 {
|
if len(albumIDs) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -65,3 +70,23 @@ func (c *Client) GetAlbumsWithTracks(ctx context.Context, albumIDs []string) ([]
|
|||||||
}
|
}
|
||||||
return albums, nil
|
return albums, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAlbumSimilarEntities gets similar entities for an album (GET /albums/{id}/similar-entities).
|
||||||
|
func (c *Client) GetAlbumSimilarEntities(ctx context.Context, albumID string) (*models.AlbumSimilarEntities, error) {
|
||||||
|
var result models.AlbumSimilarEntities
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/albums/%s/similar-entities", albumID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAlbumTrailer gets album trailer (GET /albums/{id}/trailer).
|
||||||
|
func (c *Client) GetAlbumTrailer(ctx context.Context, albumID string) (*models.AlbumTrailer, error) {
|
||||||
|
var result models.AlbumTrailer
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/albums/%s/trailer", albumID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
+156
-28
@@ -1,3 +1,4 @@
|
|||||||
|
// Package client provides methods for interacting with Yandex Music API endpoints.
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -8,7 +9,8 @@ import (
|
|||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/utils"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetArtists gets artists by IDs
|
// GetArtists gets artists by their IDs (GET /tracks?artist-ids=...).
|
||||||
|
// Returns a slice of Artist pointers, or nil if no IDs are provided.
|
||||||
func (c *Client) GetArtists(ctx context.Context, artistIDs []string) ([]*models.Artist, error) {
|
func (c *Client) GetArtists(ctx context.Context, artistIDs []string) ([]*models.Artist, error) {
|
||||||
if len(artistIDs) == 0 {
|
if len(artistIDs) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -31,7 +33,8 @@ func (c *Client) GetArtists(ctx context.Context, artistIDs []string) ([]*models.
|
|||||||
return artists, nil
|
return artists, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetArtist gets a single artist by ID
|
// GetArtist gets a single artist by ID using GetArtists.
|
||||||
|
// Returns an error if no artist is found with the given ID.
|
||||||
func (c *Client) GetArtist(ctx context.Context, artistID string) (*models.Artist, error) {
|
func (c *Client) GetArtist(ctx context.Context, artistID string) (*models.Artist, error) {
|
||||||
artists, err := c.GetArtists(ctx, []string{artistID})
|
artists, err := c.GetArtists(ctx, []string{artistID})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -43,47 +46,172 @@ func (c *Client) GetArtist(ctx context.Context, artistID string) (*models.Artist
|
|||||||
return artists[0], nil
|
return artists[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetArtistAlbums gets albums by an artist
|
// GetArtistAlbums gets albums by an artist (GET /artists/{artist_id}/direct-albums).
|
||||||
func (c *Client) GetArtistAlbums(ctx context.Context, artistID string, page, pageSize int) ([]*models.Album, error) {
|
// The page and pageSize parameters control pagination.
|
||||||
|
func (c *Client) GetArtistAlbums(ctx context.Context, artistID string, page, pageSize int) (*models.ArtistAlbums, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"artist-id": artistID,
|
|
||||||
"page": fmt.Sprintf("%d", page),
|
"page": fmt.Sprintf("%d", page),
|
||||||
"page-size": fmt.Sprintf("%d", pageSize),
|
"page-size": fmt.Sprintf("%d", pageSize),
|
||||||
}
|
}
|
||||||
|
|
||||||
var result []models.Album
|
var result models.ArtistAlbums
|
||||||
if err := c.request.Get(ctx, "/artists/albums", params, &result); err != nil {
|
if err := c.request.Get(ctx, fmt.Sprintf("/artists/%s/direct-albums", artistID), params, &result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
result.SetClient(c)
|
||||||
albums := make([]*models.Album, len(result))
|
return &result, nil
|
||||||
for i := range result {
|
|
||||||
result[i].SetClient(c)
|
|
||||||
albums[i] = &result[i]
|
|
||||||
}
|
|
||||||
return albums, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetArtistTracks gets tracks by an artist
|
// GetArtistTracks gets tracks by an artist (GET /artists/{artist_id}/tracks).
|
||||||
func (c *Client) GetArtistTracks(ctx context.Context, artistID string, page, pageSize int) ([]*models.Track, error) {
|
// The page and pageSize parameters control pagination.
|
||||||
|
func (c *Client) GetArtistTracks(ctx context.Context, artistID string, page, pageSize int) (*models.ArtistTracks, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"artist-id": artistID,
|
|
||||||
"page": fmt.Sprintf("%d", page),
|
"page": fmt.Sprintf("%d", page),
|
||||||
"page-size": fmt.Sprintf("%d", pageSize),
|
"page-size": fmt.Sprintf("%d", pageSize),
|
||||||
}
|
}
|
||||||
|
|
||||||
var result []models.Track
|
var result models.ArtistTracks
|
||||||
if err := c.request.Get(ctx, "/artists/tracks", params, &result); err != nil {
|
if err := c.request.Get(ctx, fmt.Sprintf("/artists/%s/tracks", artistID), params, &result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
result.SetClient(c)
|
||||||
tracks := make([]*models.Track, len(result))
|
return &result, nil
|
||||||
for i := range result {
|
|
||||||
result[i].SetClient(c)
|
|
||||||
tracks[i] = &result[i]
|
|
||||||
}
|
|
||||||
return tracks, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to add fmt import
|
// GetArtistBriefInfo gets brief info about an artist (GET /artists/{artist_id}/brief-info).
|
||||||
// "fmt"
|
func (c *Client) GetArtistBriefInfo(ctx context.Context, artistID string) (*models.ArtistBriefInfo, error) {
|
||||||
|
var result models.ArtistBriefInfo
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/artists/%s/brief-info", artistID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetArtistSimilar gets similar artists (GET /artists/{artist_id}/similar).
|
||||||
|
func (c *Client) GetArtistSimilar(ctx context.Context, artistID string) (*models.ArtistSimilar, error) {
|
||||||
|
var result models.ArtistSimilar
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/artists/%s/similar", artistID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetArtistLinks gets links to artist's pages (GET /artists/{artist_id}/artist-links).
|
||||||
|
func (c *Client) GetArtistLinks(ctx context.Context, artistID string) (*models.ArtistLinks, error) {
|
||||||
|
var result models.ArtistLinks
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/artists/%s/artist-links", artistID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetArtistAlsoAlbums gets albums where artist participated (GET /artists/{artist_id}/also-albums).
|
||||||
|
func (c *Client) GetArtistAlsoAlbums(ctx context.Context, artistID string, page, pageSize int, sortBy string) (*models.ArtistAlbums, error) {
|
||||||
|
params := map[string]string{
|
||||||
|
"page": fmt.Sprintf("%d", page),
|
||||||
|
"page-size": fmt.Sprintf("%d", pageSize),
|
||||||
|
"sort-by": sortBy,
|
||||||
|
}
|
||||||
|
var result models.ArtistAlbums
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/artists/%s/also-albums", artistID), params, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetArtistDiscographyAlbums gets artist discography (GET /artists/{artist_id}/discography-albums).
|
||||||
|
func (c *Client) GetArtistDiscographyAlbums(ctx context.Context, artistID string, page, pageSize int, sortBy string) (*models.ArtistAlbums, error) {
|
||||||
|
params := map[string]string{
|
||||||
|
"page": fmt.Sprintf("%d", page),
|
||||||
|
"page-size": fmt.Sprintf("%d", pageSize),
|
||||||
|
"sort-by": sortBy,
|
||||||
|
}
|
||||||
|
var result models.ArtistAlbums
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/artists/%s/discography-albums", artistID), params, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetArtistSafeDirectAlbums gets safe direct albums (GET /artists/{artist_id}/safe-direct-albums).
|
||||||
|
func (c *Client) GetArtistSafeDirectAlbums(ctx context.Context, artistID string, sortBy, sortOrder string, limit int) (*models.ArtistAlbums, error) {
|
||||||
|
params := map[string]string{
|
||||||
|
"sort-by": sortBy,
|
||||||
|
"sort-order": sortOrder,
|
||||||
|
"limit": fmt.Sprintf("%d", limit),
|
||||||
|
}
|
||||||
|
var result models.ArtistAlbums
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/artists/%s/safe-direct-albums", artistID), params, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetArtistTrackIds gets track IDs by artist (GET /artists/{artist_id}/track-ids).
|
||||||
|
func (c *Client) GetArtistTrackIds(ctx context.Context, artistID string, page, pageSize int) ([]string, error) {
|
||||||
|
params := map[string]string{
|
||||||
|
"page": fmt.Sprintf("%d", page),
|
||||||
|
"page-size": fmt.Sprintf("%d", pageSize),
|
||||||
|
}
|
||||||
|
var result []string
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/artists/%s/track-ids", artistID), params, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetArtistAbout gets "About artist" info (GET /artists/{artist_id}/about-artist).
|
||||||
|
func (c *Client) GetArtistAbout(ctx context.Context, artistID string) (*models.ArtistAbout, error) {
|
||||||
|
var result models.ArtistAbout
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/artists/%s/about-artist", artistID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetArtistDonation gets artist donation info (GET /artists/{artist_id}/blocks/artist-donation).
|
||||||
|
func (c *Client) GetArtistDonation(ctx context.Context, artistID string) (*models.ArtistDonations, error) {
|
||||||
|
var result models.ArtistDonations
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/artists/%s/blocks/artist-donation", artistID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetArtistInfo gets detailed artist info (GET /artists/{artist_id}/info).
|
||||||
|
func (c *Client) GetArtistInfo(ctx context.Context, artistID string) (*models.ArtistInfo, error) {
|
||||||
|
var result models.ArtistInfo
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/artists/%s/info", artistID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetArtistSkeleton gets artist page skeleton (GET /artists/{artist_id}/skeletons/{skeleton_id}).
|
||||||
|
func (c *Client) GetArtistSkeleton(ctx context.Context, artistID, skeletonID string) (*models.ArtistSkeleton, error) {
|
||||||
|
var result models.ArtistSkeleton
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/artists/%s/skeletons/%s", artistID, skeletonID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetArtistTrailer gets artist trailer (GET /artists/{artist_id}/trailer).
|
||||||
|
func (c *Client) GetArtistTrailer(ctx context.Context, artistID string) (*models.ArtistTrailerStatus, error) {
|
||||||
|
var result models.ArtistTrailerStatus
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/artists/%s/trailer", artistID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
+10
-6
@@ -13,7 +13,7 @@ import (
|
|||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/utils"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DeviceCode represents the device authorization response
|
// DeviceCode represents the device authorization response from the Yandex OAuth device flow.
|
||||||
type DeviceCode struct {
|
type DeviceCode struct {
|
||||||
DeviceCode string `json:"device_code"`
|
DeviceCode string `json:"device_code"`
|
||||||
UserCode string `json:"user_code"`
|
UserCode string `json:"user_code"`
|
||||||
@@ -22,7 +22,7 @@ type DeviceCode struct {
|
|||||||
Interval int `json:"interval"`
|
Interval int `json:"interval"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// OAuthToken represents an OAuth token response
|
// OAuthToken represents an OAuth token response from the Yandex OAuth token endpoint.
|
||||||
type OAuthToken struct {
|
type OAuthToken struct {
|
||||||
AccessToken string `json:"access_token"`
|
AccessToken string `json:"access_token"`
|
||||||
RefreshToken string `json:"refresh_token"`
|
RefreshToken string `json:"refresh_token"`
|
||||||
@@ -30,7 +30,9 @@ type OAuthToken struct {
|
|||||||
ExpiresIn int `json:"expires_in"`
|
ExpiresIn int `json:"expires_in"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeviceAuth performs OAuth Device Flow authentication
|
// DeviceAuth performs OAuth Device Flow authentication.
|
||||||
|
// It requests a device code, invokes the onCode callback with it, then polls for the token.
|
||||||
|
// The onCode callback receives the DeviceCode which contains the user_code and verification URL.
|
||||||
func (r *Request) DeviceAuth(ctx context.Context, onCode func(*DeviceCode)) (*OAuthToken, error) {
|
func (r *Request) DeviceAuth(ctx context.Context, onCode func(*DeviceCode)) (*OAuthToken, error) {
|
||||||
// Step 1: Request device code
|
// Step 1: Request device code
|
||||||
deviceCode, err := r.requestDeviceCode(ctx)
|
deviceCode, err := r.requestDeviceCode(ctx)
|
||||||
@@ -47,7 +49,7 @@ func (r *Request) DeviceAuth(ctx context.Context, onCode func(*DeviceCode)) (*OA
|
|||||||
return r.pollForToken(ctx, deviceCode)
|
return r.pollForToken(ctx, deviceCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// requestDeviceCode requests a device code from Yandex OAuth
|
// requestDeviceCode requests a device code from the Yandex OAuth device code endpoint.
|
||||||
func (r *Request) requestDeviceCode(ctx context.Context) (*DeviceCode, error) {
|
func (r *Request) requestDeviceCode(ctx context.Context) (*DeviceCode, error) {
|
||||||
// Use Yandex OAuth endpoint for device auth
|
// Use Yandex OAuth endpoint for device auth
|
||||||
data := url.Values{}
|
data := url.Values{}
|
||||||
@@ -85,7 +87,8 @@ func (r *Request) requestDeviceCode(ctx context.Context) (*DeviceCode, error) {
|
|||||||
return &deviceCode, nil
|
return &deviceCode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// pollForToken polls for the OAuth token
|
// pollForToken polls the Yandex OAuth token endpoint until the user authorizes the device code.
|
||||||
|
// It returns the OAuthToken once authorization is complete, or an error if the code expires or is denied.
|
||||||
func (r *Request) pollForToken(ctx context.Context, deviceCode *DeviceCode) (*OAuthToken, error) {
|
func (r *Request) pollForToken(ctx context.Context, deviceCode *DeviceCode) (*OAuthToken, error) {
|
||||||
interval := deviceCode.Interval
|
interval := deviceCode.Interval
|
||||||
if interval == 0 {
|
if interval == 0 {
|
||||||
@@ -155,7 +158,8 @@ func (r *Request) pollForToken(ctx context.Context, deviceCode *DeviceCode) (*OA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RefreshToken refreshes an access token using a refresh token
|
// RefreshToken refreshes an access token using the provided refresh token.
|
||||||
|
// It makes a POST request to the Yandex OAuth token endpoint with grant_type=refresh_token.
|
||||||
func (r *Request) RefreshToken(ctx context.Context, refreshToken string) (*OAuthToken, error) {
|
func (r *Request) RefreshToken(ctx context.Context, refreshToken string) (*OAuthToken, error) {
|
||||||
data := url.Values{}
|
data := url.Values{}
|
||||||
data.Set("grant_type", "refresh_token")
|
data.Set("grant_type", "refresh_token")
|
||||||
|
|||||||
+28
-20
@@ -1,3 +1,4 @@
|
|||||||
|
// Package client provides the core Yandex Music API client and related types.
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -9,7 +10,7 @@ import (
|
|||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/utils"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ClientConfig holds configuration for the Client
|
// ClientConfig holds configuration for the Client.
|
||||||
type ClientConfig struct {
|
type ClientConfig struct {
|
||||||
Token string
|
Token string
|
||||||
BaseURL string
|
BaseURL string
|
||||||
@@ -22,7 +23,9 @@ type ClientConfig struct {
|
|||||||
JSONBackend utils.JSONBackend
|
JSONBackend utils.JSONBackend
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client is the main Yandex Music API client
|
// Client is the main Yandex Music API client.
|
||||||
|
// It provides methods for interacting with the Yandex Music API,
|
||||||
|
// including tracks, albums, artists, playlists, radio, and more.
|
||||||
type Client struct {
|
type Client struct {
|
||||||
config ClientConfig
|
config ClientConfig
|
||||||
request *Request
|
request *Request
|
||||||
@@ -31,7 +34,8 @@ type Client struct {
|
|||||||
accountUID *int64
|
accountUID *int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient creates a new Yandex Music client
|
// NewClient creates a new Yandex Music client with the given configuration.
|
||||||
|
// If BaseURL, Language, or Timeout are not set in the config, sensible defaults are used.
|
||||||
func NewClient(config ClientConfig) *Client {
|
func NewClient(config ClientConfig) *Client {
|
||||||
if config.BaseURL == "" {
|
if config.BaseURL == "" {
|
||||||
config.BaseURL = DefaultBaseURL
|
config.BaseURL = DefaultBaseURL
|
||||||
@@ -66,7 +70,8 @@ func NewClient(config ClientConfig) *Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init initializes the client by fetching account info
|
// Init initializes the client by fetching account info from the /account/status endpoint.
|
||||||
|
// It populates the client's internal account state (GetMe and GetAccountUID).
|
||||||
func (c *Client) Init(ctx context.Context) error {
|
func (c *Client) Init(ctx context.Context) error {
|
||||||
status, err := c.GetAccountStatus(ctx)
|
status, err := c.GetAccountStatus(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -79,76 +84,79 @@ func (c *Client) Init(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRequest returns the underlying request handler
|
// GetRequest returns the underlying request handler used by this client.
|
||||||
|
// The returned RequestInterface can be used to make raw API requests.
|
||||||
func (c *Client) GetRequest() models.RequestInterface {
|
func (c *Client) GetRequest() models.RequestInterface {
|
||||||
return c.request
|
return c.request
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetToken returns the current token
|
// GetToken returns the current OAuth token used for authentication.
|
||||||
func (c *Client) GetToken() string {
|
func (c *Client) GetToken() string {
|
||||||
return c.config.Token
|
return c.config.Token
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetToken updates the token
|
// SetToken updates the OAuth token used for authentication.
|
||||||
|
// It also updates the underlying request handler's authorization header.
|
||||||
func (c *Client) SetToken(token string) {
|
func (c *Client) SetToken(token string) {
|
||||||
c.config.Token = token
|
c.config.Token = token
|
||||||
c.request.SetToken(token)
|
c.request.SetToken(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDevice returns the device string
|
// GetDevice returns the device identifier string used in API requests.
|
||||||
func (c *Client) GetDevice() string {
|
func (c *Client) GetDevice() string {
|
||||||
return c.device
|
return c.device
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMe returns the account status
|
// GetMe returns the account status fetched during Init, or nil if Init has not been called.
|
||||||
func (c *Client) GetMe() *Status {
|
func (c *Client) GetMe() *Status {
|
||||||
return c.me
|
return c.me
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAccountUID returns the account UID
|
// GetAccountUID returns the authenticated user's account UID, or nil if not available.
|
||||||
func (c *Client) GetAccountUID() *int64 {
|
func (c *Client) GetAccountUID() *int64 {
|
||||||
return c.accountUID
|
return c.accountUID
|
||||||
}
|
}
|
||||||
|
|
||||||
// Context returns a context for requests (can be overridden for timeouts)
|
// Context returns a context for requests (can be overridden for timeouts).
|
||||||
|
// By default it returns context.Background().
|
||||||
func (c *Client) Context() context.Context {
|
func (c *Client) Context() context.Context {
|
||||||
return context.Background()
|
return context.Background()
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithContext returns a new client with a custom context
|
// WithContext returns a new client with a custom context.
|
||||||
|
// In Go, context is typically passed to each method rather than stored, so this returns the same client.
|
||||||
func (c *Client) WithContext(ctx context.Context) *Client {
|
func (c *Client) WithContext(ctx context.Context) *Client {
|
||||||
// In Go, we typically pass context to each method rather than storing it
|
// In Go, we typically pass context to each method rather than storing it
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeviceAuth performs OAuth Device Flow authentication
|
// DeviceAuth performs OAuth Device Flow authentication.
|
||||||
|
// The onCode callback is invoked with the device code so the user can authorize on a separate device.
|
||||||
func (c *Client) DeviceAuth(ctx context.Context, onCode func(*DeviceCode)) (*OAuthToken, error) {
|
func (c *Client) DeviceAuth(ctx context.Context, onCode func(*DeviceCode)) (*OAuthToken, error) {
|
||||||
return c.request.DeviceAuth(ctx, onCode)
|
return c.request.DeviceAuth(ctx, onCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RefreshToken refreshes the access token
|
// RefreshToken refreshes the access token using the provided refresh token.
|
||||||
|
// It delegates to the underlying request handler.
|
||||||
func (c *Client) RefreshToken(ctx context.Context, refreshToken string) (*OAuthToken, error) {
|
func (c *Client) RefreshToken(ctx context.Context, refreshToken string) (*OAuthToken, error) {
|
||||||
return c.request.RefreshToken(ctx, refreshToken)
|
return c.request.RefreshToken(ctx, refreshToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status represents account status
|
// Status represents account status returned by the /account/status endpoint.
|
||||||
type Status struct {
|
type Status struct {
|
||||||
Account *Account `json:"account"`
|
Account *Account `json:"account"`
|
||||||
// Other fields...
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Account represents a user account
|
// Account represents a user account.
|
||||||
type Account struct {
|
type Account struct {
|
||||||
UID int64 `json:"uid"`
|
UID int64 `json:"uid"`
|
||||||
Login string `json:"login"`
|
Login string `json:"login"`
|
||||||
DisplayName string `json:"display_name"`
|
DisplayName string `json:"display_name"`
|
||||||
// Other fields...
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track represents a music track (minimal for now)
|
// Track represents a music track (minimal subset of fields).
|
||||||
type Track struct {
|
type Track struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Duration int `json:"duration_ms"`
|
Duration int `json:"duration_ms"`
|
||||||
// Other fields...
|
|
||||||
}
|
}
|
||||||
+17
-10
@@ -1,3 +1,4 @@
|
|||||||
|
// Package client provides methods for interacting with Yandex Music API endpoints.
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -7,7 +8,7 @@ import (
|
|||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetClips gets clips
|
// GetClips gets clips with pagination (GET /clips).
|
||||||
func (c *Client) GetClips(ctx context.Context, page, pageSize int) ([]*models.Clip, error) {
|
func (c *Client) GetClips(ctx context.Context, page, pageSize int) ([]*models.Clip, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"page": "1",
|
"page": "1",
|
||||||
@@ -33,29 +34,35 @@ func (c *Client) GetClips(ctx context.Context, page, pageSize int) ([]*models.Cl
|
|||||||
return clips, nil
|
return clips, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetClipsWillLike gets clips the user might like
|
// GetClipsWillLike gets clips the user might like (GET /clips/will/like).
|
||||||
func (c *Client) GetClipsWillLike(ctx context.Context) (*models.ClipsWillLike, error) {
|
func (c *Client) GetClipsWillLike(ctx context.Context) (*models.ClipsWillLike, error) {
|
||||||
var result models.ClipsWillLike
|
var result models.ClipsWillLike
|
||||||
if err := c.request.Get(ctx, "/clips/will-like", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/clips/will/like", nil, &result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetArtistClips gets clips by an artist
|
// GetArtistClips gets clips by an artist (GET /artists/{artistID}/blocks/artist-clips).
|
||||||
func (c *Client) GetArtistClips(ctx context.Context, artistID string) (*models.ArtistClipData, error) {
|
func (c *Client) GetArtistClips(ctx context.Context, artistID string) (*models.ArtistClipData, error) {
|
||||||
params := map[string]string{
|
|
||||||
"artist_id": artistID,
|
|
||||||
}
|
|
||||||
|
|
||||||
var result models.ArtistClipData
|
var result models.ArtistClipData
|
||||||
if err := c.request.Get(ctx, "/artists/clips", params, &result); err != nil {
|
if err := c.request.Get(ctx, fmt.Sprintf("/artists/%s/blocks/artist-clips", artistID), nil, &result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetShots gets shots
|
// GetClipsDisclaimer gets clips disclaimer (GET /clips/{id}/disclaimer).
|
||||||
|
func (c *Client) GetClipsDisclaimer(ctx context.Context, clipID string) (*models.Disclaimer, error) {
|
||||||
|
var result models.Disclaimer
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/clips/%s/disclaimer", clipID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetShots gets shots with pagination (GET /shots).
|
||||||
func (c *Client) GetShots(ctx context.Context, page, pageSize int) ([]*models.Shot, error) {
|
func (c *Client) GetShots(ctx context.Context, page, pageSize int) ([]*models.Shot, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"page": "1",
|
"page": "1",
|
||||||
|
|||||||
+31
-24
@@ -1,3 +1,4 @@
|
|||||||
|
// Package client provides methods for interacting with Yandex Music API endpoints.
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -7,17 +8,17 @@ import (
|
|||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetConcerts gets concerts
|
// GetConcerts gets concerts with pagination (GET /concerts).
|
||||||
func (c *Client) GetConcerts(ctx context.Context, page, pageSize int) (*models.ConcertFeed, error) {
|
func (c *Client) GetConcerts(ctx context.Context, page, pageSize int) (*models.ConcertFeed, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"page": "1",
|
"page": "1",
|
||||||
"page_size": "20",
|
"page_size": "20",
|
||||||
}
|
}
|
||||||
if page > 0 {
|
if page > 0 {
|
||||||
params["page"] = fmt.Sprintf("%d", page)
|
params["page"] = fmt.Sprint(page)
|
||||||
}
|
}
|
||||||
if pageSize > 0 {
|
if pageSize > 0 {
|
||||||
params["page_size"] = fmt.Sprintf("%d", pageSize)
|
params["page_size"] = fmt.Sprint(pageSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
var result models.ConcertFeed
|
var result models.ConcertFeed
|
||||||
@@ -27,7 +28,7 @@ func (c *Client) GetConcerts(ctx context.Context, page, pageSize int) (*models.C
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetConcertFeed gets concert feed
|
// GetConcertFeed gets the concert feed (GET /concerts/feed).
|
||||||
func (c *Client) GetConcertFeed(ctx context.Context) (*models.ConcertFeed, error) {
|
func (c *Client) GetConcertFeed(ctx context.Context) (*models.ConcertFeed, error) {
|
||||||
var result models.ConcertFeed
|
var result models.ConcertFeed
|
||||||
if err := c.request.Get(ctx, "/concerts/feed", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/concerts/feed", nil, &result); err != nil {
|
||||||
@@ -36,20 +37,16 @@ func (c *Client) GetConcertFeed(ctx context.Context) (*models.ConcertFeed, error
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetConcertInfo gets concert info
|
// GetConcertInfo gets concert info by ID (GET /concerts/{concertID}/info).
|
||||||
func (c *Client) GetConcertInfo(ctx context.Context, concertID string) (*models.ConcertInfo, error) {
|
func (c *Client) GetConcertInfo(ctx context.Context, concertID string) (*models.ConcertInfo, error) {
|
||||||
params := map[string]string{
|
|
||||||
"concert_id": concertID,
|
|
||||||
}
|
|
||||||
|
|
||||||
var result models.ConcertInfo
|
var result models.ConcertInfo
|
||||||
if err := c.request.Get(ctx, "/concerts/info", params, &result); err != nil {
|
if err := c.request.Get(ctx, fmt.Sprintf("/concerts/%s/info", concertID), nil, &result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetConcertLocations gets concert locations
|
// GetConcertLocations gets concert locations (GET /concerts/locations).
|
||||||
func (c *Client) GetConcertLocations(ctx context.Context) (*models.ConcertLocations, error) {
|
func (c *Client) GetConcertLocations(ctx context.Context) (*models.ConcertLocations, error) {
|
||||||
var result models.ConcertLocations
|
var result models.ConcertLocations
|
||||||
if err := c.request.Get(ctx, "/concerts/locations", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/concerts/locations", nil, &result); err != nil {
|
||||||
@@ -58,21 +55,31 @@ func (c *Client) GetConcertLocations(ctx context.Context) (*models.ConcertLocati
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetConcertTabs gets concert tabs
|
// GetConcertTabs gets concert tab configuration (GET /concerts/tab-config).
|
||||||
func (c *Client) GetConcertTabs(ctx context.Context, concertID string) ([]*models.ConcertTabConfig, error) {
|
func (c *Client) GetConcertTabs(ctx context.Context) (*models.ConcertTabConfig, error) {
|
||||||
params := map[string]string{
|
var result models.ConcertTabConfig
|
||||||
"concert_id": concertID,
|
if err := c.request.Get(ctx, "/concerts/tab-config", nil, &result); err != nil {
|
||||||
}
|
|
||||||
|
|
||||||
var result []models.ConcertTabConfig
|
|
||||||
if err := c.request.Get(ctx, "/concerts/tabs", params, &result); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
tabs := make([]*models.ConcertTabConfig, len(result))
|
// GetArtistConcerts gets concerts by artist (GET /artists/{id}/concerts).
|
||||||
for i := range result {
|
func (c *Client) GetArtistConcerts(ctx context.Context, artistID string) (*models.ArtistConcerts, error) {
|
||||||
result[i].SetClient(c)
|
var result models.ArtistConcerts
|
||||||
tabs[i] = &result[i]
|
if err := c.request.Get(ctx, fmt.Sprintf("/artists/%s/concerts", artistID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
return tabs, nil
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConcertSkeleton gets concert skeleton (GET /concerts/{id}/skeletons/{skeleton_id}).
|
||||||
|
func (c *Client) GetConcertSkeleton(ctx context.Context, concertID, skeletonID string) (*models.ConcertSkeleton, error) {
|
||||||
|
var result models.ConcertSkeleton
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/concerts/%s/skeletons/%s", concertID, skeletonID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
}
|
}
|
||||||
+13
-11
@@ -1,12 +1,14 @@
|
|||||||
|
// Package client provides methods for interacting with Yandex Music API endpoints.
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetFeed gets the main feed
|
// GetFeed gets the main feed (GET /feed).
|
||||||
func (c *Client) GetFeed(ctx context.Context) (*models.Feed, error) {
|
func (c *Client) GetFeed(ctx context.Context) (*models.Feed, error) {
|
||||||
var result models.Feed
|
var result models.Feed
|
||||||
if err := c.request.Get(ctx, "/feed", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/feed", nil, &result); err != nil {
|
||||||
@@ -15,7 +17,7 @@ func (c *Client) GetFeed(ctx context.Context) (*models.Feed, error) {
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFeedBlocks gets feed blocks
|
// GetFeedBlocks gets feed blocks (GET /feed/blocks).
|
||||||
func (c *Client) GetFeedBlocks(ctx context.Context) ([]*models.DayBlock, error) {
|
func (c *Client) GetFeedBlocks(ctx context.Context) ([]*models.DayBlock, error) {
|
||||||
var result []models.DayBlock
|
var result []models.DayBlock
|
||||||
if err := c.request.Get(ctx, "/feed/blocks", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/feed/blocks", nil, &result); err != nil {
|
||||||
@@ -30,7 +32,7 @@ func (c *Client) GetFeedBlocks(ctx context.Context) ([]*models.DayBlock, error)
|
|||||||
return blocks, nil
|
return blocks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFeedGeneratedPlaylist gets a generated playlist by ID from feed
|
// GetFeedGeneratedPlaylist gets a generated playlist by ID from the feed (GET /feed/generated-playlist).
|
||||||
func (c *Client) GetFeedGeneratedPlaylist(ctx context.Context, playlistID string) (*models.GeneratedPlaylist, error) {
|
func (c *Client) GetFeedGeneratedPlaylist(ctx context.Context, playlistID string) (*models.GeneratedPlaylist, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"playlist_id": playlistID,
|
"playlist_id": playlistID,
|
||||||
@@ -44,7 +46,7 @@ func (c *Client) GetFeedGeneratedPlaylist(ctx context.Context, playlistID string
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFeedDay gets a specific day from the feed
|
// GetFeedDay gets a specific day from the feed by date (GET /feed/day).
|
||||||
func (c *Client) GetFeedDay(ctx context.Context, date string) (*models.Day, error) {
|
func (c *Client) GetFeedDay(ctx context.Context, date string) (*models.Day, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"date": date,
|
"date": date,
|
||||||
@@ -57,7 +59,7 @@ func (c *Client) GetFeedDay(ctx context.Context, date string) (*models.Day, erro
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGeneratedPlaylists gets generated playlists
|
// GetGeneratedPlaylists gets generated playlists (GET /generated-playlists).
|
||||||
func (c *Client) GetGeneratedPlaylists(ctx context.Context) ([]*models.GeneratedPlaylist, error) {
|
func (c *Client) GetGeneratedPlaylists(ctx context.Context) ([]*models.GeneratedPlaylist, error) {
|
||||||
var result []models.GeneratedPlaylist
|
var result []models.GeneratedPlaylist
|
||||||
if err := c.request.Get(ctx, "/generated-playlists", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/generated-playlists", nil, &result); err != nil {
|
||||||
@@ -72,36 +74,36 @@ func (c *Client) GetGeneratedPlaylists(ctx context.Context) ([]*models.Generated
|
|||||||
return playlists, nil
|
return playlists, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLanding gets a landing page
|
// GetLanding gets a landing page by ID (GET /landing3/{landingID}).
|
||||||
func (c *Client) GetLanding(ctx context.Context, landingID string) (*models.Landing, error) {
|
func (c *Client) GetLanding(ctx context.Context, landingID string) (*models.Landing, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"landing_id": landingID,
|
"landing_id": landingID,
|
||||||
}
|
}
|
||||||
|
|
||||||
var result models.Landing
|
var result models.Landing
|
||||||
if err := c.request.Get(ctx, "/landing", params, &result); err != nil {
|
if err := c.request.Get(ctx, fmt.Sprintf("/landing3/%s", landingID), params, &result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLandingList gets a list of landings
|
// GetLandingList gets a list of landings (GET /landing3/list).
|
||||||
func (c *Client) GetLandingList(ctx context.Context) (*models.LandingList, error) {
|
func (c *Client) GetLandingList(ctx context.Context) (*models.LandingList, error) {
|
||||||
var result models.LandingList
|
var result models.LandingList
|
||||||
if err := c.request.Get(ctx, "/landing/list", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/landing3/list", nil, &result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLandingBlocks gets landing blocks by block IDs
|
// GetLandingBlocks gets landing blocks by block IDs (GET /landing3/blocks).
|
||||||
func (c *Client) GetLandingBlocks(ctx context.Context, blockIDs []string) ([]*models.LandingBlock, error) {
|
func (c *Client) GetLandingBlocks(ctx context.Context, blockIDs []string) ([]*models.LandingBlock, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"blocks": joinStrings(blockIDs, ","),
|
"blocks": joinStrings(blockIDs, ","),
|
||||||
}
|
}
|
||||||
|
|
||||||
var result []models.LandingBlock
|
var result []models.LandingBlock
|
||||||
if err := c.request.Get(ctx, "/landing/blocks", params, &result); err != nil {
|
if err := c.request.Get(ctx, "/landing3/blocks", params, &result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Package client provides methods for interacting with Yandex Music API endpoints.
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -7,7 +8,7 @@ import (
|
|||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetMusicHistory gets music history
|
// GetMusicHistory gets the user's music history (GET /music-history).
|
||||||
func (c *Client) GetMusicHistory(ctx context.Context) (*models.MusicHistory, error) {
|
func (c *Client) GetMusicHistory(ctx context.Context) (*models.MusicHistory, error) {
|
||||||
var result models.MusicHistory
|
var result models.MusicHistory
|
||||||
if err := c.request.Get(ctx, "/music-history", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/music-history", nil, &result); err != nil {
|
||||||
@@ -16,7 +17,7 @@ func (c *Client) GetMusicHistory(ctx context.Context) (*models.MusicHistory, err
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMusicHistoryTabs gets music history tabs
|
// GetMusicHistoryTabs gets music history tabs (GET /music-history/tabs).
|
||||||
func (c *Client) GetMusicHistoryTabs(ctx context.Context) ([]*models.MusicHistoryTab, error) {
|
func (c *Client) GetMusicHistoryTabs(ctx context.Context) ([]*models.MusicHistoryTab, error) {
|
||||||
var result []models.MusicHistoryTab
|
var result []models.MusicHistoryTab
|
||||||
if err := c.request.Get(ctx, "/music-history/tabs", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/music-history/tabs", nil, &result); err != nil {
|
||||||
@@ -31,7 +32,7 @@ func (c *Client) GetMusicHistoryTabs(ctx context.Context) ([]*models.MusicHistor
|
|||||||
return tabs, nil
|
return tabs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMusicHistoryItems gets music history items
|
// GetMusicHistoryItems gets music history items for a tab (GET /music-history/items).
|
||||||
func (c *Client) GetMusicHistoryItems(ctx context.Context, tabID string, page, pageSize int) (*models.MusicHistoryItems, error) {
|
func (c *Client) GetMusicHistoryItems(ctx context.Context, tabID string, page, pageSize int) (*models.MusicHistoryItems, error) {
|
||||||
params := map[string]string{}
|
params := map[string]string{}
|
||||||
if tabID != "" {
|
if tabID != "" {
|
||||||
|
|||||||
+10
-17
@@ -1,3 +1,4 @@
|
|||||||
|
// Package client provides methods for interacting with Yandex Music API endpoints.
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -7,7 +8,7 @@ import (
|
|||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetLabels gets all labels
|
// GetLabels gets all labels (GET /labels).
|
||||||
func (c *Client) GetLabels(ctx context.Context) ([]*models.Label, error) {
|
func (c *Client) GetLabels(ctx context.Context) ([]*models.Label, error) {
|
||||||
var result []models.Label
|
var result []models.Label
|
||||||
if err := c.request.Get(ctx, "/labels", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/labels", nil, &result); err != nil {
|
||||||
@@ -22,25 +23,19 @@ func (c *Client) GetLabels(ctx context.Context) ([]*models.Label, error) {
|
|||||||
return labels, nil
|
return labels, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLabel gets a label by ID
|
// GetLabel gets a label by ID (GET /labels/{labelID}).
|
||||||
func (c *Client) GetLabel(ctx context.Context, labelID string) (*models.Label, error) {
|
func (c *Client) GetLabel(ctx context.Context, labelID string) (*models.Label, error) {
|
||||||
params := map[string]string{
|
|
||||||
"label_id": labelID,
|
|
||||||
}
|
|
||||||
|
|
||||||
var result models.Label
|
var result models.Label
|
||||||
if err := c.request.Get(ctx, "/labels", params, &result); err != nil {
|
if err := c.request.Get(ctx, fmt.Sprintf("/labels/%s", labelID), nil, &result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
result.SetClient(c)
|
result.SetClient(c)
|
||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLabelAlbums gets albums for a label
|
// GetLabelAlbums gets albums for a label (GET /labels/{labelID}/albums).
|
||||||
func (c *Client) GetLabelAlbums(ctx context.Context, labelID string, page, pageSize int) (*models.LabelAlbums, error) {
|
func (c *Client) GetLabelAlbums(ctx context.Context, labelID string, page, pageSize int) (*models.LabelAlbums, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{}
|
||||||
"label_id": labelID,
|
|
||||||
}
|
|
||||||
if page > 0 {
|
if page > 0 {
|
||||||
params["page"] = fmt.Sprintf("%d", page)
|
params["page"] = fmt.Sprintf("%d", page)
|
||||||
}
|
}
|
||||||
@@ -49,17 +44,15 @@ func (c *Client) GetLabelAlbums(ctx context.Context, labelID string, page, pageS
|
|||||||
}
|
}
|
||||||
|
|
||||||
var result models.LabelAlbums
|
var result models.LabelAlbums
|
||||||
if err := c.request.Get(ctx, "/labels/albums", params, &result); err != nil {
|
if err := c.request.Get(ctx, fmt.Sprintf("/labels/%s/albums", labelID), params, &result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLabelArtists gets artists for a label
|
// GetLabelArtists gets artists for a label (GET /labels/{labelID}/artists).
|
||||||
func (c *Client) GetLabelArtists(ctx context.Context, labelID string, page, pageSize int) (*models.LabelArtists, error) {
|
func (c *Client) GetLabelArtists(ctx context.Context, labelID string, page, pageSize int) (*models.LabelArtists, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{}
|
||||||
"label_id": labelID,
|
|
||||||
}
|
|
||||||
if page > 0 {
|
if page > 0 {
|
||||||
params["page"] = fmt.Sprintf("%d", page)
|
params["page"] = fmt.Sprintf("%d", page)
|
||||||
}
|
}
|
||||||
@@ -68,7 +61,7 @@ func (c *Client) GetLabelArtists(ctx context.Context, labelID string, page, page
|
|||||||
}
|
}
|
||||||
|
|
||||||
var result models.LabelArtists
|
var result models.LabelArtists
|
||||||
if err := c.request.Get(ctx, "/labels/artists", params, &result); err != nil {
|
if err := c.request.Get(ctx, fmt.Sprintf("/labels/%s/artists", labelID), params, &result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &result, nil
|
return &result, nil
|
||||||
|
|||||||
+33
-32
@@ -1,3 +1,4 @@
|
|||||||
|
// Package client provides methods for interacting with Yandex Music API endpoints.
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -7,82 +8,82 @@ import (
|
|||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LikeTrack likes a track
|
// LikeTrack likes a track (POST /users/me/likes/tracks/add-multiple).
|
||||||
func (c *Client) LikeTrack(ctx context.Context, trackID string) error {
|
func (c *Client) LikeTrack(ctx context.Context, trackID string) error {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"track_id": trackID,
|
"track-ids": trackID,
|
||||||
}
|
}
|
||||||
var result map[string]any
|
var result map[string]any
|
||||||
return c.request.Post(ctx, "/users/likes/tracks/add", params, &result)
|
return c.request.Post(ctx, "/users/me/likes/tracks/add-multiple", params, &result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnlikeTrack unlikes a track
|
// UnlikeTrack unlikes a track (POST /users/me/likes/tracks/remove).
|
||||||
func (c *Client) UnlikeTrack(ctx context.Context, trackID string) error {
|
func (c *Client) UnlikeTrack(ctx context.Context, trackID string) error {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"track_id": trackID,
|
"track-ids": trackID,
|
||||||
}
|
}
|
||||||
var result map[string]any
|
var result map[string]any
|
||||||
return c.request.Post(ctx, "/users/likes/tracks/remove", params, &result)
|
return c.request.Post(ctx, "/users/me/likes/tracks/remove", params, &result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LikeAlbum likes an album
|
// LikeAlbum likes an album (POST /users/me/likes/albums/add-multiple).
|
||||||
func (c *Client) LikeAlbum(ctx context.Context, albumID string) error {
|
func (c *Client) LikeAlbum(ctx context.Context, albumID string) error {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"album_id": albumID,
|
"album-ids": albumID,
|
||||||
}
|
}
|
||||||
var result map[string]any
|
var result map[string]any
|
||||||
return c.request.Post(ctx, "/users/likes/albums/add", params, &result)
|
return c.request.Post(ctx, "/users/me/likes/albums/add-multiple", params, &result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnlikeAlbum unlikes an album
|
// UnlikeAlbum unlikes an album (POST /users/me/likes/albums/remove).
|
||||||
func (c *Client) UnlikeAlbum(ctx context.Context, albumID string) error {
|
func (c *Client) UnlikeAlbum(ctx context.Context, albumID string) error {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"album_id": albumID,
|
"album-ids": albumID,
|
||||||
}
|
}
|
||||||
var result map[string]any
|
var result map[string]any
|
||||||
return c.request.Post(ctx, "/users/likes/albums/remove", params, &result)
|
return c.request.Post(ctx, "/users/me/likes/albums/remove", params, &result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LikeArtist likes an artist
|
// LikeArtist likes an artist (POST /users/me/likes/artists/add-multiple).
|
||||||
func (c *Client) LikeArtist(ctx context.Context, artistID string) error {
|
func (c *Client) LikeArtist(ctx context.Context, artistID string) error {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"artist_id": artistID,
|
"artist-ids": artistID,
|
||||||
}
|
}
|
||||||
var result map[string]any
|
var result map[string]any
|
||||||
return c.request.Post(ctx, "/users/likes/artists/add", params, &result)
|
return c.request.Post(ctx, "/users/me/likes/artists/add-multiple", params, &result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnlikeArtist unlikes an artist
|
// UnlikeArtist unlikes an artist (POST /users/me/likes/artists/remove).
|
||||||
func (c *Client) UnlikeArtist(ctx context.Context, artistID string) error {
|
func (c *Client) UnlikeArtist(ctx context.Context, artistID string) error {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"artist_id": artistID,
|
"artist-ids": artistID,
|
||||||
}
|
}
|
||||||
var result map[string]any
|
var result map[string]any
|
||||||
return c.request.Post(ctx, "/users/likes/artists/remove", params, &result)
|
return c.request.Post(ctx, "/users/me/likes/artists/remove", params, &result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LikePlaylist likes a playlist
|
// LikePlaylist likes a playlist (POST /users/me/likes/playlists/add-multiple).
|
||||||
func (c *Client) LikePlaylist(ctx context.Context, kind int) error {
|
func (c *Client) LikePlaylist(ctx context.Context, kind int) error {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"kind": fmt.Sprintf("%d", kind),
|
"playlist-ids": fmt.Sprintf("%d", kind),
|
||||||
}
|
}
|
||||||
var result map[string]any
|
var result map[string]any
|
||||||
return c.request.Post(ctx, "/users/likes/playlists/add", params, &result)
|
return c.request.Post(ctx, "/users/me/likes/playlists/add-multiple", params, &result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnlikePlaylist unlikes a playlist
|
// UnlikePlaylist unlikes a playlist (POST /users/me/likes/playlists/remove).
|
||||||
func (c *Client) UnlikePlaylist(ctx context.Context, kind int) error {
|
func (c *Client) UnlikePlaylist(ctx context.Context, kind int) error {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"kind": fmt.Sprintf("%d", kind),
|
"playlist-ids": fmt.Sprintf("%d", kind),
|
||||||
}
|
}
|
||||||
var result map[string]any
|
var result map[string]any
|
||||||
return c.request.Post(ctx, "/users/likes/playlists/remove", params, &result)
|
return c.request.Post(ctx, "/users/me/likes/playlists/remove", params, &result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLikedTracks gets user's liked tracks
|
// GetLikedTracks gets the user's liked tracks (GET /users/me/likes/tracks).
|
||||||
func (c *Client) GetLikedTracks(ctx context.Context) ([]*models.Track, error) {
|
func (c *Client) GetLikedTracks(ctx context.Context) ([]*models.Track, error) {
|
||||||
var result []models.Track
|
var result []models.Track
|
||||||
if err := c.request.Get(ctx, "/users/likes/tracks", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/users/me/likes/tracks", nil, &result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,10 +95,10 @@ func (c *Client) GetLikedTracks(ctx context.Context) ([]*models.Track, error) {
|
|||||||
return tracks, nil
|
return tracks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLikedAlbums gets user's liked albums
|
// GetLikedAlbums gets the user's liked albums (GET /users/me/likes/albums).
|
||||||
func (c *Client) GetLikedAlbums(ctx context.Context) ([]*models.Album, error) {
|
func (c *Client) GetLikedAlbums(ctx context.Context) ([]*models.Album, error) {
|
||||||
var result []models.Album
|
var result []models.Album
|
||||||
if err := c.request.Get(ctx, "/users/likes/albums", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/users/me/likes/albums", nil, &result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,10 +110,10 @@ func (c *Client) GetLikedAlbums(ctx context.Context) ([]*models.Album, error) {
|
|||||||
return albums, nil
|
return albums, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLikedArtists gets user's liked artists
|
// GetLikedArtists gets the user's liked artists (GET /users/me/likes/artists).
|
||||||
func (c *Client) GetLikedArtists(ctx context.Context) ([]*models.Artist, error) {
|
func (c *Client) GetLikedArtists(ctx context.Context) ([]*models.Artist, error) {
|
||||||
var result []models.Artist
|
var result []models.Artist
|
||||||
if err := c.request.Get(ctx, "/users/likes/artists", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/users/me/likes/artists", nil, &result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,10 +125,10 @@ func (c *Client) GetLikedArtists(ctx context.Context) ([]*models.Artist, error)
|
|||||||
return artists, nil
|
return artists, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLikedPlaylists gets user's liked playlists
|
// GetLikedPlaylists gets the user's liked playlists (GET /users/me/likes/playlists).
|
||||||
func (c *Client) GetLikedPlaylists(ctx context.Context) ([]*models.Playlist, error) {
|
func (c *Client) GetLikedPlaylists(ctx context.Context) ([]*models.Playlist, error) {
|
||||||
var result []models.Playlist
|
var result []models.Playlist
|
||||||
if err := c.request.Get(ctx, "/users/likes/playlists", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/users/me/likes/playlists", nil, &result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-10
@@ -1,3 +1,4 @@
|
|||||||
|
// Package client provides methods for interacting with Yandex Music API endpoints.
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -7,7 +8,7 @@ import (
|
|||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetMetatags gets all metatags
|
// GetMetatags gets all metatags (GET /metatags).
|
||||||
func (c *Client) GetMetatags(ctx context.Context) ([]*models.Metatag, error) {
|
func (c *Client) GetMetatags(ctx context.Context) ([]*models.Metatag, error) {
|
||||||
var result []models.Metatag
|
var result []models.Metatag
|
||||||
if err := c.request.Get(ctx, "/metatags", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/metatags", nil, &result); err != nil {
|
||||||
@@ -22,7 +23,7 @@ func (c *Client) GetMetatags(ctx context.Context) ([]*models.Metatag, error) {
|
|||||||
return metatags, nil
|
return metatags, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMetatagTree gets metatag tree
|
// GetMetatagTree gets the metatag tree (GET /metatags/tree).
|
||||||
func (c *Client) GetMetatagTree(ctx context.Context) (*models.MetatagTree, error) {
|
func (c *Client) GetMetatagTree(ctx context.Context) (*models.MetatagTree, error) {
|
||||||
var result models.MetatagTree
|
var result models.MetatagTree
|
||||||
if err := c.request.Get(ctx, "/metatags/tree", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/metatags/tree", nil, &result); err != nil {
|
||||||
@@ -31,7 +32,7 @@ func (c *Client) GetMetatagTree(ctx context.Context) (*models.MetatagTree, error
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMetatagArtists gets artists for a metatag
|
// GetMetatagArtists gets artists for a metatag (GET /metatags/artists).
|
||||||
func (c *Client) GetMetatagArtists(ctx context.Context, metatagID string, page, pageSize int) (*models.MetatagArtists, error) {
|
func (c *Client) GetMetatagArtists(ctx context.Context, metatagID string, page, pageSize int) (*models.MetatagArtists, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"metatag_id": metatagID,
|
"metatag_id": metatagID,
|
||||||
@@ -50,7 +51,7 @@ func (c *Client) GetMetatagArtists(ctx context.Context, metatagID string, page,
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMetatagAlbums gets albums for a metatag
|
// GetMetatagAlbums gets albums for a metatag (GET /metatags/albums).
|
||||||
func (c *Client) GetMetatagAlbums(ctx context.Context, metatagID string, page, pageSize int) (*models.MetatagAlbums, error) {
|
func (c *Client) GetMetatagAlbums(ctx context.Context, metatagID string, page, pageSize int) (*models.MetatagAlbums, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"metatag_id": metatagID,
|
"metatag_id": metatagID,
|
||||||
@@ -69,7 +70,7 @@ func (c *Client) GetMetatagAlbums(ctx context.Context, metatagID string, page, p
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMetatagPlaylists gets playlists for a metatag
|
// GetMetatagPlaylists gets playlists for a metatag (GET /metatags/playlists).
|
||||||
func (c *Client) GetMetatagPlaylists(ctx context.Context, metatagID string, page, pageSize int) (*models.MetatagPlaylists, error) {
|
func (c *Client) GetMetatagPlaylists(ctx context.Context, metatagID string, page, pageSize int) (*models.MetatagPlaylists, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"metatag_id": metatagID,
|
"metatag_id": metatagID,
|
||||||
@@ -88,7 +89,7 @@ func (c *Client) GetMetatagPlaylists(ctx context.Context, metatagID string, page
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGenres gets all genres
|
// GetGenres gets all genres (GET /genres).
|
||||||
func (c *Client) GetGenres(ctx context.Context) ([]*models.Genre, error) {
|
func (c *Client) GetGenres(ctx context.Context) ([]*models.Genre, error) {
|
||||||
var result []models.Genre
|
var result []models.Genre
|
||||||
if err := c.request.Get(ctx, "/genres", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/genres", nil, &result); err != nil {
|
||||||
@@ -103,7 +104,7 @@ func (c *Client) GetGenres(ctx context.Context) ([]*models.Genre, error) {
|
|||||||
return genres, nil
|
return genres, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCharts gets charts
|
// GetCharts gets all charts (GET /charts).
|
||||||
func (c *Client) GetCharts(ctx context.Context) ([]*models.Chart, error) {
|
func (c *Client) GetCharts(ctx context.Context) ([]*models.Chart, error) {
|
||||||
var result []models.Chart
|
var result []models.Chart
|
||||||
if err := c.request.Get(ctx, "/charts", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/charts", nil, &result); err != nil {
|
||||||
@@ -118,7 +119,7 @@ func (c *Client) GetCharts(ctx context.Context) ([]*models.Chart, error) {
|
|||||||
return charts, nil
|
return charts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetChartInfo gets chart info
|
// GetChartInfo gets chart info for a chart ID (GET /charts/info).
|
||||||
func (c *Client) GetChartInfo(ctx context.Context, chartID string) (*models.ChartInfo, error) {
|
func (c *Client) GetChartInfo(ctx context.Context, chartID string) (*models.ChartInfo, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"chart_id": chartID,
|
"chart_id": chartID,
|
||||||
@@ -131,7 +132,7 @@ func (c *Client) GetChartInfo(ctx context.Context, chartID string) (*models.Char
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetChartItems gets chart items
|
// GetChartItems gets chart items for a chart ID (GET /charts/items).
|
||||||
func (c *Client) GetChartItems(ctx context.Context, chartID string, page, pageSize int) (*models.ChartItems, error) {
|
func (c *Client) GetChartItems(ctx context.Context, chartID string, page, pageSize int) (*models.ChartItems, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"chart_id": chartID,
|
"chart_id": chartID,
|
||||||
@@ -150,7 +151,7 @@ func (c *Client) GetChartItems(ctx context.Context, chartID string, page, pageSi
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetChartMenu gets chart menu
|
// GetChartMenu gets chart menu for a chart ID (GET /charts/menu).
|
||||||
func (c *Client) GetChartMenu(ctx context.Context, chartID string) (*models.ChartInfoMenu, error) {
|
func (c *Client) GetChartMenu(ctx context.Context, chartID string) (*models.ChartInfoMenu, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"chart_id": chartID,
|
"chart_id": chartID,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Package client provides methods for interacting with Yandex Music API endpoints.
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -6,7 +7,7 @@ import (
|
|||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetPins gets user's pins
|
// GetPins gets user's pins (GET /pins).
|
||||||
func (c *Client) GetPins(ctx context.Context) (*models.PinsList, error) {
|
func (c *Client) GetPins(ctx context.Context) (*models.PinsList, error) {
|
||||||
var result models.PinsList
|
var result models.PinsList
|
||||||
if err := c.request.Get(ctx, "/pins", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/pins", nil, &result); err != nil {
|
||||||
@@ -15,7 +16,7 @@ func (c *Client) GetPins(ctx context.Context) (*models.PinsList, error) {
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddPin adds a pin
|
// AddPin adds a pin (POST /pins).
|
||||||
func (c *Client) AddPin(ctx context.Context, pinType, entityID string) (*models.Pin, error) {
|
func (c *Client) AddPin(ctx context.Context, pinType, entityID string) (*models.Pin, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"type": pinType,
|
"type": pinType,
|
||||||
@@ -29,7 +30,7 @@ func (c *Client) AddPin(ctx context.Context, pinType, entityID string) (*models.
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemovePin removes a pin
|
// RemovePin removes a pin by ID (DELETE /pins).
|
||||||
func (c *Client) RemovePin(ctx context.Context, pinID string) error {
|
func (c *Client) RemovePin(ctx context.Context, pinID string) error {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"pin_id": pinID,
|
"pin_id": pinID,
|
||||||
@@ -38,7 +39,7 @@ func (c *Client) RemovePin(ctx context.Context, pinID string) error {
|
|||||||
return c.request.Delete(ctx, "/pins", params, &result)
|
return c.request.Delete(ctx, "/pins", params, &result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPresaves gets user's presaves
|
// GetPresaves gets user's presaves (GET /presaves).
|
||||||
func (c *Client) GetPresaves(ctx context.Context) (*models.Presaves, error) {
|
func (c *Client) GetPresaves(ctx context.Context) (*models.Presaves, error) {
|
||||||
var result models.Presaves
|
var result models.Presaves
|
||||||
if err := c.request.Get(ctx, "/presaves", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/presaves", nil, &result); err != nil {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Package client provides methods for interacting with Yandex Music API endpoints.
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -8,7 +9,8 @@ import (
|
|||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/utils"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetPlaylists gets playlists by IDs (kinds)
|
// GetPlaylists gets playlists by their kind IDs (GET /playlists).
|
||||||
|
// Returns a slice of Playlist pointers, or nil if no kinds are provided.
|
||||||
func (c *Client) GetPlaylists(ctx context.Context, kinds []int) ([]*models.Playlist, error) {
|
func (c *Client) GetPlaylists(ctx context.Context, kinds []int) ([]*models.Playlist, error) {
|
||||||
if len(kinds) == 0 {
|
if len(kinds) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -40,7 +42,8 @@ func (c *Client) GetPlaylists(ctx context.Context, kinds []int) ([]*models.Playl
|
|||||||
return playlists, nil
|
return playlists, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPlaylist gets a single playlist by kind
|
// GetPlaylist gets a single playlist by kind using GetPlaylists.
|
||||||
|
// Returns an error if no playlist is found with the given kind.
|
||||||
func (c *Client) GetPlaylist(ctx context.Context, kind int) (*models.Playlist, error) {
|
func (c *Client) GetPlaylist(ctx context.Context, kind int) (*models.Playlist, error) {
|
||||||
playlists, err := c.GetPlaylists(ctx, []int{kind})
|
playlists, err := c.GetPlaylists(ctx, []int{kind})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -52,14 +55,10 @@ func (c *Client) GetPlaylist(ctx context.Context, kind int) (*models.Playlist, e
|
|||||||
return playlists[0], nil
|
return playlists[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserPlaylists gets playlists for a user
|
// GetUserPlaylists gets playlists for a user (GET /users/{userID}/playlists).
|
||||||
func (c *Client) GetUserPlaylists(ctx context.Context, userID string) ([]*models.Playlist, error) {
|
func (c *Client) GetUserPlaylists(ctx context.Context, userID string) ([]*models.Playlist, error) {
|
||||||
params := map[string]string{
|
|
||||||
"user-id": userID,
|
|
||||||
}
|
|
||||||
|
|
||||||
var result []models.Playlist
|
var result []models.Playlist
|
||||||
if err := c.request.Get(ctx, "/users/playlists", params, &result); err != nil {
|
if err := c.request.Get(ctx, fmt.Sprintf("/users/%s/playlists", userID), nil, &result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +70,8 @@ func (c *Client) GetUserPlaylists(ctx context.Context, userID string) ([]*models
|
|||||||
return playlists, nil
|
return playlists, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatePlaylist creates a new playlist
|
// CreatePlaylist creates a new playlist (POST /users/me/playlists).
|
||||||
|
// The visibility parameter should be "public" or "private".
|
||||||
func (c *Client) CreatePlaylist(ctx context.Context, title string, visibility string) (*models.Playlist, error) {
|
func (c *Client) CreatePlaylist(ctx context.Context, title string, visibility string) (*models.Playlist, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"title": title,
|
"title": title,
|
||||||
@@ -86,7 +86,8 @@ func (c *Client) CreatePlaylist(ctx context.Context, title string, visibility st
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EditPlaylist edits an existing playlist
|
// EditPlaylist edits an existing playlist (PUT /users/me/playlists).
|
||||||
|
// Only non-empty parameters are updated.
|
||||||
func (c *Client) EditPlaylist(ctx context.Context, kind int, title, description, visibility string) (*models.Playlist, error) {
|
func (c *Client) EditPlaylist(ctx context.Context, kind int, title, description, visibility string) (*models.Playlist, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"kind": fmt.Sprintf("%d", kind),
|
"kind": fmt.Sprintf("%d", kind),
|
||||||
@@ -109,7 +110,7 @@ func (c *Client) EditPlaylist(ctx context.Context, kind int, title, description,
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeletePlaylist deletes a playlist
|
// DeletePlaylist deletes a playlist (DELETE /users/me/playlists).
|
||||||
func (c *Client) DeletePlaylist(ctx context.Context, kind int) error {
|
func (c *Client) DeletePlaylist(ctx context.Context, kind int) error {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"kind": fmt.Sprintf("%d", kind),
|
"kind": fmt.Sprintf("%d", kind),
|
||||||
@@ -118,7 +119,8 @@ func (c *Client) DeletePlaylist(ctx context.Context, kind int) error {
|
|||||||
return c.request.Delete(ctx, "/users/me/playlists", params, &result)
|
return c.request.Delete(ctx, "/users/me/playlists", params, &result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddTracksToPlaylist adds tracks to a playlist
|
// AddTracksToPlaylist adds tracks to a playlist (POST /users/me/playlists/tracks).
|
||||||
|
// The revision parameter is the current playlist revision for optimistic concurrency.
|
||||||
func (c *Client) AddTracksToPlaylist(ctx context.Context, kind int, trackIDs []string, revision int) (*models.Playlist, error) {
|
func (c *Client) AddTracksToPlaylist(ctx context.Context, kind int, trackIDs []string, revision int) (*models.Playlist, error) {
|
||||||
if len(trackIDs) == 0 {
|
if len(trackIDs) == 0 {
|
||||||
return nil, utils.NewYandexMusicError("no tracks provided", utils.ErrBadRequest)
|
return nil, utils.NewYandexMusicError("no tracks provided", utils.ErrBadRequest)
|
||||||
@@ -146,7 +148,8 @@ func (c *Client) AddTracksToPlaylist(ctx context.Context, kind int, trackIDs []s
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveTracksFromPlaylist removes tracks from a playlist
|
// RemoveTracksFromPlaylist removes tracks from a playlist (DELETE /users/me/playlists/tracks).
|
||||||
|
// The revision parameter is the current playlist revision for optimistic concurrency.
|
||||||
func (c *Client) RemoveTracksFromPlaylist(ctx context.Context, kind int, trackIDs []string, revision int) (*models.Playlist, error) {
|
func (c *Client) RemoveTracksFromPlaylist(ctx context.Context, kind int, trackIDs []string, revision int) (*models.Playlist, error) {
|
||||||
if len(trackIDs) == 0 {
|
if len(trackIDs) == 0 {
|
||||||
return nil, utils.NewYandexMusicError("no tracks provided", utils.ErrBadRequest)
|
return nil, utils.NewYandexMusicError("no tracks provided", utils.ErrBadRequest)
|
||||||
@@ -174,7 +177,8 @@ func (c *Client) RemoveTracksFromPlaylist(ctx context.Context, kind int, trackID
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReorderPlaylistTracks reorders tracks in a playlist
|
// ReorderPlaylistTracks reorders tracks in a playlist (PUT /users/me/playlists/tracks/reorder).
|
||||||
|
// The from and to parameters specify the position range to move.
|
||||||
func (c *Client) ReorderPlaylistTracks(ctx context.Context, kind int, from, to, revision int) (*models.Playlist, error) {
|
func (c *Client) ReorderPlaylistTracks(ctx context.Context, kind int, from, to, revision int) (*models.Playlist, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"kind": fmt.Sprintf("%d", kind),
|
"kind": fmt.Sprintf("%d", kind),
|
||||||
@@ -191,7 +195,7 @@ func (c *Client) ReorderPlaylistTracks(ctx context.Context, kind int, from, to,
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPlaylistRecommendations gets playlist recommendations
|
// GetPlaylistRecommendations gets playlist recommendations based on a playlist kind (GET /playlists/recommendations).
|
||||||
func (c *Client) GetPlaylistRecommendations(ctx context.Context, kind int) ([]*models.Playlist, error) {
|
func (c *Client) GetPlaylistRecommendations(ctx context.Context, kind int) ([]*models.Playlist, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"kind": fmt.Sprintf("%d", kind),
|
"kind": fmt.Sprintf("%d", kind),
|
||||||
|
|||||||
+199
-208
@@ -7,213 +7,10 @@ import (
|
|||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetQueue gets the current queue
|
// GetQueuesList gets the queues list (GET /queues).
|
||||||
func (c *Client) GetQueue(ctx context.Context) (*models.Queue, error) {
|
func (c *Client) GetQueuesList(ctx context.Context) ([]*models.QueueItem, error) {
|
||||||
var result models.Queue
|
|
||||||
if err := c.request.Get(ctx, "/queue", nil, &result); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result.SetClient(c)
|
|
||||||
return &result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateQueue creates a new queue
|
|
||||||
func (c *Client) CreateQueue(ctx context.Context, trackID string, queueType string) (*models.Queue, error) {
|
|
||||||
params := map[string]string{
|
|
||||||
"track_id": trackID,
|
|
||||||
"queue_type": queueType, // "radio", "album", "playlist", etc.
|
|
||||||
}
|
|
||||||
|
|
||||||
var result models.Queue
|
|
||||||
if err := c.request.Post(ctx, "/queue", params, &result); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result.SetClient(c)
|
|
||||||
return &result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetQueueItem gets a queue item
|
|
||||||
func (c *Client) GetQueueItem(ctx context.Context, queueID string) (*models.QueueItem, error) {
|
|
||||||
params := map[string]string{
|
|
||||||
"queue_id": queueID,
|
|
||||||
}
|
|
||||||
|
|
||||||
var result models.QueueItem
|
|
||||||
if err := c.request.Get(ctx, "/queue/item", params, &result); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result.SetClient(c)
|
|
||||||
return &result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddToQueue adds a track to the queue
|
|
||||||
func (c *Client) AddToQueue(ctx context.Context, queueID, trackID string, position int) (*models.Queue, error) {
|
|
||||||
params := map[string]string{
|
|
||||||
"queue_id": queueID,
|
|
||||||
"track_id": trackID,
|
|
||||||
"position": fmt.Sprintf("%d", position),
|
|
||||||
}
|
|
||||||
|
|
||||||
var result models.Queue
|
|
||||||
if err := c.request.Post(ctx, "/queue/add", params, &result); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result.SetClient(c)
|
|
||||||
return &result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveFromQueue removes a track from the queue
|
|
||||||
func (c *Client) RemoveFromQueue(ctx context.Context, queueID, trackID string) (*models.Queue, error) {
|
|
||||||
params := map[string]string{
|
|
||||||
"queue_id": queueID,
|
|
||||||
"track_id": trackID,
|
|
||||||
}
|
|
||||||
|
|
||||||
var result models.Queue
|
|
||||||
if err := c.request.Delete(ctx, "/queue/remove", params, &result); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result.SetClient(c)
|
|
||||||
return &result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReorderQueue reorders the queue
|
|
||||||
func (c *Client) ReorderQueue(ctx context.Context, queueID string, from, to int) (*models.Queue, error) {
|
|
||||||
params := map[string]string{
|
|
||||||
"queue_id": queueID,
|
|
||||||
"from": fmt.Sprintf("%d", from),
|
|
||||||
"to": fmt.Sprintf("%d", to),
|
|
||||||
}
|
|
||||||
|
|
||||||
var result models.Queue
|
|
||||||
if err := c.request.Put(ctx, "/queue/reorder", params, &result); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result.SetClient(c)
|
|
||||||
return &result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClearQueue clears the queue
|
|
||||||
func (c *Client) ClearQueue(ctx context.Context, queueID string) error {
|
|
||||||
params := map[string]string{
|
|
||||||
"queue_id": queueID,
|
|
||||||
}
|
|
||||||
var result map[string]any
|
|
||||||
return c.request.Delete(ctx, "/queue/clear", params, &result)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NextTrack moves to the next track in the queue
|
|
||||||
func (c *Client) NextTrack(ctx context.Context, queueID string) (*models.Queue, error) {
|
|
||||||
params := map[string]string{
|
|
||||||
"queue_id": queueID,
|
|
||||||
}
|
|
||||||
|
|
||||||
var result models.Queue
|
|
||||||
if err := c.request.Post(ctx, "/queue/next", params, &result); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result.SetClient(c)
|
|
||||||
return &result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PreviousTrack moves to the previous track in the queue
|
|
||||||
func (c *Client) PreviousTrack(ctx context.Context, queueID string) (*models.Queue, error) {
|
|
||||||
params := map[string]string{
|
|
||||||
"queue_id": queueID,
|
|
||||||
}
|
|
||||||
|
|
||||||
var result models.Queue
|
|
||||||
if err := c.request.Post(ctx, "/queue/prev", params, &result); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result.SetClient(c)
|
|
||||||
return &result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Seek seeks to a specific position in the current track (in milliseconds)
|
|
||||||
func (c *Client) Seek(ctx context.Context, queueID string, positionMs int) (*models.Queue, error) {
|
|
||||||
params := map[string]string{
|
|
||||||
"queue_id": queueID,
|
|
||||||
"position": fmt.Sprintf("%d", positionMs),
|
|
||||||
}
|
|
||||||
|
|
||||||
var result models.Queue
|
|
||||||
if err := c.request.Post(ctx, "/queue/seek", params, &result); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result.SetClient(c)
|
|
||||||
return &result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetRepeatMode sets the repeat mode for the queue
|
|
||||||
// mode can be "off", "one", or "all"
|
|
||||||
func (c *Client) SetRepeatMode(ctx context.Context, queueID, mode string) (*models.Queue, error) {
|
|
||||||
params := map[string]string{
|
|
||||||
"queue_id": queueID,
|
|
||||||
"mode": mode,
|
|
||||||
}
|
|
||||||
|
|
||||||
var result models.Queue
|
|
||||||
if err := c.request.Post(ctx, "/queue/repeat", params, &result); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result.SetClient(c)
|
|
||||||
return &result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetShuffle enables or disables shuffle for the queue
|
|
||||||
func (c *Client) SetShuffle(ctx context.Context, queueID string, enabled bool) (*models.Queue, error) {
|
|
||||||
params := map[string]string{
|
|
||||||
"queue_id": queueID,
|
|
||||||
"enabled": fmt.Sprintf("%t", enabled),
|
|
||||||
}
|
|
||||||
|
|
||||||
var result models.Queue
|
|
||||||
if err := c.request.Post(ctx, "/queue/shuffle", params, &result); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result.SetClient(c)
|
|
||||||
return &result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetVolume sets the volume for the queue (0-100)
|
|
||||||
func (c *Client) SetVolume(ctx context.Context, queueID string, volume int) (*models.Queue, error) {
|
|
||||||
params := map[string]string{
|
|
||||||
"queue_id": queueID,
|
|
||||||
"volume": fmt.Sprintf("%d", volume),
|
|
||||||
}
|
|
||||||
|
|
||||||
var result models.Queue
|
|
||||||
if err := c.request.Post(ctx, "/queue/volume", params, &result); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result.SetClient(c)
|
|
||||||
return &result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCurrentTrack gets the currently playing track from the queue
|
|
||||||
func (c *Client) GetCurrentTrack(ctx context.Context, queueID string) (*models.QueueItem, error) {
|
|
||||||
params := map[string]string{
|
|
||||||
"queue_id": queueID,
|
|
||||||
}
|
|
||||||
|
|
||||||
var result models.QueueItem
|
|
||||||
if err := c.request.Get(ctx, "/queue/current", params, &result); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result.SetClient(c)
|
|
||||||
return &result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetQueueHistory gets the queue history (recently played tracks)
|
|
||||||
func (c *Client) GetQueueHistory(ctx context.Context, queueID string, limit int) ([]*models.QueueItem, error) {
|
|
||||||
params := map[string]string{
|
|
||||||
"queue_id": queueID,
|
|
||||||
"limit": fmt.Sprintf("%d", limit),
|
|
||||||
}
|
|
||||||
|
|
||||||
var result []models.QueueItem
|
var result []models.QueueItem
|
||||||
if err := c.request.Get(ctx, "/queue/history", params, &result); err != nil {
|
if err := c.request.Get(ctx, "/queues", nil, &result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +22,201 @@ func (c *Client) GetQueueHistory(ctx context.Context, queueID string, limit int)
|
|||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPlayContexts gets play contexts
|
// GetQueue gets the current queue
|
||||||
|
func (c *Client) GetQueue(ctx context.Context) (*models.Queue, error) {
|
||||||
|
var result models.Queue
|
||||||
|
if err := c.request.Get(ctx, "/queues", nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateQueue creates a new playback queue (POST /queues).
|
||||||
|
// The queueType parameter specifies the type of queue (e.g., "radio", "album", "playlist").
|
||||||
|
func (c *Client) CreateQueue(ctx context.Context, trackID string, queueType string) (*models.Queue, error) {
|
||||||
|
params := map[string]string{
|
||||||
|
"track_id": trackID,
|
||||||
|
"queue_type": queueType, // "radio", "album", "playlist", etc.
|
||||||
|
}
|
||||||
|
|
||||||
|
var result models.Queue
|
||||||
|
if err := c.request.Post(ctx, "/queues", params, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetQueueItem gets a queue item by queue ID (GET /queues/{queue_id}).
|
||||||
|
func (c *Client) GetQueueItem(ctx context.Context, queueID string) (*models.QueueItem, error) {
|
||||||
|
var result models.QueueItem
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/queues/%s", queueID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddToQueue adds a track to the queue at the given position (POST /queues/{queue_id}/add).
|
||||||
|
func (c *Client) AddToQueue(ctx context.Context, queueID, trackID string, position int) (*models.Queue, error) {
|
||||||
|
params := map[string]string{
|
||||||
|
"track_id": trackID,
|
||||||
|
"position": fmt.Sprintf("%d", position),
|
||||||
|
}
|
||||||
|
|
||||||
|
var result models.Queue
|
||||||
|
if err := c.request.Post(ctx, fmt.Sprintf("/queues/%s/add", queueID), params, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveFromQueue removes a track from the queue (DELETE /queues/{queue_id}/remove).
|
||||||
|
func (c *Client) RemoveFromQueue(ctx context.Context, queueID, trackID string) (*models.Queue, error) {
|
||||||
|
params := map[string]string{
|
||||||
|
"track_id": trackID,
|
||||||
|
}
|
||||||
|
|
||||||
|
var result models.Queue
|
||||||
|
if err := c.request.Delete(ctx, fmt.Sprintf("/queues/%s/remove", queueID), params, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReorderQueue reorders items in the queue from one position to another (PUT /queues/{queue_id}/reorder).
|
||||||
|
func (c *Client) ReorderQueue(ctx context.Context, queueID string, from, to int) (*models.Queue, error) {
|
||||||
|
params := map[string]string{
|
||||||
|
"from": fmt.Sprintf("%d", from),
|
||||||
|
"to": fmt.Sprintf("%d", to),
|
||||||
|
}
|
||||||
|
|
||||||
|
var result models.Queue
|
||||||
|
if err := c.request.Put(ctx, fmt.Sprintf("/queues/%s/reorder", queueID), params, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearQueue clears the queue (DELETE /queues/{queue_id}/clear).
|
||||||
|
func (c *Client) ClearQueue(ctx context.Context, queueID string) error {
|
||||||
|
var result map[string]any
|
||||||
|
return c.request.Delete(ctx, fmt.Sprintf("/queues/%s/clear", queueID), nil, &result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextTrack moves to the next track in the queue (POST /queues/{queue_id}/next).
|
||||||
|
func (c *Client) NextTrack(ctx context.Context, queueID string) (*models.Queue, error) {
|
||||||
|
var result models.Queue
|
||||||
|
if err := c.request.Post(ctx, fmt.Sprintf("/queues/%s/next", queueID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PreviousTrack moves to the previous track in the queue (POST /queues/{queue_id}/prev).
|
||||||
|
func (c *Client) PreviousTrack(ctx context.Context, queueID string) (*models.Queue, error) {
|
||||||
|
var result models.Queue
|
||||||
|
if err := c.request.Post(ctx, fmt.Sprintf("/queues/%s/prev", queueID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seek seeks to a specific position in the current track (POST /queues/{queue_id}/seek).
|
||||||
|
// The positionMs parameter is the position in milliseconds.
|
||||||
|
func (c *Client) Seek(ctx context.Context, queueID string, positionMs int) (*models.Queue, error) {
|
||||||
|
params := map[string]string{
|
||||||
|
"position": fmt.Sprintf("%d", positionMs),
|
||||||
|
}
|
||||||
|
|
||||||
|
var result models.Queue
|
||||||
|
if err := c.request.Post(ctx, fmt.Sprintf("/queues/%s/seek", queueID), params, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRepeatMode sets the repeat mode for the queue (POST /queues/{queue_id}/repeat).
|
||||||
|
// The mode parameter can be "off", "one", or "all".
|
||||||
|
func (c *Client) SetRepeatMode(ctx context.Context, queueID, mode string) (*models.Queue, error) {
|
||||||
|
params := map[string]string{
|
||||||
|
"mode": mode,
|
||||||
|
}
|
||||||
|
|
||||||
|
var result models.Queue
|
||||||
|
if err := c.request.Post(ctx, fmt.Sprintf("/queues/%s/repeat", queueID), params, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetShuffle enables or disables shuffle for the queue (POST /queues/{queue_id}/shuffle).
|
||||||
|
func (c *Client) SetShuffle(ctx context.Context, queueID string, enabled bool) (*models.Queue, error) {
|
||||||
|
params := map[string]string{
|
||||||
|
"enabled": fmt.Sprintf("%t", enabled),
|
||||||
|
}
|
||||||
|
|
||||||
|
var result models.Queue
|
||||||
|
if err := c.request.Post(ctx, fmt.Sprintf("/queues/%s/shuffle", queueID), params, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetVolume sets the volume for the queue (POST /queues/{queue_id}/volume).
|
||||||
|
// The volume parameter should be between 0 and 100.
|
||||||
|
func (c *Client) SetVolume(ctx context.Context, queueID string, volume int) (*models.Queue, error) {
|
||||||
|
params := map[string]string{
|
||||||
|
"volume": fmt.Sprintf("%d", volume),
|
||||||
|
}
|
||||||
|
|
||||||
|
var result models.Queue
|
||||||
|
if err := c.request.Post(ctx, fmt.Sprintf("/queues/%s/volume", queueID), params, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCurrentTrack gets the currently playing track from the queue (GET /queues/{queue_id}/current).
|
||||||
|
func (c *Client) GetCurrentTrack(ctx context.Context, queueID string) (*models.QueueItem, error) {
|
||||||
|
var result models.QueueItem
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/queues/%s/current", queueID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetQueueHistory gets the queue history (recently played tracks) (GET /queues/{queue_id}/history).
|
||||||
|
func (c *Client) GetQueueHistory(ctx context.Context, queueID string, limit int) ([]*models.QueueItem, error) {
|
||||||
|
params := map[string]string{
|
||||||
|
"limit": fmt.Sprintf("%d", limit),
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []models.QueueItem
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/queues/%s/history", queueID), params, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
items := make([]*models.QueueItem, len(result))
|
||||||
|
for i := range result {
|
||||||
|
result[i].SetClient(c)
|
||||||
|
items[i] = &result[i]
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPlayContexts gets play contexts (GET /play-contexts).
|
||||||
func (c *Client) GetPlayContexts(ctx context.Context) ([]*models.PlayContext, error) {
|
func (c *Client) GetPlayContexts(ctx context.Context) ([]*models.PlayContext, error) {
|
||||||
var result []models.PlayContext
|
var result []models.PlayContext
|
||||||
if err := c.request.Get(ctx, "/play-contexts", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/play-contexts", nil, &result); err != nil {
|
||||||
@@ -240,7 +231,7 @@ func (c *Client) GetPlayContexts(ctx context.Context) ([]*models.PlayContext, er
|
|||||||
return contexts, nil
|
return contexts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPlayContextsData gets play contexts data
|
// GetPlayContextsData gets play contexts data (GET /play-contexts/data).
|
||||||
func (c *Client) GetPlayContextsData(ctx context.Context) (*models.PlayContextsData, error) {
|
func (c *Client) GetPlayContextsData(ctx context.Context) (*models.PlayContextsData, error) {
|
||||||
var result models.PlayContextsData
|
var result models.PlayContextsData
|
||||||
if err := c.request.Get(ctx, "/play-contexts/data", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/play-contexts/data", nil, &result); err != nil {
|
||||||
|
|||||||
+77
-34
@@ -1,3 +1,4 @@
|
|||||||
|
// Package client provides methods for interacting with Yandex Music API endpoints.
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -7,7 +8,7 @@ import (
|
|||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetRadioStations gets radio stations
|
// GetRadioStations gets radio stations (GET /radio/stations).
|
||||||
func (c *Client) GetRadioStations(ctx context.Context) ([]*models.RadioStation, error) {
|
func (c *Client) GetRadioStations(ctx context.Context) ([]*models.RadioStation, error) {
|
||||||
var result []models.RadioStation
|
var result []models.RadioStation
|
||||||
if err := c.request.Get(ctx, "/radio/stations", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/radio/stations", nil, &result); err != nil {
|
||||||
@@ -22,37 +23,31 @@ func (c *Client) GetRadioStations(ctx context.Context) ([]*models.RadioStation,
|
|||||||
return stations, nil
|
return stations, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRadioStation gets a radio station by ID
|
// GetRadioStation gets a radio station by ID (GET /rotor/station/{stationID}/info).
|
||||||
func (c *Client) GetRadioStation(ctx context.Context, stationID string) (*models.RadioStation, error) {
|
func (c *Client) GetRadioStation(ctx context.Context, stationID string) (*models.RadioStation, error) {
|
||||||
params := map[string]string{
|
|
||||||
"station_id": stationID,
|
|
||||||
}
|
|
||||||
|
|
||||||
var result models.RadioStation
|
var result models.RadioStation
|
||||||
if err := c.request.Get(ctx, "/radio/station", params, &result); err != nil {
|
if err := c.request.Get(ctx, fmt.Sprintf("/rotor/station/%s/info", stationID), nil, &result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
result.SetClient(c)
|
result.SetClient(c)
|
||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetStationTracks gets tracks for a radio station
|
// GetStationTracks gets tracks for a radio station (GET /rotor/station/{stationID}/tracks).
|
||||||
func (c *Client) GetStationTracks(ctx context.Context, stationID string, limit int) (*models.StationTracksResult, error) {
|
func (c *Client) GetStationTracks(ctx context.Context, stationID string, limit int) (*models.StationTracksResult, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{}
|
||||||
"station_id": stationID,
|
|
||||||
}
|
|
||||||
if limit > 0 {
|
if limit > 0 {
|
||||||
params["limit"] = fmt.Sprintf("%d", limit)
|
params["limit"] = fmt.Sprintf("%d", limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
var result models.StationTracksResult
|
var result models.StationTracksResult
|
||||||
if err := c.request.Get(ctx, "/radio/station/tracks", params, &result); err != nil {
|
if err := c.request.Get(ctx, fmt.Sprintf("/rotor/station/%s/tracks", stationID), params, &result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRotorStations gets rotor stations (generative)
|
// GetRotorStations gets rotor stations (generative stations) (GET /rotor/stations).
|
||||||
func (c *Client) GetRotorStations(ctx context.Context) ([]*models.RotorStation, error) {
|
func (c *Client) GetRotorStations(ctx context.Context) ([]*models.RotorStation, error) {
|
||||||
var result []models.RotorStation
|
var result []models.RotorStation
|
||||||
if err := c.request.Get(ctx, "/rotor/stations", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/rotor/stations", nil, &result); err != nil {
|
||||||
@@ -67,51 +62,41 @@ func (c *Client) GetRotorStations(ctx context.Context) ([]*models.RotorStation,
|
|||||||
return stations, nil
|
return stations, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRotorStation gets a rotor station by ID
|
// GetRotorStation gets a rotor station by ID (GET /rotor/station/{stationID}/info).
|
||||||
func (c *Client) GetRotorStation(ctx context.Context, stationID string) (*models.RotorStation, error) {
|
func (c *Client) GetRotorStation(ctx context.Context, stationID string) (*models.RotorStation, error) {
|
||||||
params := map[string]string{
|
|
||||||
"station_id": stationID,
|
|
||||||
}
|
|
||||||
|
|
||||||
var result models.RotorStation
|
var result models.RotorStation
|
||||||
if err := c.request.Get(ctx, "/rotor/station", params, &result); err != nil {
|
if err := c.request.Get(ctx, fmt.Sprintf("/rotor/station/%s/info", stationID), nil, &result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
result.SetClient(c)
|
result.SetClient(c)
|
||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRotorStationTracks gets tracks for a rotor station
|
// GetRotorStationTracks gets tracks for a rotor station (GET /rotor/station/{stationID}/tracks).
|
||||||
func (c *Client) GetRotorStationTracks(ctx context.Context, stationID string, limit int) (*models.RotorStationTracksResult, error) {
|
func (c *Client) GetRotorStationTracks(ctx context.Context, stationID string, limit int) (*models.RotorStationTracksResult, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{}
|
||||||
"station_id": stationID,
|
|
||||||
}
|
|
||||||
if limit > 0 {
|
if limit > 0 {
|
||||||
params["limit"] = fmt.Sprintf("%d", limit)
|
params["limit"] = fmt.Sprintf("%d", limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
var result models.RotorStationTracksResult
|
var result models.RotorStationTracksResult
|
||||||
if err := c.request.Get(ctx, "/rotor/station/tracks", params, &result); err != nil {
|
if err := c.request.Get(ctx, fmt.Sprintf("/rotor/station/%s/tracks", stationID), params, &result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartRotorSession starts a rotor session
|
// StartRotorSession starts a rotor session (POST /rotor/station/{stationID}/session/start).
|
||||||
func (c *Client) StartRotorSession(ctx context.Context, stationID string) (*models.RotorSession, error) {
|
func (c *Client) StartRotorSession(ctx context.Context, stationID string) (*models.RotorSession, error) {
|
||||||
params := map[string]string{
|
|
||||||
"station_id": stationID,
|
|
||||||
}
|
|
||||||
|
|
||||||
var result models.RotorSession
|
var result models.RotorSession
|
||||||
if err := c.request.Post(ctx, "/rotor/session/start", params, &result); err != nil {
|
if err := c.request.Post(ctx, fmt.Sprintf("/rotor/station/%s/session/start", stationID), nil, &result); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
result.SetClient(c)
|
result.SetClient(c)
|
||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRotorSession gets rotor session info
|
// GetRotorSession gets rotor session info by session ID (GET /rotor/session).
|
||||||
func (c *Client) GetRotorSession(ctx context.Context, sessionID string) (*models.RotorSession, error) {
|
func (c *Client) GetRotorSession(ctx context.Context, sessionID string) (*models.RotorSession, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"session_id": sessionID,
|
"session_id": sessionID,
|
||||||
@@ -125,14 +110,72 @@ func (c *Client) GetRotorSession(ctx context.Context, sessionID string) (*models
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RotorSessionFeedback sends feedback for a rotor session track
|
// RotorSessionFeedback sends feedback for a rotor session track (POST /rotor/station/{stationID}/feedback).
|
||||||
|
// The feedbackType parameter can be "like", "dislike", or "skip".
|
||||||
func (c *Client) RotorSessionFeedback(ctx context.Context, sessionID, trackID, feedbackType string) error {
|
func (c *Client) RotorSessionFeedback(ctx context.Context, sessionID, trackID, feedbackType string) error {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"session_id": sessionID,
|
|
||||||
"track_id": trackID,
|
"track_id": trackID,
|
||||||
"feedback": feedbackType, // "like", "dislike", "skip"
|
"feedback": feedbackType, // "like", "dislike", "skip"
|
||||||
}
|
}
|
||||||
|
|
||||||
var result map[string]any
|
var result map[string]any
|
||||||
return c.request.Post(ctx, "/rotor/session/feedback", params, &result)
|
return c.request.Post(ctx, fmt.Sprintf("/rotor/station/%s/feedback", sessionID), params, &result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRotorStationsDashboard gets rotor stations dashboard (GET /rotor/stations/dashboard).
|
||||||
|
func (c *Client) GetRotorStationsDashboard(ctx context.Context) (*models.Dashboard, error) {
|
||||||
|
var result models.Dashboard
|
||||||
|
if err := c.request.Get(ctx, "/rotor/stations/dashboard", nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRotorStationsList gets rotor stations list (GET /rotor/stations/list).
|
||||||
|
func (c *Client) GetRotorStationsList(ctx context.Context) ([]*models.StationResult, error) {
|
||||||
|
var result []models.StationResult
|
||||||
|
if err := c.request.Get(ctx, "/rotor/stations/list", nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
stations := make([]*models.StationResult, len(result))
|
||||||
|
for i := range result {
|
||||||
|
result[i].SetClient(c)
|
||||||
|
stations[i] = &result[i]
|
||||||
|
}
|
||||||
|
return stations, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRotorStationInfo gets rotor station info (GET /rotor/station/{id}/info).
|
||||||
|
func (c *Client) GetRotorStationInfo(ctx context.Context, stationID string) (*models.RotorStation, error) {
|
||||||
|
var result models.RotorStation
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/rotor/station/%s/info", stationID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRotorStationStream gets rotor station stream (GET /rotor/station/{id}/stream).
|
||||||
|
func (c *Client) GetRotorStationStream(ctx context.Context, stationID string) (*models.GenerativeStream, error) {
|
||||||
|
var result models.GenerativeStream
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/rotor/station/%s/stream", stationID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRotorStationSettings gets rotor station settings (POST /rotor/station/{id}/settings3).
|
||||||
|
func (c *Client) GetRotorStationSettings(ctx context.Context, stationID string, moodEnergy, diversity, language string) (bool, error) {
|
||||||
|
params := map[string]string{
|
||||||
|
"mood-energy": moodEnergy,
|
||||||
|
"diversity": diversity,
|
||||||
|
"language": language,
|
||||||
|
}
|
||||||
|
var result bool
|
||||||
|
if err := c.request.Post(ctx, fmt.Sprintf("/rotor/station/%s/settings3", stationID), params, &result); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
}
|
}
|
||||||
+22
-13
@@ -13,7 +13,7 @@ import (
|
|||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/utils"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Default values
|
// Default values for the Yandex Music API client.
|
||||||
const (
|
const (
|
||||||
DefaultBaseURL = "https://api.music.yandex.net"
|
DefaultBaseURL = "https://api.music.yandex.net"
|
||||||
DefaultTimeout = 5 * time.Second
|
DefaultTimeout = 5 * time.Second
|
||||||
@@ -21,7 +21,7 @@ const (
|
|||||||
DefaultClientHeader = "YandexMusicAndroid/24023621"
|
DefaultClientHeader = "YandexMusicAndroid/24023621"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RequestConfig holds configuration for the request client
|
// RequestConfig holds configuration for the request client.
|
||||||
type RequestConfig struct {
|
type RequestConfig struct {
|
||||||
BaseURL string
|
BaseURL string
|
||||||
Token string
|
Token string
|
||||||
@@ -36,14 +36,16 @@ type RequestConfig struct {
|
|||||||
OnSchemaMismatch utils.SchemaMismatchHandler
|
OnSchemaMismatch utils.SchemaMismatchHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request handles HTTP requests to Yandex Music API
|
// Request handles HTTP requests to the Yandex Music API.
|
||||||
|
// It manages the HTTP client, authentication headers, and request signing.
|
||||||
type Request struct {
|
type Request struct {
|
||||||
config RequestConfig
|
config RequestConfig
|
||||||
client *http.Client
|
client *http.Client
|
||||||
schemaTracker *utils.SchemaMismatchTracker
|
schemaTracker *utils.SchemaMismatchTracker
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRequest creates a new Request instance
|
// NewRequest creates a new Request instance with the given configuration.
|
||||||
|
// It sets up the HTTP client, default headers, and authentication if a token is provided.
|
||||||
func NewRequest(config RequestConfig) *Request {
|
func NewRequest(config RequestConfig) *Request {
|
||||||
if config.BaseURL == "" {
|
if config.BaseURL == "" {
|
||||||
config.BaseURL = DefaultBaseURL
|
config.BaseURL = DefaultBaseURL
|
||||||
@@ -92,7 +94,8 @@ func NewRequest(config RequestConfig) *Request {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetToken updates the authorization token
|
// SetToken updates the authorization token used for API requests.
|
||||||
|
// When a token is provided, it sets the Authorization header to "OAuth <token>".
|
||||||
func (r *Request) SetToken(token string) {
|
func (r *Request) SetToken(token string) {
|
||||||
r.config.Token = token
|
r.config.Token = token
|
||||||
if token != "" {
|
if token != "" {
|
||||||
@@ -102,33 +105,38 @@ func (r *Request) SetToken(token string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetLanguage sets the Accept-Language header
|
// SetLanguage sets the Accept-Language header for API requests.
|
||||||
func (r *Request) SetLanguage(lang string) {
|
func (r *Request) SetLanguage(lang string) {
|
||||||
r.config.Language = lang
|
r.config.Language = lang
|
||||||
r.config.Headers["Accept-Language"] = lang
|
r.config.Headers["Accept-Language"] = lang
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get performs a GET request
|
// Get performs a GET request to the given path with query parameters.
|
||||||
|
// The response is unmarshaled into the result pointer.
|
||||||
func (r *Request) Get(ctx context.Context, path string, params map[string]string, result any) error {
|
func (r *Request) Get(ctx context.Context, path string, params map[string]string, result any) error {
|
||||||
return r.doRequest(ctx, "GET", path, params, nil, result)
|
return r.doRequest(ctx, "GET", path, params, nil, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Post performs a POST request
|
// Post performs a POST request to the given path with a JSON body.
|
||||||
|
// The response is unmarshaled into the result pointer.
|
||||||
func (r *Request) Post(ctx context.Context, path string, body any, result any) error {
|
func (r *Request) Post(ctx context.Context, path string, body any, result any) error {
|
||||||
return r.doRequest(ctx, "POST", path, nil, body, result)
|
return r.doRequest(ctx, "POST", path, nil, body, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put performs a PUT request
|
// Put performs a PUT request to the given path with a JSON body.
|
||||||
|
// The response is unmarshaled into the result pointer.
|
||||||
func (r *Request) Put(ctx context.Context, path string, body any, result any) error {
|
func (r *Request) Put(ctx context.Context, path string, body any, result any) error {
|
||||||
return r.doRequest(ctx, "PUT", path, nil, body, result)
|
return r.doRequest(ctx, "PUT", path, nil, body, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete performs a DELETE request
|
// Delete performs a DELETE request to the given path with an optional JSON body.
|
||||||
|
// The response is unmarshaled into the result pointer.
|
||||||
func (r *Request) Delete(ctx context.Context, path string, body any, result any) error {
|
func (r *Request) Delete(ctx context.Context, path string, body any, result any) error {
|
||||||
return r.doRequest(ctx, "DELETE", path, nil, body, result)
|
return r.doRequest(ctx, "DELETE", path, nil, body, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// doRequest performs the actual HTTP request
|
// doRequest performs the actual HTTP request to the Yandex Music API.
|
||||||
|
// It handles URL building, request signing, response parsing, and error handling.
|
||||||
func (r *Request) doRequest(ctx context.Context, method, path string, params map[string]string, body any, result any) error {
|
func (r *Request) doRequest(ctx context.Context, method, path string, params map[string]string, body any, result any) error {
|
||||||
// Build URL
|
// Build URL
|
||||||
fullURL := r.config.BaseURL + path
|
fullURL := r.config.BaseURL + path
|
||||||
@@ -209,7 +217,7 @@ func (r *Request) doRequest(ctx context.Context, method, path string, params map
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleErrorResponse handles HTTP error responses
|
// handleErrorResponse handles HTTP error responses by mapping status codes to typed errors.
|
||||||
func (r *Request) handleErrorResponse(statusCode int, body []byte) error {
|
func (r *Request) handleErrorResponse(statusCode int, body []byte) error {
|
||||||
var msg string
|
var msg string
|
||||||
apiResp, err := utils.DeJSON(body)
|
apiResp, err := utils.DeJSON(body)
|
||||||
@@ -235,7 +243,8 @@ func (r *Request) handleErrorResponse(statusCode int, body []byte) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Download downloads a file from a URL
|
// Download downloads a file from the given URL and returns the raw response body.
|
||||||
|
// It is used for downloading track files and lyrics text.
|
||||||
func (r *Request) Download(ctx context.Context, urlStr string) ([]byte, error) {
|
func (r *Request) Download(ctx context.Context, urlStr string) ([]byte, error) {
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", urlStr, nil)
|
req, err := http.NewRequestWithContext(ctx, "GET", urlStr, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+12
-10
@@ -1,3 +1,4 @@
|
|||||||
|
// Package client provides methods for interacting with Yandex Music API endpoints.
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -7,7 +8,8 @@ import (
|
|||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Search performs a multi-type search
|
// Search performs a multi-type search (GET /search).
|
||||||
|
// The searchType parameter specifies what to search for (e.g., "track", "album", "artist").
|
||||||
func (c *Client) Search(ctx context.Context, query string, searchType string, page, pageSize int) (*models.SearchResult, error) {
|
func (c *Client) Search(ctx context.Context, query string, searchType string, page, pageSize int) (*models.SearchResult, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"text": query,
|
"text": query,
|
||||||
@@ -46,7 +48,7 @@ func (c *Client) Search(ctx context.Context, query string, searchType string, pa
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchTracks searches for tracks
|
// SearchTracks searches for tracks using Search with type "track".
|
||||||
func (c *Client) SearchTracks(ctx context.Context, query string, page, pageSize int) (*models.SearchTracksResult, error) {
|
func (c *Client) SearchTracks(ctx context.Context, query string, page, pageSize int) (*models.SearchTracksResult, error) {
|
||||||
result, err := c.Search(ctx, query, "track", page, pageSize)
|
result, err := c.Search(ctx, query, "track", page, pageSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -55,7 +57,7 @@ func (c *Client) SearchTracks(ctx context.Context, query string, page, pageSize
|
|||||||
return result.Tracks, nil
|
return result.Tracks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchAlbums searches for albums
|
// SearchAlbums searches for albums using Search with type "album".
|
||||||
func (c *Client) SearchAlbums(ctx context.Context, query string, page, pageSize int) (*models.SearchAlbumsResult, error) {
|
func (c *Client) SearchAlbums(ctx context.Context, query string, page, pageSize int) (*models.SearchAlbumsResult, error) {
|
||||||
result, err := c.Search(ctx, query, "album", page, pageSize)
|
result, err := c.Search(ctx, query, "album", page, pageSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -64,7 +66,7 @@ func (c *Client) SearchAlbums(ctx context.Context, query string, page, pageSize
|
|||||||
return result.Albums, nil
|
return result.Albums, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchArtists searches for artists
|
// SearchArtists searches for artists using Search with type "artist".
|
||||||
func (c *Client) SearchArtists(ctx context.Context, query string, page, pageSize int) (*models.SearchArtistsResult, error) {
|
func (c *Client) SearchArtists(ctx context.Context, query string, page, pageSize int) (*models.SearchArtistsResult, error) {
|
||||||
result, err := c.Search(ctx, query, "artist", page, pageSize)
|
result, err := c.Search(ctx, query, "artist", page, pageSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -73,7 +75,7 @@ func (c *Client) SearchArtists(ctx context.Context, query string, page, pageSize
|
|||||||
return result.Artists, nil
|
return result.Artists, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchPlaylists searches for playlists
|
// SearchPlaylists searches for playlists using Search with type "playlist".
|
||||||
func (c *Client) SearchPlaylists(ctx context.Context, query string, page, pageSize int) (*models.SearchPlaylistsResult, error) {
|
func (c *Client) SearchPlaylists(ctx context.Context, query string, page, pageSize int) (*models.SearchPlaylistsResult, error) {
|
||||||
result, err := c.Search(ctx, query, "playlist", page, pageSize)
|
result, err := c.Search(ctx, query, "playlist", page, pageSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -82,7 +84,7 @@ func (c *Client) SearchPlaylists(ctx context.Context, query string, page, pageSi
|
|||||||
return result.Playlists, nil
|
return result.Playlists, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchVideos searches for videos
|
// SearchVideos searches for videos using Search with type "video".
|
||||||
func (c *Client) SearchVideos(ctx context.Context, query string, page, pageSize int) (*models.SearchVideosResult, error) {
|
func (c *Client) SearchVideos(ctx context.Context, query string, page, pageSize int) (*models.SearchVideosResult, error) {
|
||||||
result, err := c.Search(ctx, query, "video", page, pageSize)
|
result, err := c.Search(ctx, query, "video", page, pageSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -91,7 +93,7 @@ func (c *Client) SearchVideos(ctx context.Context, query string, page, pageSize
|
|||||||
return result.Videos, nil
|
return result.Videos, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchUsers searches for users
|
// SearchUsers searches for users using Search with type "user".
|
||||||
func (c *Client) SearchUsers(ctx context.Context, query string, page, pageSize int) (*models.SearchUsersResult, error) {
|
func (c *Client) SearchUsers(ctx context.Context, query string, page, pageSize int) (*models.SearchUsersResult, error) {
|
||||||
result, err := c.Search(ctx, query, "user", page, pageSize)
|
result, err := c.Search(ctx, query, "user", page, pageSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -100,7 +102,7 @@ func (c *Client) SearchUsers(ctx context.Context, query string, page, pageSize i
|
|||||||
return result.Users, nil
|
return result.Users, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchSuggestions gets search suggestions
|
// SearchSuggestions gets search suggestions for a query (GET /search/suggest?type=suggest).
|
||||||
func (c *Client) SearchSuggestions(ctx context.Context, query string) ([]string, error) {
|
func (c *Client) SearchSuggestions(ctx context.Context, query string) ([]string, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"text": query,
|
"text": query,
|
||||||
@@ -116,7 +118,7 @@ func (c *Client) SearchSuggestions(ctx context.Context, query string) ([]string,
|
|||||||
return result.Suggestions, nil
|
return result.Suggestions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchBanners gets search banners
|
// SearchBanners gets search banners for a query (GET /search/banner?type=banner).
|
||||||
func (c *Client) SearchBanners(ctx context.Context, query string) ([]models.SearchBanner, error) {
|
func (c *Client) SearchBanners(ctx context.Context, query string) ([]models.SearchBanner, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"text": query,
|
"text": query,
|
||||||
@@ -132,7 +134,7 @@ func (c *Client) SearchBanners(ctx context.Context, query string) ([]models.Sear
|
|||||||
return result.Banners, nil
|
return result.Banners, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchTags gets search tags
|
// SearchTags gets search tags for a query (GET /search/tag?type=tag).
|
||||||
func (c *Client) SearchTags(ctx context.Context, query string) ([]models.Tag, error) {
|
func (c *Client) SearchTags(ctx context.Context, query string) ([]models.Tag, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"text": query,
|
"text": query,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Package client provides methods for interacting with Yandex Music API endpoints.
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -6,7 +7,7 @@ import (
|
|||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetSettings gets user settings
|
// GetSettings gets user settings (GET /account/settings).
|
||||||
func (c *Client) GetSettings(ctx context.Context) (*models.AccountSettings, error) {
|
func (c *Client) GetSettings(ctx context.Context) (*models.AccountSettings, error) {
|
||||||
var result models.AccountSettings
|
var result models.AccountSettings
|
||||||
if err := c.request.Get(ctx, "/account/settings", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/account/settings", nil, &result); err != nil {
|
||||||
@@ -15,7 +16,7 @@ func (c *Client) GetSettings(ctx context.Context) (*models.AccountSettings, erro
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateSettings updates user settings
|
// UpdateSettings updates user settings (PUT /account/settings).
|
||||||
func (c *Client) UpdateSettings(ctx context.Context, settings *models.AccountSettings) (*models.AccountSettings, error) {
|
func (c *Client) UpdateSettings(ctx context.Context, settings *models.AccountSettings) (*models.AccountSettings, error) {
|
||||||
var result models.AccountSettings
|
var result models.AccountSettings
|
||||||
if err := c.request.Put(ctx, "/account/settings", settings, &result); err != nil {
|
if err := c.request.Put(ctx, "/account/settings", settings, &result); err != nil {
|
||||||
@@ -24,7 +25,7 @@ func (c *Client) UpdateSettings(ctx context.Context, settings *models.AccountSet
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExperiments gets experiments
|
// GetExperiments gets experiments (GET /experiments).
|
||||||
func (c *Client) GetExperiments(ctx context.Context) (*models.Experiments, error) {
|
func (c *Client) GetExperiments(ctx context.Context) (*models.Experiments, error) {
|
||||||
var result models.Experiments
|
var result models.Experiments
|
||||||
if err := c.request.Get(ctx, "/experiments", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/experiments", nil, &result); err != nil {
|
||||||
@@ -33,7 +34,7 @@ func (c *Client) GetExperiments(ctx context.Context) (*models.Experiments, error
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExperimentDetails gets experiment details
|
// GetExperimentDetails gets experiment details for the given experiment ID (GET /experiments/details).
|
||||||
func (c *Client) GetExperimentDetails(ctx context.Context, experimentID string) (*models.ExperimentDetail, error) {
|
func (c *Client) GetExperimentDetails(ctx context.Context, experimentID string) (*models.ExperimentDetail, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"experiment_id": experimentID,
|
"experiment_id": experimentID,
|
||||||
@@ -45,7 +46,7 @@ func (c *Client) GetExperimentDetails(ctx context.Context, experimentID string)
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPermissions gets user permissions
|
// GetPermissions gets user permissions (GET /permissions).
|
||||||
func (c *Client) GetPermissions(ctx context.Context) (*models.Permissions, error) {
|
func (c *Client) GetPermissions(ctx context.Context) (*models.Permissions, error) {
|
||||||
var result models.Permissions
|
var result models.Permissions
|
||||||
if err := c.request.Get(ctx, "/permissions", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/permissions", nil, &result); err != nil {
|
||||||
@@ -54,7 +55,7 @@ func (c *Client) GetPermissions(ctx context.Context) (*models.Permissions, error
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPermissionAlerts gets permission alerts
|
// GetPermissionAlerts gets permission alerts (GET /permission-alerts).
|
||||||
func (c *Client) GetPermissionAlerts(ctx context.Context) (*models.PermissionAlerts, error) {
|
func (c *Client) GetPermissionAlerts(ctx context.Context) (*models.PermissionAlerts, error) {
|
||||||
var result models.PermissionAlerts
|
var result models.PermissionAlerts
|
||||||
if err := c.request.Get(ctx, "/permission-alerts", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/permission-alerts", nil, &result); err != nil {
|
||||||
@@ -63,7 +64,7 @@ func (c *Client) GetPermissionAlerts(ctx context.Context) (*models.PermissionAle
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetContentRestrictions gets content restrictions
|
// GetContentRestrictions gets content restrictions (GET /content-restrictions).
|
||||||
func (c *Client) GetContentRestrictions(ctx context.Context) (*models.ContentRestrictions, error) {
|
func (c *Client) GetContentRestrictions(ctx context.Context) (*models.ContentRestrictions, error) {
|
||||||
var result models.ContentRestrictions
|
var result models.ContentRestrictions
|
||||||
if err := c.request.Get(ctx, "/content-restrictions", nil, &result); err != nil {
|
if err := c.request.Get(ctx, "/content-restrictions", nil, &result); err != nil {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Package client provides methods for interacting with Yandex Music API endpoints.
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -9,8 +10,7 @@ import (
|
|||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/utils"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetTrackSupplement gets supplement for a track
|
// GetTrackSupplement gets supplement for a track (GET /tracks/{track_id}/supplement).
|
||||||
// GET /tracks/{track_id}/supplement
|
|
||||||
func (c *Client) GetTrackSupplement(ctx context.Context, trackID string) (*models.Supplement, error) {
|
func (c *Client) GetTrackSupplement(ctx context.Context, trackID string) (*models.Supplement, error) {
|
||||||
path := fmt.Sprintf("/tracks/%s/supplement", trackID)
|
path := fmt.Sprintf("/tracks/%s/supplement", trackID)
|
||||||
|
|
||||||
@@ -21,8 +21,9 @@ func (c *Client) GetTrackSupplement(ctx context.Context, trackID string) (*model
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTrackLyrics gets lyrics for a track (new endpoint with signing)
|
// GetTrackLyrics gets lyrics for a track (GET /tracks/{track_id}/lyrics).
|
||||||
// GET /tracks/{track_id}/lyrics
|
// The format parameter specifies the lyrics format (e.g., "TEXT" or "LRC").
|
||||||
|
// The request is signed using the default signing key.
|
||||||
func (c *Client) GetTrackLyrics(ctx context.Context, trackID string, format string) (*models.TrackLyrics, error) {
|
func (c *Client) GetTrackLyrics(ctx context.Context, trackID string, format string) (*models.TrackLyrics, error) {
|
||||||
path := fmt.Sprintf("/tracks/%s/lyrics", trackID)
|
path := fmt.Sprintf("/tracks/%s/lyrics", trackID)
|
||||||
|
|
||||||
@@ -42,7 +43,7 @@ func (c *Client) GetTrackLyrics(ctx context.Context, trackID string, format stri
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTrackLyricsText fetches the full lyrics text from the download URL
|
// GetTrackLyricsText fetches the full lyrics text from the download URL provided in TrackLyrics.
|
||||||
func (c *Client) GetTrackLyricsText(ctx context.Context, trackLyrics *models.TrackLyrics) (string, error) {
|
func (c *Client) GetTrackLyricsText(ctx context.Context, trackLyrics *models.TrackLyrics) (string, error) {
|
||||||
data, err := c.request.Download(ctx, trackLyrics.DownloadURL)
|
data, err := c.request.Download(ctx, trackLyrics.DownloadURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -51,8 +52,7 @@ func (c *Client) GetTrackLyricsText(ctx context.Context, trackLyrics *models.Tra
|
|||||||
return string(data), nil
|
return string(data), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLyrics gets lyrics info for a track (legacy endpoint)
|
// GetLyrics gets lyrics info for a track using the legacy endpoint (GET /tracks/lyrics).
|
||||||
// GET /tracks/lyrics?track_id={track_id}
|
|
||||||
func (c *Client) GetLyrics(ctx context.Context, trackID string) (*models.LyricsInfo, error) {
|
func (c *Client) GetLyrics(ctx context.Context, trackID string) (*models.LyricsInfo, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"track_id": trackID,
|
"track_id": trackID,
|
||||||
@@ -65,8 +65,7 @@ func (c *Client) GetLyrics(ctx context.Context, trackID string) (*models.LyricsI
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVideoSupplement gets video supplement for a track (legacy endpoint)
|
// GetVideoSupplement gets video supplement for a track using the legacy endpoint (GET /tracks/video-supplement).
|
||||||
// GET /tracks/video-supplement?track_id={track_id}
|
|
||||||
func (c *Client) GetVideoSupplement(ctx context.Context, trackID string) (*models.VideoSupplement, error) {
|
func (c *Client) GetVideoSupplement(ctx context.Context, trackID string) (*models.VideoSupplement, error) {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"track_id": trackID,
|
"track_id": trackID,
|
||||||
@@ -79,44 +78,43 @@ func (c *Client) GetVideoSupplement(ctx context.Context, trackID string) (*model
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLyricsByTrackID is an alias for GetTrackLyrics for backward compatibility
|
// GetLyricsByTrackID is an alias for GetTrackLyrics for backward compatibility (GET /tracks/{track_id}/lyrics).
|
||||||
// GET /tracks/{track_id}/lyrics
|
|
||||||
func (c *Client) GetLyricsByTrackID(ctx context.Context, trackID string, format string) (*models.TrackLyrics, error) {
|
func (c *Client) GetLyricsByTrackID(ctx context.Context, trackID string, format string) (*models.TrackLyrics, error) {
|
||||||
return c.GetTrackLyrics(ctx, trackID, format)
|
return c.GetTrackLyrics(ctx, trackID, format)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LyricsFormat represents the lyrics format
|
// LyricsFormat represents the lyrics format.
|
||||||
type LyricsFormat string
|
type LyricsFormat string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// LyricsFormatText is plain text format
|
// LyricsFormatText is plain text lyrics format.
|
||||||
LyricsFormatText LyricsFormat = "TEXT"
|
LyricsFormatText LyricsFormat = "TEXT"
|
||||||
// LyricsFormatLRC is LRC format with timestamps
|
// LyricsFormatLRC is LRC format lyrics with timestamps.
|
||||||
LyricsFormatLRC LyricsFormat = "LRC"
|
LyricsFormatLRC LyricsFormat = "LRC"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetTrackLyricsWithOptions gets lyrics with options
|
// GetTrackLyricsWithOptions gets lyrics with options using a LyricsFormat value.
|
||||||
func (c *Client) GetTrackLyricsWithOptions(ctx context.Context, trackID string, format LyricsFormat) (*models.TrackLyrics, error) {
|
func (c *Client) GetTrackLyricsWithOptions(ctx context.Context, trackID string, format LyricsFormat) (*models.TrackLyrics, error) {
|
||||||
return c.GetTrackLyrics(ctx, trackID, string(format))
|
return c.GetTrackLyrics(ctx, trackID, string(format))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SupplementOptions holds options for supplement requests
|
// SupplementOptions holds options for supplement requests.
|
||||||
type SupplementOptions struct {
|
type SupplementOptions struct {
|
||||||
TrackID string
|
TrackID string
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSupplement gets track supplement with options
|
// GetSupplement gets track supplement with options.
|
||||||
func (c *Client) GetSupplement(ctx context.Context, opts SupplementOptions) (*models.Supplement, error) {
|
func (c *Client) GetSupplement(ctx context.Context, opts SupplementOptions) (*models.Supplement, error) {
|
||||||
return c.GetTrackSupplement(ctx, opts.TrackID)
|
return c.GetTrackSupplement(ctx, opts.TrackID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LyricsOptions holds options for lyrics requests
|
// LyricsOptions holds options for lyrics requests.
|
||||||
type LyricsOptions struct {
|
type LyricsOptions struct {
|
||||||
TrackID string
|
TrackID string
|
||||||
Format LyricsFormat
|
Format LyricsFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLyricsWithOptions gets track lyrics with options
|
// GetLyricsWithOptions gets track lyrics with options.
|
||||||
func (c *Client) GetLyricsWithOptions(ctx context.Context, opts LyricsOptions) (*models.TrackLyrics, error) {
|
func (c *Client) GetLyricsWithOptions(ctx context.Context, opts LyricsOptions) (*models.TrackLyrics, error) {
|
||||||
format := string(opts.Format)
|
format := string(opts.Format)
|
||||||
if format == "" {
|
if format == "" {
|
||||||
@@ -125,13 +123,34 @@ func (c *Client) GetLyricsWithOptions(ctx context.Context, opts LyricsOptions) (
|
|||||||
return c.GetTrackLyrics(ctx, opts.TrackID, format)
|
return c.GetTrackLyrics(ctx, opts.TrackID, format)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign represents a request signature
|
// Sign represents a request signature for signed API requests.
|
||||||
type Sign struct {
|
type Sign struct {
|
||||||
Timestamp int64
|
Timestamp int64
|
||||||
Value string
|
Value string
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSignRequest creates a signature for a track request (exported for external use)
|
// GetTracksCredits gets track credits (GET /tracks/{id}/credits).
|
||||||
|
func (c *Client) GetTracksCredits(ctx context.Context, trackID string) (*models.Credits, error) {
|
||||||
|
var result models.Credits
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/tracks/%s/credits", trackID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetClipsCredits gets clip credits (GET /clips/{id}/credits).
|
||||||
|
func (c *Client) GetClipsCredits(ctx context.Context, clipID string) (*models.Credits, error) {
|
||||||
|
var result models.Credits
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/clips/%s/credits", clipID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSignRequest creates a signature for a track request (exported for external use).
|
||||||
|
// It delegates to utils.GetSignRequest with the default signing key.
|
||||||
func GetSignRequest(trackID string) Sign {
|
func GetSignRequest(trackID string) Sign {
|
||||||
h := utils.GetSignRequest(trackID, utils.DefaultSignKey)
|
h := utils.GetSignRequest(trackID, utils.DefaultSignKey)
|
||||||
|
|
||||||
|
|||||||
+154
-15
@@ -1,14 +1,52 @@
|
|||||||
|
// Package client provides methods for interacting with Yandex Music API endpoints.
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models"
|
||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/utils"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetTracks gets tracks by IDs
|
const downloadSignSalt = "XGRlBW9FXlekgbPrRHuSiA"
|
||||||
|
|
||||||
|
// downloadInfoXML represents the XML response from download_info_url.
|
||||||
|
type downloadInfoXML struct {
|
||||||
|
Host string `xml:"host"`
|
||||||
|
Path string `xml:"path"`
|
||||||
|
Ts string `xml:"ts"`
|
||||||
|
S string `xml:"s"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolveDownloadURL downloads the XML from downloadInfoURL, parses host/path/ts/s,
|
||||||
|
// computes the MD5 signature, and returns the signed download URL:
|
||||||
|
// https://{host}/get-mp3/{sign}/{ts}{path}
|
||||||
|
func resolveDownloadURL(ctx context.Context, downloadInfoURL string, ri models.RequestInterface) (string, error) {
|
||||||
|
data, err := ri.Download(ctx, downloadInfoURL)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var xmlData downloadInfoXML
|
||||||
|
if err := xml.Unmarshal(data, &xmlData); err != nil {
|
||||||
|
return "", fmt.Errorf("failed to parse download info XML: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if xmlData.Path == "" || xmlData.S == "" {
|
||||||
|
return "", utils.NewYandexMusicError("invalid download info XML: missing path or s", utils.ErrBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
sign := fmt.Sprintf("%x", md5.Sum([]byte(downloadSignSalt+xmlData.Path[1:]+xmlData.S)))
|
||||||
|
|
||||||
|
return fmt.Sprintf("https://%s/get-mp3/%s/%s%s", xmlData.Host, sign, xmlData.Ts, xmlData.Path), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTracks gets tracks by their IDs (GET /tracks).
|
||||||
|
// Returns a slice of Track pointers, or nil if no IDs are provided.
|
||||||
func (c *Client) GetTracks(ctx context.Context, trackIDs []string) ([]*models.Track, error) {
|
func (c *Client) GetTracks(ctx context.Context, trackIDs []string) ([]*models.Track, error) {
|
||||||
if len(trackIDs) == 0 {
|
if len(trackIDs) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -31,7 +69,8 @@ func (c *Client) GetTracks(ctx context.Context, trackIDs []string) ([]*models.Tr
|
|||||||
return tracks, nil
|
return tracks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTrack gets a single track by ID
|
// GetTrack gets a single track by ID using GetTracks.
|
||||||
|
// Returns an error if no track is found with the given ID.
|
||||||
func (c *Client) GetTrack(ctx context.Context, trackID string) (*models.Track, error) {
|
func (c *Client) GetTrack(ctx context.Context, trackID string) (*models.Track, error) {
|
||||||
tracks, err := c.GetTracks(ctx, []string{trackID})
|
tracks, err := c.GetTracks(ctx, []string{trackID})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -43,13 +82,15 @@ func (c *Client) GetTrack(ctx context.Context, trackID string) (*models.Track, e
|
|||||||
return tracks[0], nil
|
return tracks[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTrackDownloadInfo gets download info for a track
|
// GetTrackDownloadInfo gets download info for a track (GET /tracks/{track_id}/download-info).
|
||||||
|
// The quality parameter specifies the desired audio quality (e.g., "mp3").
|
||||||
func (c *Client) GetTrackDownloadInfo(ctx context.Context, trackID, quality string) ([]models.DownloadInfo, error) {
|
func (c *Client) GetTrackDownloadInfo(ctx context.Context, trackID, quality string) ([]models.DownloadInfo, error) {
|
||||||
// This requires signing - use the sign utility
|
|
||||||
// For now, return basic implementation
|
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"track_id": trackID,
|
"track_id": trackID,
|
||||||
}
|
}
|
||||||
|
if quality != "" {
|
||||||
|
params["quality"] = quality
|
||||||
|
}
|
||||||
|
|
||||||
var result []models.DownloadInfo
|
var result []models.DownloadInfo
|
||||||
if err := c.request.Get(ctx, fmt.Sprintf("/tracks/%s/download-info", trackID), params, &result); err != nil {
|
if err := c.request.Get(ctx, fmt.Sprintf("/tracks/%s/download-info", trackID), params, &result); err != nil {
|
||||||
@@ -58,7 +99,45 @@ func (c *Client) GetTrackDownloadInfo(ctx context.Context, trackID, quality stri
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DownloadTrack downloads a track
|
// GetTrackDownloadURL returns a signed direct download URL for a track.
|
||||||
|
// It fetches download info, finds a matching entry, downloads the XML from its
|
||||||
|
// download_info_url, parses host/path/ts/s, computes the MD5 signature, and
|
||||||
|
// returns https://{host}/get-mp3/{sign}/{ts}{path}.
|
||||||
|
func (c *Client) GetTrackDownloadURL(ctx context.Context, trackID, format string, bitrate int) (string, error) {
|
||||||
|
info, err := c.GetTrackDownloadInfo(ctx, trackID, format)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find matching download info
|
||||||
|
var di *models.DownloadInfo
|
||||||
|
for i := range info {
|
||||||
|
if info[i].Codec == format && (bitrate == 0 || info[i].Bitrate == bitrate) {
|
||||||
|
di = &info[i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if di == nil && len(info) > 0 {
|
||||||
|
di = &info[0]
|
||||||
|
}
|
||||||
|
if di == nil {
|
||||||
|
return "", utils.NewYandexMusicError("no download info available", utils.ErrNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
if di.URL != "" {
|
||||||
|
return di.URL, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if di.DownloadInfoURL == "" {
|
||||||
|
return "", utils.NewYandexMusicError("no download URL available", utils.ErrNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolveDownloadURL(ctx, di.DownloadInfoURL, c.request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DownloadTrack downloads a track by ID.
|
||||||
|
// It first fetches download info, finds a matching format/bitrate, resolves the
|
||||||
|
// signed URL if needed, then downloads the file content.
|
||||||
func (c *Client) DownloadTrack(ctx context.Context, trackID, format string, bitrate int) ([]byte, error) {
|
func (c *Client) DownloadTrack(ctx context.Context, trackID, format string, bitrate int) ([]byte, error) {
|
||||||
info, err := c.GetTrackDownloadInfo(ctx, trackID, format)
|
info, err := c.GetTrackDownloadInfo(ctx, trackID, format)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -66,31 +145,91 @@ func (c *Client) DownloadTrack(ctx context.Context, trackID, format string, bitr
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find matching download info
|
// Find matching download info
|
||||||
var url string
|
var di *models.DownloadInfo
|
||||||
for _, di := range info {
|
for i := range info {
|
||||||
if di.Codec == format && (bitrate == 0 || di.Bitrate == bitrate) {
|
if info[i].Codec == format && (bitrate == 0 || info[i].Bitrate == bitrate) {
|
||||||
url = di.URL
|
di = &info[i]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if di == nil && len(info) > 0 {
|
||||||
if url == "" && len(info) > 0 {
|
di = &info[0]
|
||||||
url = info[0].URL
|
}
|
||||||
|
if di == nil {
|
||||||
|
return nil, utils.NewYandexMusicError("no download info available", utils.ErrNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
url := di.URL
|
||||||
if url == "" {
|
if url == "" {
|
||||||
|
if di.DownloadInfoURL == "" {
|
||||||
return nil, utils.NewYandexMusicError("no download URL available", utils.ErrNotFound)
|
return nil, utils.NewYandexMusicError("no download URL available", utils.ErrNotFound)
|
||||||
}
|
}
|
||||||
|
url, err = resolveDownloadURL(ctx, di.DownloadInfoURL, c.request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return c.request.Download(ctx, url)
|
return c.request.Download(ctx, url)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchResult represents search results
|
// GetTracksFileInfo gets file info for a track (GET /get-file-info).
|
||||||
|
func (c *Client) GetTracksFileInfo(ctx context.Context, trackID, quality string, codecs []string, transport string) (*models.FileInfo, error) {
|
||||||
|
params := map[string]string{
|
||||||
|
"track_id": trackID,
|
||||||
|
"quality": quality,
|
||||||
|
}
|
||||||
|
if len(codecs) > 0 {
|
||||||
|
params["codecs"] = strings.Join(codecs, ",")
|
||||||
|
}
|
||||||
|
if transport != "" {
|
||||||
|
params["transport"] = transport
|
||||||
|
}
|
||||||
|
|
||||||
|
var result models.FileInfo
|
||||||
|
if err := c.request.Get(ctx, "/get-file-info", params, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTracksSimilar gets similar tracks (GET /tracks/{track_id}/similar).
|
||||||
|
func (c *Client) GetTracksSimilar(ctx context.Context, trackID string) (*models.SimilarTracks, error) {
|
||||||
|
var result models.SimilarTracks
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/tracks/%s/similar", trackID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTrackTrailer gets track trailer (GET /tracks/{track_id}/trailer).
|
||||||
|
func (c *Client) GetTrackTrailer(ctx context.Context, trackID string) (*models.TrackTrailer, error) {
|
||||||
|
var result models.TrackTrailer
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/tracks/%s/trailer", trackID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTrackFullInfo gets full track info (GET /tracks/{track_id}/full-info).
|
||||||
|
func (c *Client) GetTrackFullInfo(ctx context.Context, trackID string) (*models.TrackFullInfo, error) {
|
||||||
|
var result models.TrackFullInfo
|
||||||
|
if err := c.request.Get(ctx, fmt.Sprintf("/tracks/%s/full-info", trackID), nil, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.SetClient(c)
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchResult represents search results containing tracks.
|
||||||
type SearchResult struct {
|
type SearchResult struct {
|
||||||
Tracks *SearchTracksResult `json:"tracks"`
|
Tracks *SearchTracksResult `json:"tracks"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchTracksResult represents track search results
|
// SearchTracksResult represents track search results with total count and results list.
|
||||||
type SearchTracksResult struct {
|
type SearchTracksResult struct {
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
Results []models.Track `json:"results"`
|
Results []models.Track `json:"results"`
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ func TestClient_GetTracks(t *testing.T) {
|
|||||||
"id": "12345",
|
"id": "12345",
|
||||||
"title": "Test Track",
|
"title": "Test Track",
|
||||||
"duration_ms": 180000,
|
"duration_ms": 180000,
|
||||||
"storage_id": "67890",
|
"storage_dir": "67890",
|
||||||
"cover_uri": "https://example.com/cover.jpg",
|
"cover_uri": "https://example.com/cover.jpg",
|
||||||
"genre": "rock",
|
"genre": "rock",
|
||||||
"version": "album",
|
"version": "album",
|
||||||
@@ -42,7 +42,7 @@ func TestClient_GetTracks(t *testing.T) {
|
|||||||
"artists": [{"id": "1", "name": "Artist 1", "cover_uri": "https://example.com/artist.jpg"}],
|
"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}],
|
"albums": [{"id": "789", "title": "Test Album", "cover_uri": "https://example.com/album.jpg", "year": 2023}],
|
||||||
"major": {"id": "major1", "name": "Major Label", "description": "Big label"},
|
"major": {"id": "major1", "name": "Major Label", "description": "Big label"},
|
||||||
"lyrics": {"id": "lyr1", "text": "Test lyrics", "available": true, "has_text": true}
|
"lyrics_info": {"has_available_sync_lyrics": true, "has_available_text_lyrics": true}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}`),
|
}`),
|
||||||
@@ -63,8 +63,8 @@ func TestClient_GetTracks(t *testing.T) {
|
|||||||
if tr.Major == nil || tr.Major.Name != "Major Label" {
|
if tr.Major == nil || tr.Major.Name != "Major Label" {
|
||||||
t.Errorf("Expected Major 'Major Label'")
|
t.Errorf("Expected Major 'Major Label'")
|
||||||
}
|
}
|
||||||
if tr.Lyrics == nil || tr.Lyrics.Text != "Test lyrics" {
|
if tr.LyricsInfo == nil || tr.LyricsInfo.HasAvailableSyncLyrics != true {
|
||||||
t.Errorf("Expected Lyrics 'Test lyrics'")
|
t.Errorf("Expected LyricsInfo.HasAvailableSyncLyrics true")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -73,8 +73,8 @@ func TestClient_GetTracks(t *testing.T) {
|
|||||||
trackIDs: []string{"12345", "67890"},
|
trackIDs: []string{"12345", "67890"},
|
||||||
mockResponse: []byte(`{
|
mockResponse: []byte(`{
|
||||||
"result": [
|
"result": [
|
||||||
{"id": "12345", "title": "Track 1", "duration_ms": 100000, "storage_id": "1", "cover_uri": "", "genre": "", "version": "", "explicit": false, "available": true, "available_for_premium_users": true, "r128": 0, "track_sharing_flag": "", "artists": [], "albums": []},
|
{"id": "12345", "title": "Track 1", "duration_ms": 100000, "storage_dir": "1", "cover_uri": "", "genre": "", "version": "", "explicit": false, "available": true, "available_for_premium_users": true, "r128": 0, "track_sharing_flag": "", "artists": [], "albums": []},
|
||||||
{"id": "67890", "title": "Track 2", "duration_ms": 200000, "storage_id": "2", "cover_uri": "", "genre": "", "version": "", "explicit": false, "available": true, "available_for_premium_users": true, "r128": 0, "track_sharing_flag": "", "artists": [], "albums": []}
|
{"id": "67890", "title": "Track 2", "duration_ms": 200000, "storage_dir": "2", "cover_uri": "", "genre": "", "version": "", "explicit": false, "available": true, "available_for_premium_users": true, "r128": 0, "track_sharing_flag": "", "artists": [], "albums": []}
|
||||||
]
|
]
|
||||||
}`),
|
}`),
|
||||||
expectedTracks: 2,
|
expectedTracks: 2,
|
||||||
@@ -189,7 +189,7 @@ func TestClient_GetTrack(t *testing.T) {
|
|||||||
"id": "12345",
|
"id": "12345",
|
||||||
"title": "Test Track",
|
"title": "Test Track",
|
||||||
"duration_ms": 180000,
|
"duration_ms": 180000,
|
||||||
"storage_id": "67890",
|
"storage_dir": "67890",
|
||||||
"cover_uri": "https://example.com/cover.jpg",
|
"cover_uri": "https://example.com/cover.jpg",
|
||||||
"genre": "rock",
|
"genre": "rock",
|
||||||
"version": "album",
|
"version": "album",
|
||||||
@@ -201,7 +201,7 @@ func TestClient_GetTrack(t *testing.T) {
|
|||||||
"artists": [{"id": "1", "name": "Artist 1", "cover_uri": "https://example.com/artist.jpg"}],
|
"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}],
|
"albums": [{"id": "789", "title": "Test Album", "cover_uri": "https://example.com/album.jpg", "year": 2023}],
|
||||||
"major": {"id": "major1", "name": "Major Label", "description": "Big label"},
|
"major": {"id": "major1", "name": "Major Label", "description": "Big label"},
|
||||||
"lyrics": {"id": "lyr1", "text": "Test lyrics", "available": true, "has_text": true}
|
"lyrics_info": {"has_available_sync_lyrics": true, "has_available_text_lyrics": true}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}`),
|
}`),
|
||||||
@@ -311,7 +311,7 @@ func TestClient_SearchTracks(t *testing.T) {
|
|||||||
"id": "1",
|
"id": "1",
|
||||||
"title": "Track 1",
|
"title": "Track 1",
|
||||||
"duration_ms": 100000,
|
"duration_ms": 100000,
|
||||||
"storage_id": "1",
|
"storage_dir": "1",
|
||||||
"cover_uri": "",
|
"cover_uri": "",
|
||||||
"genre": "",
|
"genre": "",
|
||||||
"version": "",
|
"version": "",
|
||||||
@@ -327,7 +327,7 @@ func TestClient_SearchTracks(t *testing.T) {
|
|||||||
"id": "2",
|
"id": "2",
|
||||||
"title": "Track 2",
|
"title": "Track 2",
|
||||||
"duration_ms": 200000,
|
"duration_ms": 200000,
|
||||||
"storage_id": "2",
|
"storage_dir": "2",
|
||||||
"cover_uri": "",
|
"cover_uri": "",
|
||||||
"genre": "",
|
"genre": "",
|
||||||
"version": "",
|
"version": "",
|
||||||
@@ -408,7 +408,7 @@ func TestClient_SearchTracks_Mocked(t *testing.T) {
|
|||||||
"id": "1",
|
"id": "1",
|
||||||
"title": "Track 1",
|
"title": "Track 1",
|
||||||
"duration_ms": 100000,
|
"duration_ms": 100000,
|
||||||
"storage_id": "1",
|
"storage_dir": "1",
|
||||||
"cover_uri": "",
|
"cover_uri": "",
|
||||||
"genre": "",
|
"genre": "",
|
||||||
"version": "",
|
"version": "",
|
||||||
@@ -424,7 +424,7 @@ func TestClient_SearchTracks_Mocked(t *testing.T) {
|
|||||||
"id": "2",
|
"id": "2",
|
||||||
"title": "Track 2",
|
"title": "Track 2",
|
||||||
"duration_ms": 200000,
|
"duration_ms": 200000,
|
||||||
"storage_id": "2",
|
"storage_dir": "2",
|
||||||
"cover_uri": "",
|
"cover_uri": "",
|
||||||
"genre": "",
|
"genre": "",
|
||||||
"version": "",
|
"version": "",
|
||||||
|
|||||||
+14
-13
@@ -1,10 +1,11 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AccountSettings represents account settings
|
// AccountSettings represents account settings from the Yandex Music API.
|
||||||
type AccountSettings struct {
|
type AccountSettings struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Language string `json:"language"`
|
Language string `json:"language"`
|
||||||
@@ -26,7 +27,7 @@ type AccountSettings struct {
|
|||||||
DownloadOnWifiOnly bool `json:"download_on_wifi_only"`
|
DownloadOnWifiOnly bool `json:"download_on_wifi_only"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes AccountSettings from JSON
|
// DeJSON deserializes AccountSettings from JSON data.
|
||||||
func (a *AccountSettings) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (a *AccountSettings) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -90,7 +91,7 @@ func (a *AccountSettings) DeJSON(data []byte, c ClientInterface) (Model, error)
|
|||||||
return settings, nil
|
return settings, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of AccountSettings
|
// DeList deserializes a list of AccountSettings from JSON data.
|
||||||
func (a *AccountSettings) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (a *AccountSettings) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -108,10 +109,10 @@ func (a *AccountSettings) DeList(data []byte, c ClientInterface) ([]Model, error
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscription represents subscription info
|
// Subscription represents subscription info.
|
||||||
type Subscription struct {
|
type Subscription struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
StartDate string `json:"start_date"`
|
StartDate string `json:"start_date"`
|
||||||
@@ -127,7 +128,7 @@ type Subscription struct {
|
|||||||
TrialUsed bool `json:"trial_used"`
|
TrialUsed bool `json:"trial_used"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes Subscription from JSON
|
// DeJSON deserializes Subscription from JSON data.
|
||||||
func (s *Subscription) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (s *Subscription) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -182,7 +183,7 @@ func (s *Subscription) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
return sub, nil
|
return sub, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Subscriptions
|
// DeList deserializes a list of Subscriptions from JSON data.
|
||||||
func (s *Subscription) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (s *Subscription) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -200,7 +201,7 @@ func (s *Subscription) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PlusInfo represents Plus subscription info (from /account/plus or account status)
|
// PlusInfo represents Plus subscription info.
|
||||||
type PlusInfo struct {
|
type PlusInfo struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
HasPlus bool `json:"has_plus"`
|
HasPlus bool `json:"has_plus"`
|
||||||
@@ -208,7 +209,7 @@ type PlusInfo struct {
|
|||||||
Migrated *bool `json:"migrated,omitempty"`
|
Migrated *bool `json:"migrated,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes PlusInfo from JSON
|
// DeJSON deserializes PlusInfo from JSON data.
|
||||||
func (p *PlusInfo) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (p *PlusInfo) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -232,7 +233,7 @@ func (p *PlusInfo) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
return plus, nil
|
return plus, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of PlusInfo
|
// DeList deserializes a list of PlusInfo from JSON data.
|
||||||
func (p *PlusInfo) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (p *PlusInfo) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -250,7 +251,7 @@ func (p *PlusInfo) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PromoCodeStatus represents promo code status
|
// PromoCodeStatus represents promo code status.
|
||||||
type PromoCodeStatus struct {
|
type PromoCodeStatus struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Code string `json:"code"`
|
Code string `json:"code"`
|
||||||
@@ -262,7 +263,7 @@ type PromoCodeStatus struct {
|
|||||||
Activated bool `json:"activated"`
|
Activated bool `json:"activated"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes PromoCodeStatus from JSON
|
// DeJSON deserializes PromoCodeStatus from JSON data.
|
||||||
func (p *PromoCodeStatus) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (p *PromoCodeStatus) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -296,7 +297,7 @@ func (p *PromoCodeStatus) DeJSON(data []byte, c ClientInterface) (Model, error)
|
|||||||
return promo, nil
|
return promo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of PromoCodeStatus
|
// DeList deserializes a list of PromoCodeStatus from JSON data.
|
||||||
func (p *PromoCodeStatus) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (p *PromoCodeStatus) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
|
|||||||
+283
-29
@@ -1,40 +1,128 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Album represents a full album
|
// Album represents a full album from the Yandex Music API.
|
||||||
type Album struct {
|
type Album struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
|
Error string `json:"error"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
CoverURI string `json:"cover_uri"`
|
|
||||||
Genre string `json:"genre"`
|
|
||||||
Year int `json:"year"`
|
|
||||||
TrackCount int `json:"track_count"`
|
TrackCount int `json:"track_count"`
|
||||||
Available bool `json:"available"`
|
|
||||||
ReleaseDate string `json:"release_date"`
|
|
||||||
Artists []Artist `json:"artists"`
|
Artists []Artist `json:"artists"`
|
||||||
Labels []Label `json:"labels"`
|
Labels []LabelOrString `json:"labels"`
|
||||||
Volumes [][]Track `json:"volumes"`
|
Available bool `json:"available"`
|
||||||
|
AvailableForPremiumUsers bool `json:"available_for_premium_users"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
CoverURI string `json:"cover_uri"`
|
||||||
|
ContentWarning string `json:"content_warning"`
|
||||||
|
OriginalReleaseYear int `json:"original_release_year"`
|
||||||
|
Genre string `json:"genre"`
|
||||||
|
TextColor string `json:"text_color"`
|
||||||
|
ShortDescription string `json:"short_description"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
|
IsPremiere bool `json:"is_premiere"`
|
||||||
|
IsBanner bool `json:"is_banner"`
|
||||||
|
MetaType string `json:"meta_type"`
|
||||||
|
StorageDir string `json:"storage_dir"`
|
||||||
|
OgImage string `json:"og_image"`
|
||||||
|
Buy []json.RawMessage `json:"buy"`
|
||||||
|
Recent bool `json:"recent"`
|
||||||
|
VeryImportant bool `json:"very_important"`
|
||||||
|
AvailableForMobile bool `json:"available_for_mobile"`
|
||||||
|
AvailablePartially bool `json:"available_partially"`
|
||||||
|
Bests []int `json:"bests"`
|
||||||
|
Duplicates []Album `json:"duplicates"`
|
||||||
|
Prerolls []json.RawMessage `json:"prerolls"`
|
||||||
|
Volumes [][]Track `json:"volumes"`
|
||||||
|
Year int `json:"year"`
|
||||||
|
ReleaseDate string `json:"release_date"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
TrackPosition *TrackPosition `json:"track_position"`
|
||||||
|
Regions []string `json:"regions"`
|
||||||
|
AvailableAsRbt bool `json:"available_as_rbt"`
|
||||||
|
LyricsAvailable bool `json:"lyrics_available"`
|
||||||
|
RememberPosition bool `json:"remember_position"`
|
||||||
|
Albums []Album `json:"albums"`
|
||||||
|
DurationMs int `json:"duration_ms"`
|
||||||
|
Explicit bool `json:"explicit"`
|
||||||
|
StartDate string `json:"start_date"`
|
||||||
|
LikesCount int `json:"likes_count"`
|
||||||
|
Deprecation *Deprecation `json:"deprecation"`
|
||||||
|
AvailableRegions []string `json:"available_regions"`
|
||||||
|
AvailableForOptions []string `json:"available_for_options"`
|
||||||
|
ListeningFinished bool `json:"listening_finished"`
|
||||||
|
Disclaimers []string `json:"disclaimers"`
|
||||||
|
ActionButton *AlbumActionButton `json:"action_button"`
|
||||||
|
Cover *Cover `json:"cover"`
|
||||||
|
DerivedColors *CoverDerivedColors `json:"derived_colors"`
|
||||||
|
MetaTagID string `json:"meta_tag_id"`
|
||||||
|
ChildContent bool `json:"child_content"`
|
||||||
|
BackgroundImageURL string `json:"background_image_url"`
|
||||||
|
CustomWave *CustomWave `json:"custom_wave"`
|
||||||
|
DurationSec int `json:"duration_sec"`
|
||||||
|
HasTrailer bool `json:"has_trailer"`
|
||||||
|
Trailer *AlbumTrailerStatus `json:"trailer"`
|
||||||
|
Pager *Pager `json:"pager"`
|
||||||
|
SortOrder string `json:"sort_order"`
|
||||||
Meta *AlbumMeta `json:"meta"`
|
Meta *AlbumMeta `json:"meta"`
|
||||||
Best *Best `json:"best"`
|
Best *Best `json:"best"`
|
||||||
// Additional fields
|
|
||||||
Region string `json:"region"`
|
Region string `json:"region"`
|
||||||
AvailableForPremiumUsers bool `json:"available_for_premium_users"`
|
|
||||||
AvailableForPremiumUsersOnly bool `json:"available_for_premium_users_only"`
|
AvailableForPremiumUsersOnly bool `json:"available_for_premium_users_only"`
|
||||||
ContentWarning string `json:"content_warning"`
|
|
||||||
Label string `json:"label"`
|
Label string `json:"label"`
|
||||||
CatalogNumber string `json:"catalog_number"`
|
CatalogNumber string `json:"catalog_number"`
|
||||||
Options []string `json:"options"`
|
Options []string `json:"options"`
|
||||||
TrackPositions []TrackPosition `json:"track_positions"`
|
TrackPositions []TrackPosition `json:"track_positions"`
|
||||||
SimilarAlbums []Album `json:"similar_albums"`
|
SimilarAlbums []Album `json:"similar_albums"`
|
||||||
Trailer *TrailerInfo `json:"trailer"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes an Album from JSON
|
// LabelOrString represents a label that can be either a Label object or a string.
|
||||||
|
type LabelOrString struct {
|
||||||
|
Label *Label `json:"-"`
|
||||||
|
Str string `json:"-"`
|
||||||
|
IsStr bool `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaler, accepting both Label objects and strings.
|
||||||
|
func (l *LabelOrString) UnmarshalJSON(data []byte) error {
|
||||||
|
var s string
|
||||||
|
if err := json.Unmarshal(data, &s); err == nil {
|
||||||
|
l.Str = s
|
||||||
|
l.IsStr = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var label Label
|
||||||
|
if err := json.Unmarshal(data, &label); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
l.Label = &label
|
||||||
|
l.IsStr = false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements json.Marshaler.
|
||||||
|
func (l LabelOrString) MarshalJSON() ([]byte, error) {
|
||||||
|
if l.IsStr {
|
||||||
|
return json.Marshal(l.Str)
|
||||||
|
}
|
||||||
|
return json.Marshal(l.Label)
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the label as a string.
|
||||||
|
func (l LabelOrString) String() string {
|
||||||
|
if l.IsStr {
|
||||||
|
return l.Str
|
||||||
|
}
|
||||||
|
if l.Label != nil {
|
||||||
|
return l.Label.Name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes an Album from JSON data.
|
||||||
func (a *Album) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (a *Album) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -47,6 +135,9 @@ func (a *Album) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
if v, ok := raw["id"]; ok {
|
if v, ok := raw["id"]; ok {
|
||||||
json.Unmarshal(v, &album.ID)
|
json.Unmarshal(v, &album.ID)
|
||||||
}
|
}
|
||||||
|
if v, ok := raw["error"]; ok {
|
||||||
|
json.Unmarshal(v, &album.Error)
|
||||||
|
}
|
||||||
if v, ok := raw["title"]; ok {
|
if v, ok := raw["title"]; ok {
|
||||||
json.Unmarshal(v, &album.Title)
|
json.Unmarshal(v, &album.Title)
|
||||||
}
|
}
|
||||||
@@ -100,10 +191,11 @@ func (a *Album) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
album.Artists = artists
|
album.Artists = artists
|
||||||
}
|
}
|
||||||
if v, ok := raw["labels"]; ok {
|
if v, ok := raw["labels"]; ok {
|
||||||
var labels []Label
|
var labels []LabelOrString
|
||||||
json.Unmarshal(v, &labels)
|
if err := json.Unmarshal(v, &labels); err == nil {
|
||||||
album.Labels = labels
|
album.Labels = labels
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if v, ok := raw["volumes"]; ok {
|
if v, ok := raw["volumes"]; ok {
|
||||||
var volumes [][]Track
|
var volumes [][]Track
|
||||||
json.Unmarshal(v, &volumes)
|
json.Unmarshal(v, &volumes)
|
||||||
@@ -130,7 +222,7 @@ func (a *Album) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
album.SimilarAlbums = similar
|
album.SimilarAlbums = similar
|
||||||
}
|
}
|
||||||
if v, ok := raw["trailer"]; ok {
|
if v, ok := raw["trailer"]; ok {
|
||||||
var trailer TrailerInfo
|
var trailer AlbumTrailerStatus
|
||||||
json.Unmarshal(v, &trailer)
|
json.Unmarshal(v, &trailer)
|
||||||
album.Trailer = &trailer
|
album.Trailer = &trailer
|
||||||
}
|
}
|
||||||
@@ -138,7 +230,7 @@ func (a *Album) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
return album, nil
|
return album, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Albums
|
// DeList deserializes a list of Albums from JSON data.
|
||||||
func (a *Album) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (a *Album) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -156,14 +248,14 @@ func (a *Album) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AlbumMeta represents album metadata
|
// AlbumMeta represents album metadata.
|
||||||
type AlbumMeta struct {
|
type AlbumMeta struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Availability *Availability `json:"availability"`
|
Availability *Availability `json:"availability"`
|
||||||
Upsell *Upsell `json:"upsell"`
|
Upsell *Upsell `json:"upsell"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes an AlbumMeta from JSON
|
// DeJSON deserializes an AlbumMeta from JSON data.
|
||||||
func (am *AlbumMeta) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (am *AlbumMeta) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -186,7 +278,7 @@ func (am *AlbumMeta) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
return meta, nil
|
return meta, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of AlbumMeta
|
// DeList deserializes a list of AlbumMeta from JSON data.
|
||||||
func (am *AlbumMeta) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (am *AlbumMeta) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -204,33 +296,33 @@ func (am *AlbumMeta) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Availability represents availability info
|
// Availability represents availability info for an album.
|
||||||
type Availability struct {
|
type Availability struct {
|
||||||
AvailableForPremiumUsers bool `json:"available_for_premium_users"`
|
AvailableForPremiumUsers bool `json:"available_for_premium_users"`
|
||||||
Territories []string `json:"territories"`
|
Territories []string `json:"territories"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upsell represents upsell info
|
// Upsell represents upsell info for an album.
|
||||||
type Upsell struct {
|
type Upsell struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Best represents best tracks info
|
// Best represents best tracks info for an album.
|
||||||
type Best struct {
|
type Best struct {
|
||||||
Tracks []Track `json:"tracks"`
|
Tracks []Track `json:"tracks"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrailerInfo represents album/track trailer info
|
// TrailerInfo represents album/track trailer info.
|
||||||
type TrailerInfo struct {
|
type TrailerInfo struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
PreviewURI string `json:"preview_uri"`
|
PreviewURI string `json:"preview_uri"`
|
||||||
TrackID string `json:"track_id"`
|
TrackID JSONID `json:"track_id"`
|
||||||
AlbumID string `json:"album_id"`
|
AlbumID JSONID `json:"album_id"`
|
||||||
Duration int `json:"duration"`
|
Duration int `json:"duration"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a TrailerInfo from JSON
|
// DeJSON deserializes a TrailerInfo from JSON data.
|
||||||
func (ti *TrailerInfo) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (ti *TrailerInfo) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -255,7 +347,7 @@ func (ti *TrailerInfo) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
return trailer, nil
|
return trailer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of TrailerInfo
|
// DeList deserializes a list of TrailerInfo from JSON data.
|
||||||
func (ti *TrailerInfo) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (ti *TrailerInfo) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -272,3 +364,165 @@ func (ti *TrailerInfo) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
|||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AlbumTrailerStatus represents trailer availability status for an album.
|
||||||
|
type AlbumTrailerStatus struct {
|
||||||
|
BaseModel
|
||||||
|
Available bool `json:"available"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes AlbumTrailerStatus from JSON data.
|
||||||
|
func (ats *AlbumTrailerStatus) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
status := &AlbumTrailerStatus{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["available"]; ok {
|
||||||
|
json.Unmarshal(v, &status.Available)
|
||||||
|
}
|
||||||
|
|
||||||
|
return status, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of AlbumTrailerStatus from JSON data.
|
||||||
|
func (ats *AlbumTrailerStatus) 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 {
|
||||||
|
status := &AlbumTrailerStatus{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, status); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, status)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecation represents album deprecation info.
|
||||||
|
type Deprecation struct {
|
||||||
|
BaseModel
|
||||||
|
TargetAlbumID JSONID `json:"target_album_id"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Done bool `json:"done"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AlbumActionButton represents an action button for an album.
|
||||||
|
type AlbumActionButton struct {
|
||||||
|
BaseModel
|
||||||
|
Text string `json:"text"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
Color string `json:"color"`
|
||||||
|
ViewBrowser bool `json:"view_browser"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AlbumSimilarEntities represents similar entities for an album.
|
||||||
|
type AlbumSimilarEntities struct {
|
||||||
|
BaseModel
|
||||||
|
Items []SimilarEntityItem `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes AlbumSimilarEntities from JSON data.
|
||||||
|
func (ae *AlbumSimilarEntities) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
entities := &AlbumSimilarEntities{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["items"]; ok {
|
||||||
|
var items []SimilarEntityItem
|
||||||
|
json.Unmarshal(v, &items)
|
||||||
|
entities.Items = items
|
||||||
|
}
|
||||||
|
|
||||||
|
return entities, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of AlbumSimilarEntities from JSON data.
|
||||||
|
func (ae *AlbumSimilarEntities) 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 {
|
||||||
|
entities := &AlbumSimilarEntities{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, entities); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, entities)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimilarEntityItem represents a similar entity item.
|
||||||
|
type SimilarEntityItem struct {
|
||||||
|
BaseModel
|
||||||
|
ID JSONID `json:"id"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Data json.RawMessage `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AlbumTrailer represents album trailer info.
|
||||||
|
type AlbumTrailer struct {
|
||||||
|
BaseModel
|
||||||
|
Album *Album `json:"album"`
|
||||||
|
Artists []Artist `json:"artists"`
|
||||||
|
Trailer *TrailerInfo `json:"trailer"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes AlbumTrailer from JSON data.
|
||||||
|
func (at *AlbumTrailer) 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 := &AlbumTrailer{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["album"]; ok {
|
||||||
|
var album Album
|
||||||
|
json.Unmarshal(v, &album)
|
||||||
|
trailer.Album = &album
|
||||||
|
}
|
||||||
|
if v, ok := raw["artists"]; ok {
|
||||||
|
var artists []Artist
|
||||||
|
json.Unmarshal(v, &artists)
|
||||||
|
trailer.Artists = artists
|
||||||
|
}
|
||||||
|
if v, ok := raw["trailer"]; ok {
|
||||||
|
var trailerInfo TrailerInfo
|
||||||
|
json.Unmarshal(v, &trailerInfo)
|
||||||
|
trailer.Trailer = &trailerInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
return trailer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of AlbumTrailer from JSON data.
|
||||||
|
func (at *AlbumTrailer) 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 := &AlbumTrailer{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, trailer); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, trailer)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ func TestAlbum_DeJSON(t *testing.T) {
|
|||||||
"best": {"tracks": [{"id": "bt1", "title": "Best Track", "duration_ms": 200000}]},
|
"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}],
|
"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}],
|
"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}
|
"trailer": {"available": true}
|
||||||
}`)
|
}`)
|
||||||
|
|
||||||
album := &Album{BaseModel: *NewBaseModel(client)}
|
album := &Album{BaseModel: *NewBaseModel(client)}
|
||||||
@@ -101,8 +101,8 @@ func TestAlbum_DeJSON(t *testing.T) {
|
|||||||
if len(resultAlbum.Labels) != 1 {
|
if len(resultAlbum.Labels) != 1 {
|
||||||
t.Errorf("Expected 1 label, got %d", len(resultAlbum.Labels))
|
t.Errorf("Expected 1 label, got %d", len(resultAlbum.Labels))
|
||||||
}
|
}
|
||||||
if resultAlbum.Labels[0].Name != "Label 1" {
|
if resultAlbum.Labels[0].String() != "Label 1" {
|
||||||
t.Errorf("Expected label name 'Label 1', got '%s'", resultAlbum.Labels[0].Name)
|
t.Errorf("Expected label name 'Label 1', got '%s'", resultAlbum.Labels[0].String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test volumes
|
// Test volumes
|
||||||
@@ -164,17 +164,8 @@ func TestAlbum_DeJSON(t *testing.T) {
|
|||||||
if resultAlbum.Trailer == nil {
|
if resultAlbum.Trailer == nil {
|
||||||
t.Fatal("Expected Trailer to be non-nil")
|
t.Fatal("Expected Trailer to be non-nil")
|
||||||
}
|
}
|
||||||
if resultAlbum.Trailer.PreviewURI != "https://example.com/preview.mp3" {
|
if !resultAlbum.Trailer.Available {
|
||||||
t.Errorf("Expected PreviewURI 'https://example.com/preview.mp3', got '%s'", resultAlbum.Trailer.PreviewURI)
|
t.Errorf("Expected Trailer.Available true, got false")
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,50 +299,38 @@ func TestAlbumMeta_DeList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTrailerInfo_DeJSON(t *testing.T) {
|
func TestAlbumTrailerStatus_DeJSON(t *testing.T) {
|
||||||
client := newMockClient()
|
client := newMockClient()
|
||||||
data := []byte(`{
|
data := []byte(`{
|
||||||
"preview_uri": "https://example.com/preview.mp3",
|
"available": true
|
||||||
"track_id": "track123",
|
|
||||||
"album_id": "album456",
|
|
||||||
"duration": 45
|
|
||||||
}`)
|
}`)
|
||||||
|
|
||||||
trailer := &TrailerInfo{BaseModel: *NewBaseModel(client)}
|
status := &AlbumTrailerStatus{BaseModel: *NewBaseModel(client)}
|
||||||
result, err := trailer.DeJSON(data, client)
|
result, err := status.DeJSON(data, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("DeJSON failed: %v", err)
|
t.Fatalf("DeJSON failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
resultTrailer := result.(*TrailerInfo)
|
resultStatus := result.(*AlbumTrailerStatus)
|
||||||
if resultTrailer.PreviewURI != "https://example.com/preview.mp3" {
|
if !resultStatus.Available {
|
||||||
t.Errorf("Expected PreviewURI 'https://example.com/preview.mp3', got '%s'", resultTrailer.PreviewURI)
|
t.Errorf("Expected Available true, got false")
|
||||||
}
|
|
||||||
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) {
|
func TestAlbumTrailerStatus_DeList(t *testing.T) {
|
||||||
client := newMockClient()
|
client := newMockClient()
|
||||||
data := []byte(`[
|
data := []byte(`[
|
||||||
{"preview_uri": "https://example.com/preview1.mp3", "track_id": "t1", "album_id": "a1", "duration": 30},
|
{"available": true},
|
||||||
{"preview_uri": "https://example.com/preview2.mp3", "track_id": "t2", "album_id": "a2", "duration": 45}
|
{"available": false}
|
||||||
]`)
|
]`)
|
||||||
|
|
||||||
trailer := &TrailerInfo{BaseModel: *NewBaseModel(client)}
|
status := &AlbumTrailerStatus{BaseModel: *NewBaseModel(client)}
|
||||||
result, err := trailer.DeList(data, client)
|
result, err := status.DeList(data, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("DeList failed: %v", err)
|
t.Fatalf("DeList failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(result) != 2 {
|
if len(result) != 2 {
|
||||||
t.Errorf("Expected 2 trailers, got %d", len(result))
|
t.Errorf("Expected 2 statuses, got %d", len(result))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+561
-41
@@ -1,32 +1,32 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Artist represents a full artist
|
// Artist represents a full artist from the Yandex Music API.
|
||||||
type Artist struct {
|
type Artist struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
CoverURI string `json:"cover_uri"`
|
CoverURI string `json:"cover_uri"`
|
||||||
Genres []string `json:"genres"`
|
Genres []string `json:"genres"`
|
||||||
Tracks int `json:"tracks"`
|
Tracks int `json:"tracks"`
|
||||||
Albums int `json:"albums"`
|
Albums int `json:"albums"`
|
||||||
Link string `json:"link"`
|
|
||||||
Available bool `json:"available"`
|
Available bool `json:"available"`
|
||||||
Description string `json:"description"`
|
|
||||||
Composer bool `json:"composer"`
|
Composer bool `json:"composer"`
|
||||||
Various bool `json:"various"`
|
Various bool `json:"various"`
|
||||||
Decomposed []Artist `json:"decomposed"`
|
Decomposed []Decomposed `json:"decomposed"`
|
||||||
Ratings *Ratings `json:"ratings"`
|
Ratings *Ratings `json:"ratings"`
|
||||||
Counts *Counts `json:"counts"`
|
Counts *Counts `json:"counts"`
|
||||||
SocialLinks []SocialLink `json:"social_links"`
|
Links []Link `json:"social_links"`
|
||||||
|
Description *Description `json:"description"`
|
||||||
// Additional fields
|
// Additional fields
|
||||||
IDForFrom string `json:"id_for_from"`
|
IDForFrom string `json:"id_for_from"`
|
||||||
Cover *Cover `json:"cover"`
|
Cover *Cover `json:"cover"`
|
||||||
BriefInfo *ArtistBriefInfo `json:"brief_info"`
|
BriefInfo *ArtistBriefInfo `json:"brief_info"`
|
||||||
Donations *ArtistDonations `json:"donations"`
|
DonationInfo *ArtistDonationInfo `json:"donation_info"`
|
||||||
Concerts []Concert `json:"concerts"`
|
Concerts []Concert `json:"concerts"`
|
||||||
Clips []Clip `json:"clips"`
|
Clips []Clip `json:"clips"`
|
||||||
Similar []Artist `json:"similar"`
|
Similar []Artist `json:"similar"`
|
||||||
@@ -34,7 +34,7 @@ type Artist struct {
|
|||||||
TracksData []Track `json:"tracks_data"`
|
TracksData []Track `json:"tracks_data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes an Artist from JSON
|
// DeJSON deserializes an Artist from JSON data.
|
||||||
func (a *Artist) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (a *Artist) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -62,15 +62,9 @@ func (a *Artist) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
if v, ok := raw["albums"]; ok {
|
if v, ok := raw["albums"]; ok {
|
||||||
json.Unmarshal(v, &artist.Albums)
|
json.Unmarshal(v, &artist.Albums)
|
||||||
}
|
}
|
||||||
if v, ok := raw["link"]; ok {
|
|
||||||
json.Unmarshal(v, &artist.Link)
|
|
||||||
}
|
|
||||||
if v, ok := raw["available"]; ok {
|
if v, ok := raw["available"]; ok {
|
||||||
json.Unmarshal(v, &artist.Available)
|
json.Unmarshal(v, &artist.Available)
|
||||||
}
|
}
|
||||||
if v, ok := raw["description"]; ok {
|
|
||||||
json.Unmarshal(v, &artist.Description)
|
|
||||||
}
|
|
||||||
if v, ok := raw["composer"]; ok {
|
if v, ok := raw["composer"]; ok {
|
||||||
json.Unmarshal(v, &artist.Composer)
|
json.Unmarshal(v, &artist.Composer)
|
||||||
}
|
}
|
||||||
@@ -83,10 +77,11 @@ func (a *Artist) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
|
|
||||||
// Nested objects
|
// Nested objects
|
||||||
if v, ok := raw["decomposed"]; ok {
|
if v, ok := raw["decomposed"]; ok {
|
||||||
var decomposed []Artist
|
var decomposed []Decomposed
|
||||||
json.Unmarshal(v, &decomposed)
|
if err := json.Unmarshal(v, &decomposed); err == nil {
|
||||||
artist.Decomposed = decomposed
|
artist.Decomposed = decomposed
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if v, ok := raw["ratings"]; ok {
|
if v, ok := raw["ratings"]; ok {
|
||||||
var ratings Ratings
|
var ratings Ratings
|
||||||
json.Unmarshal(v, &ratings)
|
json.Unmarshal(v, &ratings)
|
||||||
@@ -98,9 +93,10 @@ func (a *Artist) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
artist.Counts = &counts
|
artist.Counts = &counts
|
||||||
}
|
}
|
||||||
if v, ok := raw["social_links"]; ok {
|
if v, ok := raw["social_links"]; ok {
|
||||||
var links []SocialLink
|
var links []Link
|
||||||
json.Unmarshal(v, &links)
|
if err := json.Unmarshal(v, &links); err == nil {
|
||||||
artist.SocialLinks = links
|
artist.Links = links
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if v, ok := raw["cover"]; ok {
|
if v, ok := raw["cover"]; ok {
|
||||||
var cover Cover
|
var cover Cover
|
||||||
@@ -112,10 +108,10 @@ func (a *Artist) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
json.Unmarshal(v, &brief)
|
json.Unmarshal(v, &brief)
|
||||||
artist.BriefInfo = &brief
|
artist.BriefInfo = &brief
|
||||||
}
|
}
|
||||||
if v, ok := raw["donations"]; ok {
|
if v, ok := raw["donation_info"]; ok {
|
||||||
var donations ArtistDonations
|
var donation ArtistDonationInfo
|
||||||
json.Unmarshal(v, &donations)
|
json.Unmarshal(v, &donation)
|
||||||
artist.Donations = &donations
|
artist.DonationInfo = &donation
|
||||||
}
|
}
|
||||||
if v, ok := raw["concerts"]; ok {
|
if v, ok := raw["concerts"]; ok {
|
||||||
var concerts []Concert
|
var concerts []Concert
|
||||||
@@ -146,7 +142,7 @@ func (a *Artist) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
return artist, nil
|
return artist, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Artists
|
// DeList deserializes a list of Artists from JSON data.
|
||||||
func (a *Artist) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (a *Artist) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -164,27 +160,29 @@ func (a *Artist) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ratings represents artist ratings
|
// Ratings represents artist ratings.
|
||||||
type Ratings struct {
|
type Ratings struct {
|
||||||
Rating float64 `json:"rating"`
|
Rating int `json:"rating"`
|
||||||
Votes int `json:"votes"`
|
Votes int `json:"votes"`
|
||||||
|
Week int `json:"week"`
|
||||||
|
Day int `json:"day"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Counts represents artist counts
|
// Counts represents artist counts.
|
||||||
type Counts struct {
|
type Counts struct {
|
||||||
Tracks int `json:"tracks"`
|
Tracks int `json:"tracks"`
|
||||||
Albums int `json:"albums"`
|
Albums int `json:"albums"`
|
||||||
Folders int `json:"folders"`
|
Folders int `json:"folders"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SocialLink represents a social media link
|
// SocialLink represents a social media link.
|
||||||
type SocialLink struct {
|
type SocialLink struct {
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cover represents cover image info
|
// Cover represents cover image info.
|
||||||
type Cover struct {
|
type Cover struct {
|
||||||
URI string `json:"uri"`
|
URI string `json:"uri"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
@@ -193,23 +191,25 @@ type Cover struct {
|
|||||||
Background string `json:"background"`
|
Background string `json:"background"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ArtistBriefInfo represents brief artist info
|
// ArtistBriefInfo represents brief artist info.
|
||||||
type ArtistBriefInfo struct {
|
type ArtistBriefInfo struct {
|
||||||
|
BaseModel
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Available bool `json:"available"`
|
Available bool `json:"available"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ArtistDonations represents artist donations info
|
// ArtistDonations represents artist donations info.
|
||||||
type ArtistDonations struct {
|
type ArtistDonations struct {
|
||||||
|
BaseModel
|
||||||
Items []DonationItem `json:"items"`
|
Items []DonationItem `json:"items"`
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
Goal int `json:"goal"`
|
Goal int `json:"goal"`
|
||||||
Raised int `json:"raised"`
|
Raised int `json:"raised"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DonationItem represents a donation item
|
// DonationItem represents a donation item.
|
||||||
type DonationItem struct {
|
type DonationItem struct {
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Amount int `json:"amount"`
|
Amount int `json:"amount"`
|
||||||
@@ -218,10 +218,182 @@ type DonationItem struct {
|
|||||||
Currency string `json:"currency"`
|
Currency string `json:"currency"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConcertShort represents a concert (minimal for artist)
|
// Decomposed represents a decomposed artist that can be either a string or an Artist object.
|
||||||
|
type Decomposed struct {
|
||||||
|
Artist *Artist `json:"-"`
|
||||||
|
Str string `json:"-"`
|
||||||
|
IsStr bool `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaler, accepting both string and Artist object.
|
||||||
|
func (d *Decomposed) UnmarshalJSON(data []byte) error {
|
||||||
|
var s string
|
||||||
|
if err := json.Unmarshal(data, &s); err == nil {
|
||||||
|
d.Str = s
|
||||||
|
d.IsStr = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var artist Artist
|
||||||
|
if err := json.Unmarshal(data, &artist); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.Artist = &artist
|
||||||
|
d.IsStr = false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements json.Marshaler.
|
||||||
|
func (d Decomposed) MarshalJSON() ([]byte, error) {
|
||||||
|
if d.IsStr {
|
||||||
|
return json.Marshal(d.Str)
|
||||||
|
}
|
||||||
|
return json.Marshal(d.Artist)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Link represents a link to an artist's official page or social network.
|
||||||
|
type Link struct {
|
||||||
|
BaseModel
|
||||||
|
Title string `json:"title"`
|
||||||
|
Href string `json:"href"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
SocialNetwork string `json:"social_network"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes Link from JSON data.
|
||||||
|
func (l *Link) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
link := &Link{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["title"]; ok {
|
||||||
|
json.Unmarshal(v, &link.Title)
|
||||||
|
}
|
||||||
|
if v, ok := raw["href"]; ok {
|
||||||
|
json.Unmarshal(v, &link.Href)
|
||||||
|
}
|
||||||
|
if v, ok := raw["type"]; ok {
|
||||||
|
json.Unmarshal(v, &link.Type)
|
||||||
|
}
|
||||||
|
if v, ok := raw["social_network"]; ok {
|
||||||
|
json.Unmarshal(v, &link.SocialNetwork)
|
||||||
|
}
|
||||||
|
|
||||||
|
return link, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of Links from JSON data.
|
||||||
|
func (l *Link) 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 {
|
||||||
|
link := &Link{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, link); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, link)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Description represents artist description.
|
||||||
|
type Description struct {
|
||||||
|
BaseModel
|
||||||
|
Text string `json:"text"`
|
||||||
|
URI string `json:"uri"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes Description from JSON data.
|
||||||
|
func (d *Description) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
desc := &Description{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["text"]; ok {
|
||||||
|
json.Unmarshal(v, &desc.Text)
|
||||||
|
}
|
||||||
|
if v, ok := raw["uri"]; ok {
|
||||||
|
json.Unmarshal(v, &desc.URI)
|
||||||
|
}
|
||||||
|
|
||||||
|
return desc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of Descriptions from JSON data.
|
||||||
|
func (d *Description) 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 {
|
||||||
|
desc := &Description{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, desc); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, desc)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArtistDonationInfo represents artist donation info.
|
||||||
|
type ArtistDonationInfo struct {
|
||||||
|
BaseModel
|
||||||
|
Title string `json:"title"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes ArtistDonationInfo from JSON data.
|
||||||
|
func (adi *ArtistDonationInfo) 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 := &ArtistDonationInfo{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["title"]; ok {
|
||||||
|
json.Unmarshal(v, &info.Title)
|
||||||
|
}
|
||||||
|
if v, ok := raw["url"]; ok {
|
||||||
|
json.Unmarshal(v, &info.URL)
|
||||||
|
}
|
||||||
|
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of ArtistDonationInfo from JSON data.
|
||||||
|
func (adi *ArtistDonationInfo) 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 := &ArtistDonationInfo{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, info); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, info)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConcertShort represents a concert (minimal for artist).
|
||||||
type ConcertShort struct {
|
type ConcertShort struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Date string `json:"date"`
|
Date string `json:"date"`
|
||||||
Venue string `json:"venue"`
|
Venue string `json:"venue"`
|
||||||
@@ -233,7 +405,7 @@ type ConcertShort struct {
|
|||||||
Available bool `json:"available"`
|
Available bool `json:"available"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a ConcertShort from JSON
|
// DeJSON deserializes a ConcertShort from JSON data.
|
||||||
func (c *ConcertShort) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (c *ConcertShort) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -276,7 +448,7 @@ func (c *ConcertShort) DeJSON(data []byte, client ClientInterface) (Model, error
|
|||||||
return concert, nil
|
return concert, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of ConcertShort
|
// DeList deserializes a list of ConcertShort from JSON data.
|
||||||
func (c *ConcertShort) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (c *ConcertShort) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -294,10 +466,10 @@ func (c *ConcertShort) DeList(data []byte, client ClientInterface) ([]Model, err
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClipShort represents a clip (minimal for artist)
|
// ClipShort represents a clip (minimal for artist).
|
||||||
type ClipShort struct {
|
type ClipShort struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Duration int `json:"duration"`
|
Duration int `json:"duration"`
|
||||||
CoverURI string `json:"cover_uri"`
|
CoverURI string `json:"cover_uri"`
|
||||||
@@ -308,7 +480,7 @@ type ClipShort struct {
|
|||||||
CreatedAt string `json:"created_at"`
|
CreatedAt string `json:"created_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a ClipShort from JSON
|
// DeJSON deserializes a ClipShort from JSON data.
|
||||||
func (c *ClipShort) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (c *ClipShort) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -348,7 +520,7 @@ func (c *ClipShort) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
|||||||
return clip, nil
|
return clip, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of ClipShort
|
// DeList deserializes a list of ClipShort from JSON data.
|
||||||
func (c *ClipShort) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (c *ClipShort) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -365,3 +537,351 @@ func (c *ClipShort) DeList(data []byte, client ClientInterface) ([]Model, error)
|
|||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ArtistSimilar represents similar artists.
|
||||||
|
type ArtistSimilar struct {
|
||||||
|
BaseModel
|
||||||
|
Artist *Artist `json:"artist"`
|
||||||
|
SimilarArtists []Artist `json:"similar_artists"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes ArtistSimilar from JSON data.
|
||||||
|
func (as *ArtistSimilar) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
similar := &ArtistSimilar{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["artist"]; ok {
|
||||||
|
var artist Artist
|
||||||
|
json.Unmarshal(v, &artist)
|
||||||
|
similar.Artist = &artist
|
||||||
|
}
|
||||||
|
if v, ok := raw["similar_artists"]; ok {
|
||||||
|
var artists []Artist
|
||||||
|
json.Unmarshal(v, &artists)
|
||||||
|
similar.SimilarArtists = artists
|
||||||
|
}
|
||||||
|
|
||||||
|
return similar, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of ArtistSimilar from JSON data.
|
||||||
|
func (as *ArtistSimilar) 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 {
|
||||||
|
similar := &ArtistSimilar{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, similar); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, similar)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArtistLinks represents links to artist's official pages or social networks.
|
||||||
|
type ArtistLinks struct {
|
||||||
|
BaseModel
|
||||||
|
Links []Link `json:"links"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes ArtistLinks from JSON data.
|
||||||
|
func (al *ArtistLinks) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
links := &ArtistLinks{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["links"]; ok {
|
||||||
|
var linkList []Link
|
||||||
|
json.Unmarshal(v, &linkList)
|
||||||
|
links.Links = linkList
|
||||||
|
}
|
||||||
|
|
||||||
|
return links, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of ArtistLinks from JSON data.
|
||||||
|
func (al *ArtistLinks) 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 {
|
||||||
|
links := &ArtistLinks{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, links); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, links)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArtistAbout represents information "About artist".
|
||||||
|
type ArtistAbout struct {
|
||||||
|
BaseModel
|
||||||
|
Artist *Artist `json:"artist"`
|
||||||
|
Stats *Stats `json:"stats"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Links []ArtistLink `json:"links"`
|
||||||
|
Covers []Cover `json:"covers"`
|
||||||
|
ArtistType string `json:"artist_type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes ArtistAbout from JSON data.
|
||||||
|
func (aa *ArtistAbout) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
about := &ArtistAbout{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["artist"]; ok {
|
||||||
|
var artist Artist
|
||||||
|
json.Unmarshal(v, &artist)
|
||||||
|
about.Artist = &artist
|
||||||
|
}
|
||||||
|
if v, ok := raw["stats"]; ok {
|
||||||
|
var stats Stats
|
||||||
|
json.Unmarshal(v, &stats)
|
||||||
|
about.Stats = &stats
|
||||||
|
}
|
||||||
|
if v, ok := raw["description"]; ok {
|
||||||
|
json.Unmarshal(v, &about.Description)
|
||||||
|
}
|
||||||
|
if v, ok := raw["links"]; ok {
|
||||||
|
var linkList []ArtistLink
|
||||||
|
json.Unmarshal(v, &linkList)
|
||||||
|
about.Links = linkList
|
||||||
|
}
|
||||||
|
if v, ok := raw["covers"]; ok {
|
||||||
|
var covers []Cover
|
||||||
|
json.Unmarshal(v, &covers)
|
||||||
|
about.Covers = covers
|
||||||
|
}
|
||||||
|
if v, ok := raw["artist_type"]; ok {
|
||||||
|
json.Unmarshal(v, &about.ArtistType)
|
||||||
|
}
|
||||||
|
|
||||||
|
return about, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of ArtistAbout from JSON data.
|
||||||
|
func (aa *ArtistAbout) 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 {
|
||||||
|
about := &ArtistAbout{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, about); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, about)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArtistInfo represents detailed artist info.
|
||||||
|
type ArtistInfo struct {
|
||||||
|
BaseModel
|
||||||
|
Artist *Artist `json:"artist"`
|
||||||
|
LikesCount int `json:"likes_count"`
|
||||||
|
Stats *Stats `json:"stats"`
|
||||||
|
Trailer *ArtistTrailerStatus `json:"trailer"`
|
||||||
|
Covers []Cover `json:"covers"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
ArtistType string `json:"artist_type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes ArtistInfo from JSON data.
|
||||||
|
func (ai *ArtistInfo) 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 := &ArtistInfo{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["artist"]; ok {
|
||||||
|
var artist Artist
|
||||||
|
json.Unmarshal(v, &artist)
|
||||||
|
info.Artist = &artist
|
||||||
|
}
|
||||||
|
if v, ok := raw["likes_count"]; ok {
|
||||||
|
json.Unmarshal(v, &info.LikesCount)
|
||||||
|
}
|
||||||
|
if v, ok := raw["stats"]; ok {
|
||||||
|
var stats Stats
|
||||||
|
json.Unmarshal(v, &stats)
|
||||||
|
info.Stats = &stats
|
||||||
|
}
|
||||||
|
if v, ok := raw["trailer"]; ok {
|
||||||
|
var trailer ArtistTrailerStatus
|
||||||
|
json.Unmarshal(v, &trailer)
|
||||||
|
info.Trailer = &trailer
|
||||||
|
}
|
||||||
|
if v, ok := raw["covers"]; ok {
|
||||||
|
var covers []Cover
|
||||||
|
json.Unmarshal(v, &covers)
|
||||||
|
info.Covers = covers
|
||||||
|
}
|
||||||
|
if v, ok := raw["description"]; ok {
|
||||||
|
json.Unmarshal(v, &info.Description)
|
||||||
|
}
|
||||||
|
if v, ok := raw["artist_type"]; ok {
|
||||||
|
json.Unmarshal(v, &info.ArtistType)
|
||||||
|
}
|
||||||
|
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of ArtistInfo from JSON data.
|
||||||
|
func (ai *ArtistInfo) 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 := &ArtistInfo{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, info); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, info)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArtistSkeleton represents artist page skeleton.
|
||||||
|
type ArtistSkeleton struct {
|
||||||
|
BaseModel
|
||||||
|
ID string `json:"id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Blocks []SkeletonBlock `json:"blocks"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes ArtistSkeleton from JSON data.
|
||||||
|
func (as *ArtistSkeleton) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
skeleton := &ArtistSkeleton{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["id"]; ok {
|
||||||
|
json.Unmarshal(v, &skeleton.ID)
|
||||||
|
}
|
||||||
|
if v, ok := raw["title"]; ok {
|
||||||
|
json.Unmarshal(v, &skeleton.Title)
|
||||||
|
}
|
||||||
|
if v, ok := raw["blocks"]; ok {
|
||||||
|
var blocks []SkeletonBlock
|
||||||
|
json.Unmarshal(v, &blocks)
|
||||||
|
skeleton.Blocks = blocks
|
||||||
|
}
|
||||||
|
|
||||||
|
return skeleton, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of ArtistSkeleton from JSON data.
|
||||||
|
func (as *ArtistSkeleton) 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 {
|
||||||
|
skeleton := &ArtistSkeleton{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, skeleton); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, skeleton)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArtistTrailerStatus represents trailer availability for artist.
|
||||||
|
type ArtistTrailerStatus struct {
|
||||||
|
BaseModel
|
||||||
|
Available bool `json:"available"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes ArtistTrailerStatus from JSON data.
|
||||||
|
func (ats *ArtistTrailerStatus) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
status := &ArtistTrailerStatus{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["available"]; ok {
|
||||||
|
json.Unmarshal(v, &status.Available)
|
||||||
|
}
|
||||||
|
|
||||||
|
return status, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of ArtistTrailerStatus from JSON data.
|
||||||
|
func (ats *ArtistTrailerStatus) 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 {
|
||||||
|
status := &ArtistTrailerStatus{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, status); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, status)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArtistLink represents a link for artist about page.
|
||||||
|
type ArtistLink struct {
|
||||||
|
BaseModel
|
||||||
|
Title string `json:"title"`
|
||||||
|
Subtitle string `json:"subtitle,omitempty"`
|
||||||
|
URL string `json:"url,omitempty"`
|
||||||
|
ImgURL string `json:"img_url,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stats represents artist stats.
|
||||||
|
type Stats struct {
|
||||||
|
BaseModel
|
||||||
|
Rating int `json:"rating"`
|
||||||
|
Votes int `json:"votes"`
|
||||||
|
Month int `json:"month"`
|
||||||
|
Week int `json:"week"`
|
||||||
|
Day int `json:"day"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SkeletonBlock represents a skeleton block.
|
||||||
|
type SkeletonBlock struct {
|
||||||
|
BaseModel
|
||||||
|
ID string `json:"id"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Data json.RawMessage `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ArtistAlbums represents a page of albums by an artist.
|
||||||
|
type ArtistAlbums struct {
|
||||||
|
BaseModel
|
||||||
|
Albums []Album `json:"albums"`
|
||||||
|
Pager *Pager `json:"pager"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes an ArtistAlbums from JSON data.
|
||||||
|
func (aa *ArtistAlbums) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
albums := &ArtistAlbums{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["albums"]; ok {
|
||||||
|
var albumList []Album
|
||||||
|
if err := json.Unmarshal(v, &albumList); err == nil {
|
||||||
|
albums.Albums = albumList
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v, ok := raw["pager"]; ok {
|
||||||
|
var pager Pager
|
||||||
|
if err := json.Unmarshal(v, &pager); err == nil {
|
||||||
|
albums.Pager = &pager
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return albums, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of ArtistAlbums from JSON data.
|
||||||
|
func (aa *ArtistAlbums) 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 {
|
||||||
|
albums := &ArtistAlbums{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, albums); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, albums)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ArtistTracks represents a page of tracks by an artist.
|
||||||
|
type ArtistTracks struct {
|
||||||
|
BaseModel
|
||||||
|
Tracks []Track `json:"tracks"`
|
||||||
|
Pager *Pager `json:"pager"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes an ArtistTracks from JSON data.
|
||||||
|
func (at *ArtistTracks) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tracks := &ArtistTracks{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["tracks"]; ok {
|
||||||
|
var trackList []Track
|
||||||
|
if err := json.Unmarshal(v, &trackList); err == nil {
|
||||||
|
tracks.Tracks = trackList
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v, ok := raw["pager"]; ok {
|
||||||
|
var pager Pager
|
||||||
|
if err := json.Unmarshal(v, &pager); err == nil {
|
||||||
|
tracks.Pager = &pager
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tracks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of ArtistTracks from JSON data.
|
||||||
|
func (at *ArtistTracks) 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 {
|
||||||
|
tracks := &ArtistTracks{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, tracks); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, tracks)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
+114
-13
@@ -1,40 +1,47 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
|
// All models implement the Model interface with DeJSON/DeList deserialization methods.
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/utils"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Model is the base interface for all models
|
// Model is the base interface for all models.
|
||||||
|
// All model types implement this interface for JSON deserialization and serialization.
|
||||||
type Model interface {
|
type Model interface {
|
||||||
// DeJSON deserializes from JSON
|
// DeJSON deserializes a model from JSON data.
|
||||||
DeJSON(data []byte, c ClientInterface) (Model, error)
|
DeJSON(data []byte, c ClientInterface) (Model, error)
|
||||||
// DeList deserializes a list of models
|
// DeList deserializes a list of models from JSON data.
|
||||||
DeList(data []byte, c ClientInterface) ([]Model, error)
|
DeList(data []byte, c ClientInterface) ([]Model, error)
|
||||||
// ToJSON serializes to JSON
|
// ToJSON serializes the model to JSON.
|
||||||
ToJSON() ([]byte, error)
|
ToJSON() ([]byte, error)
|
||||||
// ToMap converts to map
|
// ToMap converts the model to a map.
|
||||||
ToMap() (map[string]any, error)
|
ToMap() (map[string]any, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BaseModel provides common functionality for models
|
// BaseModel provides common functionality for models, including a client reference.
|
||||||
type BaseModel struct {
|
type BaseModel struct {
|
||||||
Client ClientInterface `json:"-"`
|
Client ClientInterface `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBaseModel creates a new BaseModel
|
// NewBaseModel creates a new BaseModel with the given client interface.
|
||||||
func NewBaseModel(c ClientInterface) *BaseModel {
|
func NewBaseModel(c ClientInterface) *BaseModel {
|
||||||
return &BaseModel{Client: c}
|
return &BaseModel{Client: c}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON implements Model.DeJSON for basic models
|
// DeJSON implements Model.DeJSON for basic models.
|
||||||
|
// This should be overridden by concrete types.
|
||||||
func (b *BaseModel) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (b *BaseModel) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
// This should be overridden by concrete types
|
// This should be overridden by concrete types
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList implements Model.DeList for basic models
|
// DeList implements Model.DeList for basic models.
|
||||||
|
// This should be overridden by concrete types.
|
||||||
func (b *BaseModel) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (b *BaseModel) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -49,12 +56,12 @@ func (b *BaseModel) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToJSON serializes the model to JSON
|
// ToJSON serializes the model to JSON using the default JSON backend.
|
||||||
func (b *BaseModel) ToJSON() ([]byte, error) {
|
func (b *BaseModel) ToJSON() ([]byte, error) {
|
||||||
return utils.Marshal(b)
|
return utils.Marshal(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToMap converts the model to a map
|
// ToMap converts the model to a map by serializing to JSON and unmarshaling into a map.
|
||||||
func (b *BaseModel) ToMap() (map[string]any, error) {
|
func (b *BaseModel) ToMap() (map[string]any, error) {
|
||||||
data, err := b.ToJSON()
|
data, err := b.ToJSON()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -67,12 +74,106 @@ func (b *BaseModel) ToMap() (map[string]any, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetClient sets the client on the model
|
// SetClient sets the client interface on the model.
|
||||||
func (b *BaseModel) SetClient(c ClientInterface) {
|
func (b *BaseModel) SetClient(c ClientInterface) {
|
||||||
b.Client = c
|
b.Client = c
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetClient returns the client
|
// GetClient returns the client interface associated with the model.
|
||||||
func (b *BaseModel) GetClient() ClientInterface {
|
func (b *BaseModel) GetClient() ClientInterface {
|
||||||
return b.Client
|
return b.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JSONID is an ID that can be represented as either a JSON string or a JSON number.
|
||||||
|
// The Yandex Music API sometimes returns IDs as numbers (e.g., 12345) and sometimes
|
||||||
|
// as strings (e.g., "12345"). JSONID accepts both and stores the value as a string.
|
||||||
|
type JSONID string
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaler, accepting both JSON strings and numbers.
|
||||||
|
func (id *JSONID) UnmarshalJSON(data []byte) error {
|
||||||
|
// Try string first
|
||||||
|
var s string
|
||||||
|
if err := json.Unmarshal(data, &s); err == nil {
|
||||||
|
*id = JSONID(s)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Try number (float64 is the default JSON number decoding)
|
||||||
|
var f float64
|
||||||
|
if err := json.Unmarshal(data, &f); err != nil {
|
||||||
|
return fmt.Errorf("cannot unmarshal %v into JSONID: %w", string(data), err)
|
||||||
|
}
|
||||||
|
*id = JSONID(strconv.FormatFloat(f, 'f', -1, 64))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the ID as a Go string.
|
||||||
|
func (id JSONID) String() string {
|
||||||
|
return string(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// R128 represents EBU R 128 loudness normalization parameters.
|
||||||
|
// The Yandex Music API returns this either as a number (e.g., -23.5) or as an object
|
||||||
|
// with fields i, tp, important_secs.
|
||||||
|
type R128 struct {
|
||||||
|
BaseModel
|
||||||
|
I float64 `json:"i"`
|
||||||
|
Tp float64 `json:"tp"`
|
||||||
|
ImportantSecs int `json:"important_secs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaler, accepting both JSON numbers and objects.
|
||||||
|
func (r *R128) UnmarshalJSON(data []byte) error {
|
||||||
|
// Try float64 first (API sometimes returns just a number)
|
||||||
|
var f float64
|
||||||
|
if err := json.Unmarshal(data, &f); err == nil {
|
||||||
|
r.I = f
|
||||||
|
r.Tp = 0
|
||||||
|
r.ImportantSecs = 0
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Try object with fields i, tp, important_secs
|
||||||
|
var obj struct {
|
||||||
|
I float64 `json:"i"`
|
||||||
|
Tp float64 `json:"tp"`
|
||||||
|
ImportantSecs int `json:"important_secs"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, &obj); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r.I = obj.I
|
||||||
|
r.Tp = obj.Tp
|
||||||
|
r.ImportantSecs = obj.ImportantSecs
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64 returns the integrated loudness (i) value as a float64.
|
||||||
|
func (r R128) Float64() float64 {
|
||||||
|
return r.I
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes an R128 from JSON data.
|
||||||
|
func (r *R128) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
r128 := &R128{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := r128.UnmarshalJSON(data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return r128, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of R128 from JSON data.
|
||||||
|
func (r *R128) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
|
var rawList []json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make([]Model, 0, len(rawList))
|
||||||
|
for _, item := range rawList {
|
||||||
|
r128 := &R128{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := r128.UnmarshalJSON(item); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, r128)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
@@ -1,19 +1,28 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ClientInterface defines the minimal client interface needed by models
|
// ClientInterface defines the minimal client interface needed by models.
|
||||||
|
// Models use this to access the underlying request handler.
|
||||||
type ClientInterface interface {
|
type ClientInterface interface {
|
||||||
|
// GetRequest returns the underlying request handler.
|
||||||
GetRequest() RequestInterface
|
GetRequest() RequestInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequestInterface defines the minimal request interface needed by models
|
// RequestInterface defines the minimal request interface needed by models.
|
||||||
|
// It provides methods for making HTTP requests to the Yandex Music API.
|
||||||
type RequestInterface interface {
|
type RequestInterface interface {
|
||||||
|
// Get performs a GET request to the given path with query parameters.
|
||||||
Get(ctx context.Context, path string, params map[string]string, result any) error
|
Get(ctx context.Context, path string, params map[string]string, result any) error
|
||||||
|
// Post performs a POST request to the given path with a JSON body.
|
||||||
Post(ctx context.Context, path string, body any, result any) error
|
Post(ctx context.Context, path string, body any, result any) error
|
||||||
|
// Put performs a PUT request to the given path with a JSON body.
|
||||||
Put(ctx context.Context, path string, body any, result any) error
|
Put(ctx context.Context, path string, body any, result any) error
|
||||||
|
// Delete performs a DELETE request to the given path with an optional JSON body.
|
||||||
Delete(ctx context.Context, path string, body any, result any) error
|
Delete(ctx context.Context, path string, body any, result any) error
|
||||||
|
// Download downloads a file from the given URL and returns the raw response body.
|
||||||
Download(ctx context.Context, url string) ([]byte, error)
|
Download(ctx context.Context, url string) ([]byte, error)
|
||||||
}
|
}
|
||||||
+61
-52
@@ -1,30 +1,34 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Clip represents a clip (short video)
|
// Clip represents a clip (short video) from the Yandex Music API.
|
||||||
type Clip struct {
|
type Clip struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
PlayerID string `json:"player_id"`
|
||||||
|
UUID string `json:"uuid"`
|
||||||
|
Thumbnail string `json:"thumbnail"`
|
||||||
|
PreviewURL string `json:"preview_url"`
|
||||||
Duration int `json:"duration"`
|
Duration int `json:"duration"`
|
||||||
CoverURI string `json:"cover_uri"`
|
TrackIDs []int `json:"track_ids"`
|
||||||
PreviewURI string `json:"preview_uri"`
|
Artists []Artist `json:"artists"`
|
||||||
Available bool `json:"available"`
|
Disclaimers []string `json:"disclaimers"`
|
||||||
Views int `json:"views"`
|
Explicit bool `json:"explicit"`
|
||||||
Likes int `json:"likes"`
|
Cover *Cover `json:"cover"`
|
||||||
CreatedAt string `json:"created_at"`
|
ContentRestrictions *ContentRestrictions `json:"content_restrictions"`
|
||||||
Artist *Artist `json:"artist"`
|
Client *ClientInterface `json:"-"`
|
||||||
Track *Track `json:"track"`
|
|
||||||
Playlist *Playlist `json:"playlist"`
|
|
||||||
ClipType string `json:"clip_type"`
|
ClipType string `json:"clip_type"`
|
||||||
IsVertical bool `json:"is_vertical"`
|
IsVertical bool `json:"is_vertical"`
|
||||||
AspectRatio string `json:"aspect_ratio"`
|
AspectRatio string `json:"aspect_ratio"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a Clip from JSON
|
// DeJSON deserializes a Clip from JSON data.
|
||||||
func (c *Clip) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (c *Clip) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -39,26 +43,47 @@ func (c *Clip) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
|||||||
if v, ok := raw["title"]; ok {
|
if v, ok := raw["title"]; ok {
|
||||||
json.Unmarshal(v, &clip.Title)
|
json.Unmarshal(v, &clip.Title)
|
||||||
}
|
}
|
||||||
|
if v, ok := raw["version"]; ok {
|
||||||
|
json.Unmarshal(v, &clip.Version)
|
||||||
|
}
|
||||||
|
if v, ok := raw["player_id"]; ok {
|
||||||
|
json.Unmarshal(v, &clip.PlayerID)
|
||||||
|
}
|
||||||
|
if v, ok := raw["uuid"]; ok {
|
||||||
|
json.Unmarshal(v, &clip.UUID)
|
||||||
|
}
|
||||||
|
if v, ok := raw["thumbnail"]; ok {
|
||||||
|
json.Unmarshal(v, &clip.Thumbnail)
|
||||||
|
}
|
||||||
|
if v, ok := raw["preview_url"]; ok {
|
||||||
|
json.Unmarshal(v, &clip.PreviewURL)
|
||||||
|
}
|
||||||
if v, ok := raw["duration"]; ok {
|
if v, ok := raw["duration"]; ok {
|
||||||
json.Unmarshal(v, &clip.Duration)
|
json.Unmarshal(v, &clip.Duration)
|
||||||
}
|
}
|
||||||
if v, ok := raw["cover_uri"]; ok {
|
if v, ok := raw["track_ids"]; ok {
|
||||||
json.Unmarshal(v, &clip.CoverURI)
|
json.Unmarshal(v, &clip.TrackIDs)
|
||||||
}
|
}
|
||||||
if v, ok := raw["preview_uri"]; ok {
|
if v, ok := raw["artists"]; ok {
|
||||||
json.Unmarshal(v, &clip.PreviewURI)
|
var artists []Artist
|
||||||
|
json.Unmarshal(v, &artists)
|
||||||
|
clip.Artists = artists
|
||||||
}
|
}
|
||||||
if v, ok := raw["available"]; ok {
|
if v, ok := raw["disclaimers"]; ok {
|
||||||
json.Unmarshal(v, &clip.Available)
|
json.Unmarshal(v, &clip.Disclaimers)
|
||||||
}
|
}
|
||||||
if v, ok := raw["views"]; ok {
|
if v, ok := raw["explicit"]; ok {
|
||||||
json.Unmarshal(v, &clip.Views)
|
json.Unmarshal(v, &clip.Explicit)
|
||||||
}
|
}
|
||||||
if v, ok := raw["likes"]; ok {
|
if v, ok := raw["cover"]; ok {
|
||||||
json.Unmarshal(v, &clip.Likes)
|
var cover Cover
|
||||||
|
json.Unmarshal(v, &cover)
|
||||||
|
clip.Cover = &cover
|
||||||
}
|
}
|
||||||
if v, ok := raw["created_at"]; ok {
|
if v, ok := raw["content_restrictions"]; ok {
|
||||||
json.Unmarshal(v, &clip.CreatedAt)
|
var cr ContentRestrictions
|
||||||
|
json.Unmarshal(v, &cr)
|
||||||
|
clip.ContentRestrictions = &cr
|
||||||
}
|
}
|
||||||
if v, ok := raw["clip_type"]; ok {
|
if v, ok := raw["clip_type"]; ok {
|
||||||
json.Unmarshal(v, &clip.ClipType)
|
json.Unmarshal(v, &clip.ClipType)
|
||||||
@@ -70,26 +95,10 @@ func (c *Clip) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
|||||||
json.Unmarshal(v, &clip.AspectRatio)
|
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
|
return clip, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Clips
|
// DeList deserializes a list of Clips from JSON data.
|
||||||
func (c *Clip) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (c *Clip) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -107,31 +116,31 @@ func (c *Clip) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClipsWillLike represents clips the user might like
|
// ClipsWillLike represents clips the user might like.
|
||||||
type ClipsWillLike struct {
|
type ClipsWillLike struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Clips []Clip `json:"clips"`
|
Clips []Clip `json:"clips"`
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ArtistClipData represents artist clip data
|
// ArtistClipData represents artist clip data.
|
||||||
type ArtistClipData struct {
|
type ArtistClipData struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Clips []Clip `json:"clips"`
|
Clips []Clip `json:"clips"`
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ArtistClipItem represents an artist clip item
|
// ArtistClipItem represents an artist clip item.
|
||||||
type ArtistClipItem struct {
|
type ArtistClipItem struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Clip *Clip `json:"clip"`
|
Clip *Clip `json:"clip"`
|
||||||
Index int `json:"index"`
|
Index int `json:"index"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shot represents a shot (short video)
|
// Shot represents a shot (short video).
|
||||||
type Shot struct {
|
type Shot struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Duration int `json:"duration"`
|
Duration int `json:"duration"`
|
||||||
@@ -150,7 +159,7 @@ type Shot struct {
|
|||||||
AspectRatio string `json:"aspect_ratio"`
|
AspectRatio string `json:"aspect_ratio"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a Shot from JSON
|
// DeJSON deserializes a Shot from JSON data.
|
||||||
func (s *Shot) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (s *Shot) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -219,7 +228,7 @@ func (s *Shot) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
|||||||
return shot, nil
|
return shot, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Shots
|
// DeList deserializes a list of Shots from JSON data.
|
||||||
func (s *Shot) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (s *Shot) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -237,14 +246,14 @@ func (s *Shot) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShotData represents shot data
|
// ShotData represents shot data.
|
||||||
type ShotData struct {
|
type ShotData struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Shots []Shot `json:"shots"`
|
Shots []Shot `json:"shots"`
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShotEvent represents a shot event
|
// ShotEvent represents a shot event.
|
||||||
type ShotEvent struct {
|
type ShotEvent struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
EventID string `json:"event_id"`
|
EventID string `json:"event_id"`
|
||||||
@@ -254,10 +263,10 @@ type ShotEvent struct {
|
|||||||
Action string `json:"action"`
|
Action string `json:"action"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShotType represents a shot type
|
// ShotType represents a shot type.
|
||||||
type ShotType struct {
|
type ShotType struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Icon string `json:"icon"`
|
Icon string `json:"icon"`
|
||||||
|
|||||||
+100
-21
@@ -1,17 +1,19 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Concert represents a concert
|
// Concert represents a concert from the Yandex Music API.
|
||||||
type Concert struct {
|
type Concert struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Date string `json:"date"`
|
Date string `json:"date"`
|
||||||
Time string `json:"time"`
|
Time string `json:"time"`
|
||||||
|
Datetime string `json:"datetime"`
|
||||||
Venue *ConcertVenue `json:"venue"`
|
Venue *ConcertVenue `json:"venue"`
|
||||||
Location *ConcertLocation `json:"location"`
|
Location *ConcertLocation `json:"location"`
|
||||||
MinPrice int `json:"min_price"`
|
MinPrice int `json:"min_price"`
|
||||||
@@ -26,9 +28,16 @@ type Concert struct {
|
|||||||
Cashback *ConcertCashback `json:"cashback"`
|
Cashback *ConcertCashback `json:"cashback"`
|
||||||
Tabs []ConcertTabConfig `json:"tabs"`
|
Tabs []ConcertTabConfig `json:"tabs"`
|
||||||
Skeleton *ConcertSkeleton `json:"skeleton"`
|
Skeleton *ConcertSkeleton `json:"skeleton"`
|
||||||
|
AfishaURL string `json:"afisha_url"`
|
||||||
|
City string `json:"city"`
|
||||||
|
Place string `json:"place"`
|
||||||
|
Address string `json:"address"`
|
||||||
|
ContentRating string `json:"content_rating"`
|
||||||
|
DataSessionID string `json:"data_session_id"`
|
||||||
|
EventInfo *ConcertEventInfo `json:"event_info"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a Concert from JSON
|
// DeJSON deserializes a Concert from JSON data.
|
||||||
func (c *Concert) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (c *Concert) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -76,6 +85,30 @@ func (c *Concert) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
|||||||
if v, ok := raw["genres"]; ok {
|
if v, ok := raw["genres"]; ok {
|
||||||
json.Unmarshal(v, &concert.Genres)
|
json.Unmarshal(v, &concert.Genres)
|
||||||
}
|
}
|
||||||
|
if v, ok := raw["datetime"]; ok {
|
||||||
|
json.Unmarshal(v, &concert.Datetime)
|
||||||
|
}
|
||||||
|
if v, ok := raw["afisha_url"]; ok {
|
||||||
|
json.Unmarshal(v, &concert.AfishaURL)
|
||||||
|
}
|
||||||
|
if v, ok := raw["city"]; ok {
|
||||||
|
json.Unmarshal(v, &concert.City)
|
||||||
|
}
|
||||||
|
if v, ok := raw["place"]; ok {
|
||||||
|
json.Unmarshal(v, &concert.Place)
|
||||||
|
}
|
||||||
|
if v, ok := raw["address"]; ok {
|
||||||
|
json.Unmarshal(v, &concert.Address)
|
||||||
|
}
|
||||||
|
if v, ok := raw["content_rating"]; ok {
|
||||||
|
json.Unmarshal(v, &concert.ContentRating)
|
||||||
|
}
|
||||||
|
if v, ok := raw["data_session_id"]; ok {
|
||||||
|
json.Unmarshal(v, &concert.DataSessionID)
|
||||||
|
}
|
||||||
|
if v, ok := raw["event_info"]; ok {
|
||||||
|
json.Unmarshal(v, &concert.EventInfo)
|
||||||
|
}
|
||||||
|
|
||||||
if v, ok := raw["venue"]; ok {
|
if v, ok := raw["venue"]; ok {
|
||||||
var venue ConcertVenue
|
var venue ConcertVenue
|
||||||
@@ -111,7 +144,7 @@ func (c *Concert) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
|||||||
return concert, nil
|
return concert, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Concerts
|
// DeList deserializes a list of Concerts from JSON data.
|
||||||
func (c *Concert) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (c *Concert) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -129,10 +162,10 @@ func (c *Concert) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConcertVenue represents a concert venue
|
// ConcertVenue represents a concert venue.
|
||||||
type ConcertVenue struct {
|
type ConcertVenue struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Address string `json:"address"`
|
Address string `json:"address"`
|
||||||
City string `json:"city"`
|
City string `json:"city"`
|
||||||
@@ -141,10 +174,10 @@ type ConcertVenue struct {
|
|||||||
ImageURI string `json:"image_uri"`
|
ImageURI string `json:"image_uri"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConcertLocation represents a concert location
|
// ConcertLocation represents a concert location.
|
||||||
type ConcertLocation struct {
|
type ConcertLocation struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
City string `json:"city"`
|
City string `json:"city"`
|
||||||
Country string `json:"country"`
|
Country string `json:"country"`
|
||||||
@@ -152,7 +185,7 @@ type ConcertLocation struct {
|
|||||||
Venues []ConcertVenue `json:"venues"`
|
Venues []ConcertVenue `json:"venues"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConcertLocations represents concert locations
|
// ConcertLocations represents concert locations.
|
||||||
type ConcertLocations struct {
|
type ConcertLocations struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Locations []ConcertLocation `json:"locations"`
|
Locations []ConcertLocation `json:"locations"`
|
||||||
@@ -161,7 +194,7 @@ type ConcertLocations struct {
|
|||||||
PageSize int `json:"page_size"`
|
PageSize int `json:"page_size"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConcertFeed represents a concert feed
|
// ConcertFeed represents a concert feed.
|
||||||
type ConcertFeed struct {
|
type ConcertFeed struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Concerts []Concert `json:"concerts"`
|
Concerts []Concert `json:"concerts"`
|
||||||
@@ -170,14 +203,14 @@ type ConcertFeed struct {
|
|||||||
PageSize int `json:"page_size"`
|
PageSize int `json:"page_size"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConcertInfo represents concert info
|
// ConcertInfo represents concert info.
|
||||||
type ConcertInfo struct {
|
type ConcertInfo struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Concert *Concert `json:"concert"`
|
Concert *Concert `json:"concert"`
|
||||||
Related []Concert `json:"related"`
|
Related []Concert `json:"related"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConcertEventInfo represents concert event info
|
// ConcertEventInfo represents concert event info.
|
||||||
type ConcertEventInfo struct {
|
type ConcertEventInfo struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
EventID string `json:"event_id"`
|
EventID string `json:"event_id"`
|
||||||
@@ -186,7 +219,7 @@ type ConcertEventInfo struct {
|
|||||||
Data json.RawMessage `json:"data"`
|
Data json.RawMessage `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConcertDescription represents concert description
|
// ConcertDescription represents concert description.
|
||||||
type ConcertDescription struct {
|
type ConcertDescription struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Text string `json:"text"`
|
Text string `json:"text"`
|
||||||
@@ -194,7 +227,7 @@ type ConcertDescription struct {
|
|||||||
ShortText string `json:"short_text"`
|
ShortText string `json:"short_text"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConcertCashback represents concert cashback
|
// ConcertCashback represents concert cashback.
|
||||||
type ConcertCashback struct {
|
type ConcertCashback struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Amount int `json:"amount"`
|
Amount int `json:"amount"`
|
||||||
@@ -203,41 +236,87 @@ type ConcertCashback struct {
|
|||||||
Expires string `json:"expires"`
|
Expires string `json:"expires"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConcertMinPrice represents concert min price
|
// ConcertMinPrice represents concert min price.
|
||||||
type ConcertMinPrice struct {
|
type ConcertMinPrice struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Price int `json:"price"`
|
Price int `json:"price"`
|
||||||
Currency string `json:"currency"`
|
Currency string `json:"currency"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConcertTabConfig represents concert tab config
|
// ConcertTabConfig represents concert tab config.
|
||||||
type ConcertTabConfig struct {
|
type ConcertTabConfig struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Active bool `json:"active"`
|
Active bool `json:"active"`
|
||||||
Range *ConcertTabRange `json:"range"`
|
Range *ConcertTabRange `json:"range"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConcertTabRange represents concert tab range
|
// ConcertTabRange represents concert tab range.
|
||||||
type ConcertTabRange struct {
|
type ConcertTabRange struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
From string `json:"from"`
|
From string `json:"from"`
|
||||||
To string `json:"to"`
|
To string `json:"to"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConcertSkeleton represents concert skeleton
|
// ConcertSkeleton represents concert skeleton.
|
||||||
type ConcertSkeleton struct {
|
type ConcertSkeleton struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Blocks []ConcertSkeletonBlock `json:"blocks"`
|
Blocks []ConcertSkeletonBlock `json:"blocks"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConcertSkeletonBlock represents a concert skeleton block
|
// ConcertSkeletonBlock represents a concert skeleton block.
|
||||||
type ConcertSkeletonBlock struct {
|
type ConcertSkeletonBlock struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Data json.RawMessage `json:"data"`
|
Data json.RawMessage `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ArtistConcerts represents concerts by an artist.
|
||||||
|
type ArtistConcerts struct {
|
||||||
|
BaseModel
|
||||||
|
ArtistTitle string `json:"artist_title"`
|
||||||
|
Concerts []Concert `json:"concerts"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes ArtistConcerts from JSON data.
|
||||||
|
func (ac *ArtistConcerts) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
acObj := &ArtistConcerts{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["artist_title"]; ok {
|
||||||
|
json.Unmarshal(v, &acObj.ArtistTitle)
|
||||||
|
}
|
||||||
|
if v, ok := raw["concerts"]; ok {
|
||||||
|
var concerts []Concert
|
||||||
|
json.Unmarshal(v, &concerts)
|
||||||
|
acObj.Concerts = concerts
|
||||||
|
}
|
||||||
|
|
||||||
|
return acObj, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of ArtistConcerts from JSON data.
|
||||||
|
func (ac *ArtistConcerts) 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 {
|
||||||
|
ac := &ArtistConcerts{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, ac); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, ac)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
@@ -1,17 +1,18 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Credits represents track credits
|
// Credits represents track credits from the Yandex Music API.
|
||||||
type Credits struct {
|
type Credits struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Items []Credit `json:"items"`
|
Items []Credit `json:"items"`
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes Credits from JSON
|
// DeJSON deserializes Credits from JSON data.
|
||||||
func (c *Credits) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (c *Credits) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -32,7 +33,7 @@ func (c *Credits) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
|||||||
return credits, nil
|
return credits, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Credits
|
// DeList deserializes a list of Credits from JSON data. from JSON data.
|
||||||
func (c *Credits) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (c *Credits) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -50,7 +51,7 @@ func (c *Credits) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Credit represents a credit
|
// Credit represents a credit.
|
||||||
type Credit struct {
|
type Credit struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Role string `json:"role"`
|
Role string `json:"role"`
|
||||||
@@ -62,7 +63,7 @@ type Credit struct {
|
|||||||
AlbumID string `json:"album_id"`
|
AlbumID string `json:"album_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a Credit from JSON
|
// DeJSON deserializes a Credit from JSON data.
|
||||||
func (c *Credit) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (c *Credit) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -114,7 +115,7 @@ func (c *Credit) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LicenceTextPart represents a licence text part
|
// LicenceTextPart represents a licence text part.
|
||||||
type LicenceTextPart struct {
|
type LicenceTextPart struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Text string `json:"text"`
|
Text string `json:"text"`
|
||||||
@@ -124,7 +125,7 @@ type LicenceTextPart struct {
|
|||||||
IsMain bool `json:"is_main"`
|
IsMain bool `json:"is_main"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a LicenceTextPart from JSON
|
// DeJSON deserializes a LicenceTextPart from JSON data.
|
||||||
func (ltp *LicenceTextPart) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (ltp *LicenceTextPart) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -152,7 +153,7 @@ func (ltp *LicenceTextPart) DeJSON(data []byte, client ClientInterface) (Model,
|
|||||||
return part, nil
|
return part, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of LicenceTextPart
|
// DeList deserializes a list of LicenceTextPart from JSON data.
|
||||||
func (ltp *LicenceTextPart) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (ltp *LicenceTextPart) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -169,3 +170,85 @@ func (ltp *LicenceTextPart) DeList(data []byte, client ClientInterface) ([]Model
|
|||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Disclaimer represents a disclaimer.
|
||||||
|
type Disclaimer struct {
|
||||||
|
BaseModel
|
||||||
|
ForeignAgent *ForeignAgent `json:"foreign_agent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes Disclaimer from JSON data.
|
||||||
|
func (d *Disclaimer) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
disclaimer := &Disclaimer{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["foreign_agent"]; ok {
|
||||||
|
var fa ForeignAgent
|
||||||
|
json.Unmarshal(v, &fa)
|
||||||
|
disclaimer.ForeignAgent = &fa
|
||||||
|
}
|
||||||
|
|
||||||
|
return disclaimer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of Disclaimers from JSON data.
|
||||||
|
func (d *Disclaimer) 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 {
|
||||||
|
disclaimer := &Disclaimer{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, disclaimer); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, disclaimer)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForeignAgent represents a foreign agent.
|
||||||
|
type ForeignAgent struct {
|
||||||
|
BaseModel
|
||||||
|
Text string `json:"text"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes ForeignAgent from JSON data.
|
||||||
|
func (fa *ForeignAgent) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
agent := &ForeignAgent{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["text"]; ok {
|
||||||
|
json.Unmarshal(v, &agent.Text)
|
||||||
|
}
|
||||||
|
|
||||||
|
return agent, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of ForeignAgent from JSON data.
|
||||||
|
func (fa *ForeignAgent) 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 {
|
||||||
|
agent := &ForeignAgent{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, agent); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, agent)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
+44
-26
@@ -1,18 +1,25 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Feed represents the main feed
|
// Feed represents the main feed from the Yandex Music API.
|
||||||
type Feed struct {
|
type Feed struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
|
CanGetMoreEvents bool `json:"can_get_more_events"`
|
||||||
|
Pumpkin bool `json:"pumpkin"`
|
||||||
|
IsWizardPassed bool `json:"is_wizard_passed"`
|
||||||
|
Headlines []string `json:"headlines"`
|
||||||
|
Today string `json:"today"`
|
||||||
Days []Day `json:"days"`
|
Days []Day `json:"days"`
|
||||||
GeneratedPlaylists []GeneratedPlaylist `json:"generated_playlists"`
|
GeneratedPlaylists []GeneratedPlaylist `json:"generated_playlists"`
|
||||||
PlayContexts []PlayContext `json:"play_contexts"`
|
PlayContexts []PlayContext `json:"play_contexts"`
|
||||||
|
NextRevision string `json:"next_revision"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a Feed from JSON
|
// DeJSON deserializes a Feed from JSON data.
|
||||||
func (f *Feed) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (f *Feed) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -21,6 +28,21 @@ func (f *Feed) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
|
|
||||||
feed := &Feed{BaseModel: *NewBaseModel(c)}
|
feed := &Feed{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["can_get_more_events"]; ok {
|
||||||
|
json.Unmarshal(v, &feed.CanGetMoreEvents)
|
||||||
|
}
|
||||||
|
if v, ok := raw["pumpkin"]; ok {
|
||||||
|
json.Unmarshal(v, &feed.Pumpkin)
|
||||||
|
}
|
||||||
|
if v, ok := raw["is_wizard_passed"]; ok {
|
||||||
|
json.Unmarshal(v, &feed.IsWizardPassed)
|
||||||
|
}
|
||||||
|
if v, ok := raw["headlines"]; ok {
|
||||||
|
json.Unmarshal(v, &feed.Headlines)
|
||||||
|
}
|
||||||
|
if v, ok := raw["today"]; ok {
|
||||||
|
json.Unmarshal(v, &feed.Today)
|
||||||
|
}
|
||||||
if v, ok := raw["days"]; ok {
|
if v, ok := raw["days"]; ok {
|
||||||
var days []Day
|
var days []Day
|
||||||
json.Unmarshal(v, &days)
|
json.Unmarshal(v, &days)
|
||||||
@@ -36,11 +58,14 @@ func (f *Feed) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
json.Unmarshal(v, &contexts)
|
json.Unmarshal(v, &contexts)
|
||||||
feed.PlayContexts = contexts
|
feed.PlayContexts = contexts
|
||||||
}
|
}
|
||||||
|
if v, ok := raw["next_revision"]; ok {
|
||||||
|
json.Unmarshal(v, &feed.NextRevision)
|
||||||
|
}
|
||||||
|
|
||||||
return feed, nil
|
return feed, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Feeds
|
// DeList deserializes a list of Feeds from JSON data.
|
||||||
func (f *Feed) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (f *Feed) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -58,7 +83,7 @@ func (f *Feed) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Day represents a day in the feed
|
// Day represents a day in the feed.
|
||||||
type Day struct {
|
type Day struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Date string `json:"date"`
|
Date string `json:"date"`
|
||||||
@@ -68,7 +93,7 @@ type Day struct {
|
|||||||
GeneratedPlaylists []GeneratedPlaylist `json:"generated_playlists"`
|
GeneratedPlaylists []GeneratedPlaylist `json:"generated_playlists"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a Day from JSON
|
// DeJSON deserializes a Day from JSON data.
|
||||||
func (d *Day) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (d *Day) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -100,7 +125,7 @@ func (d *Day) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
return day, nil
|
return day, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Days
|
// DeList deserializes a list of Days from JSON data.
|
||||||
func (d *Day) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (d *Day) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -118,17 +143,17 @@ func (d *Day) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DayBlock represents a block in a day
|
// DayBlock represents a block in a day.
|
||||||
type DayBlock struct {
|
type DayBlock struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Data *DayBlockData `json:"data"`
|
Data *DayBlockData `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DayBlockData represents data in a day block
|
// DayBlockData represents data in a day block.
|
||||||
type DayBlockData struct {
|
type DayBlockData struct {
|
||||||
Tracks []Track `json:"tracks"`
|
Tracks []Track `json:"tracks"`
|
||||||
Playlists []Playlist `json:"playlists"`
|
Playlists []Playlist `json:"playlists"`
|
||||||
@@ -137,10 +162,10 @@ type DayBlockData struct {
|
|||||||
GeneratedPlaylist *GeneratedPlaylist `json:"generated_playlist"`
|
GeneratedPlaylist *GeneratedPlaylist `json:"generated_playlist"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GeneratedPlaylist represents a generated playlist
|
// GeneratedPlaylist represents a generated playlist.
|
||||||
type GeneratedPlaylist struct {
|
type GeneratedPlaylist struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
CoverURI string `json:"cover_uri"`
|
CoverURI string `json:"cover_uri"`
|
||||||
@@ -153,7 +178,7 @@ type GeneratedPlaylist struct {
|
|||||||
Tracks []Track `json:"tracks"`
|
Tracks []Track `json:"tracks"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a GeneratedPlaylist from JSON
|
// DeJSON deserializes a GeneratedPlaylist from JSON data.
|
||||||
func (gp *GeneratedPlaylist) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (gp *GeneratedPlaylist) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -201,7 +226,7 @@ func (gp *GeneratedPlaylist) DeJSON(data []byte, c ClientInterface) (Model, erro
|
|||||||
return playlist, nil
|
return playlist, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of GeneratedPlaylists
|
// DeList deserializes a list of GeneratedPlaylists from JSON data.
|
||||||
func (gp *GeneratedPlaylist) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (gp *GeneratedPlaylist) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -219,7 +244,7 @@ func (gp *GeneratedPlaylist) DeList(data []byte, c ClientInterface) ([]Model, er
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Event represents a feed event
|
// Event represents a feed event.
|
||||||
type Event struct {
|
type Event struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Timestamp string `json:"timestamp"`
|
Timestamp string `json:"timestamp"`
|
||||||
@@ -231,7 +256,7 @@ type Event struct {
|
|||||||
Action string `json:"action"`
|
Action string `json:"action"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AlbumEvent represents an album event
|
// AlbumEvent represents an album event.
|
||||||
type AlbumEvent struct {
|
type AlbumEvent struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Album *Album `json:"album"`
|
Album *Album `json:"album"`
|
||||||
@@ -240,7 +265,7 @@ type AlbumEvent struct {
|
|||||||
Action string `json:"action"`
|
Action string `json:"action"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ArtistEvent represents an artist event
|
// ArtistEvent represents an artist event.
|
||||||
type ArtistEvent struct {
|
type ArtistEvent struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Artist *Artist `json:"artist"`
|
Artist *Artist `json:"artist"`
|
||||||
@@ -249,7 +274,7 @@ type ArtistEvent struct {
|
|||||||
Action string `json:"action"`
|
Action string `json:"action"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrackWithAds represents a track with ads
|
// TrackWithAds represents a track with ads.
|
||||||
type TrackWithAds struct {
|
type TrackWithAds struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Track *Track `json:"track"`
|
Track *Track `json:"track"`
|
||||||
@@ -257,10 +282,10 @@ type TrackWithAds struct {
|
|||||||
AdParams *AdParams `json:"ad_params"`
|
AdParams *AdParams `json:"ad_params"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ad represents an ad
|
// Ad represents an ad.
|
||||||
type Ad struct {
|
type Ad struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
@@ -269,10 +294,3 @@ type Ad struct {
|
|||||||
Duration int `json:"duration"`
|
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"`
|
|
||||||
}
|
|
||||||
+23
-10
@@ -1,23 +1,27 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Label represents a label
|
// Label represents a label from the Yandex Music API.
|
||||||
type Label struct {
|
type Label struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
CoverURI string `json:"cover_uri"`
|
CoverURI string `json:"cover_uri"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
|
DescriptionFormatted string `json:"description_formatted"`
|
||||||
|
Image string `json:"image"`
|
||||||
Website string `json:"website"`
|
Website string `json:"website"`
|
||||||
SocialLinks []SocialLink `json:"social_links"`
|
Links []Link `json:"links"`
|
||||||
|
Type string `json:"type"`
|
||||||
Available bool `json:"available"`
|
Available bool `json:"available"`
|
||||||
Owner *User `json:"owner"`
|
Owner *User `json:"owner"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a Label from JSON
|
// DeJSON deserializes a Label from JSON data.
|
||||||
func (l *Label) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (l *Label) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -44,10 +48,19 @@ func (l *Label) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
|||||||
if v, ok := raw["available"]; ok {
|
if v, ok := raw["available"]; ok {
|
||||||
json.Unmarshal(v, &label.Available)
|
json.Unmarshal(v, &label.Available)
|
||||||
}
|
}
|
||||||
if v, ok := raw["social_links"]; ok {
|
if v, ok := raw["description_formatted"]; ok {
|
||||||
var links []SocialLink
|
json.Unmarshal(v, &label.DescriptionFormatted)
|
||||||
|
}
|
||||||
|
if v, ok := raw["image"]; ok {
|
||||||
|
json.Unmarshal(v, &label.Image)
|
||||||
|
}
|
||||||
|
if v, ok := raw["links"]; ok {
|
||||||
|
var links []Link
|
||||||
json.Unmarshal(v, &links)
|
json.Unmarshal(v, &links)
|
||||||
label.SocialLinks = links
|
label.Links = links
|
||||||
|
}
|
||||||
|
if v, ok := raw["type"]; ok {
|
||||||
|
json.Unmarshal(v, &label.Type)
|
||||||
}
|
}
|
||||||
if v, ok := raw["owner"]; ok {
|
if v, ok := raw["owner"]; ok {
|
||||||
var user User
|
var user User
|
||||||
@@ -58,7 +71,7 @@ func (l *Label) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
|||||||
return label, nil
|
return label, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Labels
|
// DeList deserializes a list of Labels from JSON data.
|
||||||
func (l *Label) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (l *Label) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -76,7 +89,7 @@ func (l *Label) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LabelAlbums represents label albums
|
// LabelAlbums represents label albums.
|
||||||
type LabelAlbums struct {
|
type LabelAlbums struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Albums []Album `json:"albums"`
|
Albums []Album `json:"albums"`
|
||||||
@@ -85,7 +98,7 @@ type LabelAlbums struct {
|
|||||||
PageSize int `json:"page_size"`
|
PageSize int `json:"page_size"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// LabelArtists represents label artists
|
// LabelArtists represents label artists.
|
||||||
type LabelArtists struct {
|
type LabelArtists struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Artists []Artist `json:"artists"`
|
Artists []Artist `json:"artists"`
|
||||||
|
|||||||
+70
-10
@@ -1,22 +1,25 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Landing represents a landing page
|
// Landing represents a landing page from the Yandex Music API.
|
||||||
type Landing struct {
|
type Landing struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
CoverURI string `json:"cover_uri"`
|
CoverURI string `json:"cover_uri"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Blocks []LandingBlock `json:"blocks"`
|
Blocks []LandingBlock `json:"blocks"`
|
||||||
Available bool `json:"available"`
|
Available bool `json:"available"`
|
||||||
|
Pumpkin bool `json:"pumpkin"`
|
||||||
|
ContentID string `json:"content_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a Landing from JSON
|
// DeJSON deserializes a Landing from JSON data.
|
||||||
func (l *Landing) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (l *Landing) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -43,6 +46,12 @@ func (l *Landing) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
if v, ok := raw["available"]; ok {
|
if v, ok := raw["available"]; ok {
|
||||||
json.Unmarshal(v, &landing.Available)
|
json.Unmarshal(v, &landing.Available)
|
||||||
}
|
}
|
||||||
|
if v, ok := raw["pumpkin"]; ok {
|
||||||
|
json.Unmarshal(v, &landing.Pumpkin)
|
||||||
|
}
|
||||||
|
if v, ok := raw["content_id"]; ok {
|
||||||
|
json.Unmarshal(v, &landing.ContentID)
|
||||||
|
}
|
||||||
|
|
||||||
if v, ok := raw["blocks"]; ok {
|
if v, ok := raw["blocks"]; ok {
|
||||||
var blocks []LandingBlock
|
var blocks []LandingBlock
|
||||||
@@ -53,7 +62,7 @@ func (l *Landing) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
return landing, nil
|
return landing, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Landings
|
// DeList deserializes a list of Landings from JSON data.
|
||||||
func (l *Landing) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (l *Landing) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -71,17 +80,17 @@ func (l *Landing) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LandingBlock represents a block in a landing
|
// LandingBlock represents a block in a landing.
|
||||||
type LandingBlock struct {
|
type LandingBlock struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Data *LandingBlockData `json:"data"`
|
Data *LandingBlockData `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// LandingBlockData represents data in a landing block
|
// LandingBlockData represents data in a landing block.
|
||||||
type LandingBlockData struct {
|
type LandingBlockData struct {
|
||||||
Tracks []Track `json:"tracks"`
|
Tracks []Track `json:"tracks"`
|
||||||
Playlists []Playlist `json:"playlists"`
|
Playlists []Playlist `json:"playlists"`
|
||||||
@@ -90,16 +99,67 @@ type LandingBlockData struct {
|
|||||||
GeneratedPlaylist *GeneratedPlaylist `json:"generated_playlist"`
|
GeneratedPlaylist *GeneratedPlaylist `json:"generated_playlist"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// LandingList represents a list of landings
|
// LandingList represents a list of landings.
|
||||||
type LandingList struct {
|
type LandingList struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
|
Type string `json:"type"`
|
||||||
|
TypeForFrom string `json:"type_for_from"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
ID string `json:"id"`
|
||||||
Landings []Landing `json:"landings"`
|
Landings []Landing `json:"landings"`
|
||||||
|
NewReleases []int `json:"new_releases"`
|
||||||
|
NewPlaylists []PlaylistID `json:"new_playlists"`
|
||||||
|
Podcasts []int `json:"podcasts"`
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
Page int `json:"page"`
|
Page int `json:"page"`
|
||||||
PageSize int `json:"page_size"`
|
PageSize int `json:"page_size"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a LandingList from JSON
|
// PlaylistID represents a playlist ID reference.
|
||||||
|
type PlaylistID struct {
|
||||||
|
BaseModel
|
||||||
|
UID int `json:"uid"`
|
||||||
|
Kind int `json:"kind"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes a PlaylistID from JSON data.
|
||||||
|
func (pid *PlaylistID) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
playlistID := &PlaylistID{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["uid"]; ok {
|
||||||
|
json.Unmarshal(v, &playlistID.UID)
|
||||||
|
}
|
||||||
|
if v, ok := raw["kind"]; ok {
|
||||||
|
json.Unmarshal(v, &playlistID.Kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
return playlistID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of PlaylistID from JSON data.
|
||||||
|
func (pid *PlaylistID) 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 {
|
||||||
|
pid := &PlaylistID{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, pid); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, pid)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes a LandingList from JSON data.
|
||||||
func (ll *LandingList) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (ll *LandingList) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -126,7 +186,7 @@ func (ll *LandingList) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
return list, nil
|
return list, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of LandingLists
|
// DeList deserializes a list of LandingLists from JSON data.
|
||||||
func (ll *LandingList) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (ll *LandingList) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
|
|||||||
+30
-29
@@ -1,13 +1,14 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Metatag represents a metatag
|
// Metatag represents a metatag from the Yandex Music API.
|
||||||
type Metatag struct {
|
type Metatag struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Image string `json:"image"`
|
Image string `json:"image"`
|
||||||
@@ -16,7 +17,7 @@ type Metatag struct {
|
|||||||
Children []Metatag `json:"children"`
|
Children []Metatag `json:"children"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a Metatag from JSON
|
// DeJSON deserializes a Metatag from JSON data.
|
||||||
func (m *Metatag) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (m *Metatag) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -52,7 +53,7 @@ func (m *Metatag) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
|||||||
return metatag, nil
|
return metatag, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Metatags
|
// DeList deserializes a list of Metatags from JSON data.
|
||||||
func (m *Metatag) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (m *Metatag) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -70,17 +71,17 @@ func (m *Metatag) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MetatagTree represents a metatag tree
|
// MetatagTree represents a metatag tree.
|
||||||
type MetatagTree struct {
|
type MetatagTree struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Root *Metatag `json:"root"`
|
Root *Metatag `json:"root"`
|
||||||
Leaves []Metatag `json:"leaves"`
|
Leaves []Metatag `json:"leaves"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MetatagLeaf represents a metatag leaf
|
// MetatagLeaf represents a metatag leaf.
|
||||||
type MetatagLeaf struct {
|
type MetatagLeaf struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Image string `json:"image"`
|
Image string `json:"image"`
|
||||||
@@ -88,7 +89,7 @@ type MetatagLeaf struct {
|
|||||||
Position int `json:"position"`
|
Position int `json:"position"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MetatagArtists represents metatag artists
|
// MetatagArtists represents metatag artists.
|
||||||
type MetatagArtists struct {
|
type MetatagArtists struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Artists []Artist `json:"artists"`
|
Artists []Artist `json:"artists"`
|
||||||
@@ -97,7 +98,7 @@ type MetatagArtists struct {
|
|||||||
PageSize int `json:"page_size"`
|
PageSize int `json:"page_size"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MetatagAlbums represents metatag albums
|
// MetatagAlbums represents metatag albums.
|
||||||
type MetatagAlbums struct {
|
type MetatagAlbums struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Albums []Album `json:"albums"`
|
Albums []Album `json:"albums"`
|
||||||
@@ -106,7 +107,7 @@ type MetatagAlbums struct {
|
|||||||
PageSize int `json:"page_size"`
|
PageSize int `json:"page_size"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MetatagPlaylists represents metatag playlists
|
// MetatagPlaylists represents metatag playlists.
|
||||||
type MetatagPlaylists struct {
|
type MetatagPlaylists struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Playlists []Playlist `json:"playlists"`
|
Playlists []Playlist `json:"playlists"`
|
||||||
@@ -115,30 +116,30 @@ type MetatagPlaylists struct {
|
|||||||
PageSize int `json:"page_size"`
|
PageSize int `json:"page_size"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MetatagTitle represents a metatag title
|
// MetatagTitle represents a metatag title.
|
||||||
type MetatagTitle struct {
|
type MetatagTitle struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MetatagSortByValue represents metatag sort by value
|
// MetatagSortByValue represents metatag sort by value.
|
||||||
type MetatagSortByValue struct {
|
type MetatagSortByValue struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
Label string `json:"label"`
|
Label string `json:"label"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MetatagArtistEntry represents a metatag artist entry
|
// MetatagArtistEntry represents a metatag artist entry.
|
||||||
type MetatagArtistEntry struct {
|
type MetatagArtistEntry struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Artist *Artist `json:"artist"`
|
Artist *Artist `json:"artist"`
|
||||||
Score float64 `json:"score"`
|
PopularTracks []Track `json:"popular_tracks"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Genre represents a genre
|
// Genre represents a genre from the Yandex Music API.
|
||||||
type Genre struct {
|
type Genre struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Image string `json:"image"`
|
Image string `json:"image"`
|
||||||
@@ -147,7 +148,7 @@ type Genre struct {
|
|||||||
Children []Genre `json:"children"`
|
Children []Genre `json:"children"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a Genre from JSON
|
// DeJSON deserializes a Genre from JSON data.
|
||||||
func (g *Genre) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (g *Genre) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -183,7 +184,7 @@ func (g *Genre) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
|||||||
return genre, nil
|
return genre, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Genres
|
// DeList deserializes a list of Genres from JSON data.
|
||||||
func (g *Genre) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (g *Genre) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -201,10 +202,10 @@ func (g *Genre) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chart represents a chart
|
// Chart represents a chart from the Yandex Music API.
|
||||||
type Chart struct {
|
type Chart struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
CoverURI string `json:"cover_uri"`
|
CoverURI string `json:"cover_uri"`
|
||||||
@@ -212,7 +213,7 @@ type Chart struct {
|
|||||||
Items []ChartItem `json:"items"`
|
Items []ChartItem `json:"items"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a Chart from JSON
|
// DeJSON deserializes a Chart from JSON data.
|
||||||
func (c *Chart) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (c *Chart) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -245,7 +246,7 @@ func (c *Chart) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
|||||||
return chart, nil
|
return chart, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Charts
|
// DeList deserializes a list of Charts from JSON data.
|
||||||
func (c *Chart) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (c *Chart) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -263,14 +264,14 @@ func (c *Chart) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChartInfo represents chart info
|
// ChartInfo represents chart info.
|
||||||
type ChartInfo struct {
|
type ChartInfo struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Chart *Chart `json:"chart"`
|
Chart *Chart `json:"chart"`
|
||||||
Menu []ChartInfoMenu `json:"menu"`
|
Menu []ChartInfoMenu `json:"menu"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChartItem represents a chart item
|
// ChartItem represents a chart item.
|
||||||
type ChartItem struct {
|
type ChartItem struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Position int `json:"position"`
|
Position int `json:"position"`
|
||||||
@@ -282,25 +283,25 @@ type ChartItem struct {
|
|||||||
Trend string `json:"trend"`
|
Trend string `json:"trend"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChartInfoMenu represents a chart info menu
|
// ChartInfoMenu represents a chart info menu.
|
||||||
type ChartInfoMenu struct {
|
type ChartInfoMenu struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Items []ChartInfoMenuItem `json:"items"`
|
Items []ChartInfoMenuItem `json:"items"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChartInfoMenuItem represents a chart info menu item
|
// ChartInfoMenuItem represents a chart info menu item.
|
||||||
type ChartInfoMenuItem struct {
|
type ChartInfoMenuItem struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Action string `json:"action"`
|
Action string `json:"action"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChartItems represents chart items response
|
// ChartItems represents chart items response.
|
||||||
type ChartItems struct {
|
type ChartItems struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Items []ChartItem `json:"items"`
|
Items []ChartItem `json:"items"`
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MusicHistory represents music history
|
// MusicHistory represents music history from the Yandex Music API.
|
||||||
type MusicHistory struct {
|
type MusicHistory struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Tabs []MusicHistoryTab `json:"tabs"`
|
Tabs []MusicHistoryTab `json:"tabs"`
|
||||||
@@ -13,7 +14,7 @@ type MusicHistory struct {
|
|||||||
Context *MusicHistoryContextFullModel `json:"context"`
|
Context *MusicHistoryContextFullModel `json:"context"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a MusicHistory from JSON
|
// DeJSON deserializes a MusicHistory from JSON data.
|
||||||
func (mh *MusicHistory) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (mh *MusicHistory) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -46,7 +47,7 @@ func (mh *MusicHistory) DeJSON(data []byte, client ClientInterface) (Model, erro
|
|||||||
return history, nil
|
return history, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of MusicHistory
|
// DeList deserializes a list of MusicHistory from JSON data.
|
||||||
func (mh *MusicHistory) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (mh *MusicHistory) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -64,10 +65,10 @@ func (mh *MusicHistory) DeList(data []byte, client ClientInterface) ([]Model, er
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MusicHistoryTab represents a music history tab
|
// MusicHistoryTab represents a music history tab.
|
||||||
type MusicHistoryTab struct {
|
type MusicHistoryTab struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Icon string `json:"icon"`
|
Icon string `json:"icon"`
|
||||||
@@ -75,20 +76,20 @@ type MusicHistoryTab struct {
|
|||||||
Position int `json:"position"`
|
Position int `json:"position"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MusicHistoryGroup represents a music history group
|
// MusicHistoryGroup represents a music history group.
|
||||||
type MusicHistoryGroup struct {
|
type MusicHistoryGroup struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Items []MusicHistoryItem `json:"items"`
|
Items []MusicHistoryItem `json:"items"`
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MusicHistoryItem represents a music history item
|
// MusicHistoryItem represents a music history item.
|
||||||
type MusicHistoryItem struct {
|
type MusicHistoryItem struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Type string `json:"type"` // "track", "album", "artist", "playlist"
|
Type string `json:"type"` // "track", "album", "artist", "playlist"
|
||||||
Track *Track `json:"track"`
|
Track *Track `json:"track"`
|
||||||
Album *Album `json:"album"`
|
Album *Album `json:"album"`
|
||||||
@@ -100,7 +101,7 @@ type MusicHistoryItem struct {
|
|||||||
Context *MusicHistoryItemData `json:"context"`
|
Context *MusicHistoryItemData `json:"context"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MusicHistoryItemData represents music history item data
|
// MusicHistoryItemData represents music history item data.
|
||||||
type MusicHistoryItemData struct {
|
type MusicHistoryItemData struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Source string `json:"source"`
|
Source string `json:"source"`
|
||||||
@@ -109,17 +110,16 @@ type MusicHistoryItemData struct {
|
|||||||
PlayContext *PlayContext `json:"play_context"`
|
PlayContext *PlayContext `json:"play_context"`
|
||||||
Position int `json:"position"`
|
Position int `json:"position"`
|
||||||
Duration int `json:"duration"`
|
Duration int `json:"duration"`
|
||||||
Progress float64 `json:"progress"`
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// MusicHistoryItemID represents music history item ID
|
// MusicHistoryItemID represents music history item ID.
|
||||||
type MusicHistoryItemID struct {
|
type MusicHistoryItemID struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MusicHistoryItems represents music history items
|
// MusicHistoryItems represents music history items.
|
||||||
type MusicHistoryItems struct {
|
type MusicHistoryItems struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Items []MusicHistoryItem `json:"items"`
|
Items []MusicHistoryItem `json:"items"`
|
||||||
@@ -128,7 +128,7 @@ type MusicHistoryItems struct {
|
|||||||
PageSize int `json:"page_size"`
|
PageSize int `json:"page_size"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MusicHistoryContextFullModel represents music history context full model
|
// MusicHistoryContextFullModel represents music history context full model.
|
||||||
type MusicHistoryContextFullModel struct {
|
type MusicHistoryContextFullModel struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
DeviceID string `json:"device_id"`
|
DeviceID string `json:"device_id"`
|
||||||
|
|||||||
+57
-11
@@ -1,13 +1,14 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Pin represents a pin
|
// Pin represents a pin from the Yandex Music API.
|
||||||
type Pin struct {
|
type Pin struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Image string `json:"image"`
|
Image string `json:"image"`
|
||||||
@@ -20,9 +21,10 @@ type Pin struct {
|
|||||||
CreatedAt string `json:"created_at"`
|
CreatedAt string `json:"created_at"`
|
||||||
ExpiresAt string `json:"expires_at"`
|
ExpiresAt string `json:"expires_at"`
|
||||||
Active bool `json:"active"`
|
Active bool `json:"active"`
|
||||||
|
ContentRestrictions *ContentRestrictions `json:"content_restrictions"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a Pin from JSON
|
// DeJSON deserializes a Pin from JSON data.
|
||||||
func (p *Pin) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (p *Pin) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -58,6 +60,11 @@ func (p *Pin) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
|||||||
if v, ok := raw["active"]; ok {
|
if v, ok := raw["active"]; ok {
|
||||||
json.Unmarshal(v, &pin.Active)
|
json.Unmarshal(v, &pin.Active)
|
||||||
}
|
}
|
||||||
|
if v, ok := raw["content_restrictions"]; ok {
|
||||||
|
var cr ContentRestrictions
|
||||||
|
json.Unmarshal(v, &cr)
|
||||||
|
pin.ContentRestrictions = &cr
|
||||||
|
}
|
||||||
|
|
||||||
if v, ok := raw["track"]; ok {
|
if v, ok := raw["track"]; ok {
|
||||||
var track Track
|
var track Track
|
||||||
@@ -83,7 +90,7 @@ func (p *Pin) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
|||||||
return pin, nil
|
return pin, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Pins
|
// DeList deserializes a list of Pins from JSON data.
|
||||||
func (p *Pin) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (p *Pin) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -101,14 +108,14 @@ func (p *Pin) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PinData represents pin data
|
// PinData represents pin data.
|
||||||
type PinData struct {
|
type PinData struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Pins []Pin `json:"pins"`
|
Pins []Pin `json:"pins"`
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PinsList represents a list of pins
|
// PinsList represents a list of pins.
|
||||||
type PinsList struct {
|
type PinsList struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Pins []Pin `json:"pins"`
|
Pins []Pin `json:"pins"`
|
||||||
@@ -117,19 +124,21 @@ type PinsList struct {
|
|||||||
PageSize int `json:"page_size"`
|
PageSize int `json:"page_size"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Presaves represents presaves
|
// Presaves represents presaves.
|
||||||
type Presaves struct {
|
type Presaves struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
|
UpcomingAlbums []Album `json:"upcoming_albums"`
|
||||||
|
ReleasedAlbums []Album `json:"released_albums"`
|
||||||
Presaves []Presave `json:"presaves"`
|
Presaves []Presave `json:"presaves"`
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
Page int `json:"page"`
|
Page int `json:"page"`
|
||||||
PageSize int `json:"page_size"`
|
PageSize int `json:"page_size"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Presave represents a presave
|
// Presave represents a presave.
|
||||||
type Presave struct {
|
type Presave struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Image string `json:"image"`
|
Image string `json:"image"`
|
||||||
@@ -142,7 +151,7 @@ type Presave struct {
|
|||||||
UpdatedAt string `json:"updated_at"`
|
UpdatedAt string `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a Presave from JSON
|
// DeJSON deserializes a Presave from JSON data.
|
||||||
func (p *Presave) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (p *Presave) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -195,7 +204,7 @@ func (p *Presave) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
|||||||
return presave, nil
|
return presave, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Presaves
|
// DeList deserializes a list of Presaves from JSON data.
|
||||||
func (p *Presave) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (p *Presave) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -212,3 +221,40 @@ func (p *Presave) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
|||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes Presaves from JSON data.
|
||||||
|
func (p *Presaves) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
presaves := &Presaves{BaseModel: *NewBaseModel(client)}
|
||||||
|
|
||||||
|
if v, ok := raw["upcoming_albums"]; ok {
|
||||||
|
var albums []Album
|
||||||
|
json.Unmarshal(v, &albums)
|
||||||
|
presaves.UpcomingAlbums = albums
|
||||||
|
}
|
||||||
|
if v, ok := raw["released_albums"]; ok {
|
||||||
|
var albums []Album
|
||||||
|
json.Unmarshal(v, &albums)
|
||||||
|
presaves.ReleasedAlbums = albums
|
||||||
|
}
|
||||||
|
if v, ok := raw["presaves"]; ok {
|
||||||
|
var presaveList []Presave
|
||||||
|
json.Unmarshal(v, &presaveList)
|
||||||
|
presaves.Presaves = presaveList
|
||||||
|
}
|
||||||
|
if v, ok := raw["total"]; ok {
|
||||||
|
json.Unmarshal(v, &presaves.Total)
|
||||||
|
}
|
||||||
|
if v, ok := raw["page"]; ok {
|
||||||
|
json.Unmarshal(v, &presaves.Page)
|
||||||
|
}
|
||||||
|
if v, ok := raw["page_size"]; ok {
|
||||||
|
json.Unmarshal(v, &presaves.PageSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
return presaves, nil
|
||||||
|
}
|
||||||
+12
-11
@@ -1,10 +1,11 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Playlist represents a playlist
|
// Playlist represents a playlist from the Yandex Music API.
|
||||||
type Playlist struct {
|
type Playlist struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Kind int `json:"kind"`
|
Kind int `json:"kind"`
|
||||||
@@ -36,7 +37,7 @@ type Playlist struct {
|
|||||||
Trailer *TrailerInfo `json:"trailer"`
|
Trailer *TrailerInfo `json:"trailer"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a Playlist from JSON
|
// DeJSON deserializes a Playlist from JSON data.
|
||||||
func (p *Playlist) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (p *Playlist) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -142,7 +143,7 @@ func (p *Playlist) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
return playlist, nil
|
return playlist, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Playlists
|
// DeList deserializes a list of Playlists from JSON data.
|
||||||
func (p *Playlist) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (p *Playlist) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -160,7 +161,7 @@ func (p *Playlist) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// User represents a user (playlist owner)
|
// User represents a user (playlist owner) from the Yandex Music API.
|
||||||
type User struct {
|
type User struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
UID int64 `json:"uid"`
|
UID int64 `json:"uid"`
|
||||||
@@ -184,7 +185,7 @@ type User struct {
|
|||||||
Counters *UserCounters `json:"counters"`
|
Counters *UserCounters `json:"counters"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a User from JSON
|
// DeJSON deserializes a User from JSON data.
|
||||||
func (u *User) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (u *User) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -255,7 +256,7 @@ func (u *User) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Users
|
// DeList deserializes a list of Users from JSON data.
|
||||||
func (u *User) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (u *User) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -273,7 +274,7 @@ func (u *User) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserSettings represents user settings (from /account/settings)
|
// UserSettings represents user settings from /account/settings.
|
||||||
type UserSettings struct {
|
type UserSettings struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
UID int64 `json:"uid"`
|
UID int64 `json:"uid"`
|
||||||
@@ -295,7 +296,7 @@ type UserSettings struct {
|
|||||||
ShowDiskTracksInLibrary *bool `json:"show_disk_tracks_in_library,omitempty"`
|
ShowDiskTracksInLibrary *bool `json:"show_disk_tracks_in_library,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes UserSettings from JSON
|
// DeJSON deserializes UserSettings from JSON data.
|
||||||
func (u *UserSettings) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (u *UserSettings) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -365,7 +366,7 @@ func (u *UserSettings) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
return settings, nil
|
return settings, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of UserSettings
|
// DeList deserializes a list of UserSettings from JSON data.
|
||||||
func (u *UserSettings) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (u *UserSettings) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -383,7 +384,7 @@ func (u *UserSettings) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserCounters represents user counters
|
// UserCounters represents user counters.
|
||||||
type UserCounters struct {
|
type UserCounters struct {
|
||||||
Tracks int `json:"tracks"`
|
Tracks int `json:"tracks"`
|
||||||
Albums int `json:"albums"`
|
Albums int `json:"albums"`
|
||||||
@@ -393,7 +394,7 @@ type UserCounters struct {
|
|||||||
Likes int `json:"likes"`
|
Likes int `json:"likes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Image represents an image with multiple sizes
|
// Image represents an image with multiple sizes.
|
||||||
type Image struct {
|
type Image struct {
|
||||||
URI string `json:"uri"`
|
URI string `json:"uri"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
|||||||
+20
-17
@@ -1,13 +1,14 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Queue represents a playback queue
|
// Queue represents a playback queue from the Yandex Music API.
|
||||||
type Queue struct {
|
type Queue struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
TrackIDs []string `json:"track_ids"`
|
TrackIDs []string `json:"track_ids"`
|
||||||
CurrentIndex int `json:"current_index"`
|
CurrentIndex int `json:"current_index"`
|
||||||
QueueType string `json:"queue_type"`
|
QueueType string `json:"queue_type"`
|
||||||
@@ -20,7 +21,7 @@ type Queue struct {
|
|||||||
TotalDuration int `json:"total_duration_ms"`
|
TotalDuration int `json:"total_duration_ms"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a Queue from JSON
|
// DeJSON deserializes a Queue from JSON data.
|
||||||
func (q *Queue) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (q *Queue) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -71,7 +72,7 @@ func (q *Queue) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
return queue, nil
|
return queue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Queues
|
// DeList deserializes a list of Queues from JSON data.
|
||||||
func (q *Queue) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (q *Queue) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -89,19 +90,21 @@ func (q *Queue) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueueItem represents a queue item
|
// QueueItem represents a queue item.
|
||||||
type QueueItem struct {
|
type QueueItem struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
|
ID JSONID `json:"id"`
|
||||||
TrackID string `json:"track_id"`
|
TrackID string `json:"track_id"`
|
||||||
Track *Track `json:"track"`
|
Track *Track `json:"track"`
|
||||||
Position int `json:"position"`
|
Position int `json:"position"`
|
||||||
AddedAt string `json:"added_at"`
|
AddedAt string `json:"added_at"`
|
||||||
AddedBy string `json:"added_by"`
|
AddedBy string `json:"added_by"`
|
||||||
Playable bool `json:"playable"`
|
Playable bool `json:"playable"`
|
||||||
PlayContext *PlayContext `json:"play_context"`
|
Modified string `json:"modified"`
|
||||||
|
Context *PlayContext `json:"context"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a QueueItem from JSON
|
// DeJSON deserializes a QueueItem from JSON data.
|
||||||
func (qi *QueueItem) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (qi *QueueItem) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -131,16 +134,16 @@ func (qi *QueueItem) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
json.Unmarshal(v, &track)
|
json.Unmarshal(v, &track)
|
||||||
item.Track = &track
|
item.Track = &track
|
||||||
}
|
}
|
||||||
if v, ok := raw["play_context"]; ok {
|
if v, ok := raw["context"]; ok {
|
||||||
var ctx PlayContext
|
var ctx PlayContext
|
||||||
json.Unmarshal(v, &ctx)
|
json.Unmarshal(v, &ctx)
|
||||||
item.PlayContext = &ctx
|
item.Context = &ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
return item, nil
|
return item, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of QueueItems
|
// DeList deserializes a list of QueueItems from JSON data.
|
||||||
func (qi *QueueItem) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (qi *QueueItem) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -158,10 +161,10 @@ func (qi *QueueItem) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PlayContext represents a play context
|
// PlayContext represents a play context.
|
||||||
type PlayContext struct {
|
type PlayContext struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Type string `json:"type"` // "playlist", "album", "artist", "radio", "search"
|
Type string `json:"type"` // "playlist", "album", "artist", "radio", "search"
|
||||||
SourceID string `json:"source_id"`
|
SourceID string `json:"source_id"`
|
||||||
SourceKind string `json:"source_kind"`
|
SourceKind string `json:"source_kind"`
|
||||||
@@ -173,7 +176,7 @@ type PlayContext struct {
|
|||||||
Available bool `json:"available"`
|
Available bool `json:"available"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a PlayContext from JSON
|
// DeJSON deserializes a PlayContext from JSON data.
|
||||||
func (pc *PlayContext) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (pc *PlayContext) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -219,7 +222,7 @@ func (pc *PlayContext) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
return ctx, nil
|
return ctx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of PlayContexts
|
// DeList deserializes a list of PlayContexts from JSON data.
|
||||||
func (pc *PlayContext) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (pc *PlayContext) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -237,7 +240,7 @@ func (pc *PlayContext) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PlayContextsData represents play contexts data
|
// PlayContextsData represents play contexts data.
|
||||||
type PlayContextsData struct {
|
type PlayContextsData struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Contexts []PlayContext `json:"contexts"`
|
Contexts []PlayContext `json:"contexts"`
|
||||||
@@ -246,7 +249,7 @@ type PlayContextsData struct {
|
|||||||
PageSize int `json:"page_size"`
|
PageSize int `json:"page_size"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes PlayContextsData from JSON
|
// DeJSON deserializes PlayContextsData from JSON data.
|
||||||
func (pcd *PlayContextsData) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (pcd *PlayContextsData) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -273,7 +276,7 @@ func (pcd *PlayContextsData) DeJSON(data []byte, c ClientInterface) (Model, erro
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of PlayContextsData
|
// DeList deserializes a list of PlayContextsData from JSON data.
|
||||||
func (pcd *PlayContextsData) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (pcd *PlayContextsData) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
|
|||||||
+414
-22
@@ -1,13 +1,14 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RadioStation represents a radio station
|
// RadioStation represents a radio station from the Yandex Music API.
|
||||||
type RadioStation struct {
|
type RadioStation struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
CoverURI string `json:"cover_uri"`
|
CoverURI string `json:"cover_uri"`
|
||||||
@@ -16,7 +17,7 @@ type RadioStation struct {
|
|||||||
IsPersonal bool `json:"is_personal"`
|
IsPersonal bool `json:"is_personal"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a RadioStation from JSON
|
// DeJSON deserializes a RadioStation from JSON data.
|
||||||
func (r *RadioStation) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (r *RadioStation) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -50,7 +51,7 @@ func (r *RadioStation) DeJSON(data []byte, client ClientInterface) (Model, error
|
|||||||
return station, nil
|
return station, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of RadioStations
|
// DeList deserializes a list of RadioStations from JSON data.
|
||||||
func (r *RadioStation) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (r *RadioStation) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -68,7 +69,7 @@ func (r *RadioStation) DeList(data []byte, client ClientInterface) ([]Model, err
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// StationTracksResult represents station tracks result
|
// StationTracksResult represents station tracks result.
|
||||||
type StationTracksResult struct {
|
type StationTracksResult struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Tracks []Track `json:"tracks"`
|
Tracks []Track `json:"tracks"`
|
||||||
@@ -76,7 +77,7 @@ type StationTracksResult struct {
|
|||||||
Sequence string `json:"sequence"`
|
Sequence string `json:"sequence"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes StationTracksResult from JSON
|
// DeJSON deserializes StationTracksResult from JSON data.
|
||||||
func (s *StationTracksResult) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (s *StationTracksResult) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -100,7 +101,7 @@ func (s *StationTracksResult) DeJSON(data []byte, client ClientInterface) (Model
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of StationTracksResult
|
// DeList deserializes a list of StationTracksResult from JSON data.
|
||||||
func (s *StationTracksResult) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (s *StationTracksResult) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -118,10 +119,10 @@ func (s *StationTracksResult) DeList(data []byte, client ClientInterface) ([]Mod
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RotorStation represents a rotor (generative) station
|
// RotorStation represents a rotor (generative) station.
|
||||||
type RotorStation struct {
|
type RotorStation struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
CoverURI string `json:"cover_uri"`
|
CoverURI string `json:"cover_uri"`
|
||||||
@@ -131,7 +132,7 @@ type RotorStation struct {
|
|||||||
Settings *RotorSettings `json:"settings"`
|
Settings *RotorSettings `json:"settings"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a RotorStation from JSON
|
// DeJSON deserializes a RotorStation from JSON data.
|
||||||
func (r *RotorStation) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (r *RotorStation) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -170,7 +171,7 @@ func (r *RotorStation) DeJSON(data []byte, client ClientInterface) (Model, error
|
|||||||
return station, nil
|
return station, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of RotorStations
|
// DeList deserializes a list of RotorStations from JSON data.
|
||||||
func (r *RotorStation) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (r *RotorStation) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -188,11 +189,14 @@ func (r *RotorStation) DeList(data []byte, client ClientInterface) ([]Model, err
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RotorSettings represents rotor station settings
|
// RotorSettings represents rotor station settings.
|
||||||
type RotorSettings struct {
|
type RotorSettings struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Diversity float64 `json:"diversity"`
|
Language string `json:"language"`
|
||||||
Energy float64 `json:"energy"`
|
Diversity string `json:"diversity"`
|
||||||
|
Mood int `json:"mood"`
|
||||||
|
Energy int `json:"energy"`
|
||||||
|
MoodEnergy string `json:"mood_energy"`
|
||||||
Acousticness float64 `json:"acousticness"`
|
Acousticness float64 `json:"acousticness"`
|
||||||
Instrumentalness float64 `json:"instrumentalness"`
|
Instrumentalness float64 `json:"instrumentalness"`
|
||||||
Live float64 `json:"live"`
|
Live float64 `json:"live"`
|
||||||
@@ -201,7 +205,7 @@ type RotorSettings struct {
|
|||||||
Valence float64 `json:"valence"`
|
Valence float64 `json:"valence"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RotorStationTracksResult represents rotor station tracks result
|
// RotorStationTracksResult represents rotor station tracks result.
|
||||||
type RotorStationTracksResult struct {
|
type RotorStationTracksResult struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Tracks []Track `json:"tracks"`
|
Tracks []Track `json:"tracks"`
|
||||||
@@ -209,7 +213,7 @@ type RotorStationTracksResult struct {
|
|||||||
Sequence string `json:"sequence"`
|
Sequence string `json:"sequence"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes RotorStationTracksResult from JSON
|
// DeJSON deserializes RotorStationTracksResult from JSON data.
|
||||||
func (r *RotorStationTracksResult) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (r *RotorStationTracksResult) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -233,7 +237,7 @@ func (r *RotorStationTracksResult) DeJSON(data []byte, client ClientInterface) (
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of RotorStationTracksResult
|
// DeList deserializes a list of RotorStationTracksResult from JSON data.
|
||||||
func (r *RotorStationTracksResult) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (r *RotorStationTracksResult) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -251,7 +255,7 @@ func (r *RotorStationTracksResult) DeList(data []byte, client ClientInterface) (
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RotorSession represents a rotor session
|
// RotorSession represents a rotor session.
|
||||||
type RotorSession struct {
|
type RotorSession struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
SessionID string `json:"session_id"`
|
SessionID string `json:"session_id"`
|
||||||
@@ -262,7 +266,7 @@ type RotorSession struct {
|
|||||||
CreatedAt string `json:"created_at"`
|
CreatedAt string `json:"created_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a RotorSession from JSON
|
// DeJSON deserializes a RotorSession from JSON data.
|
||||||
func (r *RotorSession) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (r *RotorSession) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -295,7 +299,7 @@ func (r *RotorSession) DeJSON(data []byte, client ClientInterface) (Model, error
|
|||||||
return session, nil
|
return session, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of RotorSessions
|
// DeList deserializes a list of RotorSessions from JSON data.
|
||||||
func (r *RotorSession) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (r *RotorSession) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -313,7 +317,71 @@ func (r *RotorSession) DeList(data []byte, client ClientInterface) ([]Model, err
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SessionFeedback represents session feedback
|
// AdParams represents ad parameters.
|
||||||
|
type AdParams struct {
|
||||||
|
BaseModel
|
||||||
|
PartnerID string `json:"partner_id"`
|
||||||
|
CategoryID string `json:"category_id"`
|
||||||
|
PageRef string `json:"page_ref"`
|
||||||
|
TargetRef string `json:"target_ref"`
|
||||||
|
OtherParams string `json:"other_params"`
|
||||||
|
GenreID string `json:"genre_id"`
|
||||||
|
GenreName string `json:"genre_name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes AdParams from JSON data.
|
||||||
|
func (ap *AdParams) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
params := &AdParams{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["partner_id"]; ok {
|
||||||
|
json.Unmarshal(v, ¶ms.PartnerID)
|
||||||
|
}
|
||||||
|
if v, ok := raw["category_id"]; ok {
|
||||||
|
json.Unmarshal(v, ¶ms.CategoryID)
|
||||||
|
}
|
||||||
|
if v, ok := raw["page_ref"]; ok {
|
||||||
|
json.Unmarshal(v, ¶ms.PageRef)
|
||||||
|
}
|
||||||
|
if v, ok := raw["target_ref"]; ok {
|
||||||
|
json.Unmarshal(v, ¶ms.TargetRef)
|
||||||
|
}
|
||||||
|
if v, ok := raw["other_params"]; ok {
|
||||||
|
json.Unmarshal(v, ¶ms.OtherParams)
|
||||||
|
}
|
||||||
|
if v, ok := raw["genre_id"]; ok {
|
||||||
|
json.Unmarshal(v, ¶ms.GenreID)
|
||||||
|
}
|
||||||
|
if v, ok := raw["genre_name"]; ok {
|
||||||
|
json.Unmarshal(v, ¶ms.GenreName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return params, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of AdParams from JSON data.
|
||||||
|
func (ap *AdParams) 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 {
|
||||||
|
params := &AdParams{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, params); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, params)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SessionFeedback represents session feedback.
|
||||||
type SessionFeedback struct {
|
type SessionFeedback struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
TrackID string `json:"track_id"`
|
TrackID string `json:"track_id"`
|
||||||
@@ -321,8 +389,332 @@ type SessionFeedback struct {
|
|||||||
Timestamp string `json:"timestamp"`
|
Timestamp string `json:"timestamp"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SessionFeedbacks represents multiple session feedbacks
|
// SessionFeedbacks represents multiple session feedbacks.
|
||||||
type SessionFeedbacks struct {
|
type SessionFeedbacks struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Feedbacks []SessionFeedback `json:"feedbacks"`
|
Feedbacks []SessionFeedback `json:"feedbacks"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dashboard represents rotor stations dashboard.
|
||||||
|
type Dashboard struct {
|
||||||
|
BaseModel
|
||||||
|
DashboardID string `json:"dashboard_id"`
|
||||||
|
Stations []StationResult `json:"stations"`
|
||||||
|
Pumpkin bool `json:"pumpkin"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes Dashboard from JSON data.
|
||||||
|
func (d *Dashboard) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dashboard := &Dashboard{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["dashboard_id"]; ok {
|
||||||
|
json.Unmarshal(v, &dashboard.DashboardID)
|
||||||
|
}
|
||||||
|
if v, ok := raw["stations"]; ok {
|
||||||
|
var stations []StationResult
|
||||||
|
json.Unmarshal(v, &stations)
|
||||||
|
dashboard.Stations = stations
|
||||||
|
}
|
||||||
|
if v, ok := raw["pumpkin"]; ok {
|
||||||
|
json.Unmarshal(v, &dashboard.Pumpkin)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dashboard, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of Dashboards from JSON data.
|
||||||
|
func (d *Dashboard) 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 {
|
||||||
|
dashboard := &Dashboard{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, dashboard); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, dashboard)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StationResult represents a station result.
|
||||||
|
type StationResult struct {
|
||||||
|
BaseModel
|
||||||
|
Station *Station `json:"station"`
|
||||||
|
Settings *RotorSettings `json:"settings"`
|
||||||
|
Settings2 *RotorSettings `json:"settings2"`
|
||||||
|
AdParams *AdParams `json:"ad_params"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes StationResult from JSON data.
|
||||||
|
func (sr *StationResult) 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 := &StationResult{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["station"]; ok {
|
||||||
|
var station Station
|
||||||
|
json.Unmarshal(v, &station)
|
||||||
|
result.Station = &station
|
||||||
|
}
|
||||||
|
if v, ok := raw["settings"]; ok {
|
||||||
|
var settings RotorSettings
|
||||||
|
json.Unmarshal(v, &settings)
|
||||||
|
result.Settings = &settings
|
||||||
|
}
|
||||||
|
if v, ok := raw["settings2"]; ok {
|
||||||
|
var settings2 RotorSettings
|
||||||
|
json.Unmarshal(v, &settings2)
|
||||||
|
result.Settings2 = &settings2
|
||||||
|
}
|
||||||
|
if v, ok := raw["ad_params"]; ok {
|
||||||
|
var adParams AdParams
|
||||||
|
json.Unmarshal(v, &adParams)
|
||||||
|
result.AdParams = &adParams
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of StationResults from JSON data.
|
||||||
|
func (sr *StationResult) 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 {
|
||||||
|
sr := &StationResult{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, sr); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, sr)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerativeStream represents a generative stream.
|
||||||
|
type GenerativeStream struct {
|
||||||
|
BaseModel
|
||||||
|
Data *GenerativeStreamData `json:"data"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
Stream *GenerativeStreamInfo `json:"stream"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes GenerativeStream from JSON data.
|
||||||
|
func (gs *GenerativeStream) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
stream := &GenerativeStream{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["data"]; ok {
|
||||||
|
var data GenerativeStreamData
|
||||||
|
json.Unmarshal(v, &data)
|
||||||
|
stream.Data = &data
|
||||||
|
}
|
||||||
|
if v, ok := raw["version"]; ok {
|
||||||
|
json.Unmarshal(v, &stream.Version)
|
||||||
|
}
|
||||||
|
if v, ok := raw["stream"]; ok {
|
||||||
|
var streamInfo GenerativeStreamInfo
|
||||||
|
json.Unmarshal(v, &streamInfo)
|
||||||
|
stream.Stream = &streamInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of GenerativeStreams from JSON data.
|
||||||
|
func (gs *GenerativeStream) 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 {
|
||||||
|
stream := &GenerativeStream{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, stream); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, stream)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Station represents a radio station (used in StationResult).
|
||||||
|
type Station struct {
|
||||||
|
BaseModel
|
||||||
|
ID JSONID `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Icon string `json:"icon"`
|
||||||
|
IDForFrom string `json:"id_for_from"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes Station from JSON data.
|
||||||
|
func (s *Station) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
station := &Station{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["id"]; ok {
|
||||||
|
json.Unmarshal(v, &station.ID)
|
||||||
|
}
|
||||||
|
if v, ok := raw["name"]; ok {
|
||||||
|
json.Unmarshal(v, &station.Name)
|
||||||
|
}
|
||||||
|
if v, ok := raw["icon"]; ok {
|
||||||
|
json.Unmarshal(v, &station.Icon)
|
||||||
|
}
|
||||||
|
if v, ok := raw["id_for_from"]; ok {
|
||||||
|
json.Unmarshal(v, &station.IDForFrom)
|
||||||
|
}
|
||||||
|
|
||||||
|
return station, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of Stations from JSON data.
|
||||||
|
func (s *Station) 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 {
|
||||||
|
station := &Station{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, station); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, station)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerativeStreamData represents generative stream data.
|
||||||
|
type GenerativeStreamData struct {
|
||||||
|
BaseModel
|
||||||
|
Title string `json:"title"`
|
||||||
|
Subtitle string `json:"subtitle"`
|
||||||
|
BackgroundColor string `json:"background_color"`
|
||||||
|
DerivedColors *CoverDerivedColors `json:"derived_colors"`
|
||||||
|
ImageURL string `json:"image_url"`
|
||||||
|
VideoCoverURI string `json:"video_cover_uri"`
|
||||||
|
Explanations string `json:"explanations"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes GenerativeStreamData from JSON data.
|
||||||
|
func (gsd *GenerativeStreamData) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gsdData := &GenerativeStreamData{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["title"]; ok {
|
||||||
|
json.Unmarshal(v, &gsdData.Title)
|
||||||
|
}
|
||||||
|
if v, ok := raw["subtitle"]; ok {
|
||||||
|
json.Unmarshal(v, &gsdData.Subtitle)
|
||||||
|
}
|
||||||
|
if v, ok := raw["background_color"]; ok {
|
||||||
|
json.Unmarshal(v, &gsdData.BackgroundColor)
|
||||||
|
}
|
||||||
|
if v, ok := raw["derived_colors"]; ok {
|
||||||
|
var dc CoverDerivedColors
|
||||||
|
json.Unmarshal(v, &dc)
|
||||||
|
gsdData.DerivedColors = &dc
|
||||||
|
}
|
||||||
|
if v, ok := raw["image_url"]; ok {
|
||||||
|
json.Unmarshal(v, &gsdData.ImageURL)
|
||||||
|
}
|
||||||
|
if v, ok := raw["video_cover_uri"]; ok {
|
||||||
|
json.Unmarshal(v, &gsdData.VideoCoverURI)
|
||||||
|
}
|
||||||
|
if v, ok := raw["explanations"]; ok {
|
||||||
|
json.Unmarshal(v, &gsdData.Explanations)
|
||||||
|
}
|
||||||
|
|
||||||
|
return gsdData, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of GenerativeStreamData from JSON data.
|
||||||
|
func (gsd *GenerativeStreamData) 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 {
|
||||||
|
data := &GenerativeStreamData{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, data); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, data)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerativeStreamInfo represents generative stream info.
|
||||||
|
type GenerativeStreamInfo struct {
|
||||||
|
BaseModel
|
||||||
|
ID string `json:"id"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes GenerativeStreamInfo from JSON data.
|
||||||
|
func (gsi *GenerativeStreamInfo) 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 := &GenerativeStreamInfo{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["id"]; ok {
|
||||||
|
json.Unmarshal(v, &info.ID)
|
||||||
|
}
|
||||||
|
if v, ok := raw["url"]; ok {
|
||||||
|
json.Unmarshal(v, &info.URL)
|
||||||
|
}
|
||||||
|
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of GenerativeStreamInfo from JSON data.
|
||||||
|
func (gsi *GenerativeStreamInfo) 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 := &GenerativeStreamInfo{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, info); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, info)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
+27
-13
@@ -1,54 +1,68 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
package models
|
package models
|
||||||
|
|
||||||
// SearchResult represents search results
|
// SearchResult represents search results from the Yandex Music API.
|
||||||
type SearchResult struct {
|
type SearchResult struct {
|
||||||
|
SearchRequestID string `json:"search_request_id"`
|
||||||
|
Text string `json:"text"`
|
||||||
|
Best *Best `json:"best"`
|
||||||
Tracks *SearchTracksResult `json:"tracks"`
|
Tracks *SearchTracksResult `json:"tracks"`
|
||||||
Albums *SearchAlbumsResult `json:"albums"`
|
Albums *SearchAlbumsResult `json:"albums"`
|
||||||
Artists *SearchArtistsResult `json:"artists"`
|
Artists *SearchArtistsResult `json:"artists"`
|
||||||
Playlists *SearchPlaylistsResult `json:"playlists"`
|
Playlists *SearchPlaylistsResult `json:"playlists"`
|
||||||
Videos *SearchVideosResult `json:"videos"`
|
Videos *SearchVideosResult `json:"videos"`
|
||||||
Users *SearchUsersResult `json:"users"`
|
Users *SearchUsersResult `json:"users"`
|
||||||
|
Podcasts *SearchAlbumsResult `json:"podcasts"`
|
||||||
|
PodcastEpisodes *SearchTracksResult `json:"podcast_episodes"`
|
||||||
|
Clips *SearchVideosResult `json:"clips"`
|
||||||
|
Banner *SearchBanner `json:"banner"`
|
||||||
|
Page int `json:"page"`
|
||||||
|
PerPage int `json:"per_page"`
|
||||||
|
MisspellResult bool `json:"misspell_result"`
|
||||||
|
MisspellOriginal string `json:"misspell_original"`
|
||||||
|
MisspellCorrected bool `json:"misspell_corrected"`
|
||||||
|
Nocorrect bool `json:"nocorrect"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchTracksResult represents track search results
|
// SearchTracksResult represents track search results.
|
||||||
type SearchTracksResult struct {
|
type SearchTracksResult struct {
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
Results []Track `json:"results"`
|
Results []Track `json:"results"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchAlbumsResult represents album search results
|
// SearchAlbumsResult represents album search results.
|
||||||
type SearchAlbumsResult struct {
|
type SearchAlbumsResult struct {
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
Results []Album `json:"results"`
|
Results []Album `json:"results"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchArtistsResult represents artist search results
|
// SearchArtistsResult represents artist search results.
|
||||||
type SearchArtistsResult struct {
|
type SearchArtistsResult struct {
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
Results []Artist `json:"results"`
|
Results []Artist `json:"results"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchPlaylistsResult represents playlist search results
|
// SearchPlaylistsResult represents playlist search results.
|
||||||
type SearchPlaylistsResult struct {
|
type SearchPlaylistsResult struct {
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
Results []Playlist `json:"results"`
|
Results []Playlist `json:"results"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchVideosResult represents video search results
|
// SearchVideosResult represents video search results.
|
||||||
type SearchVideosResult struct {
|
type SearchVideosResult struct {
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
Results []Video `json:"results"`
|
Results []Video `json:"results"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchUsersResult represents user search results
|
// SearchUsersResult represents user search results.
|
||||||
type SearchUsersResult struct {
|
type SearchUsersResult struct {
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
Results []User `json:"results"`
|
Results []User `json:"results"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchBanner represents a search banner
|
// SearchBanner represents a search banner.
|
||||||
type SearchBanner struct {
|
type SearchBanner struct {
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Image string `json:"image"`
|
Image string `json:"image"`
|
||||||
@@ -57,19 +71,19 @@ type SearchBanner struct {
|
|||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tag represents a search tag
|
// Tag represents a search tag.
|
||||||
type Tag struct {
|
type Tag struct {
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Count int `json:"count"`
|
Count int `json:"count"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Video represents a video (minimal)
|
// Video represents a video (minimal).
|
||||||
type Video struct {
|
type Video struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Duration int `json:"duration"`
|
Duration int `json:"duration"`
|
||||||
CoverURI string `json:"cover_uri"`
|
CoverURI string `json:"cover_uri"`
|
||||||
|
|||||||
+20
-19
@@ -1,17 +1,18 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Experiments represents experiments
|
// Experiments represents experiments from the Yandex Music API.
|
||||||
type Experiments struct {
|
type Experiments struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Experiments []ExperimentDetail `json:"experiments"`
|
Experiments []ExperimentDetail `json:"experiments"`
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes Experiments from JSON
|
// DeJSON deserializes Experiments from JSON data.
|
||||||
func (e *Experiments) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (e *Experiments) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -32,7 +33,7 @@ func (e *Experiments) DeJSON(data []byte, client ClientInterface) (Model, error)
|
|||||||
return experiments, nil
|
return experiments, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Experiments
|
// DeList deserializes a list of Experiments from JSON data.
|
||||||
func (e *Experiments) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (e *Experiments) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -50,10 +51,10 @@ func (e *Experiments) DeList(data []byte, client ClientInterface) ([]Model, erro
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExperimentDetail represents experiment details
|
// ExperimentDetail represents experiment details.
|
||||||
type ExperimentDetail struct {
|
type ExperimentDetail struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
@@ -62,7 +63,7 @@ type ExperimentDetail struct {
|
|||||||
EndDate string `json:"end_date"`
|
EndDate string `json:"end_date"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes ExperimentDetail from JSON
|
// DeJSON deserializes ExperimentDetail from JSON data.
|
||||||
func (e *ExperimentDetail) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (e *ExperimentDetail) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -96,7 +97,7 @@ func (e *ExperimentDetail) DeJSON(data []byte, client ClientInterface) (Model, e
|
|||||||
return detail, nil
|
return detail, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of ExperimentDetails
|
// DeList deserializes a list of ExperimentDetails from JSON data.
|
||||||
func (e *ExperimentDetail) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (e *ExperimentDetail) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -114,7 +115,7 @@ func (e *ExperimentDetail) DeList(data []byte, client ClientInterface) ([]Model,
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Permissions represents user permissions
|
// Permissions represents user permissions.
|
||||||
type Permissions struct {
|
type Permissions struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
CanPlay bool `json:"can_play"`
|
CanPlay bool `json:"can_play"`
|
||||||
@@ -129,7 +130,7 @@ type Permissions struct {
|
|||||||
CanUseLossless bool `json:"can_use_lossless"`
|
CanUseLossless bool `json:"can_use_lossless"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes Permissions from JSON
|
// DeJSON deserializes Permissions from JSON data.
|
||||||
func (p *Permissions) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (p *Permissions) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -172,7 +173,7 @@ func (p *Permissions) DeJSON(data []byte, client ClientInterface) (Model, error)
|
|||||||
return perms, nil
|
return perms, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Permissions
|
// DeList deserializes a list of Permissions from JSON data.
|
||||||
func (p *Permissions) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (p *Permissions) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -190,14 +191,14 @@ func (p *Permissions) DeList(data []byte, client ClientInterface) ([]Model, erro
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PermissionAlerts represents permission alerts
|
// PermissionAlerts represents permission alerts.
|
||||||
type PermissionAlerts struct {
|
type PermissionAlerts struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Alerts []PermissionAlert `json:"alerts"`
|
Alerts []PermissionAlert `json:"alerts"`
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes PermissionAlerts from JSON
|
// DeJSON deserializes PermissionAlerts from JSON data.
|
||||||
func (p *PermissionAlerts) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (p *PermissionAlerts) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -218,7 +219,7 @@ func (p *PermissionAlerts) DeJSON(data []byte, client ClientInterface) (Model, e
|
|||||||
return alerts, nil
|
return alerts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of PermissionAlerts
|
// DeList deserializes a list of PermissionAlerts from JSON data. from JSON data.
|
||||||
func (p *PermissionAlerts) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (p *PermissionAlerts) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -236,10 +237,10 @@ func (p *PermissionAlerts) DeList(data []byte, client ClientInterface) ([]Model,
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PermissionAlert represents a permission alert
|
// PermissionAlert represents a permission alert.
|
||||||
type PermissionAlert struct {
|
type PermissionAlert struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
@@ -248,7 +249,7 @@ type PermissionAlert struct {
|
|||||||
CreatedAt string `json:"created_at"`
|
CreatedAt string `json:"created_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes PermissionAlert from JSON
|
// DeJSON deserializes PermissionAlert from JSON data.
|
||||||
func (p *PermissionAlert) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (p *PermissionAlert) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -300,7 +301,7 @@ func (p *PermissionAlert) DeList(data []byte, client ClientInterface) ([]Model,
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContentRestrictions represents content restrictions
|
// ContentRestrictions represents content restrictions.
|
||||||
type ContentRestrictions struct {
|
type ContentRestrictions struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
HasExplicitContent bool `json:"has_explicit_content"`
|
HasExplicitContent bool `json:"has_explicit_content"`
|
||||||
@@ -311,7 +312,7 @@ type ContentRestrictions struct {
|
|||||||
BlockedArtists []string `json:"blocked_artists"`
|
BlockedArtists []string `json:"blocked_artists"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes ContentRestrictions from JSON
|
// DeJSON deserializes ContentRestrictions from JSON data.
|
||||||
func (c *ContentRestrictions) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
func (c *ContentRestrictions) DeJSON(data []byte, client ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -342,7 +343,7 @@ func (c *ContentRestrictions) DeJSON(data []byte, client ClientInterface) (Model
|
|||||||
return restrictions, nil
|
return restrictions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of ContentRestrictions
|
// DeList deserializes a list of ContentRestrictions from JSON data.
|
||||||
func (c *ContentRestrictions) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
func (c *ContentRestrictions) DeList(data []byte, client ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LyricsMajor represents a lyrics provider (e.g., Genius, Musixmatch)
|
// LyricsMajor represents a lyrics provider (e.g., Genius, Musixmatch).
|
||||||
type LyricsMajor struct {
|
type LyricsMajor struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
@@ -12,7 +13,7 @@ type LyricsMajor struct {
|
|||||||
PrettyName string `json:"pretty_name"`
|
PrettyName string `json:"pretty_name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes LyricsMajor from JSON
|
// DeJSON deserializes LyricsMajor from JSON data.
|
||||||
func (lm *LyricsMajor) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (lm *LyricsMajor) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -34,7 +35,7 @@ func (lm *LyricsMajor) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
return major, nil
|
return major, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of LyricsMajor
|
// DeList deserializes a list of LyricsMajor from JSON data.
|
||||||
func (lm *LyricsMajor) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (lm *LyricsMajor) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -52,7 +53,7 @@ func (lm *LyricsMajor) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrackLyrics represents lyrics information from /tracks/{id}/lyrics endpoint
|
// TrackLyrics represents lyrics information from /tracks/{id}/lyrics endpoint.
|
||||||
type TrackLyrics struct {
|
type TrackLyrics struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
DownloadURL string `json:"download_url"`
|
DownloadURL string `json:"download_url"`
|
||||||
@@ -62,7 +63,7 @@ type TrackLyrics struct {
|
|||||||
Major *LyricsMajor `json:"major"`
|
Major *LyricsMajor `json:"major"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes TrackLyrics from JSON
|
// DeJSON deserializes TrackLyrics from JSON data.
|
||||||
func (tl *TrackLyrics) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (tl *TrackLyrics) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -92,7 +93,7 @@ func (tl *TrackLyrics) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
return lyrics, nil
|
return lyrics, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of TrackLyrics
|
// DeList deserializes a list of TrackLyrics from JSON data.
|
||||||
func (tl *TrackLyrics) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (tl *TrackLyrics) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -110,7 +111,7 @@ func (tl *TrackLyrics) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SupplementLyrics represents the actual lyrics content (from supplement)
|
// SupplementLyrics represents the actual lyrics content from supplement.
|
||||||
type SupplementLyrics struct {
|
type SupplementLyrics struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
@@ -123,7 +124,7 @@ type SupplementLyrics struct {
|
|||||||
Major *LyricsMajor `json:"major"`
|
Major *LyricsMajor `json:"major"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes SupplementLyrics from JSON
|
// DeJSON deserializes SupplementLyrics from JSON data.
|
||||||
func (l *SupplementLyrics) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (l *SupplementLyrics) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -162,7 +163,7 @@ func (l *SupplementLyrics) DeJSON(data []byte, c ClientInterface) (Model, error)
|
|||||||
return lyrics, nil
|
return lyrics, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of SupplementLyrics
|
// DeList deserializes a list of SupplementLyrics from JSON data.
|
||||||
func (l *SupplementLyrics) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (l *SupplementLyrics) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -180,7 +181,7 @@ func (l *SupplementLyrics) DeList(data []byte, c ClientInterface) ([]Model, erro
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LyricsInfo represents lyrics availability information
|
// LyricsInfo represents lyrics availability information.
|
||||||
type LyricsInfo struct {
|
type LyricsInfo struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
TrackID string `json:"track_id"`
|
TrackID string `json:"track_id"`
|
||||||
@@ -196,7 +197,7 @@ type LyricsInfo struct {
|
|||||||
HasAvailableTextLyrics bool `json:"has_available_text_lyrics"`
|
HasAvailableTextLyrics bool `json:"has_available_text_lyrics"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes LyricsInfo from JSON
|
// DeJSON deserializes LyricsInfo from JSON data.
|
||||||
func (li *LyricsInfo) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (li *LyricsInfo) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -247,7 +248,7 @@ func (li *LyricsInfo) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
return info, nil
|
return info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of LyricsInfo
|
// DeList deserializes a list of LyricsInfo from JSON data.
|
||||||
func (li *LyricsInfo) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (li *LyricsInfo) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -265,7 +266,7 @@ func (li *LyricsInfo) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// VideoSupplement represents a video supplement (from supplement endpoint)
|
// VideoSupplement represents a video supplement from supplement endpoint.
|
||||||
type VideoSupplement struct {
|
type VideoSupplement struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Cover string `json:"cover"`
|
Cover string `json:"cover"`
|
||||||
@@ -277,7 +278,7 @@ type VideoSupplement struct {
|
|||||||
Embed string `json:"embed"`
|
Embed string `json:"embed"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes VideoSupplement from JSON
|
// DeJSON deserializes VideoSupplement from JSON data.
|
||||||
func (vs *VideoSupplement) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (vs *VideoSupplement) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -311,7 +312,7 @@ func (vs *VideoSupplement) DeJSON(data []byte, c ClientInterface) (Model, error)
|
|||||||
return supp, nil
|
return supp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of VideoSupplements
|
// DeList deserializes a list of VideoSupplements from JSON data.
|
||||||
func (vs *VideoSupplement) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (vs *VideoSupplement) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -329,10 +330,10 @@ func (vs *VideoSupplement) DeList(data []byte, c ClientInterface) ([]Model, erro
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Supplement represents a track supplement
|
// Supplement represents a track supplement.
|
||||||
type Supplement struct {
|
type Supplement struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Lyrics *LyricsInfo `json:"lyrics"`
|
Lyrics *LyricsInfo `json:"lyrics"`
|
||||||
Videos []VideoSupplement `json:"videos"`
|
Videos []VideoSupplement `json:"videos"`
|
||||||
RadioIsAvailable bool `json:"radio_is_available"`
|
RadioIsAvailable bool `json:"radio_is_available"`
|
||||||
@@ -340,7 +341,7 @@ type Supplement struct {
|
|||||||
Available bool `json:"available"`
|
Available bool `json:"available"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes Supplement from JSON
|
// DeJSON deserializes Supplement from JSON data.
|
||||||
func (s *Supplement) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (s *Supplement) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -376,7 +377,7 @@ func (s *Supplement) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
return supp, nil
|
return supp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Supplements
|
// DeList deserializes a list of Supplements from JSON data.
|
||||||
func (s *Supplement) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (s *Supplement) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
|
|||||||
+513
-31
@@ -1,33 +1,78 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Track represents a full track
|
// Track represents a full track from the Yandex Music API.
|
||||||
type Track struct {
|
type Track struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
DurationMs int `json:"duration_ms"`
|
Available bool `json:"available"`
|
||||||
StorageID string `json:"storage_id"`
|
|
||||||
CoverURI string `json:"cover_uri"`
|
|
||||||
Artists []Artist `json:"artists"`
|
Artists []Artist `json:"artists"`
|
||||||
Albums []Album `json:"albums"`
|
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"`
|
AvailableForPremiumUsers bool `json:"available_for_premium_users"`
|
||||||
R128 float64 `json:"r128"`
|
LyricsAvailable bool `json:"lyrics_available"`
|
||||||
TrackSharingFlag string `json:"track_sharing_flag"`
|
Best bool `json:"best"`
|
||||||
|
RealID JSONID `json:"real_id"`
|
||||||
|
OgImage string `json:"og_image"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
CoverURI string `json:"cover_uri"`
|
||||||
Major *Major `json:"major"`
|
Major *Major `json:"major"`
|
||||||
Lyrics *TrackLyricsInfo `json:"lyrics"`
|
DurationMs int `json:"duration_ms"`
|
||||||
|
StorageDir string `json:"storage_dir"`
|
||||||
|
FileSize int64 `json:"file_size"`
|
||||||
|
Genre string `json:"genre"`
|
||||||
|
AvailableAsRingtone bool `json:"available_as_ringtone"`
|
||||||
|
RingtoneID string `json:"ringtone_id"`
|
||||||
SimilarTracks []Track `json:"similar_tracks"`
|
SimilarTracks []Track `json:"similar_tracks"`
|
||||||
|
Position *TrackPosition `json:"position"`
|
||||||
|
Substituted *Track `json:"substituted"`
|
||||||
|
MatchedTrack *Track `json:"matched_track"`
|
||||||
|
Normalization *Normalization `json:"normalization"`
|
||||||
|
Error string `json:"error"`
|
||||||
|
CanPublish bool `json:"can_publish"`
|
||||||
|
State string `json:"state"`
|
||||||
|
DesiredVisibility string `json:"desired_visibility"`
|
||||||
|
Filename string `json:"filename"`
|
||||||
|
UserInfo *User `json:"user_info"`
|
||||||
|
MetaData *MetaData `json:"meta_data"`
|
||||||
|
Regions []string `json:"regions"`
|
||||||
|
AvailableAsRbt bool `json:"available_as_rbt"`
|
||||||
|
ContentWarning string `json:"content_warning"`
|
||||||
|
Explicit bool `json:"explicit"`
|
||||||
|
PreviewDurationMs int `json:"preview_duration_ms"`
|
||||||
|
AvailableFullWithoutPermission bool `json:"available_full_without_permission"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
RememberPosition bool `json:"remember_position"`
|
||||||
|
BackgroundVideoURI string `json:"background_video_uri"`
|
||||||
|
ShortDescription string `json:"short_description"`
|
||||||
|
IsSuitableForChildren bool `json:"is_suitable_for_children"`
|
||||||
|
TrackSource string `json:"track_source"`
|
||||||
|
AvailableForOptions []string `json:"available_for_options"`
|
||||||
|
R128 *R128 `json:"r128"`
|
||||||
|
LyricsInfo *TrackLyricsInfo `json:"lyrics_info"`
|
||||||
|
TrackSharingFlag string `json:"track_sharing_flag"`
|
||||||
|
DerivedColors *CoverDerivedColors `json:"derived_colors"`
|
||||||
|
Fade *Fade `json:"fade"`
|
||||||
|
SmartPreviewParams *SmartPreviewParams `json:"smart_preview_params"`
|
||||||
|
SpecialAudioResources []string `json:"special_audio_resources"`
|
||||||
|
Disclaimers []string `json:"disclaimers"`
|
||||||
|
BackgroundVideoID string `json:"background_video_id"`
|
||||||
|
PlayerID string `json:"player_id"`
|
||||||
|
MixFade *Fade `json:"mix_fade"`
|
||||||
|
Chart *Chart `json:"chart"`
|
||||||
|
ClipIDs []int `json:"clip_ids"`
|
||||||
|
Isrc string `json:"isrc"`
|
||||||
|
UgcArtistName string `json:"ugc_artist_name"`
|
||||||
|
PodcastEpisodeType string `json:"podcast_episode_type"`
|
||||||
|
PubDate string `json:"pub_date"`
|
||||||
DownloadInfo []DownloadInfo `json:"download_info"`
|
DownloadInfo []DownloadInfo `json:"download_info"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a Track from JSON
|
// DeJSON deserializes a Track from JSON data.
|
||||||
func (t *Track) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (t *Track) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -46,8 +91,8 @@ func (t *Track) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
if v, ok := raw["duration_ms"]; ok {
|
if v, ok := raw["duration_ms"]; ok {
|
||||||
json.Unmarshal(v, &track.DurationMs)
|
json.Unmarshal(v, &track.DurationMs)
|
||||||
}
|
}
|
||||||
if v, ok := raw["storage_id"]; ok {
|
if v, ok := raw["storage_dir"]; ok {
|
||||||
json.Unmarshal(v, &track.StorageID)
|
json.Unmarshal(v, &track.StorageDir)
|
||||||
}
|
}
|
||||||
if v, ok := raw["cover_uri"]; ok {
|
if v, ok := raw["cover_uri"]; ok {
|
||||||
json.Unmarshal(v, &track.CoverURI)
|
json.Unmarshal(v, &track.CoverURI)
|
||||||
@@ -73,6 +118,12 @@ func (t *Track) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
if v, ok := raw["track_sharing_flag"]; ok {
|
if v, ok := raw["track_sharing_flag"]; ok {
|
||||||
json.Unmarshal(v, &track.TrackSharingFlag)
|
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
|
// Nested objects
|
||||||
if v, ok := raw["artists"]; ok {
|
if v, ok := raw["artists"]; ok {
|
||||||
@@ -93,10 +144,10 @@ func (t *Track) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
track.Major = &major
|
track.Major = &major
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if v, ok := raw["lyrics"]; ok {
|
if v, ok := raw["lyrics_info"]; ok {
|
||||||
var lyrics TrackLyricsInfo
|
var lyrics TrackLyricsInfo
|
||||||
if err := json.Unmarshal(v, &lyrics); err == nil {
|
if err := json.Unmarshal(v, &lyrics); err == nil {
|
||||||
track.Lyrics = &lyrics
|
track.LyricsInfo = &lyrics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if v, ok := raw["similar_tracks"]; ok {
|
if v, ok := raw["similar_tracks"]; ok {
|
||||||
@@ -111,11 +162,17 @@ func (t *Track) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
track.DownloadInfo = downloadInfo
|
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
|
return track, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of Tracks
|
// DeList deserializes a list of Tracks from JSON data.
|
||||||
func (t *Track) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (t *Track) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -133,7 +190,7 @@ func (t *Track) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDownloadInfo returns download info for a specific quality
|
// GetDownloadInfo returns download info for a specific quality, or nil if not found.
|
||||||
func (t *Track) GetDownloadInfo(quality string) *DownloadInfo {
|
func (t *Track) GetDownloadInfo(quality string) *DownloadInfo {
|
||||||
for _, info := range t.DownloadInfo {
|
for _, info := range t.DownloadInfo {
|
||||||
if info.Quality == quality {
|
if info.Quality == quality {
|
||||||
@@ -143,26 +200,58 @@ func (t *Track) GetDownloadInfo(quality string) *DownloadInfo {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: Artist and Album types are defined in their respective files
|
// Major represents major label info for a track.
|
||||||
// These are imported automatically since they're in the same package
|
|
||||||
|
|
||||||
// Major represents major info
|
|
||||||
type Major struct {
|
type Major struct {
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrackLyricsInfo represents minimal lyrics info for a track
|
// TrackLyricsInfo represents lyrics availability info for a track.
|
||||||
type TrackLyricsInfo struct {
|
type TrackLyricsInfo struct {
|
||||||
ID string `json:"id"`
|
BaseModel
|
||||||
Text string `json:"text"`
|
HasAvailableSyncLyrics bool `json:"has_available_sync_lyrics"`
|
||||||
Major *Major `json:"major"`
|
HasAvailableTextLyrics bool `json:"has_available_text_lyrics"`
|
||||||
Available bool `json:"available"`
|
|
||||||
HasText bool `json:"has_text"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DownloadInfo represents file download info
|
// DeJSON deserializes TrackLyricsInfo from JSON data.
|
||||||
|
func (tli *TrackLyricsInfo) 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 := &TrackLyricsInfo{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of TrackLyricsInfo from JSON data.
|
||||||
|
func (tli *TrackLyricsInfo) 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 := &TrackLyricsInfo{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, info); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, info)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DownloadInfo represents file download info for a track.
|
||||||
type DownloadInfo struct {
|
type DownloadInfo struct {
|
||||||
Quality string `json:"quality"`
|
Quality string `json:"quality"`
|
||||||
Codec string `json:"codec"`
|
Codec string `json:"codec"`
|
||||||
@@ -170,4 +259,397 @@ type DownloadInfo struct {
|
|||||||
Size int64 `json:"size"`
|
Size int64 `json:"size"`
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
DirectLink bool `json:"direct_link"`
|
DirectLink bool `json:"direct_link"`
|
||||||
|
DownloadInfoURL string `json:"download_info_url"`
|
||||||
|
DirectLinkURL string `json:"-"` // Computed signed download URL
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalization represents track normalization values.
|
||||||
|
type Normalization struct {
|
||||||
|
BaseModel
|
||||||
|
Gain float64 `json:"gain"`
|
||||||
|
Peak int `json:"peak"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MetaData represents track metadata.
|
||||||
|
type MetaData struct {
|
||||||
|
BaseModel
|
||||||
|
Album string `json:"album"`
|
||||||
|
Volume int `json:"volume"`
|
||||||
|
Year int `json:"year"`
|
||||||
|
Number int `json:"number"`
|
||||||
|
Genre string `json:"genre"`
|
||||||
|
Lyricist string `json:"lyricist"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
Composer string `json:"composer"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fade represents fade parameters for a track.
|
||||||
|
type Fade struct {
|
||||||
|
BaseModel
|
||||||
|
InStart float64 `json:"in_start"`
|
||||||
|
InStop float64 `json:"in_stop"`
|
||||||
|
OutStart float64 `json:"out_start"`
|
||||||
|
OutStop float64 `json:"out_stop"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SmartPreviewParams represents smart preview parameters.
|
||||||
|
type SmartPreviewParams struct {
|
||||||
|
BaseModel
|
||||||
|
DurationMs int `json:"duration_ms"`
|
||||||
|
Fade *Fade `json:"fade"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CoverDerivedColors represents derived colors from cover art.
|
||||||
|
type CoverDerivedColors struct {
|
||||||
|
BaseModel
|
||||||
|
Average string `json:"average"`
|
||||||
|
WaveText string `json:"wave_text"`
|
||||||
|
MiniPlayer string `json:"mini_player"`
|
||||||
|
Accent string `json:"accent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CustomWave represents a custom wave for playlists.
|
||||||
|
type CustomWave struct {
|
||||||
|
BaseModel
|
||||||
|
Title string `json:"title"`
|
||||||
|
AnimationURL string `json:"animation_url"`
|
||||||
|
Position string `json:"position"`
|
||||||
|
Header string `json:"header"`
|
||||||
|
BackgroundImageURL string `json:"background_image_url"`
|
||||||
|
SquareAgentAnimation string `json:"square_agent_animation"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrackId represents a track ID reference.
|
||||||
|
type TrackId struct {
|
||||||
|
BaseModel
|
||||||
|
ID JSONID `json:"id"`
|
||||||
|
TrackID JSONID `json:"track_id"`
|
||||||
|
AlbumID JSONID `json:"album_id"`
|
||||||
|
From string `json:"from"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes a TrackId from JSON data.
|
||||||
|
func (ti *TrackId) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tid := &TrackId{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["id"]; ok {
|
||||||
|
json.Unmarshal(v, &tid.ID)
|
||||||
|
}
|
||||||
|
if v, ok := raw["track_id"]; ok {
|
||||||
|
json.Unmarshal(v, &tid.TrackID)
|
||||||
|
}
|
||||||
|
if v, ok := raw["album_id"]; ok {
|
||||||
|
json.Unmarshal(v, &tid.AlbumID)
|
||||||
|
}
|
||||||
|
if v, ok := raw["from"]; ok {
|
||||||
|
json.Unmarshal(v, &tid.From)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of TrackId from JSON data.
|
||||||
|
func (ti *TrackId) 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 {
|
||||||
|
tid := &TrackId{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, tid); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, tid)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrackFullInfo represents full track info.
|
||||||
|
type TrackFullInfo struct {
|
||||||
|
BaseModel
|
||||||
|
Track *Track `json:"track"`
|
||||||
|
SimilarTracks []Track `json:"similar_tracks"`
|
||||||
|
AlsoInAlbums []Track `json:"also_in_albums"`
|
||||||
|
Aliases []string `json:"aliases"`
|
||||||
|
Artists []Artist `json:"artists"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes a TrackFullInfo from JSON data.
|
||||||
|
func (tfi *TrackFullInfo) 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 := &TrackFullInfo{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["track"]; ok {
|
||||||
|
var track Track
|
||||||
|
if err := json.Unmarshal(v, &track); err == nil {
|
||||||
|
info.Track = &track
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v, ok := raw["similar_tracks"]; ok {
|
||||||
|
var tracks []Track
|
||||||
|
if err := json.Unmarshal(v, &tracks); err == nil {
|
||||||
|
info.SimilarTracks = tracks
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v, ok := raw["also_in_albums"]; ok {
|
||||||
|
var tracks []Track
|
||||||
|
if err := json.Unmarshal(v, &tracks); err == nil {
|
||||||
|
info.AlsoInAlbums = tracks
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v, ok := raw["aliases"]; ok {
|
||||||
|
json.Unmarshal(v, &info.Aliases)
|
||||||
|
}
|
||||||
|
if v, ok := raw["artists"]; ok {
|
||||||
|
var artists []Artist
|
||||||
|
if err := json.Unmarshal(v, &artists); err == nil {
|
||||||
|
info.Artists = artists
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of TrackFullInfo from JSON data.
|
||||||
|
func (tfi *TrackFullInfo) 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 := &TrackFullInfo{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, info); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, info)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimilarTracks represents similar tracks.
|
||||||
|
type SimilarTracks struct {
|
||||||
|
BaseModel
|
||||||
|
Track *Track `json:"track"`
|
||||||
|
SimilarTracks []Track `json:"similar_tracks"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes SimilarTracks from JSON data.
|
||||||
|
func (st *SimilarTracks) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
|
var raw map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
similar := &SimilarTracks{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["track"]; ok {
|
||||||
|
var track Track
|
||||||
|
if err := json.Unmarshal(v, &track); err == nil {
|
||||||
|
similar.Track = &track
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v, ok := raw["similar_tracks"]; ok {
|
||||||
|
var tracks []Track
|
||||||
|
if err := json.Unmarshal(v, &tracks); err == nil {
|
||||||
|
similar.SimilarTracks = tracks
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return similar, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of SimilarTracks from JSON data.
|
||||||
|
func (st *SimilarTracks) 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 {
|
||||||
|
similar := &SimilarTracks{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, similar); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, similar)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrackTrailer represents track trailer info.
|
||||||
|
type TrackTrailer struct {
|
||||||
|
BaseModel
|
||||||
|
Title string `json:"title"`
|
||||||
|
Track *Track `json:"track"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes a TrackTrailer from JSON data.
|
||||||
|
func (tt *TrackTrailer) 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 := &TrackTrailer{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["title"]; ok {
|
||||||
|
json.Unmarshal(v, &trailer.Title)
|
||||||
|
}
|
||||||
|
if v, ok := raw["track"]; ok {
|
||||||
|
var track Track
|
||||||
|
if err := json.Unmarshal(v, &track); err == nil {
|
||||||
|
trailer.Track = &track
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return trailer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of TrackTrailer from JSON data.
|
||||||
|
func (tt *TrackTrailer) 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 := &TrackTrailer{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, trailer); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, trailer)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileInfo represents file info for a track.
|
||||||
|
type FileInfo struct {
|
||||||
|
BaseModel
|
||||||
|
DownloadInfo *FileDownloadInfo `json:"download_info"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes FileInfo from JSON data.
|
||||||
|
func (fi *FileInfo) 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 := &FileInfo{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["download_info"]; ok {
|
||||||
|
var di FileDownloadInfo
|
||||||
|
json.Unmarshal(v, &di)
|
||||||
|
info.DownloadInfo = &di
|
||||||
|
}
|
||||||
|
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of FileInfo from JSON data.
|
||||||
|
func (fi *FileInfo) 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 := &FileInfo{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, info); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, info)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileDownloadInfo represents file download info.
|
||||||
|
type FileDownloadInfo struct {
|
||||||
|
BaseModel
|
||||||
|
TrackID string `json:"track_id"`
|
||||||
|
Quality string `json:"quality"`
|
||||||
|
Codec string `json:"codec"`
|
||||||
|
Bitrate int `json:"bitrate"`
|
||||||
|
Transport string `json:"transport"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
URLs []string `json:"urls"`
|
||||||
|
RealID string `json:"real_id"`
|
||||||
|
Gain bool `json:"gain"`
|
||||||
|
Key string `json:"key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeJSON deserializes FileDownloadInfo from JSON data.
|
||||||
|
func (fdi *FileDownloadInfo) 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 := &FileDownloadInfo{BaseModel: *NewBaseModel(c)}
|
||||||
|
|
||||||
|
if v, ok := raw["track_id"]; ok {
|
||||||
|
json.Unmarshal(v, &info.TrackID)
|
||||||
|
}
|
||||||
|
if v, ok := raw["quality"]; ok {
|
||||||
|
json.Unmarshal(v, &info.Quality)
|
||||||
|
}
|
||||||
|
if v, ok := raw["codec"]; ok {
|
||||||
|
json.Unmarshal(v, &info.Codec)
|
||||||
|
}
|
||||||
|
if v, ok := raw["bitrate"]; ok {
|
||||||
|
json.Unmarshal(v, &info.Bitrate)
|
||||||
|
}
|
||||||
|
if v, ok := raw["transport"]; ok {
|
||||||
|
json.Unmarshal(v, &info.Transport)
|
||||||
|
}
|
||||||
|
if v, ok := raw["url"]; ok {
|
||||||
|
json.Unmarshal(v, &info.URL)
|
||||||
|
}
|
||||||
|
if v, ok := raw["urls"]; ok {
|
||||||
|
json.Unmarshal(v, &info.URLs)
|
||||||
|
}
|
||||||
|
if v, ok := raw["real_id"]; ok {
|
||||||
|
json.Unmarshal(v, &info.RealID)
|
||||||
|
}
|
||||||
|
if v, ok := raw["gain"]; ok {
|
||||||
|
json.Unmarshal(v, &info.Gain)
|
||||||
|
}
|
||||||
|
if v, ok := raw["key"]; ok {
|
||||||
|
json.Unmarshal(v, &info.Key)
|
||||||
|
}
|
||||||
|
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeList deserializes a list of FileDownloadInfo from JSON data.
|
||||||
|
func (fdi *FileDownloadInfo) 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 := &FileDownloadInfo{BaseModel: *NewBaseModel(c)}
|
||||||
|
if err := json.Unmarshal(item, info); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, info)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,17 @@
|
|||||||
|
// Package models provides data models for the Yandex Music API.
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TrackShort represents a lightweight track (used in lists)
|
// TrackShort represents a lightweight track used in lists.
|
||||||
type TrackShort struct {
|
type TrackShort struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ID string `json:"id"`
|
ID JSONID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
DurationMs int `json:"duration_ms"`
|
DurationMs int `json:"duration_ms"`
|
||||||
StorageID string `json:"storage_id"`
|
StorageDir string `json:"storage_dir"`
|
||||||
CoverURI string `json:"cover_uri"`
|
CoverURI string `json:"cover_uri"`
|
||||||
Artists []Artist `json:"artists"`
|
Artists []Artist `json:"artists"`
|
||||||
Albums []Album `json:"albums"`
|
Albums []Album `json:"albums"`
|
||||||
@@ -19,10 +20,10 @@ type TrackShort struct {
|
|||||||
Explicit bool `json:"explicit"`
|
Explicit bool `json:"explicit"`
|
||||||
Available bool `json:"available"`
|
Available bool `json:"available"`
|
||||||
AvailableForPremiumUsers bool `json:"available_for_premium_users"`
|
AvailableForPremiumUsers bool `json:"available_for_premium_users"`
|
||||||
R128 float64 `json:"r128"`
|
R128 *R128 `json:"r128"`
|
||||||
TrackSharingFlag string `json:"track_sharing_flag"`
|
TrackSharingFlag string `json:"track_sharing_flag"`
|
||||||
Major *Major `json:"major"`
|
Major *Major `json:"major"`
|
||||||
Lyrics *SupplementLyrics `json:"lyrics"`
|
Lyrics *TrackLyricsInfo `json:"lyrics"`
|
||||||
SimilarTracks []TrackShort `json:"similar_tracks"`
|
SimilarTracks []TrackShort `json:"similar_tracks"`
|
||||||
DownloadInfo []DownloadInfo `json:"download_info"`
|
DownloadInfo []DownloadInfo `json:"download_info"`
|
||||||
// Additional fields from track_short.py
|
// Additional fields from track_short.py
|
||||||
@@ -31,7 +32,7 @@ type TrackShort struct {
|
|||||||
RingtoneID string `json:"ringtone_id"`
|
RingtoneID string `json:"ringtone_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a TrackShort from JSON
|
// DeJSON deserializes a TrackShort from JSON data.
|
||||||
func (t *TrackShort) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (t *TrackShort) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -50,8 +51,8 @@ func (t *TrackShort) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
if v, ok := raw["duration_ms"]; ok {
|
if v, ok := raw["duration_ms"]; ok {
|
||||||
json.Unmarshal(v, &track.DurationMs)
|
json.Unmarshal(v, &track.DurationMs)
|
||||||
}
|
}
|
||||||
if v, ok := raw["storage_id"]; ok {
|
if v, ok := raw["storage_dir"]; ok {
|
||||||
json.Unmarshal(v, &track.StorageID)
|
json.Unmarshal(v, &track.StorageDir)
|
||||||
}
|
}
|
||||||
if v, ok := raw["cover_uri"]; ok {
|
if v, ok := raw["cover_uri"]; ok {
|
||||||
json.Unmarshal(v, &track.CoverURI)
|
json.Unmarshal(v, &track.CoverURI)
|
||||||
@@ -104,7 +105,7 @@ func (t *TrackShort) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if v, ok := raw["lyrics"]; ok {
|
if v, ok := raw["lyrics"]; ok {
|
||||||
var lyrics SupplementLyrics
|
var lyrics TrackLyricsInfo
|
||||||
if err := json.Unmarshal(v, &lyrics); err == nil {
|
if err := json.Unmarshal(v, &lyrics); err == nil {
|
||||||
track.Lyrics = &lyrics
|
track.Lyrics = &lyrics
|
||||||
}
|
}
|
||||||
@@ -131,7 +132,7 @@ func (t *TrackShort) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
return track, nil
|
return track, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of TrackShort
|
// DeList deserializes a list of TrackShort from JSON data.
|
||||||
func (t *TrackShort) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (t *TrackShort) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
@@ -149,7 +150,7 @@ func (t *TrackShort) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TracksList represents a list of tracks with metadata
|
// TracksList represents a list of tracks with metadata.
|
||||||
type TracksList struct {
|
type TracksList struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Tracks []TrackShort `json:"tracks"`
|
Tracks []TrackShort `json:"tracks"`
|
||||||
@@ -159,7 +160,7 @@ type TracksList struct {
|
|||||||
Pager *Pager `json:"pager"`
|
Pager *Pager `json:"pager"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON deserializes a TracksList from JSON
|
// DeJSON deserializes a TracksList from JSON data.
|
||||||
func (t *TracksList) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
func (t *TracksList) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
||||||
var raw map[string]json.RawMessage
|
var raw map[string]json.RawMessage
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
@@ -193,7 +194,7 @@ func (t *TracksList) DeJSON(data []byte, c ClientInterface) (Model, error) {
|
|||||||
return list, nil
|
return list, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeList deserializes a list of TracksList
|
// DeList deserializes a list of TracksList from JSON data.
|
||||||
func (t *TracksList) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
func (t *TracksList) DeList(data []byte, c ClientInterface) ([]Model, error) {
|
||||||
var rawList []json.RawMessage
|
var rawList []json.RawMessage
|
||||||
if err := json.Unmarshal(data, &rawList); err != nil {
|
if err := json.Unmarshal(data, &rawList); err != nil {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ func TestTrack_DeJSON(t *testing.T) {
|
|||||||
"id": "123",
|
"id": "123",
|
||||||
"title": "Test Track",
|
"title": "Test Track",
|
||||||
"duration_ms": 180000,
|
"duration_ms": 180000,
|
||||||
"storage_id": "456",
|
"storage_dir": "456",
|
||||||
"cover_uri": "https://example.com/cover.jpg",
|
"cover_uri": "https://example.com/cover.jpg",
|
||||||
"genre": "rock",
|
"genre": "rock",
|
||||||
"version": "album",
|
"version": "album",
|
||||||
@@ -55,7 +55,7 @@ func TestTrack_DeJSON(t *testing.T) {
|
|||||||
"artists": [{"id": "1", "name": "Artist 1", "cover_uri": "https://example.com/artist.jpg"}],
|
"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}],
|
"albums": [{"id": "789", "title": "Test Album", "cover_uri": "https://example.com/album.jpg", "year": 2023}],
|
||||||
"major": {"id": "major1", "name": "Major Label", "description": "Big label"},
|
"major": {"id": "major1", "name": "Major Label", "description": "Big label"},
|
||||||
"lyrics": {"id": "lyr1", "text": "Test lyrics", "available": true, "has_text": true}
|
"lyrics_info": {"has_available_sync_lyrics": true, "has_available_text_lyrics": true}
|
||||||
}`)
|
}`)
|
||||||
|
|
||||||
track := &Track{BaseModel: *NewBaseModel(client)}
|
track := &Track{BaseModel: *NewBaseModel(client)}
|
||||||
@@ -80,8 +80,8 @@ func TestTrack_DeJSON(t *testing.T) {
|
|||||||
if resultTrack.Major == nil || resultTrack.Major.Name != "Major Label" {
|
if resultTrack.Major == nil || resultTrack.Major.Name != "Major Label" {
|
||||||
t.Errorf("Expected Major 'Major Label'")
|
t.Errorf("Expected Major 'Major Label'")
|
||||||
}
|
}
|
||||||
if resultTrack.Lyrics == nil || resultTrack.Lyrics.Text != "Test lyrics" {
|
if resultTrack.LyricsInfo == nil || resultTrack.LyricsInfo.HasAvailableSyncLyrics != true {
|
||||||
t.Errorf("Expected Lyrics 'Test lyrics'")
|
t.Errorf("Expected LyricsInfo.HasAvailableSyncLyrics true")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+23
-12
@@ -1,3 +1,4 @@
|
|||||||
|
// Package utils provides utility functions for the Yandex Music API client.
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -6,42 +7,49 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// JSONBackend defines the interface for JSON encoding/decoding
|
// JSONBackend defines the interface for JSON encoding/decoding.
|
||||||
|
// Implementations can use encoding/json, json-iterator, or other backends.
|
||||||
type JSONBackend interface {
|
type JSONBackend interface {
|
||||||
|
// Marshal encodes a Go value to JSON.
|
||||||
Marshal(v any) ([]byte, error)
|
Marshal(v any) ([]byte, error)
|
||||||
|
// Unmarshal decodes JSON data into a Go value.
|
||||||
Unmarshal(data []byte, v any) error
|
Unmarshal(data []byte, v any) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultJSONBackend uses the standard library encoding/json
|
// DefaultJSONBackend uses the standard library encoding/json.
|
||||||
type DefaultJSONBackend struct{}
|
type DefaultJSONBackend struct{}
|
||||||
|
|
||||||
|
// Marshal encodes a Go value to JSON using encoding/json.
|
||||||
func (DefaultJSONBackend) Marshal(v any) ([]byte, error) {
|
func (DefaultJSONBackend) Marshal(v any) ([]byte, error) {
|
||||||
return json.Marshal(v)
|
return json.Marshal(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unmarshal decodes JSON data into a Go value using encoding/json.
|
||||||
func (DefaultJSONBackend) Unmarshal(data []byte, v any) error {
|
func (DefaultJSONBackend) Unmarshal(data []byte, v any) error {
|
||||||
return json.Unmarshal(data, v)
|
return json.Unmarshal(data, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDefaultJSONBackend returns the default JSON backend
|
// GetDefaultJSONBackend returns the default JSON backend (encoding/json).
|
||||||
func GetDefaultJSONBackend() JSONBackend {
|
func GetDefaultJSONBackend() JSONBackend {
|
||||||
return DefaultJSONBackend{}
|
return DefaultJSONBackend{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RawMessage is a raw encoded JSON value
|
// RawMessage is a raw encoded JSON value.
|
||||||
|
// It is an alias for encoding/json.RawMessage.
|
||||||
type RawMessage = json.RawMessage
|
type RawMessage = json.RawMessage
|
||||||
|
|
||||||
// Marshal is a convenience function
|
// Marshal is a convenience function that marshals a value using the default JSON backend.
|
||||||
func Marshal(v any) ([]byte, error) {
|
func Marshal(v any) ([]byte, error) {
|
||||||
return GetDefaultJSONBackend().Marshal(v)
|
return GetDefaultJSONBackend().Marshal(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmarshal is a convenience function
|
// Unmarshal is a convenience function that unmarshals data using the default JSON backend.
|
||||||
func Unmarshal(data []byte, v any) error {
|
func Unmarshal(data []byte, v any) error {
|
||||||
return GetDefaultJSONBackend().Unmarshal(data, v)
|
return GetDefaultJSONBackend().Unmarshal(data, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToSnakeCase converts camelCase to snake_case
|
// ToSnakeCase converts camelCase to snake_case.
|
||||||
|
// For example, "camelCase" becomes "camel_case".
|
||||||
func ToSnakeCase(s string) string {
|
func ToSnakeCase(s string) string {
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return s
|
return s
|
||||||
@@ -60,7 +68,8 @@ func ToSnakeCase(s string) string {
|
|||||||
return result.String()
|
return result.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToCamelCase converts snake_case to camelCase
|
// ToCamelCase converts snake_case to camelCase.
|
||||||
|
// For example, "snake_case" becomes "snakeCase".
|
||||||
func ToCamelCase(s string) string {
|
func ToCamelCase(s string) string {
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return s
|
return s
|
||||||
@@ -79,7 +88,7 @@ func ToCamelCase(s string) string {
|
|||||||
return result.String()
|
return result.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MapKeysToSnakeCase converts all keys in a map to snake_case
|
// MapKeysToSnakeCase converts all keys in a map to snake_case.
|
||||||
func MapKeysToSnakeCase(m map[string]any) map[string]any {
|
func MapKeysToSnakeCase(m map[string]any) map[string]any {
|
||||||
result := make(map[string]any, len(m))
|
result := make(map[string]any, len(m))
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
@@ -88,7 +97,7 @@ func MapKeysToSnakeCase(m map[string]any) map[string]any {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// MapKeysToCamelCase converts all keys in a map to camelCase
|
// MapKeysToCamelCase converts all keys in a map to camelCase.
|
||||||
func MapKeysToCamelCase(m map[string]any) map[string]any {
|
func MapKeysToCamelCase(m map[string]any) map[string]any {
|
||||||
result := make(map[string]any, len(m))
|
result := make(map[string]any, len(m))
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
@@ -97,7 +106,8 @@ func MapKeysToCamelCase(m map[string]any) map[string]any {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// StructToMap converts a struct to a map using json tags
|
// StructToMap converts a struct to a map using json tags.
|
||||||
|
// The forRequest parameter is currently unused but reserved for future use.
|
||||||
func StructToMap(v any, forRequest bool) (map[string]any, error) {
|
func StructToMap(v any, forRequest bool) (map[string]any, error) {
|
||||||
data, err := Marshal(v)
|
data, err := Marshal(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -110,7 +120,8 @@ func StructToMap(v any, forRequest bool) (map[string]any, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetJSONTag returns the json tag for a struct field
|
// GetJSONTag returns the json tag name for a struct field at the given index.
|
||||||
|
// It returns an empty string if the field has no json tag or the tag is "-".
|
||||||
func GetJSONTag(t reflect.Type, fieldIndex int) string {
|
func GetJSONTag(t reflect.Type, fieldIndex int) string {
|
||||||
if fieldIndex >= t.NumField() {
|
if fieldIndex >= t.NumField() {
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
+26
-14
@@ -1,3 +1,4 @@
|
|||||||
|
// Package utils provides utility functions for the Yandex Music API client.
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -5,19 +6,20 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Response represents an API response
|
// Response represents an API response from the Yandex Music API.
|
||||||
type Response struct {
|
type Response struct {
|
||||||
Result json.RawMessage `json:"result"`
|
Result json.RawMessage `json:"result"`
|
||||||
Error string `json:"error,omitempty"`
|
Error string `json:"error,omitempty"`
|
||||||
ErrorDescription string `json:"errorDescription,omitempty"`
|
ErrorDescription string `json:"errorDescription,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetResult returns the result as raw JSON
|
// GetResult returns the result as raw JSON.
|
||||||
func (r *Response) GetResult() json.RawMessage {
|
func (r *Response) GetResult() json.RawMessage {
|
||||||
return r.Result
|
return r.Result
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetError returns the error message
|
// GetError returns the error message from the response.
|
||||||
|
// It returns Error if set, otherwise ErrorDescription, or "Unknown error" if neither is set.
|
||||||
func (r *Response) GetError() string {
|
func (r *Response) GetError() string {
|
||||||
if r.Error != "" {
|
if r.Error != "" {
|
||||||
return r.Error
|
return r.Error
|
||||||
@@ -28,12 +30,13 @@ func (r *Response) GetError() string {
|
|||||||
return "Unknown error"
|
return "Unknown error"
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasError returns true if the response contains an error
|
// HasError returns true if the response contains an error.
|
||||||
func (r *Response) HasError() bool {
|
func (r *Response) HasError() bool {
|
||||||
return r.Error != "" || r.ErrorDescription != ""
|
return r.Error != "" || r.ErrorDescription != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON implements custom unmarshaling
|
// UnmarshalJSON implements custom unmarshaling for Response.
|
||||||
|
// If result is missing, the whole response is wrapped in result.
|
||||||
func (r *Response) UnmarshalJSON(data []byte) error {
|
func (r *Response) UnmarshalJSON(data []byte) error {
|
||||||
// First try to unmarshal as a standard response
|
// First try to unmarshal as a standard response
|
||||||
type Alias Response
|
type Alias Response
|
||||||
@@ -53,7 +56,7 @@ func (r *Response) UnmarshalJSON(data []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeJSON creates a Response from JSON data
|
// DeJSON creates a Response from JSON data.
|
||||||
func DeJSON(data []byte) (*Response, error) {
|
func DeJSON(data []byte) (*Response, error) {
|
||||||
var resp Response
|
var resp Response
|
||||||
if err := json.Unmarshal(data, &resp); err != nil {
|
if err := json.Unmarshal(data, &resp); err != nil {
|
||||||
@@ -62,22 +65,30 @@ func DeJSON(data []byte) (*Response, error) {
|
|||||||
return &resp, nil
|
return &resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error types
|
// Error types for the Yandex Music API client.
|
||||||
var (
|
var (
|
||||||
|
// ErrUnauthorized is returned when authentication fails (HTTP 401/403).
|
||||||
ErrUnauthorized = errors.New("unauthorized")
|
ErrUnauthorized = errors.New("unauthorized")
|
||||||
|
// ErrBadRequest is returned when the request is malformed (HTTP 400).
|
||||||
ErrBadRequest = errors.New("bad request")
|
ErrBadRequest = errors.New("bad request")
|
||||||
|
// ErrNotFound is returned when the requested resource is not found (HTTP 404).
|
||||||
ErrNotFound = errors.New("not found")
|
ErrNotFound = errors.New("not found")
|
||||||
|
// ErrNetwork is returned for network-related errors.
|
||||||
ErrNetwork = errors.New("network error")
|
ErrNetwork = errors.New("network error")
|
||||||
|
// ErrTimeout is returned when a request times out.
|
||||||
ErrTimeout = errors.New("timeout")
|
ErrTimeout = errors.New("timeout")
|
||||||
|
// ErrSchemaMismatch is returned when the API response schema doesn't match expectations.
|
||||||
ErrSchemaMismatch = errors.New("schema mismatch")
|
ErrSchemaMismatch = errors.New("schema mismatch")
|
||||||
)
|
)
|
||||||
|
|
||||||
// YandexMusicError is the base error type
|
// YandexMusicError is the base error type for Yandex Music API errors.
|
||||||
|
// It wraps an underlying error with a descriptive message.
|
||||||
type YandexMusicError struct {
|
type YandexMusicError struct {
|
||||||
Message string
|
Message string
|
||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Error returns the error message, including the wrapped error if present.
|
||||||
func (e *YandexMusicError) Error() string {
|
func (e *YandexMusicError) Error() string {
|
||||||
if e.Err != nil {
|
if e.Err != nil {
|
||||||
return e.Message + ": " + e.Err.Error()
|
return e.Message + ": " + e.Err.Error()
|
||||||
@@ -85,16 +96,17 @@ func (e *YandexMusicError) Error() string {
|
|||||||
return e.Message
|
return e.Message
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unwrap returns the underlying error for compatibility with errors.Is and errors.As.
|
||||||
func (e *YandexMusicError) Unwrap() error {
|
func (e *YandexMusicError) Unwrap() error {
|
||||||
return e.Err
|
return e.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewYandexMusicError creates a new YandexMusicError
|
// NewYandexMusicError creates a new YandexMusicError with the given message and underlying error.
|
||||||
func NewYandexMusicError(message string, err error) *YandexMusicError {
|
func NewYandexMusicError(message string, err error) *YandexMusicError {
|
||||||
return &YandexMusicError{Message: message, Err: err}
|
return &YandexMusicError{Message: message, Err: err}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsUnauthorizedError checks if error is unauthorized
|
// IsUnauthorizedError checks if an error is an unauthorized error.
|
||||||
func IsUnauthorizedError(err error) bool {
|
func IsUnauthorizedError(err error) bool {
|
||||||
var yme *YandexMusicError
|
var yme *YandexMusicError
|
||||||
if errors.As(err, &yme) {
|
if errors.As(err, &yme) {
|
||||||
@@ -103,7 +115,7 @@ func IsUnauthorizedError(err error) bool {
|
|||||||
return errors.Is(err, ErrUnauthorized)
|
return errors.Is(err, ErrUnauthorized)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsBadRequestError checks if error is bad request
|
// IsBadRequestError checks if an error is a bad request error.
|
||||||
func IsBadRequestError(err error) bool {
|
func IsBadRequestError(err error) bool {
|
||||||
var yme *YandexMusicError
|
var yme *YandexMusicError
|
||||||
if errors.As(err, &yme) {
|
if errors.As(err, &yme) {
|
||||||
@@ -112,7 +124,7 @@ func IsBadRequestError(err error) bool {
|
|||||||
return errors.Is(err, ErrBadRequest)
|
return errors.Is(err, ErrBadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsNotFoundError checks if error is not found
|
// IsNotFoundError checks if an error is a not found error.
|
||||||
func IsNotFoundError(err error) bool {
|
func IsNotFoundError(err error) bool {
|
||||||
var yme *YandexMusicError
|
var yme *YandexMusicError
|
||||||
if errors.As(err, &yme) {
|
if errors.As(err, &yme) {
|
||||||
@@ -121,7 +133,7 @@ func IsNotFoundError(err error) bool {
|
|||||||
return errors.Is(err, ErrNotFound)
|
return errors.Is(err, ErrNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsNetworkError checks if error is network error
|
// IsNetworkError checks if an error is a network error.
|
||||||
func IsNetworkError(err error) bool {
|
func IsNetworkError(err error) bool {
|
||||||
var yme *YandexMusicError
|
var yme *YandexMusicError
|
||||||
if errors.As(err, &yme) {
|
if errors.As(err, &yme) {
|
||||||
@@ -130,7 +142,7 @@ func IsNetworkError(err error) bool {
|
|||||||
return errors.Is(err, ErrNetwork)
|
return errors.Is(err, ErrNetwork)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsTimeoutError checks if error is timeout
|
// IsTimeoutError checks if an error is a timeout error.
|
||||||
func IsTimeoutError(err error) bool {
|
func IsTimeoutError(err error) bool {
|
||||||
var yme *YandexMusicError
|
var yme *YandexMusicError
|
||||||
if errors.As(err, &yme) {
|
if errors.As(err, &yme) {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
// Package utils provides utility functions for the Yandex Music API client,
|
||||||
|
// including JSON handling, request signing, schema mismatch tracking, and error types.
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -7,16 +9,24 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SchemaMismatch represents a mismatch between expected and actual API response
|
// SchemaMismatch represents a mismatch between expected and actual API response.
|
||||||
|
// It captures details about missing fields, unknown fields, and unknown values.
|
||||||
type SchemaMismatch struct {
|
type SchemaMismatch struct {
|
||||||
|
// ModelName is the name of the model that had the mismatch.
|
||||||
ModelName string
|
ModelName string
|
||||||
|
// MissingFields lists fields that were expected but not found in the response.
|
||||||
MissingFields []string
|
MissingFields []string
|
||||||
|
// UnknownFields lists fields that were not expected but found in the response.
|
||||||
UnknownFields []string
|
UnknownFields []string
|
||||||
|
// UnknownValues maps unknown field names to their values.
|
||||||
UnknownValues map[string]any
|
UnknownValues map[string]any
|
||||||
|
// Endpoint is the API endpoint where the mismatch occurred.
|
||||||
Endpoint string
|
Endpoint string
|
||||||
|
// LibraryVersion is the version of the library when the mismatch occurred.
|
||||||
LibraryVersion string
|
LibraryVersion string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Describe returns a human-readable description of the schema mismatch.
|
||||||
func (sm *SchemaMismatch) Describe() string {
|
func (sm *SchemaMismatch) Describe() string {
|
||||||
var parts []string
|
var parts []string
|
||||||
parts = append(parts, fmt.Sprintf("Model: %s", sm.ModelName))
|
parts = append(parts, fmt.Sprintf("Model: %s", sm.ModelName))
|
||||||
@@ -34,17 +44,22 @@ func (sm *SchemaMismatch) Describe() string {
|
|||||||
return strings.Join(parts, "\n")
|
return strings.Join(parts, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
// SchemaMismatchHandler is a callback for handling schema mismatches
|
// SchemaMismatchHandler is a callback for handling schema mismatches.
|
||||||
|
// It is invoked when a schema mismatch is detected, if configured.
|
||||||
type SchemaMismatchHandler func(*SchemaMismatch)
|
type SchemaMismatchHandler func(*SchemaMismatch)
|
||||||
|
|
||||||
// SchemaMismatchConfig holds configuration for schema mismatch handling
|
// SchemaMismatchConfig holds configuration for schema mismatch handling.
|
||||||
type SchemaMismatchConfig struct {
|
type SchemaMismatchConfig struct {
|
||||||
|
// ReportUnknownFields indicates whether unknown fields should be reported.
|
||||||
ReportUnknownFields bool
|
ReportUnknownFields bool
|
||||||
|
// Strict indicates whether schema mismatches should be treated as errors.
|
||||||
Strict bool
|
Strict bool
|
||||||
|
// OnSchemaMismatch is an optional callback for custom mismatch handling.
|
||||||
OnSchemaMismatch SchemaMismatchHandler
|
OnSchemaMismatch SchemaMismatchHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultSchemaMismatchConfig returns the default configuration
|
// DefaultSchemaMismatchConfig returns the default configuration for schema mismatch handling.
|
||||||
|
// The default config does not report unknown fields, is not strict, and has no callback.
|
||||||
func DefaultSchemaMismatchConfig() SchemaMismatchConfig {
|
func DefaultSchemaMismatchConfig() SchemaMismatchConfig {
|
||||||
return SchemaMismatchConfig{
|
return SchemaMismatchConfig{
|
||||||
ReportUnknownFields: false,
|
ReportUnknownFields: false,
|
||||||
@@ -53,7 +68,9 @@ func DefaultSchemaMismatchConfig() SchemaMismatchConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReportSchemaMismatch reports a schema mismatch according to config
|
// ReportSchemaMismatch reports a schema mismatch according to the provided config.
|
||||||
|
// If a callback is configured, it is invoked with the mismatch details.
|
||||||
|
// If strict mode is enabled, an error is returned. Otherwise, a warning is logged.
|
||||||
func ReportSchemaMismatch(config SchemaMismatchConfig, modelName, endpoint string, missingFields, unknownFields []string, unknownValues map[string]any) error {
|
func ReportSchemaMismatch(config SchemaMismatchConfig, modelName, endpoint string, missingFields, unknownFields []string, unknownValues map[string]any) error {
|
||||||
mismatch := &SchemaMismatch{
|
mismatch := &SchemaMismatch{
|
||||||
ModelName: modelName,
|
ModelName: modelName,
|
||||||
@@ -78,18 +95,22 @@ func ReportSchemaMismatch(config SchemaMismatchConfig, modelName, endpoint strin
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SchemaMismatchTracker tracks reported mismatches to avoid duplicates
|
// SchemaMismatchTracker tracks reported mismatches to avoid duplicate reports.
|
||||||
|
// It is safe for concurrent use.
|
||||||
type SchemaMismatchTracker struct {
|
type SchemaMismatchTracker struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
reported map[string]bool
|
reported map[string]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewSchemaMismatchTracker creates a new SchemaMismatchTracker.
|
||||||
func NewSchemaMismatchTracker() *SchemaMismatchTracker {
|
func NewSchemaMismatchTracker() *SchemaMismatchTracker {
|
||||||
return &SchemaMismatchTracker{
|
return &SchemaMismatchTracker{
|
||||||
reported: make(map[string]bool),
|
reported: make(map[string]bool),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ShouldReport returns true if the given model and fields have not been reported before.
|
||||||
|
// It marks them as reported so subsequent calls return false for the same key.
|
||||||
func (t *SchemaMismatchTracker) ShouldReport(modelName string, fields []string) bool {
|
func (t *SchemaMismatchTracker) ShouldReport(modelName string, fields []string) bool {
|
||||||
t.mu.Lock()
|
t.mu.Lock()
|
||||||
defer t.mu.Unlock()
|
defer t.mu.Unlock()
|
||||||
|
|||||||
+12
-6
@@ -1,3 +1,4 @@
|
|||||||
|
// Package utils provides utility functions for the Yandex Music API client.
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -10,21 +11,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// DefaultSignKey is the signing key from the Android app
|
// DefaultSignKey is the signing key from the Android app.
|
||||||
DefaultSignKey = "p93jhgh689SBReK6ghtw62"
|
DefaultSignKey = "p93jhgh689SBReK6ghtw62"
|
||||||
// DesktopSignKey is the signing key from the desktop app
|
// DesktopSignKey is the signing key from the desktop app.
|
||||||
DesktopSignKey = "kzqU4XhfCaY6B6JTHODeq5"
|
DesktopSignKey = "kzqU4XhfCaY6B6JTHODeq5"
|
||||||
// DesktopClient is the X-Yandex-Music-Client header value for desktop
|
// DesktopClient is the X-Yandex-Music-Client header value for desktop.
|
||||||
DesktopClient = "YandexMusicDesktopAppWindows/5.95.0"
|
DesktopClient = "YandexMusicDesktopAppWindows/5.95.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Sign represents a request signature
|
// Sign represents a request signature for signed API requests.
|
||||||
type Sign struct {
|
type Sign struct {
|
||||||
Timestamp int64
|
Timestamp int64
|
||||||
Value string
|
Value string
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSignRequest creates a signature for a track request
|
// GetSignRequest creates a signature for a track request using HMAC-SHA256.
|
||||||
|
// It returns a Sign with the timestamp and base64-encoded signature value.
|
||||||
|
// If key is empty, DefaultSignKey is used.
|
||||||
func GetSignRequest(trackID string, key string) Sign {
|
func GetSignRequest(trackID string, key string) Sign {
|
||||||
if key == "" {
|
if key == "" {
|
||||||
key = DefaultSignKey
|
key = DefaultSignKey
|
||||||
@@ -43,7 +46,9 @@ func GetSignRequest(trackID string, key string) Sign {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFileInfoSign creates a signature for file info requests
|
// GetFileInfoSign creates a signature for file info requests using HMAC-SHA256.
|
||||||
|
// It returns a Sign with the timestamp and base64-encoded signature value (last character removed as in Python).
|
||||||
|
// If key is empty, DesktopSignKey is used.
|
||||||
func GetFileInfoSign(trackID, quality string, codecs []string, transport, key string) Sign {
|
func GetFileInfoSign(trackID, quality string, codecs []string, transport, key string) Sign {
|
||||||
if key == "" {
|
if key == "" {
|
||||||
key = DesktopSignKey
|
key = DesktopSignKey
|
||||||
@@ -66,6 +71,7 @@ func GetFileInfoSign(trackID, quality string, codecs []string, transport, key st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// joinCodecs joins a list of codec strings into a single string.
|
||||||
func joinCodecs(codecs []string) string {
|
func joinCodecs(codecs []string) string {
|
||||||
result := ""
|
result := ""
|
||||||
for _, c := range codecs {
|
for _, c := range codecs {
|
||||||
|
|||||||
+23
-19
@@ -1,3 +1,4 @@
|
|||||||
|
// Package ynison provides a Ynison WebSocket client for player synchronization across devices.
|
||||||
package ynison
|
package ynison
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -12,7 +13,7 @@ import (
|
|||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
// YnisonClient represents a Ynison WebSocket client
|
// YnisonClient represents a Ynison WebSocket client for player synchronization across devices.
|
||||||
type YnisonClient struct {
|
type YnisonClient struct {
|
||||||
client *client.Client
|
client *client.Client
|
||||||
conn *websocket.Conn
|
conn *websocket.Conn
|
||||||
@@ -28,7 +29,7 @@ type YnisonClient struct {
|
|||||||
closeOnce sync.Once // Ensures doneCh is closed only once
|
closeOnce sync.Once // Ensures doneCh is closed only once
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeviceConfig holds device configuration for Ynison
|
// DeviceConfig holds device configuration for Ynison WebSocket connections.
|
||||||
type DeviceConfig struct {
|
type DeviceConfig struct {
|
||||||
DeviceID string
|
DeviceID string
|
||||||
Title string
|
Title string
|
||||||
@@ -40,7 +41,8 @@ type DeviceConfig struct {
|
|||||||
VolumeGran int
|
VolumeGran int
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewYnisonClient creates a new Ynison client
|
// NewYnisonClient creates a new Ynison client with the given client and device config.
|
||||||
|
// Default values are applied for empty fields.
|
||||||
func NewYnisonClient(c *client.Client, config DeviceConfig) *YnisonClient {
|
func NewYnisonClient(c *client.Client, config DeviceConfig) *YnisonClient {
|
||||||
if config.DeviceID == "" {
|
if config.DeviceID == "" {
|
||||||
config.DeviceID = fmt.Sprintf("go-ynison-%d", time.Now().UnixNano())
|
config.DeviceID = fmt.Sprintf("go-ynison-%d", time.Now().UnixNano())
|
||||||
@@ -67,7 +69,8 @@ func NewYnisonClient(c *client.Client, config DeviceConfig) *YnisonClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect establishes a WebSocket connection to Ynison
|
// Connect establishes a WebSocket connection to the Ynison service.
|
||||||
|
// It sends an initial full state update after connecting.
|
||||||
func (y *YnisonClient) Connect(ctx context.Context) error {
|
func (y *YnisonClient) Connect(ctx context.Context) error {
|
||||||
token := y.client.GetToken()
|
token := y.client.GetToken()
|
||||||
if token == "" {
|
if token == "" {
|
||||||
@@ -95,12 +98,12 @@ func (y *YnisonClient) Connect(ctx context.Context) error {
|
|||||||
return y.sendUpdateFullState(ctx)
|
return y.sendUpdateFullState(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// overrideWSURL sets a custom WebSocket URL for testing
|
// overrideWSURL sets a custom WebSocket URL for testing purposes.
|
||||||
func (y *YnisonClient) overrideWSURL(url string) {
|
func (y *YnisonClient) overrideWSURL(url string) {
|
||||||
y.wsURL = url
|
y.wsURL = url
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disconnect closes the WebSocket connection
|
// Disconnect closes the WebSocket connection and cleans up resources.
|
||||||
func (y *YnisonClient) Disconnect() error {
|
func (y *YnisonClient) Disconnect() error {
|
||||||
y.mu.Lock()
|
y.mu.Lock()
|
||||||
defer y.mu.Unlock()
|
defer y.mu.Unlock()
|
||||||
@@ -117,7 +120,7 @@ func (y *YnisonClient) Disconnect() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsConnected returns true if the client is connected
|
// IsConnected returns true if the client is currently connected to the Ynison service.
|
||||||
func (y *YnisonClient) IsConnected() bool {
|
func (y *YnisonClient) IsConnected() bool {
|
||||||
y.mu.Lock()
|
y.mu.Lock()
|
||||||
defer y.mu.Unlock()
|
defer y.mu.Unlock()
|
||||||
@@ -276,21 +279,22 @@ func (y *YnisonClient) sendRequest(ctx context.Context, req *proto.PutYnisonStat
|
|||||||
return y.conn.WriteMessage(websocket.TextMessage, data)
|
return y.conn.WriteMessage(websocket.TextMessage, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterHandler registers a response handler
|
// RegisterHandler registers a response handler for the given name.
|
||||||
|
// Handlers are invoked when a PutYnisonStateResponse is received from the server.
|
||||||
func (y *YnisonClient) RegisterHandler(name string, handler func(*proto.PutYnisonStateResponse)) {
|
func (y *YnisonClient) RegisterHandler(name string, handler func(*proto.PutYnisonStateResponse)) {
|
||||||
y.mu.Lock()
|
y.mu.Lock()
|
||||||
defer y.mu.Unlock()
|
defer y.mu.Unlock()
|
||||||
y.handlers[name] = handler
|
y.handlers[name] = handler
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnregisterHandler removes a response handler
|
// UnregisterHandler removes a previously registered response handler by name.
|
||||||
func (y *YnisonClient) UnregisterHandler(name string) {
|
func (y *YnisonClient) UnregisterHandler(name string) {
|
||||||
y.mu.Lock()
|
y.mu.Lock()
|
||||||
defer y.mu.Unlock()
|
defer y.mu.Unlock()
|
||||||
delete(y.handlers, name)
|
delete(y.handlers, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatePlayingStatus updates the playing status
|
// UpdatePlayingStatus updates the playing status on the Ynison server.
|
||||||
func (y *YnisonClient) UpdatePlayingStatus(ctx context.Context, status *proto.PlayingStatus) error {
|
func (y *YnisonClient) UpdatePlayingStatus(ctx context.Context, status *proto.PlayingStatus) error {
|
||||||
req := &proto.PutYnisonStateRequest{
|
req := &proto.PutYnisonStateRequest{
|
||||||
UpdatePlayingStatus: &proto.UpdatePlayingStatus{
|
UpdatePlayingStatus: &proto.UpdatePlayingStatus{
|
||||||
@@ -302,7 +306,7 @@ func (y *YnisonClient) UpdatePlayingStatus(ctx context.Context, status *proto.Pl
|
|||||||
return y.sendRequest(ctx, req)
|
return y.sendRequest(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateVolume updates the volume
|
// UpdateVolume updates the volume for a device on the Ynison server.
|
||||||
func (y *YnisonClient) UpdateVolume(ctx context.Context, deviceID string, volume float64, version *proto.UpdateVersion) error {
|
func (y *YnisonClient) UpdateVolume(ctx context.Context, deviceID string, volume float64, version *proto.UpdateVersion) error {
|
||||||
req := &proto.PutYnisonStateRequest{
|
req := &proto.PutYnisonStateRequest{
|
||||||
UpdateVolumeInfo: &proto.UpdateVolumeInfo{
|
UpdateVolumeInfo: &proto.UpdateVolumeInfo{
|
||||||
@@ -318,7 +322,7 @@ func (y *YnisonClient) UpdateVolume(ctx context.Context, deviceID string, volume
|
|||||||
return y.sendRequest(ctx, req)
|
return y.sendRequest(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateActiveDevice updates the active device
|
// UpdateActiveDevice updates the active device on the Ynison server.
|
||||||
func (y *YnisonClient) UpdateActiveDevice(ctx context.Context, deviceID string) error {
|
func (y *YnisonClient) UpdateActiveDevice(ctx context.Context, deviceID string) error {
|
||||||
req := &proto.PutYnisonStateRequest{
|
req := &proto.PutYnisonStateRequest{
|
||||||
UpdateActiveDevice: &proto.UpdateActiveDevice{
|
UpdateActiveDevice: &proto.UpdateActiveDevice{
|
||||||
@@ -330,7 +334,7 @@ func (y *YnisonClient) UpdateActiveDevice(ctx context.Context, deviceID string)
|
|||||||
return y.sendRequest(ctx, req)
|
return y.sendRequest(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatePlayerState updates the player state (queue, repeat, shuffle)
|
// UpdatePlayerState updates the player state (queue, repeat, shuffle) on the Ynison server.
|
||||||
func (y *YnisonClient) UpdatePlayerState(ctx context.Context, state *proto.PlayerState) error {
|
func (y *YnisonClient) UpdatePlayerState(ctx context.Context, state *proto.PlayerState) error {
|
||||||
req := &proto.PutYnisonStateRequest{
|
req := &proto.PutYnisonStateRequest{
|
||||||
UpdatePlayerState: &proto.UpdatePlayerState{
|
UpdatePlayerState: &proto.UpdatePlayerState{
|
||||||
@@ -342,7 +346,7 @@ func (y *YnisonClient) UpdatePlayerState(ctx context.Context, state *proto.Playe
|
|||||||
return y.sendRequest(ctx, req)
|
return y.sendRequest(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatePlayerQueueInject updates the injected queue entity
|
// UpdatePlayerQueueInject updates the injected queue entity on the Ynison server.
|
||||||
func (y *YnisonClient) UpdatePlayerQueueInject(ctx context.Context, inject *proto.PlayerQueueInject) error {
|
func (y *YnisonClient) UpdatePlayerQueueInject(ctx context.Context, inject *proto.PlayerQueueInject) error {
|
||||||
req := &proto.PutYnisonStateRequest{
|
req := &proto.PutYnisonStateRequest{
|
||||||
UpdatePlayerQueueInject: &proto.UpdatePlayerQueueInject{
|
UpdatePlayerQueueInject: &proto.UpdatePlayerQueueInject{
|
||||||
@@ -354,7 +358,7 @@ func (y *YnisonClient) UpdatePlayerQueueInject(ctx context.Context, inject *prot
|
|||||||
return y.sendRequest(ctx, req)
|
return y.sendRequest(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SyncStateFromEOV requests synchronization from EOV
|
// SyncStateFromEOV requests synchronization from EOV (End of Verification).
|
||||||
func (y *YnisonClient) SyncStateFromEOV(ctx context.Context, actualQueueID string) error {
|
func (y *YnisonClient) SyncStateFromEOV(ctx context.Context, actualQueueID string) error {
|
||||||
req := &proto.PutYnisonStateRequest{
|
req := &proto.PutYnisonStateRequest{
|
||||||
SyncStateFromEov: &proto.SyncStateFromEOV{
|
SyncStateFromEov: &proto.SyncStateFromEOV{
|
||||||
@@ -366,25 +370,25 @@ func (y *YnisonClient) SyncStateFromEOV(ctx context.Context, actualQueueID strin
|
|||||||
return y.sendRequest(ctx, req)
|
return y.sendRequest(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDevices returns the list of connected devices from the last response
|
// GetDevices returns the list of connected devices from the last response.
|
||||||
func (y *YnisonClient) GetDevices() []*proto.Device {
|
func (y *YnisonClient) GetDevices() []*proto.Device {
|
||||||
// This would need to be implemented with proper state tracking
|
// This would need to be implemented with proper state tracking
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetActiveDeviceID returns the active device ID from the last response
|
// GetActiveDeviceID returns the active device ID from the last response.
|
||||||
func (y *YnisonClient) GetActiveDeviceID() string {
|
func (y *YnisonClient) GetActiveDeviceID() string {
|
||||||
// This would need to be implemented with proper state tracking
|
// This would need to be implemented with proper state tracking
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPlayerState returns the current player state from the last response
|
// GetPlayerState returns the current player state from the last response.
|
||||||
func (y *YnisonClient) GetPlayerState() *proto.PlayerState {
|
func (y *YnisonClient) GetPlayerState() *proto.PlayerState {
|
||||||
// This would need to be implemented with proper state tracking
|
// This would need to be implemented with proper state tracking
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitForConnection waits for the connection to be established or context to be done
|
// WaitForConnection waits for the connection to be established or the context to be done.
|
||||||
func (y *YnisonClient) WaitForConnection(ctx context.Context) error {
|
func (y *YnisonClient) WaitForConnection(ctx context.Context) error {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Package ynison provides a Ynison WebSocket client for player synchronization.
|
||||||
package ynison
|
package ynison
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -6,7 +7,8 @@ import (
|
|||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/ynison/proto"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/ynison/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreatePlayingStatus creates a playing status
|
// CreatePlayingStatus creates a playing status with the given parameters.
|
||||||
|
// The version timestamp is set to the current time.
|
||||||
func CreatePlayingStatus(progressMs, durationMs int64, paused bool, playbackSpeed float64, deviceID string) *proto.PlayingStatus {
|
func CreatePlayingStatus(progressMs, durationMs int64, paused bool, playbackSpeed float64, deviceID string) *proto.PlayingStatus {
|
||||||
return &proto.PlayingStatus{
|
return &proto.PlayingStatus{
|
||||||
ProgressMs: progressMs,
|
ProgressMs: progressMs,
|
||||||
@@ -21,7 +23,7 @@ func CreatePlayingStatus(progressMs, durationMs int64, paused bool, playbackSpee
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatePlayable creates a playable entity
|
// CreatePlayable creates a playable entity with the given parameters.
|
||||||
func CreatePlayable(playableID, albumID, from, title, coverURL string, playableType proto.PlayablePlayableType) *proto.Playable {
|
func CreatePlayable(playableID, albumID, from, title, coverURL string, playableType proto.PlayablePlayableType) *proto.Playable {
|
||||||
return &proto.Playable{
|
return &proto.Playable{
|
||||||
PlayableId: playableID,
|
PlayableId: playableID,
|
||||||
@@ -33,7 +35,7 @@ func CreatePlayable(playableID, albumID, from, title, coverURL string, playableT
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateTrackPlayable creates a track playable
|
// CreateTrackPlayable creates a track playable with the given parameters.
|
||||||
func CreateTrackPlayable(playableID, albumID, from, title, coverURL string, trackSourceKey uint32, batchID string) *proto.Playable {
|
func CreateTrackPlayable(playableID, albumID, from, title, coverURL string, trackSourceKey uint32, batchID string) *proto.Playable {
|
||||||
return &proto.Playable{
|
return &proto.Playable{
|
||||||
PlayableId: playableID,
|
PlayableId: playableID,
|
||||||
@@ -49,7 +51,7 @@ func CreateTrackPlayable(playableID, albumID, from, title, coverURL string, trac
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateVideoClipPlayable creates a video clip playable
|
// CreateVideoClipPlayable creates a video clip playable with the given parameters.
|
||||||
func CreateVideoClipPlayable(playableID, from, title, coverURL string, recommendationType proto.VideoClipInfoRecommendationType) *proto.Playable {
|
func CreateVideoClipPlayable(playableID, from, title, coverURL string, recommendationType proto.VideoClipInfoRecommendationType) *proto.Playable {
|
||||||
return &proto.Playable{
|
return &proto.Playable{
|
||||||
PlayableId: playableID,
|
PlayableId: playableID,
|
||||||
@@ -63,7 +65,7 @@ func CreateVideoClipPlayable(playableID, from, title, coverURL string, recommend
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatePlayerQueue creates a player queue
|
// CreatePlayerQueue creates a player queue with the given parameters.
|
||||||
func CreatePlayerQueue(entityID string, entityType proto.PlayerQueueEntityType, playables []*proto.Playable, currentIndex int32, deviceID string) *proto.PlayerQueue {
|
func CreatePlayerQueue(entityID string, entityType proto.PlayerQueueEntityType, playables []*proto.Playable, currentIndex int32, deviceID string) *proto.PlayerQueue {
|
||||||
return &proto.PlayerQueue{
|
return &proto.PlayerQueue{
|
||||||
EntityId: entityID,
|
EntityId: entityID,
|
||||||
@@ -82,7 +84,7 @@ func CreatePlayerQueue(entityID string, entityType proto.PlayerQueueEntityType,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateWaveQueue creates a wave queue
|
// CreateWaveQueue creates a wave queue with the given parameters.
|
||||||
func CreateWaveQueue(recommended []*proto.Playable, liveIndex int32, sessionID string, deviceID string) *proto.PlayerQueueQueue {
|
func CreateWaveQueue(recommended []*proto.Playable, liveIndex int32, sessionID string, deviceID string) *proto.PlayerQueueQueue {
|
||||||
// Build track sources from playables
|
// Build track sources from playables
|
||||||
var trackSources []*proto.PlayerQueueQueueWaveQueueEntityOptionsTrackSourceWithKey
|
var trackSources []*proto.PlayerQueueQueueWaveQueueEntityOptionsTrackSourceWithKey
|
||||||
@@ -111,7 +113,7 @@ func CreateWaveQueue(recommended []*proto.Playable, liveIndex int32, sessionID s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateGenerativeQueue creates a generative queue
|
// CreateGenerativeQueue creates a generative queue with the given ID.
|
||||||
func CreateGenerativeQueue(id string) *proto.PlayerQueueQueue {
|
func CreateGenerativeQueue(id string) *proto.PlayerQueueQueue {
|
||||||
return &proto.PlayerQueueQueue{
|
return &proto.PlayerQueueQueue{
|
||||||
GenerativeQueue: &proto.PlayerQueueQueueGenerativeQueue{
|
GenerativeQueue: &proto.PlayerQueueQueueGenerativeQueue{
|
||||||
|
|||||||
+107
-99
@@ -1,3 +1,5 @@
|
|||||||
|
// Package yandexmusic provides the public API for the Yandex Music Go client.
|
||||||
|
// It re-exports types and functions from the internal packages for convenient use.
|
||||||
package yandexmusic
|
package yandexmusic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -7,307 +9,313 @@ import (
|
|||||||
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/ynison"
|
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/ynison"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ClientConfig holds configuration for the Client
|
// ClientConfig holds configuration for the Client.
|
||||||
type ClientConfig = client.ClientConfig
|
type ClientConfig = client.ClientConfig
|
||||||
|
|
||||||
// Client is the main Yandex Music API client
|
// Client is the main Yandex Music API client.
|
||||||
type Client = client.Client
|
type Client = client.Client
|
||||||
|
|
||||||
// NewClient creates a new Yandex Music client
|
// NewClient creates a new Yandex Music client with the given configuration.
|
||||||
func NewClient(config ClientConfig) *Client {
|
func NewClient(config ClientConfig) *Client {
|
||||||
return client.NewClient(config)
|
return client.NewClient(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request is the HTTP request handler
|
// Request is the HTTP request handler.
|
||||||
type Request = client.Request
|
type Request = client.Request
|
||||||
|
|
||||||
// DeviceCode represents the device authorization response
|
// DeviceCode represents the device authorization response.
|
||||||
type DeviceCode = client.DeviceCode
|
type DeviceCode = client.DeviceCode
|
||||||
|
|
||||||
// OAuthToken represents an OAuth token response
|
// OAuthToken represents an OAuth token response.
|
||||||
type OAuthToken = client.OAuthToken
|
type OAuthToken = client.OAuthToken
|
||||||
|
|
||||||
// Status represents account status
|
// Status represents account status.
|
||||||
type Status = client.Status
|
type Status = client.Status
|
||||||
|
|
||||||
// Account represents a user account
|
// Account represents a user account.
|
||||||
type Account = client.Account
|
type Account = client.Account
|
||||||
|
|
||||||
// Track represents a music track
|
// Track represents a music track.
|
||||||
type Track = models.Track
|
type Track = models.Track
|
||||||
|
|
||||||
// Artist represents an artist
|
// Artist represents an artist.
|
||||||
type Artist = models.Artist
|
type Artist = models.Artist
|
||||||
|
|
||||||
// Album represents an album
|
// Album represents an album.
|
||||||
type Album = models.Album
|
type Album = models.Album
|
||||||
|
|
||||||
// Playlist represents a playlist
|
// Playlist represents a playlist.
|
||||||
type Playlist = models.Playlist
|
type Playlist = models.Playlist
|
||||||
|
|
||||||
// User represents a user
|
// User represents a user.
|
||||||
type User = models.User
|
type User = models.User
|
||||||
|
|
||||||
// DownloadInfo represents file download info
|
// DownloadInfo represents file download info.
|
||||||
type DownloadInfo = models.DownloadInfo
|
type DownloadInfo = models.DownloadInfo
|
||||||
|
|
||||||
// SupplementLyrics represents lyrics content from supplement
|
// SupplementLyrics represents lyrics content from supplement.
|
||||||
type SupplementLyrics = models.SupplementLyrics
|
type SupplementLyrics = models.SupplementLyrics
|
||||||
|
|
||||||
// Major represents major label info
|
// Major represents major label info.
|
||||||
type Major = models.Major
|
type Major = models.Major
|
||||||
|
|
||||||
// Label represents a label
|
// Label represents a label.
|
||||||
type Label = models.Label
|
type Label = models.Label
|
||||||
|
|
||||||
// Availability represents availability info
|
// Availability represents availability info.
|
||||||
type Availability = models.Availability
|
type Availability = models.Availability
|
||||||
|
|
||||||
// Upsell represents upsell info
|
// Upsell represents upsell info.
|
||||||
type Upsell = models.Upsell
|
type Upsell = models.Upsell
|
||||||
|
|
||||||
// AlbumMeta represents album metadata
|
// AlbumMeta represents album metadata.
|
||||||
type AlbumMeta = models.AlbumMeta
|
type AlbumMeta = models.AlbumMeta
|
||||||
|
|
||||||
// Best represents best tracks info
|
// Best represents best tracks info.
|
||||||
type Best = models.Best
|
type Best = models.Best
|
||||||
|
|
||||||
// Ratings represents artist ratings
|
// Ratings represents artist ratings.
|
||||||
type Ratings = models.Ratings
|
type Ratings = models.Ratings
|
||||||
|
|
||||||
// Counts represents artist counts
|
// Counts represents artist counts.
|
||||||
type Counts = models.Counts
|
type Counts = models.Counts
|
||||||
|
|
||||||
// TrackShort represents a lightweight track
|
// TrackShort represents a lightweight track.
|
||||||
type TrackShort = models.TrackShort
|
type TrackShort = models.TrackShort
|
||||||
|
|
||||||
// TracksList represents a list of tracks with metadata
|
// TracksList represents a list of tracks with metadata.
|
||||||
type TracksList = models.TracksList
|
type TracksList = models.TracksList
|
||||||
|
|
||||||
// Pager represents pagination info
|
// Pager represents pagination info.
|
||||||
type Pager = models.Pager
|
type Pager = models.Pager
|
||||||
|
|
||||||
// TrackPosition represents track position
|
// TrackPosition represents track position.
|
||||||
type TrackPosition = models.TrackPosition
|
type TrackPosition = models.TrackPosition
|
||||||
|
|
||||||
// TrailerInfo represents trailer info
|
// TrailerInfo represents trailer info.
|
||||||
type TrailerInfo = models.TrailerInfo
|
type TrailerInfo = models.TrailerInfo
|
||||||
|
|
||||||
// Cover represents cover image info
|
// Cover represents cover image info.
|
||||||
type Cover = models.Cover
|
type Cover = models.Cover
|
||||||
|
|
||||||
// ArtistBriefInfo represents brief artist info
|
// ArtistBriefInfo represents brief artist info.
|
||||||
type ArtistBriefInfo = models.ArtistBriefInfo
|
type ArtistBriefInfo = models.ArtistBriefInfo
|
||||||
|
|
||||||
// ArtistDonations represents artist donations info
|
// ArtistDonations represents artist donations info.
|
||||||
type ArtistDonations = models.ArtistDonations
|
type ArtistDonations = models.ArtistDonations
|
||||||
|
|
||||||
// DonationItem represents a donation item
|
// DonationItem represents a donation item.
|
||||||
type DonationItem = models.DonationItem
|
type DonationItem = models.DonationItem
|
||||||
|
|
||||||
// Concert represents a concert (minimal)
|
// Concert represents a concert (minimal).
|
||||||
type Concert = models.Concert
|
type Concert = models.Concert
|
||||||
|
|
||||||
// Clip represents a clip (short video)
|
// Clip represents a clip (short video).
|
||||||
type Clip = models.Clip
|
type Clip = models.Clip
|
||||||
|
|
||||||
// SearchResult represents search results
|
// SearchResult represents search results.
|
||||||
type SearchResult = models.SearchResult
|
type SearchResult = models.SearchResult
|
||||||
|
|
||||||
// SearchTracksResult represents track search results
|
// SearchTracksResult represents track search results.
|
||||||
type SearchTracksResult = models.SearchTracksResult
|
type SearchTracksResult = models.SearchTracksResult
|
||||||
|
|
||||||
// SearchAlbumsResult represents album search results
|
// SearchAlbumsResult represents album search results.
|
||||||
type SearchAlbumsResult = models.SearchAlbumsResult
|
type SearchAlbumsResult = models.SearchAlbumsResult
|
||||||
|
|
||||||
// SearchArtistsResult represents artist search results
|
// SearchArtistsResult represents artist search results.
|
||||||
type SearchArtistsResult = models.SearchArtistsResult
|
type SearchArtistsResult = models.SearchArtistsResult
|
||||||
|
|
||||||
// SearchPlaylistsResult represents playlist search results
|
// SearchPlaylistsResult represents playlist search results.
|
||||||
type SearchPlaylistsResult = models.SearchPlaylistsResult
|
type SearchPlaylistsResult = models.SearchPlaylistsResult
|
||||||
|
|
||||||
// SearchVideosResult represents video search results
|
// SearchVideosResult represents video search results.
|
||||||
type SearchVideosResult = models.SearchVideosResult
|
type SearchVideosResult = models.SearchVideosResult
|
||||||
|
|
||||||
// SearchUsersResult represents user search results
|
// SearchUsersResult represents user search results.
|
||||||
type SearchUsersResult = models.SearchUsersResult
|
type SearchUsersResult = models.SearchUsersResult
|
||||||
|
|
||||||
// SearchBanner represents a search banner
|
// SearchBanner represents a search banner.
|
||||||
type SearchBanner = models.SearchBanner
|
type SearchBanner = models.SearchBanner
|
||||||
|
|
||||||
// Tag represents a search tag
|
// Tag represents a search tag.
|
||||||
type Tag = models.Tag
|
type Tag = models.Tag
|
||||||
|
|
||||||
// Video represents a video
|
// Video represents a video.
|
||||||
type Video = models.Video
|
type Video = models.Video
|
||||||
|
|
||||||
// ChartInfoMenu represents a chart info menu
|
// ChartInfoMenu represents a chart info menu.
|
||||||
type ChartInfoMenu = models.ChartInfoMenu
|
type ChartInfoMenu = models.ChartInfoMenu
|
||||||
|
|
||||||
// ChartInfoMenuItem represents a chart info menu item
|
// ChartInfoMenuItem represents a chart info menu item.
|
||||||
type ChartInfoMenuItem = models.ChartInfoMenuItem
|
type ChartInfoMenuItem = models.ChartInfoMenuItem
|
||||||
|
|
||||||
// ChartItems represents chart items response
|
// ChartItems represents chart items response.
|
||||||
type ChartItems = models.ChartItems
|
type ChartItems = models.ChartItems
|
||||||
|
|
||||||
// AccountSettings represents account settings
|
// AccountSettings represents account settings.
|
||||||
type AccountSettings = models.AccountSettings
|
type AccountSettings = models.AccountSettings
|
||||||
|
|
||||||
// Subscription represents subscription info
|
// Subscription represents subscription info.
|
||||||
type Subscription = models.Subscription
|
type Subscription = models.Subscription
|
||||||
|
|
||||||
// PlusInfo represents Plus subscription info
|
// PlusInfo represents Plus subscription info.
|
||||||
type PlusInfo = models.PlusInfo
|
type PlusInfo = models.PlusInfo
|
||||||
|
|
||||||
// PromoCodeStatus represents promo code status
|
// PromoCodeStatus represents promo code status.
|
||||||
type PromoCodeStatus = models.PromoCodeStatus
|
type PromoCodeStatus = models.PromoCodeStatus
|
||||||
|
|
||||||
// Queue represents a playback queue
|
// Queue represents a playback queue.
|
||||||
type Queue = models.Queue
|
type Queue = models.Queue
|
||||||
|
|
||||||
// QueueItem represents a queue item
|
// QueueItem represents a queue item.
|
||||||
type QueueItem = models.QueueItem
|
type QueueItem = models.QueueItem
|
||||||
|
|
||||||
// PlayContext represents a play context
|
// PlayContext represents a play context.
|
||||||
type PlayContext = models.PlayContext
|
type PlayContext = models.PlayContext
|
||||||
|
|
||||||
// PlayContextsData represents play contexts data
|
// PlayContextsData represents play contexts data.
|
||||||
type PlayContextsData = models.PlayContextsData
|
type PlayContextsData = models.PlayContextsData
|
||||||
|
|
||||||
// Feed represents the main feed
|
// Feed represents the main feed.
|
||||||
type Feed = models.Feed
|
type Feed = models.Feed
|
||||||
|
|
||||||
// Day represents a day in the feed
|
// Day represents a day in the feed.
|
||||||
type Day = models.Day
|
type Day = models.Day
|
||||||
|
|
||||||
// DayBlock represents a block in a day
|
// DayBlock represents a block in a day.
|
||||||
type DayBlock = models.DayBlock
|
type DayBlock = models.DayBlock
|
||||||
|
|
||||||
// DayBlockData represents data in a day block
|
// DayBlockData represents data in a day block.
|
||||||
type DayBlockData = models.DayBlockData
|
type DayBlockData = models.DayBlockData
|
||||||
|
|
||||||
// GeneratedPlaylist represents a generated playlist
|
// GeneratedPlaylist represents a generated playlist.
|
||||||
type GeneratedPlaylist = models.GeneratedPlaylist
|
type GeneratedPlaylist = models.GeneratedPlaylist
|
||||||
|
|
||||||
// Event represents a feed event
|
// Event represents a feed event.
|
||||||
type Event = models.Event
|
type Event = models.Event
|
||||||
|
|
||||||
// AlbumEvent represents an album event
|
// AlbumEvent represents an album event.
|
||||||
type AlbumEvent = models.AlbumEvent
|
type AlbumEvent = models.AlbumEvent
|
||||||
|
|
||||||
// ArtistEvent represents an artist event
|
// ArtistEvent represents an artist event.
|
||||||
type ArtistEvent = models.ArtistEvent
|
type ArtistEvent = models.ArtistEvent
|
||||||
|
|
||||||
// TrackWithAds represents a track with ads
|
// TrackWithAds represents a track with ads.
|
||||||
type TrackWithAds = models.TrackWithAds
|
type TrackWithAds = models.TrackWithAds
|
||||||
|
|
||||||
// Ad represents an ad
|
// Ad represents an ad.
|
||||||
type Ad = models.Ad
|
type Ad = models.Ad
|
||||||
|
|
||||||
// AdParams represents ad parameters
|
// AdParams represents ad parameters.
|
||||||
type AdParams = models.AdParams
|
type AdParams = models.AdParams
|
||||||
|
|
||||||
// Landing represents a landing page
|
// Landing represents a landing page.
|
||||||
type Landing = models.Landing
|
type Landing = models.Landing
|
||||||
|
|
||||||
// LandingBlock represents a block in a landing
|
// LandingBlock represents a block in a landing.
|
||||||
type LandingBlock = models.LandingBlock
|
type LandingBlock = models.LandingBlock
|
||||||
|
|
||||||
// LandingBlockData represents data in a landing block
|
// LandingBlockData represents data in a landing block.
|
||||||
type LandingBlockData = models.LandingBlockData
|
type LandingBlockData = models.LandingBlockData
|
||||||
|
|
||||||
// LandingList represents a list of landings
|
// LandingList represents a list of landings.
|
||||||
type LandingList = models.LandingList
|
type LandingList = models.LandingList
|
||||||
|
|
||||||
// LyricsInfo represents lyrics information
|
// LyricsInfo represents lyrics information.
|
||||||
type LyricsInfo = models.LyricsInfo
|
type LyricsInfo = models.LyricsInfo
|
||||||
|
|
||||||
// VideoSupplement represents video supplement
|
// VideoSupplement represents video supplement.
|
||||||
type VideoSupplement = models.VideoSupplement
|
type VideoSupplement = models.VideoSupplement
|
||||||
|
|
||||||
// Supplement represents track supplement
|
// Supplement represents track supplement.
|
||||||
type Supplement = models.Supplement
|
type Supplement = models.Supplement
|
||||||
|
|
||||||
// LyricsMajor represents a lyrics provider (e.g., Genius, Musixmatch)
|
// LyricsMajor represents a lyrics provider (e.g., Genius, Musixmatch).
|
||||||
type LyricsMajor = models.LyricsMajor
|
type LyricsMajor = models.LyricsMajor
|
||||||
|
|
||||||
// TrackLyrics represents lyrics information from /tracks/{id}/lyrics endpoint
|
// TrackLyrics represents lyrics information from /tracks/{id}/lyrics endpoint.
|
||||||
type TrackLyrics = models.TrackLyrics
|
type TrackLyrics = models.TrackLyrics
|
||||||
|
|
||||||
// Credits represents track credits
|
// Credits represents track credits.
|
||||||
type Credits = models.Credits
|
type Credits = models.Credits
|
||||||
|
|
||||||
// Credit represents a credit item
|
// Credit represents a credit item.
|
||||||
type Credit = models.Credit
|
type Credit = models.Credit
|
||||||
|
|
||||||
// RadioStation represents a radio station
|
// ArtistTracks represents a page of tracks by an artist.
|
||||||
|
type ArtistTracks = models.ArtistTracks
|
||||||
|
|
||||||
|
// ArtistAlbums represents a page of albums by an artist.
|
||||||
|
type ArtistAlbums = models.ArtistAlbums
|
||||||
|
|
||||||
|
// RadioStation represents a radio station.
|
||||||
type RadioStation = models.RadioStation
|
type RadioStation = models.RadioStation
|
||||||
|
|
||||||
// StationTracksResult represents station tracks result
|
// StationTracksResult represents station tracks result.
|
||||||
type StationTracksResult = models.StationTracksResult
|
type StationTracksResult = models.StationTracksResult
|
||||||
|
|
||||||
// RotorStation represents a rotor (generative) station
|
// RotorStation represents a rotor (generative) station.
|
||||||
type RotorStation = models.RotorStation
|
type RotorStation = models.RotorStation
|
||||||
|
|
||||||
// RotorSettings represents rotor station settings
|
// RotorSettings represents rotor station settings.
|
||||||
type RotorSettings = models.RotorSettings
|
type RotorSettings = models.RotorSettings
|
||||||
|
|
||||||
// RotorStationTracksResult represents rotor station tracks result
|
// RotorStationTracksResult represents rotor station tracks result.
|
||||||
type RotorStationTracksResult = models.RotorStationTracksResult
|
type RotorStationTracksResult = models.RotorStationTracksResult
|
||||||
|
|
||||||
// RotorSession represents a rotor session
|
// RotorSession represents a rotor session.
|
||||||
type RotorSession = models.RotorSession
|
type RotorSession = models.RotorSession
|
||||||
|
|
||||||
// SessionFeedback represents session feedback
|
// SessionFeedback represents session feedback.
|
||||||
type SessionFeedback = models.SessionFeedback
|
type SessionFeedback = models.SessionFeedback
|
||||||
|
|
||||||
// SessionFeedbacks represents multiple session feedbacks
|
// SessionFeedbacks represents multiple session feedbacks.
|
||||||
type SessionFeedbacks = models.SessionFeedbacks
|
type SessionFeedbacks = models.SessionFeedbacks
|
||||||
|
|
||||||
// Experiments represents experiments
|
// Experiments represents experiments.
|
||||||
type Experiments = models.Experiments
|
type Experiments = models.Experiments
|
||||||
|
|
||||||
// ExperimentDetail represents experiment details
|
// ExperimentDetail represents experiment details.
|
||||||
type ExperimentDetail = models.ExperimentDetail
|
type ExperimentDetail = models.ExperimentDetail
|
||||||
|
|
||||||
// Permissions represents user permissions
|
// Permissions represents user permissions.
|
||||||
type Permissions = models.Permissions
|
type Permissions = models.Permissions
|
||||||
|
|
||||||
// PermissionAlerts represents permission alerts
|
// PermissionAlerts represents permission alerts.
|
||||||
type PermissionAlerts = models.PermissionAlerts
|
type PermissionAlerts = models.PermissionAlerts
|
||||||
|
|
||||||
// PermissionAlert represents a permission alert
|
// PermissionAlert represents a permission alert.
|
||||||
type PermissionAlert = models.PermissionAlert
|
type PermissionAlert = models.PermissionAlert
|
||||||
|
|
||||||
// ContentRestrictions represents content restrictions
|
// ContentRestrictions represents content restrictions.
|
||||||
type ContentRestrictions = models.ContentRestrictions
|
type ContentRestrictions = models.ContentRestrictions
|
||||||
|
|
||||||
// JSONBackend defines the interface for JSON encoding/decoding
|
// JSONBackend defines the interface for JSON encoding/decoding.
|
||||||
type JSONBackend = utils.JSONBackend
|
type JSONBackend = utils.JSONBackend
|
||||||
|
|
||||||
// GetDefaultJSONBackend returns the default JSON backend
|
// GetDefaultJSONBackend returns the default JSON backend.
|
||||||
func GetDefaultJSONBackend() JSONBackend {
|
func GetDefaultJSONBackend() JSONBackend {
|
||||||
return utils.GetDefaultJSONBackend()
|
return utils.GetDefaultJSONBackend()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SchemaMismatchConfig holds configuration for schema mismatch handling
|
// SchemaMismatchConfig holds configuration for schema mismatch handling.
|
||||||
type SchemaMismatchConfig = utils.SchemaMismatchConfig
|
type SchemaMismatchConfig = utils.SchemaMismatchConfig
|
||||||
|
|
||||||
// DefaultSchemaMismatchConfig returns the default configuration
|
// DefaultSchemaMismatchConfig returns the default configuration.
|
||||||
func DefaultSchemaMismatchConfig() SchemaMismatchConfig {
|
func DefaultSchemaMismatchConfig() SchemaMismatchConfig {
|
||||||
return utils.DefaultSchemaMismatchConfig()
|
return utils.DefaultSchemaMismatchConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SchemaMismatchHandler is a callback for handling schema mismatches
|
// SchemaMismatchHandler is a callback for handling schema mismatches.
|
||||||
type SchemaMismatchHandler = utils.SchemaMismatchHandler
|
type SchemaMismatchHandler = utils.SchemaMismatchHandler
|
||||||
|
|
||||||
// SchemaMismatch represents a mismatch between expected and actual API response
|
// SchemaMismatch represents a mismatch between expected and actual API response.
|
||||||
type SchemaMismatch = utils.SchemaMismatch
|
type SchemaMismatch = utils.SchemaMismatch
|
||||||
|
|
||||||
// YnisonClient represents a Ynison WebSocket client
|
// YnisonClient represents a Ynison WebSocket client.
|
||||||
type YnisonClient = ynison.YnisonClient
|
type YnisonClient = ynison.YnisonClient
|
||||||
|
|
||||||
// DeviceConfig holds device configuration for Ynison
|
// DeviceConfig holds device configuration for Ynison.
|
||||||
type DeviceConfig = ynison.DeviceConfig
|
type DeviceConfig = ynison.DeviceConfig
|
||||||
|
|
||||||
// Example usage:
|
// Example usage:
|
||||||
|
|||||||
Reference in new issue
Block a user