From 4b99efde96aef5c6dca610641af7bec03da2faa2 Mon Sep 17 00:00:00 2001 From: Dakota Walsh Date: Wed, 22 Mar 2023 17:27:31 +1300 Subject: [PATCH] add video player --- artist.go | 61 ------------ helpers.go | 6 +- home.go | 40 -------- main.go | 5 - routes.go | 169 ++++++++++++++++++++++++++++++++- templates.go | 6 +- {html => ui}/base.tmpl | 3 - {html => ui}/pages/artist.tmpl | 3 + {html => ui}/pages/home.tmpl | 3 + ui/pages/video.tmpl | 37 ++++++++ 10 files changed, 218 insertions(+), 115 deletions(-) delete mode 100644 artist.go delete mode 100644 home.go rename {html => ui}/base.tmpl (90%) rename {html => ui}/pages/artist.tmpl (96%) rename {html => ui}/pages/home.tmpl (95%) create mode 100644 ui/pages/video.tmpl diff --git a/artist.go b/artist.go deleted file mode 100644 index 5d4e825..0000000 --- a/artist.go +++ /dev/null @@ -1,61 +0,0 @@ -package main - -import ( - "fmt" - "net/http" - "os" - "path/filepath" - "strings" -) - -func (app *application) artist(w http.ResponseWriter, r *http.Request) { - path := filepath.Join(app.dir, filepath.Clean(r.URL.Path)) - info, err := os.Stat(path) - if err != nil { - app.errLog.Println(err) - http.NotFound(w, r) - return - } - fmt.Println("STATED", path) - if !info.IsDir() { - f, err := os.Open(path) - if err != nil { - app.errLog.Println(err) - http.NotFound(w, r) - return - } - http.ServeContent(w, r, path, info.ModTime(), f) - return - } - - artist := strings.TrimPrefix(path, filepath.Clean(app.dir)+"/") - entries, err := ListDir(path) - if err != nil { - app.errLog.Println(err) - http.NotFound(w, r) - return - } - - tsName := "artist.tmpl" - ts, ok := app.templateCache[tsName] - if !ok { - app.errLog.Println(fmt.Errorf( - "the template %s is missing", - tsName, - )) - http.NotFound(w, r) - return - } - err = ts.ExecuteTemplate(w, "base", ArtistPage{ - Artist: artist, - Entries: entries, - }) - if err != nil { - app.errLog.Println(err) - http.Error( - w, - http.StatusText(http.StatusInternalServerError), - http.StatusInternalServerError, - ) - } -} diff --git a/helpers.go b/helpers.go index 7afb5db..4ca5cc1 100644 --- a/helpers.go +++ b/helpers.go @@ -5,6 +5,7 @@ import ( "io" "os" "path/filepath" + "strings" "time" ) @@ -15,7 +16,7 @@ type DirEntry struct { Time string } -func ListDir(path string) ([]DirEntry, error) { +func ListVideos(path string) ([]DirEntry, error) { dirEntries, err := os.ReadDir(path) if err != nil { return nil, err @@ -24,6 +25,9 @@ func ListDir(path string) ([]DirEntry, error) { var entries []DirEntry for _, e := range dirEntries { name := e.Name() + if !strings.HasSuffix(name, ".mp4") { + continue + } if len(name) > 28 { name = name[:25] + "..." } diff --git a/home.go b/home.go deleted file mode 100644 index 4f183d7..0000000 --- a/home.go +++ /dev/null @@ -1,40 +0,0 @@ -package main - -import ( - "fmt" - "net/http" - "path/filepath" -) - -func (app *application) home(w http.ResponseWriter, r *http.Request) { - released, err := Released(filepath.Join(app.dir, "released.txt")) - if err != nil { - app.errLog.Println(err) - http.Error( - w, - http.StatusText(http.StatusInternalServerError), - http.StatusInternalServerError, - ) - return - } - - tsName := "home.tmpl" - ts, ok := app.templateCache[tsName] - if !ok { - app.errLog.Println(fmt.Errorf( - "the template %s is missing", - tsName, - )) - http.NotFound(w, r) - return - } - err = ts.ExecuteTemplate(w, "base", released) - if err != nil { - app.errLog.Println(err) - http.Error( - w, - http.StatusText(http.StatusInternalServerError), - http.StatusInternalServerError, - ) - } -} diff --git a/main.go b/main.go index 34061d4..e60e516 100644 --- a/main.go +++ b/main.go @@ -16,11 +16,6 @@ type application struct { errLog *log.Logger } -type ArtistPage struct { - Artist string - Entries []DirEntry -} - func main() { addr := flag.String("addr", ":4000", "HTTP network address") content := flag.String("path", "/var/www", "Path to serve") diff --git a/routes.go b/routes.go index 38a4cc7..1e35f7c 100644 --- a/routes.go +++ b/routes.go @@ -1,7 +1,11 @@ package main import ( + "fmt" "net/http" + "os" + "path/filepath" + "strings" "github.com/julienschmidt/httprouter" ) @@ -9,8 +13,169 @@ import ( func (app *application) routes() http.Handler { router := httprouter.New() router.HandlerFunc(http.MethodGet, "/", app.home) - router.HandlerFunc(http.MethodGet, "/:artist", app.artist) - router.HandlerFunc(http.MethodGet, "/:artist/:file", app.artist) + router.HandlerFunc(http.MethodGet, "/:path", app.path) + router.HandlerFunc(http.MethodGet, "/:path/:subpath", app.path) return app.logRequest(router) } + +// home is an http.HandlerFunc which displays the home page. +// The home page is a list of all "released" videos, which are loaded on each +// request from "released.txt". +func (app *application) home(w http.ResponseWriter, r *http.Request) { + released, err := Released(filepath.Join(app.dir, "released.txt")) + if err != nil { + app.errLog.Println(err) + http.Error( + w, + http.StatusText(http.StatusInternalServerError), + http.StatusInternalServerError, + ) + return + } + + tsName := "home.tmpl" + ts, ok := app.templateCache[tsName] + if !ok { + app.errLog.Println(fmt.Errorf( + "the template %s is missing", + tsName, + )) + http.NotFound(w, r) + return + } + err = ts.ExecuteTemplate(w, "base", released) + if err != nil { + app.errLog.Println(err) + http.Error( + w, + http.StatusText(http.StatusInternalServerError), + http.StatusInternalServerError, + ) + } +} + +// path is an http.HandlerFunc which passes the request to either artist, +// video, or file depending on if the request is for a file, video file, or +// directory. +func (app *application) path(w http.ResponseWriter, r *http.Request) { + path := filepath.Join(app.dir, filepath.Clean(r.URL.Path)) + info, err := os.Stat(path) + if err != nil { + app.errLog.Println(err) + http.NotFound(w, r) + return + } + if !info.IsDir() { + q := r.URL.Query() + _, direct := q["direct"] + if strings.HasSuffix(path, ".mp4") && !direct { + app.video(w, r) + return + } + app.file(w, r) + return + } + + app.artist(w, r) +} + +// ArtistPage is the datastructure used in the artist handler for the artist +// template. +type ArtistPage struct { + Artist string + Entries []DirEntry +} + +// artist is an http.HandlerFunc which displays a page for the requested artist. +// The artist's page is a listing of all their videos, including unreleased +// videos. +func (app *application) artist(w http.ResponseWriter, r *http.Request) { + path := filepath.Join(app.dir, filepath.Clean(r.URL.Path)) + artist := strings.TrimPrefix(path, filepath.Clean(app.dir)+"/") + entries, err := ListVideos(path) + if err != nil { + app.errLog.Println(err) + http.NotFound(w, r) + return + } + + tsName := "artist.tmpl" + ts, ok := app.templateCache[tsName] + if !ok { + app.errLog.Println(fmt.Errorf( + "the template %s is missing", + tsName, + )) + http.NotFound(w, r) + return + } + err = ts.ExecuteTemplate(w, "base", ArtistPage{ + Artist: artist, + Entries: entries, + }) + if err != nil { + app.errLog.Println(err) + http.Error( + w, + http.StatusText(http.StatusInternalServerError), + http.StatusInternalServerError, + ) + } +} + +// file is an http.HandlerFunc for files. +func (app *application) file(w http.ResponseWriter, r *http.Request) { + path := filepath.Join(app.dir, filepath.Clean(r.URL.Path)) + info, err := os.Stat(path) + if err != nil { + app.errLog.Println(err) + http.NotFound(w, r) + return + } + f, err := os.Open(path) + if err != nil { + app.errLog.Println(err) + http.NotFound(w, r) + return + } + http.ServeContent(w, r, path, info.ModTime(), f) + return +} + +// VideoPage is the datastructure used in the video handler for the video +// template. +type VideoPage struct { + Artist string + Video string +} + +// video is an http.HandlerFunc for videos. +// The video is displayed in browser with a helpful player and download link. +func (app *application) video(w http.ResponseWriter, r *http.Request) { + tsName := "video.tmpl" + ts, ok := app.templateCache[tsName] + if !ok { + app.errLog.Println(fmt.Errorf( + "the template %s is missing", + tsName, + )) + http.NotFound(w, r) + return + } + err := ts.ExecuteTemplate(w, "base", VideoPage{ + Artist: strings.TrimPrefix( + filepath.Dir(filepath.Clean(r.URL.Path)), + "/", + ), + Video: filepath.Clean(r.URL.Path), + }) + if err != nil { + app.errLog.Println(err) + http.Error( + w, + http.StatusText(http.StatusInternalServerError), + http.StatusInternalServerError, + ) + } +} diff --git a/templates.go b/templates.go index c5eb39c..6f5c031 100644 --- a/templates.go +++ b/templates.go @@ -7,13 +7,13 @@ import ( "text/template" ) -//go:embed "html" +//go:embed "ui" var EmbededFiles embed.FS func newTemplateCache() (map[string]*template.Template, error) { cache := map[string]*template.Template{} - pages, err := fs.Glob(EmbededFiles, "html/pages/*.tmpl") + pages, err := fs.Glob(EmbededFiles, "ui/pages/*.tmpl") if err != nil { return nil, err } @@ -21,7 +21,7 @@ func newTemplateCache() (map[string]*template.Template, error) { for _, page := range pages { name := filepath.Base(page) files := []string{ - "html/base.tmpl", + "ui/base.tmpl", page, } diff --git a/html/base.tmpl b/ui/base.tmpl similarity index 90% rename from html/base.tmpl rename to ui/base.tmpl index df5c449..a9b03e0 100644 --- a/html/base.tmpl +++ b/ui/base.tmpl @@ -6,9 +6,6 @@ evids - - {{template "main" .}} - {{end}} diff --git a/html/pages/artist.tmpl b/ui/pages/artist.tmpl similarity index 96% rename from html/pages/artist.tmpl rename to ui/pages/artist.tmpl index 7cf0359..670d877 100644 --- a/html/pages/artist.tmpl +++ b/ui/pages/artist.tmpl @@ -1,4 +1,6 @@ {{define "main"}} + +
{{end}} + {{end}} diff --git a/html/pages/home.tmpl b/ui/pages/home.tmpl similarity index 95% rename from html/pages/home.tmpl rename to ui/pages/home.tmpl index 97e0b63..d7e1d41 100644 --- a/html/pages/home.tmpl +++ b/ui/pages/home.tmpl @@ -1,4 +1,6 @@ {{define "main"}} + +
{{end}} + {{end}} diff --git a/ui/pages/video.tmpl b/ui/pages/video.tmpl new file mode 100644 index 0000000..e266726 --- /dev/null +++ b/ui/pages/video.tmpl @@ -0,0 +1,37 @@ +{{define "main"}} + +
+ + EVIDS + + {{ if .Artist }} + + {{.Artist}} + + {{ end }} +
+
+ + + DOWNLOAD + +
+ +{{end}} -- 2.45.2