Simplify structure by moving routes into command package
This commit is contained in:
parent
f3f852fefd
commit
2630af4921
|
|
@ -1,4 +1,4 @@
|
||||||
package routes
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -8,43 +8,11 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/a-h/templ"
|
|
||||||
"github.com/go-chi/chi/v5"
|
|
||||||
"go.fifitido.net/ytdl-web/pkg/models"
|
|
||||||
"go.fifitido.net/ytdl-web/pkg/views"
|
"go.fifitido.net/ytdl-web/pkg/views"
|
||||||
"go.fifitido.net/ytdl-web/pkg/ytdl"
|
"go.fifitido.net/ytdl-web/pkg/ytdl"
|
||||||
"go.fifitido.net/ytdl-web/pkg/ytdl/metadata"
|
"go.fifitido.net/ytdl-web/pkg/ytdl/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Router() chi.Router {
|
|
||||||
r := chi.NewRouter()
|
|
||||||
r.Get("/", home)
|
|
||||||
r.Route("/download", func(r chi.Router) {
|
|
||||||
r.Get("/", download)
|
|
||||||
r.Head("/proxy", proxyDownload)
|
|
||||||
r.Get("/proxy", proxyDownload)
|
|
||||||
})
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
func renderPage(w http.ResponseWriter, r *http.Request, component templ.Component) {
|
|
||||||
isHtmx := r.Header.Get("HX-Request") == "true"
|
|
||||||
|
|
||||||
if isHtmx {
|
|
||||||
if err := templ.RenderFragments(r.Context(), w, component, "main-content"); err != nil {
|
|
||||||
slog.ErrorContext(r.Context(), "failed to render page", slog.Any("error", err))
|
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
component.Render(r.Context(), w)
|
|
||||||
}
|
|
||||||
|
|
||||||
func home(w http.ResponseWriter, r *http.Request) {
|
|
||||||
renderPage(w, r, views.Home(nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
func getUrlParam(r *http.Request) (string, bool) {
|
func getUrlParam(r *http.Request) (string, bool) {
|
||||||
urlRaw := r.URL.Query().Get("url")
|
urlRaw := r.URL.Query().Get("url")
|
||||||
if urlRaw == "" {
|
if urlRaw == "" {
|
||||||
|
|
@ -64,17 +32,17 @@ func download(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
videoUrl, ok := getUrlParam(r)
|
videoUrl, ok := getUrlParam(r)
|
||||||
if !ok {
|
if !ok {
|
||||||
renderPage(w, r, views.Home(&views.Error{Message: "Invalid URL"}))
|
views.Render(w, r, views.Home(&views.Error{Message: "Invalid URL"}))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
meta, err := ytdl.GetMetadata(videoUrl)
|
meta, err := ytdl.GetMetadata(videoUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
renderPage(w, r, views.Home(&views.Error{Message: "Could not find a video at that url", RetryUrl: &videoUrl}))
|
views.Render(w, r, views.Home(&views.Error{Message: "Could not find a video at that url", RetryUrl: &videoUrl}))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
renderPage(w, r, views.Downloads(&views.DownloadsViewModel{Url: videoUrl, Meta: meta}))
|
views.Render(w, r, views.Downloads(&views.DownloadsViewModel{Url: videoUrl, Meta: meta}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func proxyDownload(w http.ResponseWriter, r *http.Request) {
|
func proxyDownload(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
@ -97,7 +65,7 @@ func proxyDownload(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
videos := models.GetVideosFromMetadata(meta)
|
videos := views.GetVideosFromMetadata(meta)
|
||||||
|
|
||||||
index, err := strconv.Atoi(r.URL.Query().Get("index"))
|
index, err := strconv.Atoi(r.URL.Query().Get("index"))
|
||||||
if err != nil || index < 0 || index >= len(videos) {
|
if err != nil || index < 0 || index >= len(videos) {
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
|
"github.com/dgraph-io/badger/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type badgerLogger struct {
|
||||||
|
logger *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ badger.Logger = (*badgerLogger)(nil)
|
||||||
|
|
||||||
|
// Debugf implements badger.Logger
|
||||||
|
func (l *badgerLogger) Debugf(f string, a ...any) {
|
||||||
|
l.logger.Debug(fmt.Sprintf(f, a...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorf implements badger.Logger
|
||||||
|
func (l *badgerLogger) Errorf(f string, a ...any) {
|
||||||
|
l.logger.Error(fmt.Sprintf(f, a...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infof implements badger.Logger
|
||||||
|
func (l *badgerLogger) Infof(f string, a ...any) {
|
||||||
|
l.logger.Info(fmt.Sprintf(f, a...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warningf implements badger.Logger
|
||||||
|
func (l *badgerLogger) Warningf(f string, a ...any) {
|
||||||
|
l.logger.Warn(fmt.Sprintf(f, a...))
|
||||||
|
}
|
||||||
|
|
@ -15,9 +15,8 @@ import (
|
||||||
"github.com/go-chi/chi/v5/middleware"
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
slogchi "github.com/samber/slog-chi"
|
slogchi "github.com/samber/slog-chi"
|
||||||
"go.fifitido.net/ytdl-web/pkg/config"
|
"go.fifitido.net/ytdl-web/pkg/config"
|
||||||
"go.fifitido.net/ytdl-web/pkg/routes"
|
|
||||||
"go.fifitido.net/ytdl-web/pkg/serverctx"
|
"go.fifitido.net/ytdl-web/pkg/serverctx"
|
||||||
"go.fifitido.net/ytdl-web/pkg/utils"
|
"go.fifitido.net/ytdl-web/pkg/views"
|
||||||
"go.fifitido.net/ytdl-web/pkg/ytdl"
|
"go.fifitido.net/ytdl-web/pkg/ytdl"
|
||||||
"go.fifitido.net/ytdl-web/pkg/ytdl/cache"
|
"go.fifitido.net/ytdl-web/pkg/ytdl/cache"
|
||||||
)
|
)
|
||||||
|
|
@ -57,7 +56,7 @@ func main() {
|
||||||
db, err := badger.Open(
|
db, err := badger.Open(
|
||||||
badger.
|
badger.
|
||||||
DefaultOptions(cacheDir()).
|
DefaultOptions(cacheDir()).
|
||||||
WithLogger(utils.NewBadgerLogger(logger.With("module", "badger"))),
|
WithLogger(&badgerLogger{logger: logger.With("module", "badger")}),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|
@ -87,7 +86,14 @@ func main() {
|
||||||
middleware.Recoverer,
|
middleware.Recoverer,
|
||||||
)
|
)
|
||||||
|
|
||||||
r.Mount(basePath(), routes.Router())
|
r.Route(basePath(), func(r chi.Router) {
|
||||||
|
r.Get("/", views.Handler(views.Home(nil)))
|
||||||
|
r.Route("/download", func(r chi.Router) {
|
||||||
|
r.Get("/", download)
|
||||||
|
r.Head("/proxy", proxyDownload)
|
||||||
|
r.Get("/proxy", proxyDownload)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
logger.Info("Starting HTTP server", slog.String("listen", listenAddr()))
|
logger.Info("Starting HTTP server", slog.String("listen", listenAddr()))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
package models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"go.fifitido.net/ytdl-web/pkg/ytdl/metadata"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Video struct {
|
|
||||||
Meta *metadata.Metadata
|
|
||||||
Formats []metadata.Format
|
|
||||||
OtherFormats []metadata.Format
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetVideosFromMetadata(meta *metadata.Metadata) []Video {
|
|
||||||
if meta.IsPlaylist() {
|
|
||||||
videos := make([]Video, 0, len(meta.Entries))
|
|
||||||
|
|
||||||
for _, entry := range meta.Entries {
|
|
||||||
videos = append(videos, GetVideosFromMetadata(&entry)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return videos
|
|
||||||
}
|
|
||||||
|
|
||||||
formats := []metadata.Format{}
|
|
||||||
otherFormats := []metadata.Format{}
|
|
||||||
|
|
||||||
for _, format := range meta.Formats {
|
|
||||||
if format.ACodec != "none" && format.VCodec != "none" && format.Protocol != "m3u8_native" {
|
|
||||||
formats = append(formats, format)
|
|
||||||
} else {
|
|
||||||
otherFormats = append(otherFormats, format)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, j := 0, len(formats)-1; i < j; i, j = i+1, j-1 {
|
|
||||||
formats[i], formats[j] = formats[j], formats[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
return []Video{
|
|
||||||
{
|
|
||||||
Meta: meta,
|
|
||||||
Formats: formats,
|
|
||||||
OtherFormats: otherFormats,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
"github.com/dgraph-io/badger/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
type SlogLogger struct {
|
|
||||||
logger *slog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debugf implements badger.Logger
|
|
||||||
func (l *SlogLogger) Debugf(f string, a ...interface{}) {
|
|
||||||
l.logger.Debug(fmt.Sprintf(f, a...))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Errorf implements badger.Logger
|
|
||||||
func (l *SlogLogger) Errorf(f string, a ...interface{}) {
|
|
||||||
l.logger.Error(fmt.Sprintf(f, a...))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Infof implements badger.Logger
|
|
||||||
func (l *SlogLogger) Infof(f string, a ...interface{}) {
|
|
||||||
l.logger.Info(fmt.Sprintf(f, a...))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warningf implements badger.Logger
|
|
||||||
func (l *SlogLogger) Warningf(f string, a ...interface{}) {
|
|
||||||
l.logger.Warn(fmt.Sprintf(f, a...))
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ badger.Logger = (*SlogLogger)(nil)
|
|
||||||
|
|
||||||
func NewBadgerLogger(logger *slog.Logger) badger.Logger {
|
|
||||||
return &SlogLogger{
|
|
||||||
logger: logger,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
"log/slog"
|
|
||||||
)
|
|
||||||
|
|
||||||
type loggerWriter struct {
|
|
||||||
logger *slog.Logger
|
|
||||||
logLevel slog.Level
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lw *loggerWriter) Write(p []byte) (n int, err error) {
|
|
||||||
lw.logger.Log(context.Background(), lw.logLevel, string(p))
|
|
||||||
return len(p), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoggerWriter(logger *slog.Logger, level slog.Level) io.Writer {
|
|
||||||
return &loggerWriter{logger: logger, logLevel: level}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package views
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/a-h/templ"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Handler(component templ.Component) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
Render(w, r, component)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Render(w http.ResponseWriter, r *http.Request, component templ.Component) {
|
||||||
|
isHtmx := r.Header.Get("HX-Request") == "true"
|
||||||
|
|
||||||
|
if isHtmx {
|
||||||
|
if err := templ.RenderFragments(r.Context(), w, component, "main-content"); err != nil {
|
||||||
|
slog.ErrorContext(r.Context(), "failed to render page", slog.Any("error", err))
|
||||||
|
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
component.Render(r.Context(), w)
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue