Skip to content

Commit

Permalink
breaking: -some methods; little refactoring; nil safety; new errors
Browse files Browse the repository at this point in the history
  • Loading branch information
oklookat committed Jul 27, 2023
1 parent 3efe654 commit e8fb1c3
Show file tree
Hide file tree
Showing 34 changed files with 566 additions and 1,619 deletions.
107 changes: 7 additions & 100 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# goym

Неофициальное API Яндекс.Музыки для Go.
Неофициальный клиент API Яндекс.Музыки для Go.

- Могут быть ошибки. API может перестать работать, если сменятся client_id, client_secret у приложения ЯМ для Windows.

Expand All @@ -10,111 +10,18 @@

2. Получите клиента вызвав `New`.

Токен можно получить например через [этот пакет](https://github.com/oklookat/yandexauth).
Токен можно получить например через пакет [yandexauth](https://github.com/oklookat/yandexauth).

ID и Secret (приложение для Windows):

ID: ```23cabbbdc6cd418abb4b39c32c41195d```

Secret: ```53bc75238f0c4d08a118e51fe9203300```

# Реализовано
# Полезная информация

## Account
- [x] GET /account/status
- [x] GET /account/settings
- [x] POST /account/consume-promo-code
- [x] POST /account/settings
- TLDR: если нужна проверка на отсутствие сущности, проверяйте schema.Error.Validate и пустоту полей кроме ID (например поле Name).

## Album
- [x] GET /albums/{albumId}
- [x] GET /albums/{albumId}/with-tracks
- [x] GET /users/{userId}/likes/albums
- [x] POST /albums
- [x] POST /users/{userId}/likes/albums/add
- [x] POST /users/{userId}/likes/albums/add-multiple
- [x] POST /users/{userId}/likes/albums/remove

## Artist
- [x] GET /users/{userId}/likes/artists
- [x] GET /artists/{artistId}/track-ids-by-rating
- [x] GET /artists/{artistId}/brief-info
- [x] GET /artists/{artistId}/tracks
- [x] GET /artists/{artistId}/direct-albums
- [x] POST /users/{userId}/likes/artists/add
- [x] POST /users/{userId}/likes/artists/add-multiple
- [x] POST /users/{userId}/likes/artists/remove

## Playlist
- [x] GET /users/{userId}/playlists/list
- [x] GET /users/{userId}/playlists/{kind}
- [x] GET /users/{userId}/playlists/{kind}/recommendations
- [x] POST /playlists/list
- [x] POST /users/{userId}/playlists/create
- [x] POST /users/{userId}/playlists/{kind}/name
- [x] POST /users/{userId}/playlists/{kind}/delete
- [x] POST /users/{userId}/playlists/{kind}/visibility
- [x] POST /users/{userId}/playlists/{kind}/description
- [x] POST /users/{userId}/playlists/{kind}/change-relative
- [x] POST /users/{userId}/playlists/{kind}/change
- [x] GET /users/{userId}/likes/playlists
- [x] POST /users/{userId}/likes/playlists/add
- [x] POST /users/{userId}/likes/playlists/add-multiple
- [x] POST /users/{userId}/likes/playlists/remove

## Search
- [x] GET /search
- [x] GET /search/suggest

## Track
- [x] GET /users/{userId}/likes/tracks
- [x] GET /users/{userId}/dislikes/tracks
- [x] GET /tracks/{trackId}/download-info
- [x] GET /tracks/{trackId}/supplement
- [x] GET /tracks/{trackId}/similar
- [x] GET /tracks/{trackId}
- [x] POST /users/{userId}/likes/tracks/add
- [x] POST /users/{userId}/likes/tracks/add-multiple
- [x] POST /users/{userId}/likes/tracks/remove
- [x] POST /tracks

## Tags
- [ ] /tags/{tagId}/playlist-ids

## Landing
- [ ] GET /landing3
- [ ] GET /landing3/{landingBlock}
- [ ] GET ​/landing3​/new-releases
- [ ] GET /landing3/podcasts
- [ ] GET /landing3/new-playlists
- [ ] GET /landing3/chart/{chartType}

## Rotor
- [x] GET /rotor/station/{type:tag}/tracks
- [x] GET /rotor/account/status
- [x] GET /rotor/stations/list
- [x] GET /rotor/stations/dashboard
- [x] GET /rotor/station/{type:tag}/info
- [x] POST /rotor/station/{type:tag}/feedback


## Default
- [ ] GET /settings
- [ ] GET /permission-alerts
- [ ] GET /feed/wizard/is-passed
- [ ] GET /feed
- [ ] GET /genres

# Где искать новые методы
- С помощью анализатора трафика смотреть приложения ЯМ.
- [Или тут](https://www.cherkashin.dev/yandex-music-open-api/).
- [И тут](https://github.com/MarshalX/yandex-music-api).
- [И здесь](https://github.com/K1llMan/Yandex.Music.Api).

# Чем можно помочь?
- Рефакторингом.
- Написанием нормальных комментариев к методам, документации.
- Написанием, исправлением тестов.
- Проверкой существующих методов.
- Поиском и реализацией новых методов.
- ???
Например если вы запрашиваете информацию об артисте по ID, но он не найден,
то запрос может вернуться с ошибкой validate (см. schema.Error) потому что ID некорректный, или
вернется артист с нужным ID, но с пустыми полями, кроме ID.
63 changes: 4 additions & 59 deletions account.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import (
)

// Получить информацию об аккаунте.
func (c Client) AccountStatus(ctx context.Context) (schema.Response[*schema.Status], error) {
func (c Client) AccountStatus(ctx context.Context) (schema.Response[schema.Status], error) {
// GET /account/status
endpoint := genApiPath("account", "status")

data := &schema.Response[*schema.Status]{}
data := &schema.Response[schema.Status]{}
resp, err := c.Http.R().SetResult(data).SetError(data).Get(ctx, endpoint)
if err == nil {
err = checkResponse(resp, data)
Expand All @@ -20,38 +20,11 @@ func (c Client) AccountStatus(ctx context.Context) (schema.Response[*schema.Stat
return *data, err
}

// Активировать промокод.
//
// Метод не тестировался.
func (c Client) AccountConsumePromocode(ctx context.Context, code string, language string) (schema.Response[*schema.PromocodeStatus], error) {
// POST /account/consume-promo-code
endpoint := genApiPath("account", "consume-promo-code")

body := schema.AccountConsumePromocodeRequestBody{
Code: code,
Language: language,
}

data := &schema.Response[*schema.PromocodeStatus]{}

vals, err := schema.ParamsToValues(body)
if err != nil {
return *data, err
}

resp, err := c.Http.R().SetResult(data).SetError(data).SetFormUrlValues(vals).Post(ctx, endpoint)
if err == nil {
err = checkResponse(resp, data)
}

return *data, err
}

// Получить настройки аккаунта.
func (c Client) AccountSettings(ctx context.Context) (schema.Response[*schema.AccountSettings], error) {
func (c Client) AccountSettings(ctx context.Context) (schema.Response[schema.AccountSettings], error) {
// GET /account/settings
endpoint := genApiPath("account", "settings")
data := &schema.Response[*schema.AccountSettings]{}
data := &schema.Response[schema.AccountSettings]{}

resp, err := c.Http.R().SetResult(data).SetError(data).Get(ctx, endpoint)
if err == nil {
Expand All @@ -60,31 +33,3 @@ func (c Client) AccountSettings(ctx context.Context) (schema.Response[*schema.Ac

return *data, err
}

// Изменить настройки аккаунта.
//
// Настройку нельзя изменить, если в поле AccountSettings есть url:"-".
//
// Может вернуть как AccountSettings, так и ничего.
func (c Client) ChangeAccountSettings(ctx context.Context, set schema.AccountSettings) (any, error) {
// POST /account/settings
// todo(?) иногда выдает ошибку json unmarshal при тестах.

endpoint := genApiPath("account", "settings")

body := schema.ChangeAccountSettingsRequestBody{}
body.Change(set)
vals, err := schema.ParamsToValues(body)
if err != nil {
return nil, err
}

data := &schema.Response[any]{}

resp, err := c.Http.R().SetResult(data).SetError(data).SetFormUrlValues(vals).Post(ctx, endpoint)
if err == nil {
err = checkResponse(resp, data)
}

return *data, err
}
53 changes: 7 additions & 46 deletions account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,15 @@ package goym

import (
"context"

"github.com/oklookat/goym/schema"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"testing"
)

type AccountTestSuite struct {
suite.Suite
cl *Client
require *require.Assertions
}

func (s *AccountTestSuite) SetupSuite() {
s.cl = getClient(s.T())
s.require = s.Require()
}

func (s *AccountTestSuite) TestAccountStatus() {
stat, err := s.cl.AccountStatus(context.Background())
s.require.Nil(err)
s.require.NotNil(stat.Result)
}
func TestAccountStatus(t *testing.T) {
ctx := context.Background()
cl := getClient(t)

func (s *AccountTestSuite) TestGetChangeAccountSettings() {
getSettings := func() *schema.AccountSettings {
sett, err := s.cl.AccountSettings(context.Background())
s.require.Nil(err)
s.require.NotNil(sett.Result)
return sett.Result
_, err := cl.AccountStatus(ctx)
if err != nil {
t.Fatal(err)
}

// set new settings
newSet := schema.AccountSettings{
VolumePercents: 10,
}
_, err := s.cl.ChangeAccountSettings(context.Background(), newSet)
s.require.Nil(err)

// get current and compare
sett := getSettings()
s.require.Equal(newSet.VolumePercents, sett.VolumePercents)

// set new
newSet.VolumePercents = 33
_, err = s.cl.ChangeAccountSettings(context.Background(), newSet)
s.require.Nil(err)

// get current and compare
sett = getSettings()
s.require.Equal(newSet.VolumePercents, sett.VolumePercents)
}
80 changes: 43 additions & 37 deletions album_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,65 +2,71 @@ package goym

import (
"context"

"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"testing"
)

type AlbumTestSuite struct {
suite.Suite
cl *Client
require *require.Assertions
}

func (s *AlbumTestSuite) SetupSuite() {
s.cl = getClient(s.T())
s.require = s.Require()
}

func (s *AlbumTestSuite) TestAlbum() {
func TestAlbum(t *testing.T) {
ctx := context.Background()
cl := getClient(t)

// without tracks
data, err := s.cl.Album(ctx, albumIds[0], false)
s.require.Nil(err)
_, err := cl.Album(ctx, _albumIds[0], false)
if err != nil {
t.Fatal(err)
}

// with tracks
data, err = s.cl.Album(ctx, albumIds[0], true)
s.require.Nil(err)
s.require.NotEmpty(data.Result.Volumes)
_, err = cl.Album(ctx, _albumIds[0], true)
if err != nil {
t.Fatal(err)
}
}

func (s *AlbumTestSuite) TestAlbums() {
resp, err := s.cl.Albums(context.Background(), albumIds[:])
s.require.Nil(err)
s.require.NotEmpty(resp.Result)
func TestAlbums(t *testing.T) {
ctx := context.Background()
cl := getClient(t)

_, err := cl.Albums(ctx, _albumIds[:4])
if err != nil {
t.Fatal(err)
}
}

func (s *AlbumTestSuite) TestLikeUnlikeAlbum() {
func TestLikeUnlikeAlbum(t *testing.T) {
ctx := context.Background()
cl := getClient(t)

// like
_, err := s.cl.LikeAlbum(ctx, albumIds[0])
s.require.Nil(err)
_, err := cl.LikeAlbum(ctx, _albumIds[0])
if err != nil {
t.Fatal(err)
}

// unlike
_, err = s.cl.UnlikeAlbum(ctx, albumIds[0])
s.require.Nil(err)
_, err = cl.UnlikeAlbum(ctx, _albumIds[0])
if err != nil {
t.Fatal(err)
}
}

func (s *AlbumTestSuite) TestLikeUnlikeLikedAlbums() {
func TestLikeUnlikeLikedAlbums(t *testing.T) {
ctx := context.Background()
cl := getClient(t)

// like
_, err := s.cl.LikeAlbums(ctx, albumIds[:])
s.require.Nil(err)
_, err := cl.LikeAlbums(ctx, _albumIds[:4])
if err != nil {
t.Fatal(err)
}

liked, err := s.cl.LikedAlbums(context.Background())
s.require.Nil(err)
s.require.NotEmpty(liked.Result)
_, err = cl.LikedAlbums(ctx)
if err != nil {
t.Fatal(err)
}

// unlike
_, err = s.cl.UnlikeAlbums(ctx, albumIds[:])
s.require.Nil(err)
_, err = cl.UnlikeAlbums(ctx, _albumIds[:4])
if err != nil {
t.Fatal(err)
}
}
Loading

0 comments on commit e8fb1c3

Please sign in to comment.