Skip to content

Commit

Permalink
fix: youtube search for autogenerated entities (#4)
Browse files Browse the repository at this point in the history
* fix: youtube search for autogenerated entities

* refactor: body read
  • Loading branch information
GeorgeGorbanev authored Sep 16, 2024
1 parent 7213abc commit 3a98f2b
Show file tree
Hide file tree
Showing 9 changed files with 254 additions and 238 deletions.
4 changes: 4 additions & 0 deletions entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ type Entity struct {
Provider *Provider
Type EntityType
}

func entityFullTitle(artist, title string) string {
return artist + " – " + title
}
12 changes: 6 additions & 6 deletions internal/yandex/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ var (

type Client interface {
FetchTrack(ctx context.Context, id string) (*Track, error)
SearchTrack(ctx context.Context, artistName, trackName string) (*Track, error)
SearchTrack(ctx context.Context, query string) (*Track, error)
FetchAlbum(ctx context.Context, id string) (*Album, error)
SearchAlbum(ctx context.Context, artistName, albumName string) (*Album, error)
SearchAlbum(ctx context.Context, query string) (*Album, error)
}

type HTTPClient struct {
Expand Down Expand Up @@ -87,11 +87,11 @@ func (c *HTTPClient) FetchTrack(ctx context.Context, trackID string) (*Track, er
return &tr.Result[0], nil
}

func (c *HTTPClient) SearchTrack(ctx context.Context, artistName, trackName string) (*Track, error) {
func (c *HTTPClient) SearchTrack(ctx context.Context, query string) (*Track, error) {
body, err := c.getAPI(ctx, "/search", url.Values{
"type": []string{"track"},
"page": []string{"0"},
"text": []string{fmt.Sprintf("%s – %s", artistName, trackName)},
"text": []string{query},
})
if err != nil {
return nil, fmt.Errorf("failed to get api: %s", err)
Expand Down Expand Up @@ -127,11 +127,11 @@ func (c *HTTPClient) FetchAlbum(ctx context.Context, albumID string) (*Album, er
return ar.Result, nil
}

func (c *HTTPClient) SearchAlbum(ctx context.Context, artistName, albumName string) (*Album, error) {
func (c *HTTPClient) SearchAlbum(ctx context.Context, query string) (*Album, error) {
body, err := c.getAPI(ctx, "/search", url.Values{
"type": []string{"album"},
"page": []string{"0"},
"text": []string{fmt.Sprintf("%s – %s", artistName, albumName)},
"text": []string{query},
})
if err != nil {
return nil, fmt.Errorf("failed to get api: %s", err)
Expand Down
50 changes: 22 additions & 28 deletions internal/yandex/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,16 +163,14 @@ func TestClient_FetchAlbum(t *testing.T) {

func TestClient_SearchTrack(t *testing.T) {
tests := []struct {
name string
queryArtist string
queryTrack string
want *Track
wantErr error
name string
query string
want *Track
wantErr error
}{
{
name: "when track found",
queryArtist: "Found artist",
queryTrack: "Found track",
name: "when track found",
query: "found query",
want: &Track{
ID: "1",
Title: "sample title",
Expand All @@ -197,10 +195,9 @@ func TestClient_SearchTrack(t *testing.T) {
},
},
{
name: "when track not found",
queryArtist: "any impossible artist",
queryTrack: "any impossible track",
wantErr: NotFoundError,
name: "when track not found",
query: "any not found query",
wantErr: NotFoundError,
},
}
for _, tt := range tests {
Expand All @@ -212,7 +209,7 @@ func TestClient_SearchTrack(t *testing.T) {
require.Equal(t, "track", searchType)

query := r.URL.Query().Get("text")
if query == "Found artist – Found track" {
if query == "found query" {
_, err := w.Write([]byte(`{
"result": {
"tracks":{
Expand Down Expand Up @@ -244,7 +241,7 @@ func TestClient_SearchTrack(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

result, err := client.SearchTrack(ctx, tt.queryArtist, tt.queryTrack)
result, err := client.SearchTrack(ctx, tt.query)
if tt.wantErr != nil {
require.ErrorIs(t, err, tt.wantErr)
} else {
Expand All @@ -257,16 +254,14 @@ func TestClient_SearchTrack(t *testing.T) {

func TestClient_SearchAlbum(t *testing.T) {
tests := []struct {
name string
queryArtist string
queryAlbum string
want *Album
wantErr error
name string
query string
want *Album
wantErr error
}{
{
name: "when track found",
queryArtist: "Found artist",
queryAlbum: "Found album",
name: "when track found",
query: "found query",
want: &Album{
ID: 1,
Title: "Sample Title",
Expand All @@ -279,10 +274,9 @@ func TestClient_SearchAlbum(t *testing.T) {
},
},
{
name: "when track not found",
queryArtist: "any impossible artist",
queryAlbum: "any impossible album",
wantErr: NotFoundError,
name: "when track not found",
query: "any not found query",
wantErr: NotFoundError,
},
}
for _, tt := range tests {
Expand All @@ -294,7 +288,7 @@ func TestClient_SearchAlbum(t *testing.T) {
require.Equal(t, "album", searchType)

query := r.URL.Query().Get("text")
if query == "Found artist – Found album" {
if query == "found query" {
_, err := w.Write([]byte(`{
"result": {
"albums":{
Expand All @@ -319,7 +313,7 @@ func TestClient_SearchAlbum(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

result, err := client.SearchAlbum(ctx, tt.queryArtist, tt.queryAlbum)
result, err := client.SearchAlbum(ctx, tt.query)
if tt.wantErr != nil {
require.ErrorIs(t, err, tt.wantErr)
} else {
Expand Down
39 changes: 15 additions & 24 deletions internal/youtube/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package youtube
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
Expand All @@ -14,14 +15,14 @@ const (
)

var (
NotFoundError = fmt.Errorf("not found")
NotFoundError = errors.New("not found")
)

type Client interface {
GetVideo(ctx context.Context, id string) (*Video, error)
SearchVideo(ctx context.Context, term string) (*Video, error)
SearchVideo(ctx context.Context, term string) (*SearchResponse, error)
GetPlaylist(ctx context.Context, id string) (*Playlist, error)
SearchPlaylist(ctx context.Context, term string) (*Playlist, error)
SearchPlaylist(ctx context.Context, term string) (*SearchResponse, error)
GetPlaylistItems(ctx context.Context, id string) ([]Video, error)
}

Expand All @@ -40,16 +41,15 @@ type getSnippetItem struct {
Snippet *snippet `json:"snippet"`
}

type searchSnippetResponse struct {
Items []*searchSnippetItem `json:"items"`
type SearchResponse struct {
Items []SearchItem `json:"items"`
}

type searchSnippetItem struct {
ID *searchSnippetID `json:"id"`
Snippet *snippet `json:"snippet"`
type SearchItem struct {
ID SearchID `json:"id"`
}

type searchSnippetID struct {
type SearchID struct {
VideoID string `json:"videoId"`
PlaylistID string `json:"playlistId"`
}
Expand Down Expand Up @@ -104,7 +104,7 @@ func (c *HTTPClient) GetVideo(ctx context.Context, id string) (*Video, error) {
}

// https://developers.google.com/youtube/v3/docs/search/list
func (c *HTTPClient) SearchVideo(ctx context.Context, query string) (*Video, error) {
func (c *HTTPClient) SearchVideo(ctx context.Context, query string) (*SearchResponse, error) {
body, err := c.getWithKey(ctx, "/youtube/v3/search", url.Values{
"q": {query},
"part": {"snippet"},
Expand All @@ -116,7 +116,7 @@ func (c *HTTPClient) SearchVideo(ctx context.Context, query string) (*Video, err
return nil, err
}

response := searchSnippetResponse{}
response := SearchResponse{}
if err := json.Unmarshal(body, &response); err != nil {
return nil, fmt.Errorf("failed to decode api response: %w", err)
}
Expand All @@ -125,12 +125,7 @@ func (c *HTTPClient) SearchVideo(ctx context.Context, query string) (*Video, err
return nil, NotFoundError
}

item := response.Items[0]
return &Video{
ID: item.ID.VideoID,
Title: item.Snippet.Title,
ChannelTitle: item.Snippet.ownerChannelTitle(),
}, nil
return &response, nil
}

// https://developers.google.com/youtube/v3/docs/playlists/list
Expand Down Expand Up @@ -160,7 +155,7 @@ func (c *HTTPClient) GetPlaylist(ctx context.Context, id string) (*Playlist, err
}

// https://developers.google.com/youtube/v3/docs/search/list
func (c *HTTPClient) SearchPlaylist(ctx context.Context, query string) (*Playlist, error) {
func (c *HTTPClient) SearchPlaylist(ctx context.Context, query string) (*SearchResponse, error) {
body, err := c.getWithKey(ctx, "/youtube/v3/search", url.Values{
"q": {query},
"part": {"snippet"},
Expand All @@ -171,19 +166,15 @@ func (c *HTTPClient) SearchPlaylist(ctx context.Context, query string) (*Playlis
return nil, err
}

response := searchSnippetResponse{}
response := SearchResponse{}
if err := json.Unmarshal(body, &response); err != nil {
return nil, fmt.Errorf("failed to decode api response: %w", err)
}
if len(response.Items) == 0 {
return nil, NotFoundError
}

return &Playlist{
ID: response.Items[0].ID.PlaylistID,
Title: response.Items[0].Snippet.Title,
ChannelTitle: response.Items[0].Snippet.ownerChannelTitle(),
}, nil
return &response, nil
}

// https://developers.google.com/youtube/v3/docs/playlistItems/list
Expand Down
53 changes: 31 additions & 22 deletions internal/youtube/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,11 @@ func TestHTTPClient_GetVideo(t *testing.T) {

func TestHTTPClient_SearchVideo(t *testing.T) {
tests := []struct {
name string
query string
responseMock string
expectedVideo *Video
expectedErr error
name string
query string
responseMock string
expectedResponse *SearchResponse
expectedErr error
}{
{
name: "when video found",
Expand All @@ -105,10 +105,15 @@ func TestHTTPClient_SearchVideo(t *testing.T) {
}
]
}`,
expectedVideo: &Video{
ID: "dQw4w9WgXcQ",
Title: "Rick Astley - Never Gonna Give You Up (Video)",
ChannelTitle: "RickAstleyVEVO",
expectedResponse: &SearchResponse{
Items: []SearchItem{
{
ID: SearchID{
VideoID: "dQw4w9WgXcQ",
PlaylistID: "",
},
},
},
},
},
{
Expand All @@ -117,8 +122,8 @@ func TestHTTPClient_SearchVideo(t *testing.T) {
responseMock: `{
"items": []
}`,
expectedVideo: nil,
expectedErr: NotFoundError,
expectedResponse: nil,
expectedErr: NotFoundError,
},
}
for _, tt := range tests {
Expand All @@ -127,7 +132,6 @@ func TestHTTPClient_SearchVideo(t *testing.T) {
require.Equal(t, http.MethodGet, r.Method)
require.Equal(t, "/youtube/v3/search", r.URL.Path)
require.Equal(t, sampleAPIKey, r.URL.Query().Get("key"))
require.Equal(t, "snippet", r.URL.Query().Get("part"))
require.Equal(t, tt.query, r.URL.Query().Get("q"))
require.Equal(t, "10", r.URL.Query().Get("videoCategoryId"))
require.Equal(t, "1", r.URL.Query().Get("maxResults"))
Expand All @@ -143,12 +147,12 @@ func TestHTTPClient_SearchVideo(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

video, err := client.SearchVideo(ctx, tt.query)
response, err := client.SearchVideo(ctx, tt.query)
if tt.expectedErr != nil {
require.ErrorIs(t, err, tt.expectedErr)
} else {
require.NoError(t, err)
require.Equal(t, tt.expectedVideo, video)
require.Equal(t, tt.expectedResponse, response)
}
})
}
Expand Down Expand Up @@ -227,7 +231,7 @@ func TestHTTPClient_SearchPlaylist(t *testing.T) {
name string
query string
responseMock string
expectedPlaylist *Playlist
expectedResponse *SearchResponse
expectedErr error
}{
{
Expand All @@ -246,10 +250,15 @@ func TestHTTPClient_SearchPlaylist(t *testing.T) {
}
]
}`,
expectedPlaylist: &Playlist{
ID: "PLH1JGOJgZ2u2J7bRnfjl-7kDj_vQKTPa6",
Title: "Portishead - (1994) Dummy [Full Album]",
ChannelTitle: "Harry",
expectedResponse: &SearchResponse{
Items: []SearchItem{
{
ID: SearchID{
VideoID: "",
PlaylistID: "PLH1JGOJgZ2u2J7bRnfjl-7kDj_vQKTPa6",
},
},
},
},
},
{
Expand All @@ -258,7 +267,7 @@ func TestHTTPClient_SearchPlaylist(t *testing.T) {
responseMock: `{
"items": []
}`,
expectedPlaylist: nil,
expectedResponse: nil,
expectedErr: NotFoundError,
},
}
Expand All @@ -283,12 +292,12 @@ func TestHTTPClient_SearchPlaylist(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

video, err := client.SearchPlaylist(ctx, tt.query)
response, err := client.SearchPlaylist(ctx, tt.query)
if tt.expectedErr != nil {
require.ErrorIs(t, err, tt.expectedErr)
} else {
require.NoError(t, err)
require.Equal(t, tt.expectedPlaylist, video)
require.Equal(t, tt.expectedResponse, response)
}
})
}
Expand Down
Loading

0 comments on commit 3a98f2b

Please sign in to comment.