Parent directory

resolve_channel_id.go

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