~handlerug/handlebot

ref: 7a899986d3a7d250418ed425c03a9e5391820979 handlebot/youtube/youtube.go -rw-r--r-- 3.8 KiB
7a899986Umar Getagazov Set user agent 3 months ago
                                                                                
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
144
145
146
147
148
149
150
151
152
153
154
155
package youtube

import (
	"context"
	"encoding/json"
	"net/http"
	"net/url"
	"strconv"
	"time"
)

type Client struct {
	APIKey     string
	HTTPClient *http.Client
}

type Response struct {
	Kind          string    `json:"kind"`
	ETag          string    `json:"etag"`
	NextPageToken string    `json:"nextPageToken"`
	PrevPageToken string    `json:"prevPageToken"`
	PageInfo      PageInfo  `json:"pageInfo"`
	Items         []*Video  `json:"items"`
	Error         *APIError `json:"error"`
}

type PageInfo struct {
	TotalResults   int `json:"totalResults"`
	ResultsPerPage int `json:"resultsPerPage"`
}

type Video struct {
	Kind           string          `json:"kind"`
	ETag           string          `json:"etag"`
	ID             string          `json:"id"`
	Snippet        *Snippet        `json:"snippet"`
	ContentDetails *ContentDetails `json:"contentDetails"`
	Statistics     *Statistics     `json:"statistics"`
}

type Snippet struct {
	PublishedAt          time.Time            `json:"publishedAt"`
	ChannelID            string               `json:"channelId"`
	Title                string               `json:"title"`
	Description          string               `json:"description"`
	Thumbnails           map[string]Thumbnail `json:"thumbnails"`
	ChannelTitle         string               `json:"channelTitle"`
	Tags                 []string             `json:"tags"`
	CategoryID           string               `json:"categoryId"`
	LiveBroadcastContent string               `json:"liveBroadcastContent"`
	DefaultLanguage      string               `json:"defaultLanguage"`
	Localized            struct {
		Title       string `json:"title"`
		Description string `json:"description"`
	} `json:"localized"`
	DefaultAudioLanguage string `json:"defaultAudioLanguage"`
}

type Thumbnail struct {
	URL    string `json:"url"`
	Width  uint   `json:"width"`
	Height uint   `json:"height"`
}

type ContentDetails struct {
	Duration          string  `json:"duration"`
	Dimension         string  `json:"dimension"`
	Definition        string  `json:"definition"`
	Caption           StrBool `json:"caption"`
	LicensedContent   bool    `json:"licensedContent"`
	RegionRestriction struct {
		Allowed []string `json:"allowed"`
		Blocked []string `json:"blocked"`
	} `json:"regionRestriction"`
	Projection         string `json:"projection"`
	HasCustomThumbnail bool   `json:"hasCustomThumbnail"`

	// skipped "contentRating"
}

type Statistics struct {
	ViewCount    StrUint64 `json:"viewCount"`
	LikeCount    StrUint64 `json:"likeCount"`
	DislikeCount StrUint64 `json:"dislikeCount"`
	CommentCount StrUint64 `json:"commentCount"`
}

type StrBool bool

func (v *StrBool) UnmarshalJSON(b []byte) error {
	if string(b) == "null" {
		return nil
	}
	var s string
	if err := json.Unmarshal(b, &s); err != nil {
		return err
	}
	*v = s[0] == 't'
	return nil
}

type StrUint64 uint64

func (v *StrUint64) UnmarshalJSON(b []byte) error {
	if string(b) == "null" {
		return nil
	}
	var s string
	if err := json.Unmarshal(b, &s); err != nil {
		return err
	}
	num, err := strconv.ParseUint(s, 10, 64)
	if err != nil {
		return err
	}
	*v = StrUint64(num)
	return nil
}

func (c *Client) GetVideo(ctx context.Context, id string) (*Video, error) {
	req, _ := http.NewRequestWithContext(ctx, "GET", "https://www.googleapis.com/youtube/v3/videos", nil)
	q := url.Values{}
	q.Set("part", "snippet,contentDetails,statistics")
	q.Set("key", c.APIKey)
	q.Set("id", id)
	req.URL.RawQuery = q.Encode()

	resp, err := c.httpClient().Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var res *Response
	if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
		return nil, err
	}

	if res.Error != nil {
		return nil, res.Error
	}

	if len(res.Items) == 0 {
		return nil, &NotFoundError{}
	}

	return res.Items[0], nil
}

func (c *Client) httpClient() *http.Client {
	if c.HTTPClient != nil {
		return c.HTTPClient
	}
	return http.DefaultClient
}