Move routes to a struct and add a HEAD handler for /download/proxy

This commit is contained in:
Evan Fiordeliso 2023-04-24 08:14:36 -04:00
parent dba5305302
commit 20a9e6d01a
5 changed files with 118 additions and 94 deletions

View File

@ -2,7 +2,7 @@ version: "3"
vars: vars:
OUT: ./out/ytdl-web OUT: ./out/ytdl-web
VERSION: 1.0.2 VERSION: 1.0.3
VERSION_PKG: go.fifitido.net/ytdl-web/version VERSION_PKG: go.fifitido.net/ytdl-web/version
BUILD: BUILD:
sh: git rev-parse --short HEAD sh: git rev-parse --short HEAD

107
web/routes.go Normal file
View File

@ -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)
}

View File

@ -2,104 +2,17 @@ package web
import ( import (
"fmt" "fmt"
"net/url"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"github.com/samber/lo"
"github.com/spf13/viper" "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 { func Serve() error {
engine := ViewsEngine() engine := ViewsEngine()
app := fiber.New(fiber.Config{Views: engine}) app := fiber.New(fiber.Config{Views: engine})
routes := &routes{}
app.Get("/", func(c *fiber.Ctx) error { routes.Register(app)
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)
})
listenAddr := fmt.Sprintf("%s:%d", viper.GetString("listen"), viper.GetInt("port")) listenAddr := fmt.Sprintf("%s:%d", viper.GetString("listen"), viper.GetInt("port"))

View File

@ -168,11 +168,11 @@ type Metadata struct {
// Time in seconds where the reproduction should start, as // Time in seconds where the reproduction should start, as
// specified in the URL. // specified in the URL.
StartTime *int64 `json:"start_time"` StartTime *float64 `json:"start_time"`
// Time in seconds where the reproduction should end, as // Time in seconds where the reproduction should end, as
// specified in the URL. // specified in the URL.
EndTime *int64 `json:"end_time"` EndTime *float64 `json:"end_time"`
Chapters []Chapter `json:"chapters"` Chapters []Chapter `json:"chapters"`
} }
@ -437,10 +437,10 @@ type Comment struct {
type Chapter struct { type Chapter struct {
// The start time of the chapter in seconds // 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 // The end time of the chapter in seconds
EndTime int64 `json:"end_time"` EndTime float64 `json:"end_time"`
Title *string `json:"title"` Title *string `json:"title"`
} }

View File

@ -3,6 +3,7 @@ package ytdl
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt"
"os/exec" "os/exec"
"github.com/spf13/viper" "github.com/spf13/viper"
@ -20,11 +21,14 @@ func GetMetadata(url string) (Metadata, error) {
cmd.Stdout = &out cmd.Stdout = &out
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
fmt.Printf("%+v\n", err)
return Metadata{}, err return Metadata{}, err
} }
var meta Metadata var meta Metadata
if err := json.Unmarshal(out.Bytes(), &meta); err != nil { if err := json.Unmarshal(out.Bytes(), &meta); err != nil {
fmt.Printf("%+v\n", err)
return Metadata{}, err return Metadata{}, err
} }