all repos — fixyoutube-go @ 566d29167b4dcd64442c4b91805551c4e4e23dfa

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

invidious/api.go (view raw)

  1package invidious
  2
  3import (
  4	"encoding/json"
  5	"fmt"
  6	"io"
  7	"net/http"
  8	"net/url"
  9	"strconv"
 10	"time"
 11)
 12
 13func (c *Client) fetchVideo(videoId string) (*Video, int) {
 14	endpoint := fmt.Sprintf(videosEndpoint, c.Instance, url.QueryEscape(videoId))
 15	resp, err := c.http.Get(endpoint)
 16	if err != nil {
 17		logger.Error(err)
 18		return nil, http.StatusInternalServerError
 19	}
 20	defer resp.Body.Close()
 21
 22	if resp.StatusCode != http.StatusOK {
 23		logger.Warn("Invidious gave the following status code: ", resp.StatusCode)
 24		return nil, http.StatusNotFound
 25	}
 26
 27	body, err := io.ReadAll(resp.Body)
 28	if err != nil {
 29		logger.Error(err)
 30		return nil, http.StatusInternalServerError
 31	}
 32
 33	res := &Video{}
 34	err = json.Unmarshal(body, res)
 35	if err != nil {
 36		logger.Error(err)
 37		return nil, http.StatusInternalServerError
 38	}
 39
 40	mp4Test := func(f Format) bool { return f.Container == "mp4" }
 41	res.Formats = filter(res.Formats, mp4Test)
 42
 43	expireString := expireRegex.FindStringSubmatch(res.Formats[0].Url)
 44	expireTimestamp, err := strconv.ParseInt(expireString[1], 10, 64)
 45	if err != nil {
 46		logger.Error(err)
 47		return nil, http.StatusInternalServerError
 48	}
 49	res.Expire = time.Unix(expireTimestamp, 0)
 50
 51	_, l, i := c.findCompatibleFormat(res)
 52	if l == 0 {
 53		logger.Warn("No compatible formats found for video.")
 54		res.Url = ""
 55	} else {
 56		res.Url = res.Formats[i].Url
 57	}
 58
 59	return res, http.StatusOK
 60}
 61
 62func (c *Client) isNotTimedOut(instance string) bool {
 63	for i := range c.timeouts {
 64		cur := c.timeouts[i]
 65		if instance == cur.Instance {
 66			return false
 67		}
 68	}
 69	return true
 70}
 71
 72func (c *Client) NewInstance() error {
 73	now := time.Now()
 74
 75	timeoutsTest := func(t Timeout) bool { return now.Sub(t.Timestamp) < timeoutDuration }
 76	c.timeouts = filter(c.timeouts, timeoutsTest)
 77	c.timeouts = append(c.timeouts, Timeout{c.Instance, now})
 78
 79	resp, err := c.http.Get(instancesEndpoint)
 80	if err != nil {
 81		return err
 82	}
 83	defer resp.Body.Close()
 84
 85	body, err := io.ReadAll(resp.Body)
 86	if err != nil {
 87		return err
 88	}
 89
 90	if resp.StatusCode != http.StatusOK {
 91		return fmt.Errorf("HTTP error: %d", resp.StatusCode)
 92	}
 93
 94	var jsonArray [][]interface{}
 95	err = json.Unmarshal(body, &jsonArray)
 96	if err != nil {
 97		logger.Error("Could not unmarshal JSON response for instances.")
 98		return err
 99	}
100
101	for i := range jsonArray {
102		instance := jsonArray[i][0].(string)
103		instanceTest := func(t Timeout) bool { return t.Instance == instance }
104		result := filter(c.timeouts, instanceTest)
105		if len(result) == 0 {
106			c.Instance = instance
107			logger.Info("Using new instance: ", c.Instance)
108			return nil
109		}
110	}
111
112	return fmt.Errorf("Cannot find a valid instance.")
113}