From 59230b7ad5a00c081558cdce5c66d8d3236b8cac Mon Sep 17 00:00:00 2001 From: ari melody Date: Sun, 8 Jun 2025 21:15:39 +0100 Subject: [PATCH] use go html templates --- README.md | 2 +- main.go | 129 ++++++++++++++++++--------------------------- templates/dir.html | 91 ++++++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+), 80 deletions(-) create mode 100644 templates/dir.html diff --git a/README.md b/README.md index a4ccf75..2f25adc 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,6 @@ indir [--host address] [--port port] [--root http_root] directory ``` ## to-do: -- [ ] use templates instead of hard-coded HTML (i was lazy) +- [x] use templates instead of hard-coded HTML (i was lazy) - [ ] directory header from readme file - [ ] directory stylesheet overrides diff --git a/main.go b/main.go index c9673a5..60bb278 100755 --- a/main.go +++ b/main.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "html/template" "io/fs" "mime" "net/http" @@ -13,6 +14,22 @@ import ( "time" ) +type ( + Directory struct { + Name string + Root bool + Files []*File + } + + File struct { + Name string + URI string + IsDir bool + Size string + ModifiedDate string + } +) + func main() { if len(os.Args) < 2 { printHelp() } @@ -72,47 +89,12 @@ func main() { ".DS_Store", } - stylesheet := ` - html { - background: #101010; - color: #f0f0f0; - font-family: 'Monaspace Argon', monospace; + dirTemplate, err := template.ParseGlob("./templates/dir.html") + if err != nil { + fmt.Fprintf(os.Stderr, "fatal: failed to parse directory template: %v\n", err) + os.Exit(1) } - body { - width: min(calc(100% - 1em), 1000px); - margin: 0 auto; - } - - table { - width: 100%; - border-collapse: collapse; - } - - tr:hover { - background-color: #80808040; - } - - th { - text-align: left; - } - - td { - padding: .2em 0; - } - - a { - color: #b7fd49; - } - a:hover { - color: white; - } - - footer { - padding: 1em 0; - } - ` - fmt.Printf("Now hosting \"%s\" at http://%s:%d", filesDir, host, port) if root != "/" { fmt.Printf("%s", root) } fmt.Println(".") @@ -124,25 +106,6 @@ func main() { } isRoot := r.URL.Path == root - responseText := fmt.Sprintf(` - - - Listing %s - - - - -
- `, r.URL.Path, stylesheet) - - responseText += fmt.Sprintf("

Files in %s

\n
", r.URL.Path) - - responseText += "\n" - responseText += "\n\n\n\n\n" - if !isRoot { - responseText += "\n" - } - filepath := path.Join(filesDir, strings.TrimPrefix(r.URL.Path, root)) info, err := os.Stat(filepath) if err != nil { @@ -150,13 +113,13 @@ func main() { return } - if !info.IsDir() && strings.HasSuffix(r.URL.Path, "/") { - http.Redirect(w, r, strings.TrimSuffix(r.URL.Path, "/"), http.StatusFound) - } else if info.IsDir() && !strings.HasSuffix(r.URL.Path, "/") { - http.Redirect(w, r, r.URL.Path + "/", http.StatusFound) - } - + // downloading file if !info.IsDir() { + if strings.HasSuffix(r.URL.Path, "/") { + http.Redirect(w, r, strings.TrimSuffix(r.URL.Path, "/"), http.StatusFound) + return + } + file, err := os.Open(filepath) if err != nil { http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) @@ -186,6 +149,17 @@ func main() { return } + if !strings.HasSuffix(r.URL.Path, "/") { + http.Redirect(w, r, r.URL.Path + "/", http.StatusFound) + return + } + + data := Directory{ + Root: isRoot, + Name: r.URL.Path, + Files: []*File{}, + } + fsDir := os.DirFS(filepath) directories, err := fs.ReadDir(fsDir, ".") for _, dir := range directories { @@ -202,9 +176,7 @@ func main() { uri = r.URL.Path + name } - responseText += fmt.Sprintf( - "", uri, name) - + sizeStr := "—" if !info.IsDir() { size := info.Size() sizeDenom := "B" @@ -220,28 +192,27 @@ func main() { size /= 1000 sizeDenom = "GB" } - responseText += fmt.Sprintf("", info.Size(), size, sizeDenom) - } else { - responseText += "" + sizeStr = fmt.Sprintf("%d%s", size, sizeDenom) } dateStr := info.ModTime().Format("02-Jan-2006 15:04") - responseText += fmt.Sprintf("", dateStr) - responseText += "\n" + data.Files = append(data.Files, &File{ + Name: name, + URI: uri, + IsDir: info.IsDir(), + Size: sizeStr, + ModifiedDate: dateStr, + }) } if err != nil { fmt.Fprintf(os.Stderr, "failed to open directory: %v\n", err) } - responseText += "
NameSizeModified
../
%s%d%s%s
\n" - - responseText += "
\n
\n" - responseText += "\n" - responseText += "\n\n" w.Header().Set("Content-Type", "text/html") - w.WriteHeader(200) - w.Write([]byte(responseText)) + w.Header().Set("Server", "indir") + w.WriteHeader(http.StatusOK) + dirTemplate.Execute(w, data) }))) } diff --git a/templates/dir.html b/templates/dir.html new file mode 100644 index 0000000..7d0ac2b --- /dev/null +++ b/templates/dir.html @@ -0,0 +1,91 @@ + + + + + + Files in {{.Name}} + + + +
+

Files in {{.Name}}

+
+ + + + + + + {{if not .Root}} + + + + + + {{end}} + {{range .Files}} + + + + + + {{end}} +
NameSizeModified
../
{{.Name}}{{if .IsDir}}—{{else}}{{.Size}}{{end}}{{.ModifiedDate}}
+
+
+ + +