diff --git a/cmd/errors.go b/cmd/errors.go
index 0e240bf..4bf4477 100644
--- a/cmd/errors.go
+++ b/cmd/errors.go
@@ -9,7 +9,6 @@ import (
"fmt"
"io"
"net/http"
- "strings"
"time"
"github.com/yosssi/gohtml"
@@ -25,21 +24,17 @@ var (
ErrNoMediaFound = errors.New("no supported media formats found which match all criteria")
)
-func newErrorPage(title, body string) string {
- var htmlBody strings.Builder
-
- htmlBody.WriteString(`
`)
- htmlBody.WriteString(faviconHtml)
- htmlBody.WriteString(``)
- htmlBody.WriteString(fmt.Sprintf("%s", title))
- htmlBody.WriteString(fmt.Sprintf("%s", body))
-
- return htmlBody.String()
-}
-
func notFound(w http.ResponseWriter, r *http.Request, path string) error {
startTime := time.Now()
+ w.WriteHeader(http.StatusNotFound)
+ w.Header().Add("Content-Type", "text/html")
+
+ _, err := io.WriteString(w, gohtml.Format(newPage("Not Found", "404 Page not found")))
+ if err != nil {
+ return err
+ }
+
if Verbose {
fmt.Printf("%s | ERROR: Unavailable file %s requested by %s\n",
startTime.Format(logDate),
@@ -48,20 +43,16 @@ func notFound(w http.ResponseWriter, r *http.Request, path string) error {
)
}
- w.WriteHeader(http.StatusNotFound)
- w.Header().Add("Content-Type", "text/html")
-
- _, err := io.WriteString(w, gohtml.Format(newErrorPage("Not Found", "404 Page not found")))
- if err != nil {
- return err
- }
-
return nil
}
func serverError(w http.ResponseWriter, r *http.Request, i interface{}) {
startTime := time.Now()
+ w.Header().Add("Content-Type", "text/html")
+
+ io.WriteString(w, gohtml.Format(newPage("Server Error", "An error has occurred. Please try again.")))
+
if Verbose {
fmt.Printf("%s | ERROR: Invalid request for %s from %s\n",
startTime.Format(logDate),
@@ -69,10 +60,6 @@ func serverError(w http.ResponseWriter, r *http.Request, i interface{}) {
r.RemoteAddr,
)
}
-
- w.Header().Add("Content-Type", "text/html")
-
- io.WriteString(w, gohtml.Format(newErrorPage("Server Error", "An error has occurred. Please try again.")))
}
func serverErrorHandler() func(http.ResponseWriter, *http.Request, interface{}) {
diff --git a/cmd/files.go b/cmd/files.go
index 1052ae2..92e685a 100644
--- a/cmd/files.go
+++ b/cmd/files.go
@@ -10,6 +10,7 @@ import (
"io/fs"
"math/big"
"regexp"
+ "runtime"
"slices"
"crypto/rand"
@@ -205,6 +206,10 @@ func pathIsValid(path string, paths []string) bool {
}
func hasSupportedFiles(path string, formats types.Types) (bool, error) {
+ if AllowEmpty {
+ return true, nil
+ }
+
hasRegisteredFiles := make(chan bool, 1)
err := filepath.WalkDir(path, func(p string, info os.DirEntry, err error) error {
@@ -463,7 +468,7 @@ Poll:
filesMatched+filesSkipped,
directoriesMatched,
directoriesMatched+directoriesSkipped,
- time.Since(startTime),
+ time.Since(startTime)-100*time.Millisecond,
)
}
@@ -514,7 +519,10 @@ func fileList(paths []string, filters *filters, sort string, index *fileIndex, f
func pickFile(list []string) (string, error) {
fileCount := len(list)
- if fileCount < 1 {
+ switch {
+ case fileCount < 1 && AllowEmpty:
+ return "", nil
+ case fileCount < 1:
return "", ErrNoMediaFound
}
@@ -531,6 +539,14 @@ func pickFile(list []string) (string, error) {
return list[val], nil
}
+func preparePath(prefix, path string) string {
+ if runtime.GOOS == "windows" {
+ return fmt.Sprintf("%s/%s", prefix, filepath.ToSlash(path))
+ }
+
+ return prefix + path
+}
+
func normalizePath(path string) (string, error) {
homeDir, err := os.UserHomeDir()
if err != nil {
diff --git a/cmd/root.go b/cmd/root.go
index 4160470..325fef6 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -14,12 +14,13 @@ import (
const (
AllowedCharacters string = `^[A-z0-9.\-_]+$`
- ReleaseVersion string = "3.7.2"
+ ReleaseVersion string = "3.8.0"
)
var (
AdminPrefix string
All bool
+ AllowEmpty bool
Audio bool
BinaryPrefix bool
Bind string
@@ -111,6 +112,7 @@ func Execute() {
func init() {
rootCmd.Flags().StringVar(&AdminPrefix, "admin-prefix", "", "string to prepend to administrative paths")
rootCmd.Flags().BoolVarP(&All, "all", "a", false, "enable all supported file types")
+ rootCmd.Flags().BoolVar(&AllowEmpty, "allow-empty", false, "allow specifying paths containing no supported files")
rootCmd.Flags().BoolVar(&Audio, "audio", false, "enable support for audio files")
rootCmd.Flags().BoolVar(&BinaryPrefix, "binary-prefix", false, "use IEC binary prefixes instead of SI decimal prefixes")
rootCmd.Flags().StringVarP(&Bind, "bind", "b", "0.0.0.0", "address to bind to")
diff --git a/cmd/web.go b/cmd/web.go
index a8b9e28..78503e8 100644
--- a/cmd/web.go
+++ b/cmd/web.go
@@ -42,12 +42,31 @@ const (
timeout time.Duration = 10 * time.Second
)
-func preparePath(prefix, path string) string {
- if runtime.GOOS == "windows" {
- return fmt.Sprintf("%s/%s", prefix, filepath.ToSlash(path))
- }
+func newPage(title, body string) string {
+ var htmlBody strings.Builder
- return prefix + path
+ htmlBody.WriteString(``)
+ htmlBody.WriteString(faviconHtml)
+ htmlBody.WriteString(``)
+ htmlBody.WriteString(fmt.Sprintf("%s", title))
+ htmlBody.WriteString(fmt.Sprintf("%s", body))
+
+ return htmlBody.String()
+}
+
+func noFiles(w http.ResponseWriter, r *http.Request) {
+ startTime := time.Now()
+
+ w.Header().Set("Content-Type", "text/plain")
+
+ w.Write([]byte("No files found in the specified path(s).\n"))
+
+ if Verbose {
+ fmt.Printf("%s | SERVE: Empty path notice served to %s\n",
+ startTime.Format(logDate),
+ r.RemoteAddr,
+ )
+ }
}
func serveStaticFile(paths []string, index *fileIndex, errorChannel chan<- error) httprouter.Handle {
@@ -210,6 +229,10 @@ func serveRoot(paths []string, regexes *regexes, index *fileIndex, formats types
path, err = newFile(list, sortOrder, regexes, formats)
switch {
+ case path == "":
+ noFiles(w, r)
+
+ return
case err != nil && err == ErrNoMediaFound:
notFound(w, r, path)