-
Notifications
You must be signed in to change notification settings - Fork 1
/
client.go
143 lines (125 loc) · 3.85 KB
/
client.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package client
import (
"context"
"fmt"
"html"
"net/http"
"net/url"
"strings"
"time"
"github.com/kkdai/youtube/v2"
"github.com/newrelic/go-agent/v3/newrelic"
"github.com/rl404/fairy/errors/stack"
"github.com/rl404/naka/internal/domain/youtube/entity"
"github.com/rl404/naka/internal/errors"
"github.com/rl404/naka/internal/utils"
"google.golang.org/api/googleapi/transport"
"google.golang.org/api/option"
_youtube "google.golang.org/api/youtube/v3"
)
// Client is youtube client.
type Client struct {
client *youtube.Client
service *_youtube.Service
}
// New to create new youtube client.
func New(key string) (*Client, error) {
service, err := _youtube.NewService(context.Background(), option.WithHTTPClient(&http.Client{
Transport: newrelic.NewRoundTripper(&transport.APIKey{Key: key}),
Timeout: 5 * time.Second,
}))
if err != nil {
return nil, err
}
return &Client{
client: &youtube.Client{
HTTPClient: &http.Client{
Timeout: 5 * time.Second,
},
},
service: service,
}, nil
}
// GenerateVideoURL to generate youtube video url.
func (c *Client) GenerateVideoURL(id string) string {
return fmt.Sprintf("https://www.youtube.com/watch?v=%s", id)
}
// GenerateChannelURL to generate youtube channel url.
func (c *Client) GenerateChannelURL(id string) string {
return fmt.Sprintf("https://www.youtube.com/channel/%s", id)
}
// IsURLValid to check if youtube url valid.
func (c *Client) IsURLValid(url_ string) bool {
if _, err := url.ParseRequestURI(url_); err != nil {
return false
}
id, err := c.GetIDFromURL(context.Background(), url_)
return id != "" && err == nil
}
// GetIDFromURL to get video id from url.
func (c *Client) GetIDFromURL(ctx context.Context, url string) (string, error) {
id, err := youtube.ExtractVideoID(url)
if err != nil {
return "", stack.Wrap(ctx, err, errors.ErrInvalidYoutubeURL)
}
return id, nil
}
// GetSourceURLByID to get video source url.
func (c *Client) GetSourceURLByID(ctx context.Context, id string) (string, error) {
video, err := c.client.GetVideoContext(ctx, id)
if err != nil {
return "", stack.Wrap(ctx, err)
}
format := video.Formats.WithAudioChannels()
url, err := c.client.GetStreamURLContext(ctx, video, &format[0])
if err != nil {
return "", stack.Wrap(ctx, err)
}
return url, nil
}
// GetVideos to search youtube video.
func (c *Client) GetVideos(ctx context.Context, query string, limit int64) ([]entity.Video, error) {
response, err := c.service.Search.
List([]string{"id", "snippet"}).
Q(query).
MaxResults(limit).
Order("viewCount").
Context(ctx).
Do()
if err != nil {
return nil, stack.Wrap(ctx, err)
}
res := make([]entity.Video, len(response.Items))
for i, data := range response.Items {
res[i] = entity.Video{
ID: data.Id.VideoId,
Title: strings.TrimSpace(html.UnescapeString(data.Snippet.Title)),
}
}
return res, nil
}
// GetVideo to get video detail.
func (c *Client) GetVideo(ctx context.Context, id string) (*entity.Video, error) {
response, err := c.service.Videos.
List([]string{"id", "snippet", "contentDetails", "statistics"}).
Id(id).
Context(ctx).
Do()
if err != nil {
return nil, stack.Wrap(ctx, err)
}
if len(response.Items) == 0 {
return nil, stack.Wrap(ctx, errors.ErrInvalidYoutubeID)
}
return &entity.Video{
ID: response.Items[0].Id,
Title: strings.TrimSpace(html.UnescapeString(response.Items[0].Snippet.Title)),
ChannelID: response.Items[0].Snippet.ChannelId,
ChannelTitle: strings.TrimSpace(html.UnescapeString(response.Items[0].Snippet.ChannelTitle)),
Image: response.Items[0].Snippet.Thumbnails.Default.Url,
Duration: utils.ParseDuration(response.Items[0].ContentDetails.Duration),
View: int(response.Items[0].Statistics.ViewCount),
Like: int(response.Items[0].Statistics.LikeCount),
Dislike: int(response.Items[0].Statistics.DislikeCount),
}, nil
}