Files
Mrixs 923705c7fc
CI/CD / test (push) Successful in 48s
CI/CD / build (push) Successful in 56s
CI/CD / docker (push) Successful in 2m37s
Migrate to yandex-music-api-go v0.0.0-20261018120746-dbf9a46bb2e7
Library now provides GetTrackDownloadURL (signed URL via XML download_info_url),
so ym-dl delegates to it instead of reimplementing XML parsing and MD5 signing.
Removed local DownloadTrackXML/DownloadInfoXML and unused crypto/md5, encoding/hex,
encoding/xml, io imports from client.go.

Track.Lyrics replaced by LyricsInfo (availability flags only, no text).
Lyrics text requires separate GetTrackLyrics + GetTrackLyricsText calls —
not implemented yet, lyrics field left empty.
2026-10-18 16:06:17 +03:00

159 lines
4.4 KiB
Go

package yandex
import (
"context"
"errors"
"fmt"
"log/slog"
"net/http"
"os"
"time"
"ym-dl/internal/config"
"gitea.mrixs.me/Mrixs/yandex-music-api-go/yandexmusic"
)
// TrackPosition represents track position in album
type TrackPosition struct {
Volume int `json:"volume"`
Index int `json:"index"`
}
// YandexClient wraps the external yandexmusic client
type YandexClient struct {
client *yandexmusic.Client
config *config.YandexConfig
httpClient *http.Client
debug bool
logger *slog.Logger
}
// NewYandexClient creates a new Yandex Music client wrapper
func NewYandexClient(cfg *config.YandexConfig, debug bool) (*YandexClient, error) {
if cfg.Token == "" {
return nil, errors.New("yandex.token is required")
}
httpClient := &http.Client{
Timeout: 30 * time.Second,
}
logLevel := slog.LevelInfo
if debug {
logLevel = slog.LevelDebug
}
logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: logLevel,
}))
client := yandexmusic.NewClient(yandexmusic.ClientConfig{
Token: cfg.Token,
})
if err := client.Init(context.Background()); err != nil {
return nil, fmt.Errorf("init client: %w", err)
}
return &YandexClient{
client: client,
config: cfg,
httpClient: httpClient,
debug: debug,
logger: logger,
}, nil
}
// GetArtistTracks fetches tracks for an artist
func (c *YandexClient) GetArtistTracks(ctx context.Context, artistID int, page, pageSize int) ([]*yandexmusic.Track, error) {
result, err := c.client.GetArtistTracks(ctx, fmt.Sprintf("%d", artistID), page, pageSize)
if err != nil {
return nil, err
}
tracks := make([]*yandexmusic.Track, 0, len(result.Tracks))
for i := range result.Tracks {
tracks = append(tracks, &result.Tracks[i])
}
return tracks, nil
}
// GetArtistAlbums fetches albums for an artist
func (c *YandexClient) GetArtistAlbums(ctx context.Context, artistID int, page, pageSize int) ([]*yandexmusic.Album, error) {
result, err := c.client.GetArtistAlbums(ctx, fmt.Sprintf("%d", artistID), page, pageSize)
if err != nil {
return nil, err
}
albums := make([]*yandexmusic.Album, 0, len(result.Albums))
for i := range result.Albums {
albums = append(albums, &result.Albums[i])
}
return albums, nil
}
// GetAlbumWithTracks fetches an album with its tracks
func (c *YandexClient) GetAlbumWithTracks(ctx context.Context, albumID string) (*yandexmusic.Album, error) {
albums, err := c.client.GetAlbumsWithTracks(ctx, []string{albumID})
if err != nil {
return nil, err
}
if len(albums) == 0 {
return nil, fmt.Errorf("album not found")
}
return albums[0], nil
}
// GetTrackInfo fetches a single track's info
func (c *YandexClient) GetTrackInfo(ctx context.Context, trackID string) (*yandexmusic.Track, error) {
return c.client.GetTrack(ctx, trackID)
}
// GetTrackInfoWithPosition fetches track info including track position in album
func (c *YandexClient) GetTrackInfoWithPosition(ctx context.Context, trackID string) (*yandexmusic.Track, *TrackPosition, error) {
track, err := c.client.GetTrack(ctx, trackID)
if err != nil {
return nil, nil, err
}
// Extract track position from first album
var position *TrackPosition
if len(track.Albums) > 0 {
albumID := string(track.Albums[0].ID)
albums, err := c.client.GetAlbumsWithTracks(ctx, []string{albumID})
if err == nil && len(albums) > 0 {
album := albums[0]
// Find track in album.Volumes and get position
for volIdx, volume := range album.Volumes {
for trackIdx, t := range volume {
if string(t.ID) == trackID {
position = &TrackPosition{
Volume: volIdx + 1,
Index: trackIdx + 1,
}
break
}
}
if position != nil {
break
}
}
}
}
return track, position, nil
}
// GetTrackDownloadInfo gets download info for a track
func (c *YandexClient) GetTrackDownloadInfo(ctx context.Context, trackID string) ([]yandexmusic.DownloadInfo, error) {
return c.client.GetTrackDownloadInfo(ctx, trackID, "")
}
// GetArtistInfo fetches artist info
func (c *YandexClient) GetArtistInfo(ctx context.Context, artistID int) (*yandexmusic.Artist, error) {
return c.client.GetArtist(ctx, fmt.Sprintf("%d", artistID))
}
// GetTrackDownloadURL gets the direct MP3 download URL for a track.
// Delegates to the library which handles XML download, parsing and URL signing.
func (c *YandexClient) GetTrackDownloadURL(ctx context.Context, trackID string) (string, error) {
return c.client.GetTrackDownloadURL(ctx, trackID, "mp3", 0)
}