Move routes to a struct and add a HEAD handler for /download/proxy
This commit is contained in:
		
							parent
							
								
									dba5305302
								
							
						
					
					
						commit
						20a9e6d01a
					
				| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										91
									
								
								web/serve.go
								
								
								
								
							
							
						
						
									
										91
									
								
								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"))
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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"`
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue