invidious/proxy.go (view raw)
1package invidious
2
3import (
4 "bytes"
5 "io"
6 "net/http"
7 "time"
8
9 "github.com/birabittoh/rabbitpipe"
10)
11
12const MaxSizeBytes = int64(20 * 1024 * 1024)
13
14func urlToBuffer(url string) (*VideoBuffer, int) {
15 if url == "" {
16 return nil, http.StatusBadRequest
17 }
18
19 req, err := http.NewRequest(http.MethodGet, url, nil)
20 if err != nil {
21 logger.Error(err) // bad request
22 return nil, http.StatusInternalServerError
23 }
24
25 resp, err := http.DefaultClient.Do(req)
26 if err != nil {
27 logger.Error(err) // request failed
28 return nil, http.StatusGone
29 }
30
31 if resp.StatusCode != http.StatusOK {
32 return nil, resp.StatusCode
33 }
34
35 if resp.ContentLength == 0 {
36 return nil, http.StatusNoContent
37 }
38
39 if resp.ContentLength > MaxSizeBytes {
40 logger.Debug("Content-Length exceeds max size.")
41 return nil, http.StatusBadRequest
42 }
43 defer resp.Body.Close()
44
45 b := new(bytes.Buffer)
46 l, _ := io.Copy(b, resp.Body)
47 if l != resp.ContentLength {
48 logger.Debug("Content-Length is inconsistent.")
49 return nil, http.StatusBadRequest
50 }
51
52 return &VideoBuffer{b, l}, http.StatusOK
53}
54
55func getBuffer(video rabbitpipe.Video) (*VideoBuffer, int) {
56 vb, err := buffers.Get(video.VideoID)
57 if err != nil {
58 // cached buffer not found
59 vb, s := urlToBuffer(GetVideoURL(video))
60 if vb != nil {
61 if s == http.StatusOK && vb.Length > 0 {
62 buffers.Set(video.VideoID, *vb.Clone(), 5*time.Minute)
63 return vb, s
64 }
65 }
66 return nil, s
67 }
68
69 // cached buffer found
70 return vb.Clone(), http.StatusOK
71}
72
73func ProxyVideoId(videoID string) (*VideoBuffer, int) {
74 video, err := RP.GetVideo(videoID)
75 if err != nil {
76 logger.Info("Cannot get video: https://youtu.be/", videoID)
77 return nil, http.StatusBadRequest
78 }
79 return getBuffer(*video)
80}