diff --git a/cmd/ui/index.html.tmpl b/cmd/ui/index.html.tmpl new file mode 100644 index 0000000..0572b72 --- /dev/null +++ b/cmd/ui/index.html.tmpl @@ -0,0 +1,20 @@ + + +
+ +
+ +
+ {{ range .Series }} +
+ + {{ .Thumbnail }} +

{{ .Thumbnail }}

+
+
+ {{ end }} +
+ + + diff --git a/cmd/ui/main.go b/cmd/ui/main.go new file mode 100644 index 0000000..cd38877 --- /dev/null +++ b/cmd/ui/main.go @@ -0,0 +1,120 @@ +package main + +import ( + "context" + "embed" + _ "embed" + "flag" + "fmt" + "html/template" + "log" + "net" + "net/http" + "os" + "os/signal" + "path" + "strings" + "syscall" + + "ffmpeg.d/pkg/fs" +) + +//go:embed *.tmpl +var TMPL embed.FS + +func main() { + ctx, can := signal.NotifyContext(context.Background(), syscall.SIGINT) + defer can() + + if err := Run(ctx, os.Args[1:]); err != nil { + panic(err) + } +} + +func Run(ctx context.Context, args []string) error { + flags := flag.NewFlagSet(os.Args[0], flag.ContinueOnError) + d := flags.String("d", "./testdata/", "directory containing directories of (x.jpg,x.mp4)") + p := flags.Int("p", 8080, "port to listen on") + if err := flags.Parse(args); err != nil { + return err + } + + tmpl, err := template.ParseFS(TMPL, "*.tmpl") + if err != nil { + return err + } + + s := &http.Server{ + Addr: fmt.Sprintf(":%d", *p), + Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if strings.HasPrefix(r.URL.Path, "/media/") { + http.StripPrefix("/media/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + log.Println(r.URL.Path, "vs", *d) + http.FileServer(http.Dir(*d)).ServeHTTP(w, r) + })).ServeHTTP(w, r) + return + } + + type Series struct { + HREF string + Thumbnail string + } + + ds, err := fs.LsD(*d) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + seriesByKey := map[string]Series{} + for _, d := range ds { + files, err := fs.LsF(d) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + for _, f := range files { + key := strings.Split(path.Base(f), ".")[0] + v := seriesByKey[key] + switch path.Ext(f) { + case ".jpg": + v.Thumbnail = path.Join(path.Base(d), path.Base(f)) + case ".mp4": + v.HREF = path.Join(path.Base(d), path.Base(f)) + } + seriesByKey[key] = v + } + } + series := []Series{} + for _, v := range seriesByKey { + series = append(series, v) + } + + if err := tmpl.Execute(w, map[string]any{ + "Series": series, + }); err != nil { + log.Println(err, *d) + } + }), + BaseContext: func(net.Listener) context.Context { + return ctx + }, + } + defer s.Shutdown(ctx) + + errs := make(chan error) + go func() { + defer close(errs) + + errs <- s.ListenAndServe() + }() + + select { + case err := <-errs: + return err + case <-ctx.Done(): + s.Shutdown(ctx) + for range errs { + } + } + return nil +}