From 20a9e6d01af3e821b1c7ad74b610cc98cefcd256 Mon Sep 17 00:00:00 2001 From: Evan Fiordeliso Date: Mon, 24 Apr 2023 08:14:36 -0400 Subject: [PATCH] Move routes to a struct and add a HEAD handler for /download/proxy --- Taskfile.yml | 2 +- web/routes.go | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++ web/serve.go | 91 +----------------------------------------- ytdl/data.go | 8 ++-- ytdl/meta.go | 4 ++ 5 files changed, 118 insertions(+), 94 deletions(-) create mode 100644 web/routes.go diff --git a/Taskfile.yml b/Taskfile.yml index 4966db1..73ab96f 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -2,7 +2,7 @@ version: "3" vars: OUT: ./out/ytdl-web - VERSION: 1.0.2 + VERSION: 1.0.3 VERSION_PKG: go.fifitido.net/ytdl-web/version BUILD: sh: git rev-parse --short HEAD diff --git a/web/routes.go b/web/routes.go new file mode 100644 index 0000000..8a770a7 --- /dev/null +++ b/web/routes.go @@ -0,0 +1,107 @@ +package web + +import ( + "fmt" + "net/url" + + "github.com/gofiber/fiber/v2" + "github.com/samber/lo" + "github.com/spf13/viper" + "github.com/sujit-baniya/flash" + "go.fifitido.net/ytdl-web/version" + "go.fifitido.net/ytdl-web/ytdl" + "golang.org/x/exp/slog" +) + +type routes struct{} + +func (r *routes) Register(app *fiber.App) { + app.Get("/", r.IndexHandler) + app.Get("/download", r.DownloadHandler) + app.Head("/download/proxy", r.DownloadProxyHandler) + app.Get("/download/proxy", r.DownloadProxyHandler) +} + +func (r *routes) IndexHandler(c *fiber.Ctx) error { + return c.Render("views/index", fiber.Map{ + "BasePath": viper.GetString("base_path"), + "Flash": flash.Get(c), + "Version": version.Version, + "Build": version.Build, + "YtdlpVersion": ytdl.GetVersion(), + }, "views/layouts/main") +} + +func (r *routes) DownloadHandler(c *fiber.Ctx) error { + urlBytes, err := url.QueryUnescape(c.Query("url")) + if err != nil { + return flash.WithError(c, fiber.Map{ + "error": true, + "message": "Invalid URL", + }).Redirect("/") + } + url := string(urlBytes) + if len(url) < 1 { + return flash.WithError(c, fiber.Map{ + "error": true, + "message": "Invalid URL", + }).Redirect("/") + } + + meta, err := ytdl.GetMetadata(url) + if err != nil { + return flash.WithError(c, fiber.Map{ + "error": true, + "message": "Could not find a video at that url, maybe try again?", + }).Redirect("/") + } + + return c.Render("views/download", fiber.Map{ + "BasePath": viper.GetString("base_path"), + "Url": url, + "Meta": meta, + "Videos": GetVideos(meta), + "Version": version.Version, + "Build": version.Build, + "YtdlpVersion": ytdl.GetVersion(), + }, "views/layouts/main") +} + +func (r *routes) DownloadProxyHandler(c *fiber.Ctx) error { + urlBytes, err := url.QueryUnescape(c.Query("url")) + if err != nil { + slog.Error("Failed to decode url param", slog.String("error", err.Error())) + return fiber.ErrBadRequest + } + url := string(urlBytes) + if len(url) < 1 { + return fiber.ErrBadRequest + } + + formatId := c.Query("format") + if len(formatId) < 1 { + return fiber.ErrBadRequest + } + + meta, err := ytdl.GetMetadata(url) + if err != nil { + slog.Error("Failed to get metadata", slog.String("error", err.Error())) + return fiber.ErrInternalServerError + } + + format, ok := lo.Find(meta.Formats, func(format ytdl.Format) bool { + return format.FormatID == formatId + }) + if !ok { + return fiber.ErrBadRequest + } + + c.Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s-%s.%s\"", meta.ID, format.Resolution, format.Ext)) + if format.Filesize != nil { + c.Set("Content-Length", fmt.Sprint(*format.Filesize)) + } else if format.FilesizeApprox != nil { + c.Set("Content-Length", fmt.Sprint(*format.FilesizeApprox)) + } + + return ytdl.Stream(c.Response().BodyWriter(), url, format) +} diff --git a/web/serve.go b/web/serve.go index f1a327d..ffe18f3 100644 --- a/web/serve.go +++ b/web/serve.go @@ -2,104 +2,17 @@ package web import ( "fmt" - "net/url" "github.com/gofiber/fiber/v2" - "github.com/samber/lo" "github.com/spf13/viper" - "github.com/sujit-baniya/flash" - "go.fifitido.net/ytdl-web/version" - "go.fifitido.net/ytdl-web/ytdl" - "golang.org/x/exp/slog" ) func Serve() error { engine := ViewsEngine() app := fiber.New(fiber.Config{Views: engine}) + routes := &routes{} - app.Get("/", func(c *fiber.Ctx) error { - return c.Render("views/index", fiber.Map{ - "BasePath": viper.GetString("base_path"), - "Flash": flash.Get(c), - "Version": version.Version, - "Build": version.Build, - "YtdlpVersion": ytdl.GetVersion(), - }, "views/layouts/main") - }) - - app.Get("/download", func(c *fiber.Ctx) error { - urlBytes, err := url.QueryUnescape(c.Query("url")) - if err != nil { - return flash.WithError(c, fiber.Map{ - "error": true, - "message": "Invalid URL", - }).Redirect("/") - } - url := string(urlBytes) - if len(url) < 1 { - return flash.WithError(c, fiber.Map{ - "error": true, - "message": "Invalid URL", - }).Redirect("/") - } - - meta, err := ytdl.GetMetadata(url) - if err != nil { - return flash.WithError(c, fiber.Map{ - "error": true, - "message": "Could not find a video at that url, maybe try again?", - }).Redirect("/") - } - - return c.Render("views/download", fiber.Map{ - "BasePath": viper.GetString("base_path"), - "Url": url, - "Meta": meta, - "Videos": GetVideos(meta), - "Version": version.Version, - "Build": version.Build, - "YtdlpVersion": ytdl.GetVersion(), - }, "views/layouts/main") - }) - - app.Get("/download/proxy", func(c *fiber.Ctx) error { - urlBytes, err := url.QueryUnescape(c.Query("url")) - if err != nil { - slog.Error("Failed to decode url param", slog.String("error", err.Error())) - return fiber.ErrBadRequest - } - url := string(urlBytes) - if len(url) < 1 { - return fiber.ErrBadRequest - } - - formatId := c.Query("format") - if len(formatId) < 1 { - return fiber.ErrBadRequest - } - - meta, err := ytdl.GetMetadata(url) - if err != nil { - slog.Error("Failed to get metadata", slog.String("error", err.Error())) - return fiber.ErrInternalServerError - } - - format, ok := lo.Find(meta.Formats, func(format ytdl.Format) bool { - return format.FormatID == formatId - }) - if !ok { - return fiber.ErrBadRequest - } - - c.Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s-%s.%s\"", meta.ID, format.Resolution, format.Ext)) - if format.Filesize != nil { - c.Set("Content-Length", fmt.Sprint(*format.Filesize)) - } else if format.FilesizeApprox != nil { - c.Set("Content-Length", fmt.Sprint(*format.FilesizeApprox)) - } - - return ytdl.Stream(c.Response().BodyWriter(), url, format) - }) + routes.Register(app) listenAddr := fmt.Sprintf("%s:%d", viper.GetString("listen"), viper.GetInt("port")) diff --git a/ytdl/data.go b/ytdl/data.go index 5dfa2f4..05c6775 100644 --- a/ytdl/data.go +++ b/ytdl/data.go @@ -168,11 +168,11 @@ type Metadata struct { // Time in seconds where the reproduction should start, as // specified in the URL. - StartTime *int64 `json:"start_time"` + StartTime *float64 `json:"start_time"` // Time in seconds where the reproduction should end, as // specified in the URL. - EndTime *int64 `json:"end_time"` + EndTime *float64 `json:"end_time"` Chapters []Chapter `json:"chapters"` } @@ -437,10 +437,10 @@ type Comment struct { type Chapter struct { // The start time of the chapter in seconds - StartTime int64 `json:"start_time"` + StartTime float64 `json:"start_time"` // The end time of the chapter in seconds - EndTime int64 `json:"end_time"` + EndTime float64 `json:"end_time"` Title *string `json:"title"` } diff --git a/ytdl/meta.go b/ytdl/meta.go index aeec6f3..81538d5 100644 --- a/ytdl/meta.go +++ b/ytdl/meta.go @@ -3,6 +3,7 @@ package ytdl import ( "bytes" "encoding/json" + "fmt" "os/exec" "github.com/spf13/viper" @@ -20,11 +21,14 @@ func GetMetadata(url string) (Metadata, error) { cmd.Stdout = &out if err := cmd.Run(); err != nil { + + fmt.Printf("%+v\n", err) return Metadata{}, err } var meta Metadata if err := json.Unmarshal(out.Bytes(), &meta); err != nil { + fmt.Printf("%+v\n", err) return Metadata{}, err }