all repos — fixyoutube-go @ 4bab611266395d2ba4e664ebf8fd2bec3467c99b

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

major proxy code cleanup
Marco Andronaco andronacomarco@gmail.com
Fri, 12 Jan 2024 15:27:27 +0100
commit

4bab611266395d2ba4e664ebf8fd2bec3467c99b

parent

2e2bbcb2dcdeba398ad0be06a90f662ed3a12796

2 files changed, 49 insertions(+), 34 deletions(-)

jump to
M fixyoutube.gofixyoutube.go

@@ -3,6 +3,7 @@

import ( "bytes" "html/template" + "io" "net/http" "net/url" "os"

@@ -136,15 +137,43 @@ return func(w http.ResponseWriter, r *http.Request) {

vars := mux.Vars(r) videoId := vars["videoId"] formatIndex := parseFormatIndex(vars["formatIndex"]) - httpStatus := invidiousClient.ProxyVideo(w, r, videoId, formatIndex) - if httpStatus != http.StatusOK { - logger.Error("c.ProxyVideo() failed. Code: ", httpStatus) - http.Error(w, "Something went wrong.", httpStatus) + + video, err := invidious.GetVideoDB(videoId) + if err != nil { + logger.Warn("Cannot proxy a video that is not cached: https://youtu.be/", videoId) + http.Error(w, "Something went wrong.", http.StatusBadRequest) + return } + + fmtAmount := len(video.Formats) + idx := formatIndex % fmtAmount + + var httpStatus = http.StatusNotFound + + for i := fmtAmount - 1 - idx; i >= 0; i-- { + url := video.Formats[i].Url + b, l, httpStatus := invidiousClient.ProxyVideo(url, formatIndex) + switch httpStatus { + case http.StatusOK: + header := w.Header() + header.Set("Status", "200") + header.Set("Content-Type", "video/mp4") + header.Set("Content-Length", strconv.FormatInt(l, 10)) + io.Copy(w, b) + return + case http.StatusBadRequest: + continue + default: + i = -1 + } + } + logger.Error("proxyHandler() failed. Code: ", httpStatus) + http.Error(w, "Something went wrong.", httpStatus) } } func main() { + logger.SetLevel(logrus.DebugLevel) err := godotenv.Load() if err != nil { logger.Info("No .env file provided.")
M invidious/invidious.goinvidious/invidious.go

@@ -1,6 +1,7 @@

package invidious import ( + "bytes" "encoding/json" "fmt" "io"

@@ -221,48 +222,33 @@ logger.Error("Cannot find a valid instance.")

return err } -func (c *Client) ProxyVideo(w http.ResponseWriter, r *http.Request, videoId string, formatIndex int) int { - video, err := GetVideoDB(videoId) - if err != nil { - logger.Warn("Cannot proxy a video that is not cached: https://youtu.be/", videoId) - return http.StatusBadRequest - } +func (c *Client) ProxyVideo(url string, formatIndex int) (*bytes.Buffer, int64, int) { - fmtAmount := len(video.Formats) - idx := formatIndex % fmtAmount - url := video.Formats[fmtAmount-1-idx].Url req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { - logger.Error(err) - new_video, err := c.GetVideo(videoId, false) - if err != nil { - logger.Error("Cannot get new data for video ", videoId, ":", err) - return http.StatusInternalServerError - } - return c.ProxyVideo(w, r, new_video.VideoId, formatIndex) + logger.Error(err) // bad request + return nil, 0, http.StatusInternalServerError } - resp, err := c.http.Do(req) // send video request + resp, err := c.http.Do(req) if err != nil { - logger.Error(err) - return http.StatusInternalServerError + logger.Error(err) // request failed + return nil, 0, http.StatusGone } if resp.ContentLength > maxSizeBytes { - newIndex := formatIndex + 1 - if newIndex < fmtAmount { - logger.Debug("Format ", newIndex, ": Content-Length exceeds max size. Trying another format.") - return c.ProxyVideo(w, r, videoId, newIndex) - } - logger.Error("Could not find a suitable format.") - return http.StatusBadRequest + logger.Debug("Format ", formatIndex, ": Content-Length exceeds max size.") + return nil, 0, http.StatusBadRequest } defer resp.Body.Close() - w.Header().Set("Content-Type", "video/mp4") - w.Header().Set("Status", "200") - _, err = io.Copy(w, resp.Body) - return http.StatusOK + b := new(bytes.Buffer) + l, err := io.Copy(b, resp.Body) + if l != resp.ContentLength { + return nil, 0, http.StatusBadRequest + } + + return b, l, http.StatusOK } func NewClient(httpClient *http.Client) *Client {