get_channel_image.go
1865 bytes
1package youtube
2
3import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "io"
8 "net/http"
9 "net/url"
10)
11
12type APIChannelListResponse struct {
13 Items []struct {
14 Snippet struct {
15 Thumbnails struct {
16 Medium struct {
17 URL string `json:"url"`
18 } `json:"medium"`
19 } `json:"thumbnails"`
20 } `json:"snippet"`
21 } `json:"items"`
22}
23
24func (c *youTubeClient) GetChannelImageURL(ctx context.Context, channelID string) (string, error) {
25 query := url.Values{}
26 query.Add("id", channelID)
27 query.Add("part", "snippet")
28 query.Add("fields", "items/snippet/thumbnails")
29 query.Add("key", c.apiKey)
30
31 req, err := http.NewRequestWithContext(ctx, http.MethodGet, "", nil)
32 if err != nil {
33 return "", fmt.Errorf("failed to set up request: %w", err)
34 }
35 req.URL = &url.URL{
36 Scheme: "https",
37 Host: "www.googleapis.com",
38 Path: "/youtube/v3/channels",
39 RawQuery: query.Encode(),
40 }
41
42 c.log.Info("Making request to YouTube API for channel image", "channelID", channelID)
43 resp, err := http.DefaultClient.Do(req)
44 if err != nil {
45 return "", fmt.Errorf("failed to fetch channel details: %w", err)
46 }
47 defer resp.Body.Close()
48
49 if resp.StatusCode != http.StatusOK {
50 body, err := io.ReadAll(resp.Body)
51 var bodyStr string
52 if err != nil {
53 c.log.Error("failed to decode error body", "error", err)
54 bodyStr = "failed to decode body"
55 } else {
56 bodyStr = string(body)
57 }
58 return "", fmt.Errorf("got non-200 status from YouTube API [%d]: %v", resp.StatusCode, bodyStr)
59 }
60
61 decoder := json.NewDecoder(resp.Body)
62 var respData APIChannelListResponse
63 err = decoder.Decode(&respData)
64 if err != nil {
65 return "", fmt.Errorf("failed to decode channel details: %w", err)
66 }
67
68 if len(respData.Items) == 0 {
69 return "", fmt.Errorf("channel not found [%s]", channelID)
70 }
71
72 channelData := respData.Items[0]
73 return channelData.Snippet.Thumbnails.Medium.URL, nil
74}