Allow empty paths, notifying if no valid files are found

This commit is contained in:
Seednode 2024-01-05 18:50:45 -06:00
parent ccff56d28d
commit 5167ff457e
4 changed files with 61 additions and 33 deletions

View File

@ -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(`<!DOCTYPE html><html lang="en"><head>`)
htmlBody.WriteString(faviconHtml)
htmlBody.WriteString(`<style>html,body,a{display:block;height:100%;width:100%;text-decoration:none;color:inherit;cursor:auto;}</style>`)
htmlBody.WriteString(fmt.Sprintf("<title>%s</title></head>", title))
htmlBody.WriteString(fmt.Sprintf("<body><a href=\"/\">%s</a></body></html>", 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{}) {

View File

@ -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 {

View File

@ -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")

View File

@ -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(`<!DOCTYPE html><html lang="en"><head>`)
htmlBody.WriteString(faviconHtml)
htmlBody.WriteString(`<style>html,body,a{display:block;height:100%;width:100%;text-decoration:none;color:inherit;cursor:auto;}</style>`)
htmlBody.WriteString(fmt.Sprintf("<title>%s</title></head>", title))
htmlBody.WriteString(fmt.Sprintf("<body><a href=\"/\">%s</a></body></html>", 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)