all repos — fixyoutube-go @ 558f876a7938e8fde5bbf84dfe77dde6b7669634

A better way to embed YouTube videos everywhere (inspired by FixTweet).

invidious/invidious.go (view raw)

 1package invidious
 2
 3import (
 4	"encoding/json"
 5	"fmt"
 6	"io"
 7	"net/http"
 8	"net/url"
 9	"strconv"
10	"strings"
11)
12
13type Client struct {
14	http     *http.Client
15	Instance string
16}
17
18type Format struct {
19	Url       string `json:"url"`
20	Container string `json:"container"`
21	Size      string `json:"size"`
22}
23
24type Video struct {
25	VideoId       string   `json:"videoId"`
26	Title         string   `json:"title"`
27	Description   string   `json:"description"`
28	Uploader      string   `json:"author"`
29	Duration      int      `json:"lengthSeconds"`
30	FormatStreams []Format `json:"formatStreams"`
31	Url           string
32	Height        int
33	Width         int
34}
35
36func filter[T any](ss []T, test func(T) bool) (ret []T) {
37	for _, s := range ss {
38		if test(s) {
39			ret = append(ret, s)
40		}
41	}
42	return
43}
44
45func parseOrZero(number string) int {
46	res, err := strconv.Atoi(number)
47	if err != nil {
48		return 0
49	}
50	return res
51}
52
53func (c *Client) FetchEverything(videoId string) (*Video, error) {
54	endpoint := fmt.Sprintf("https://%s/api/v1/videos/%s?fields=videoId,title,description,author,lengthSeconds,size,formatStreams", c.Instance, url.QueryEscape(videoId))
55	resp, err := c.http.Get(endpoint)
56	if err != nil {
57		return nil, err
58	}
59
60	defer resp.Body.Close()
61
62	body, err := io.ReadAll(resp.Body)
63	if err != nil {
64		return nil, err
65	}
66
67	if resp.StatusCode != http.StatusOK {
68		return nil, fmt.Errorf(string(body))
69	}
70
71	res := &Video{}
72	err = json.Unmarshal(body, res)
73	if err != nil {
74		return nil, err
75	}
76
77	mp4Test := func(f Format) bool { return f.Container == "mp4" }
78	mp4Formats := filter(res.FormatStreams, mp4Test)
79	myFormat := mp4Formats[len(mp4Formats)-1]
80	mySize := strings.Split(myFormat.Size, "x")
81
82	res.Url = myFormat.Url
83	res.Width = parseOrZero(mySize[0])
84	res.Height = parseOrZero(mySize[1])
85
86	return res, err
87}
88
89func NewClient(httpClient *http.Client, instance string) *Client {
90	return &Client{httpClient, instance}
91}