Added flags to enable/disable filtering and sorting

This commit is contained in:
Seednode 2022-10-19 20:37:12 -05:00
parent 7819cf3090
commit 6508f2d170
4 changed files with 95 additions and 32 deletions

View File

@ -14,7 +14,7 @@ Builds available [here](https://cdn.seedno.de/builds/roulette).
## Filtering ## Filtering
You can provide a comma-delimited string of patterns to match via the `include=` query parameter. You can provide a comma-delimited string of patterns to match via the `include=` query parameter, assuming the `-f|--filter` flag is enabled.
Only filenames matching one or more of the patterns will be served. Only filenames matching one or more of the patterns will be served.
@ -28,7 +28,7 @@ Both filtering parameters ignore the file extension and full path; they only com
## Sorting ## Sorting
You can specify a sorting pattern via the `sort=` query parameter. You can specify a sorting pattern via the `sort=` query parameter, assuming the `-s|--sort` flag is enabled.
A value of `asc` means files will be served in ascending order (lowest-numbered to highest). A value of `asc` means files will be served in ascending order (lowest-numbered to highest).
@ -58,9 +58,11 @@ Available Commands:
version Print version version Print version
Flags: Flags:
-f, --filter enable filtering via query parameters
-h, --help help for roulette -h, --help help for roulette
-p, --port uint16 port to listen on (default 8080) -p, --port uint16 port to listen on (default 8080)
-r, --recursive recurse into subdirectories -r, --recursive recurse into subdirectories
-s, --sort enable sorting via query parameters
-v, --verbose log accessed files to stdout -v, --verbose log accessed files to stdout
Use "roulette [command] --help" for more information about a command. Use "roulette [command] --help" for more information about a command.

View File

@ -11,8 +11,10 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
var Filter bool
var Port uint16 var Port uint16
var Recursive bool var Recursive bool
var Sort bool
var Verbose bool var Verbose bool
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
@ -36,8 +38,10 @@ func Execute() {
} }
func init() { func init() {
rootCmd.Flags().BoolVarP(&Filter, "filter", "f", false, "enable filtering via query parameters")
rootCmd.Flags().Uint16VarP(&Port, "port", "p", 8080, "port to listen on") rootCmd.Flags().Uint16VarP(&Port, "port", "p", 8080, "port to listen on")
rootCmd.Flags().BoolVarP(&Recursive, "recursive", "r", false, "recurse into subdirectories") rootCmd.Flags().BoolVarP(&Recursive, "recursive", "r", false, "recurse into subdirectories")
rootCmd.Flags().BoolVarP(&Sort, "sort", "s", false, "enable sorting via query parameters")
rootCmd.Flags().BoolVarP(&Verbose, "verbose", "v", false, "log accessed files to stdout") rootCmd.Flags().BoolVarP(&Verbose, "verbose", "v", false, "log accessed files to stdout")
rootCmd.Flags().SetInterspersed(true) rootCmd.Flags().SetInterspersed(true)
} }

View File

@ -10,7 +10,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
var Version = "0.14.2" var Version = "0.15.0"
func init() { func init() {
rootCmd.AddCommand(versionCmd) rootCmd.AddCommand(versionCmd)

View File

@ -48,7 +48,35 @@ func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
const LOGDATE string = "2006-01-02T15:04:05.000-07:00" const LOGDATE string = "2006-01-02T15:04:05.000-07:00"
const PREFIX string = "/src" const PREFIX string = "/src"
func stripQueryParam(inUrl string) (string, error) { func splitQueryParams(query string) []string {
if query == "" {
return []string{}
}
return strings.Split(query, ",")
}
func generateQueryParams(filters *Filters, sort string) string {
switch {
case Filter && !Sort:
return fmt.Sprintf("?include=%v&exclude=%v",
filters.GetIncludes(),
filters.GetExcludes(),
)
case !Filter && Sort:
return fmt.Sprintf("?sort=%v", sort)
case Filter && Sort:
return fmt.Sprintf("?include=%v&exclude=%v&sort=%v",
filters.GetIncludes(),
filters.GetExcludes(),
sort,
)
}
return ""
}
func stripQueryParams(inUrl string) (string, error) {
url, err := url.Parse(inUrl) url, err := url.Parse(inUrl)
if err != nil { if err != nil {
return "", err return "", err
@ -82,7 +110,24 @@ func serveHtml(w http.ResponseWriter, r *http.Request, filePath string) error {
htmlBody += `</title> htmlBody += `</title>
</head> </head>
<body>` <body>`
htmlBody += fmt.Sprintf(`<a href="/?include=%v&exclude=%v&sort=%v"><img src="`, r.URL.Query().Get("include"), r.URL.Query().Get("exclude"), r.URL.Query().Get("sort")) switch {
case Filter && Sort:
htmlBody += fmt.Sprintf(`<a href="/?include=%v&exclude=%v&sort=%v"><img src="`,
r.URL.Query().Get("include"),
r.URL.Query().Get("exclude"), r.URL.Query().Get("sort"),
)
case Filter && !Sort:
htmlBody += fmt.Sprintf(`<a href="/?include=%v&exclude=%v"><img src="`,
r.URL.Query().Get("include"),
r.URL.Query().Get("exclude"),
)
case !Filter && Sort:
htmlBody += fmt.Sprintf(`<a href="/?sort=%v"><img src="`,
r.URL.Query().Get("sort"),
)
default:
htmlBody += `<a href="/"><img src="`
}
htmlBody += PREFIX + filePath htmlBody += PREFIX + filePath
htmlBody += `"></img></a> htmlBody += `"></img></a>
</body> </body>
@ -97,7 +142,7 @@ func serveHtml(w http.ResponseWriter, r *http.Request, filePath string) error {
} }
func serveStaticFile(w http.ResponseWriter, r *http.Request, paths []string) error { func serveStaticFile(w http.ResponseWriter, r *http.Request, paths []string) error {
strippedUrl, err := stripQueryParam(r.URL.Path) strippedUrl, err := stripQueryParams(r.URL.Path)
if err != nil { if err != nil {
return err return err
} }
@ -155,29 +200,21 @@ func serveStaticFileHandler(paths []string) appHandler {
} }
} }
func parseQueryParams(query string) []string {
if query == "" {
return []string{}
}
return strings.Split(query, ",")
}
func serveHtmlHandler(paths []string) appHandler { func serveHtmlHandler(paths []string) appHandler {
return func(w http.ResponseWriter, r *http.Request) error { return func(w http.ResponseWriter, r *http.Request) error {
refererUri, err := stripQueryParam(refererToUri(r.Referer())) refererUri, err := stripQueryParams(refererToUri(r.Referer()))
if err != nil { if err != nil {
return err return err
} }
filters := Filters{} filters := Filters{}
filters.Includes = parseQueryParams(r.URL.Query().Get("include")) filters.Includes = splitQueryParams(r.URL.Query().Get("include"))
filters.Excludes = parseQueryParams(r.URL.Query().Get("exclude")) filters.Excludes = splitQueryParams(r.URL.Query().Get("exclude"))
sort := r.URL.Query().Get("sort") sortOrder := r.URL.Query().Get("sort")
switch { switch {
case r.URL.Path == "/" && sort == "asc" && refererUri != "": case r.URL.Path == "/" && sortOrder == "asc" && refererUri != "":
query, err := url.QueryUnescape(refererUri) query, err := url.QueryUnescape(refererUri)
if err != nil { if err != nil {
return err return err
@ -194,7 +231,7 @@ func serveHtmlHandler(paths []string) appHandler {
} }
if filePath == "" { if filePath == "" {
filePath, err = pickFile(paths, &filters, sort) filePath, err = pickFile(paths, &filters, sortOrder)
switch { switch {
case err != nil && err == ErrNoImagesFound: case err != nil && err == ErrNoImagesFound:
http.NotFound(w, r) http.NotFound(w, r)
@ -215,10 +252,14 @@ func serveHtmlHandler(paths []string) appHandler {
} }
} }
newUrl := fmt.Sprintf("%v%v?include=%v&exclude=%v&sort=%v", r.URL.Host, filePath, filters.GetIncludes(), filters.GetExcludes(), sort) newUrl := fmt.Sprintf("%v%v%v",
r.URL.Host,
filePath,
generateQueryParams(&filters, sortOrder),
)
http.Redirect(w, r, newUrl, http.StatusSeeOther) http.Redirect(w, r, newUrl, http.StatusSeeOther)
case r.URL.Path == "/" && sort == "asc" && refererUri == "": case r.URL.Path == "/" && sortOrder == "asc" && refererUri == "":
filePath, err := pickFile(paths, &filters, sort) filePath, err := pickFile(paths, &filters, sortOrder)
if err != nil && err == ErrNoImagesFound { if err != nil && err == ErrNoImagesFound {
http.NotFound(w, r) http.NotFound(w, r)
@ -237,9 +278,13 @@ func serveHtmlHandler(paths []string) appHandler {
return err return err
} }
newUrl := fmt.Sprintf("%v%v?include=%v&exclude=%v&sort=%v", r.URL.Host, filePath, filters.GetIncludes(), filters.GetExcludes(), sort) newUrl := fmt.Sprintf("%v%v%v",
r.URL.Host,
filePath,
generateQueryParams(&filters, sortOrder),
)
http.Redirect(w, r, newUrl, http.StatusSeeOther) http.Redirect(w, r, newUrl, http.StatusSeeOther)
case r.URL.Path == "/" && sort == "desc" && refererUri != "": case r.URL.Path == "/" && sortOrder == "desc" && refererUri != "":
query, err := url.QueryUnescape(refererUri) query, err := url.QueryUnescape(refererUri)
if err != nil { if err != nil {
return err return err
@ -256,7 +301,7 @@ func serveHtmlHandler(paths []string) appHandler {
} }
if filePath == "" { if filePath == "" {
filePath, err = pickFile(paths, &filters, sort) filePath, err = pickFile(paths, &filters, sortOrder)
switch { switch {
case err != nil && err == ErrNoImagesFound: case err != nil && err == ErrNoImagesFound:
http.NotFound(w, r) http.NotFound(w, r)
@ -277,10 +322,14 @@ func serveHtmlHandler(paths []string) appHandler {
} }
} }
newUrl := fmt.Sprintf("%v%v?include=%v&exclude=%v&sort=%v", r.URL.Host, filePath, filters.GetIncludes(), filters.GetExcludes(), sort) newUrl := fmt.Sprintf("%v%v%v",
r.URL.Host,
filePath,
generateQueryParams(&filters, sortOrder),
)
http.Redirect(w, r, newUrl, http.StatusSeeOther) http.Redirect(w, r, newUrl, http.StatusSeeOther)
case r.URL.Path == "/" && sort == "desc" && refererUri == "": case r.URL.Path == "/" && sortOrder == "desc" && refererUri == "":
filePath, err := pickFile(paths, &filters, sort) filePath, err := pickFile(paths, &filters, sortOrder)
if err != nil && err == ErrNoImagesFound { if err != nil && err == ErrNoImagesFound {
http.NotFound(w, r) http.NotFound(w, r)
@ -299,10 +348,14 @@ func serveHtmlHandler(paths []string) appHandler {
return err return err
} }
newUrl := fmt.Sprintf("%v%v?include=%v&exclude=%v&sort=%v", r.URL.Host, filePath, filters.GetIncludes(), filters.GetExcludes(), sort) newUrl := fmt.Sprintf("%v%v%v",
r.URL.Host,
filePath,
generateQueryParams(&filters, sortOrder),
)
http.Redirect(w, r, newUrl, http.StatusSeeOther) http.Redirect(w, r, newUrl, http.StatusSeeOther)
case r.URL.Path == "/": case r.URL.Path == "/":
filePath, err := pickFile(paths, &filters, sort) filePath, err := pickFile(paths, &filters, sortOrder)
if err != nil && err == ErrNoImagesFound { if err != nil && err == ErrNoImagesFound {
http.NotFound(w, r) http.NotFound(w, r)
@ -311,7 +364,11 @@ func serveHtmlHandler(paths []string) appHandler {
return err return err
} }
newUrl := fmt.Sprintf("%v%v?include=%v&exclude=%v&sort=%v", r.URL.Host, filePath, filters.GetIncludes(), filters.GetExcludes(), sort) newUrl := fmt.Sprintf("%v%v%v",
r.URL.Host,
filePath,
generateQueryParams(&filters, sortOrder),
)
http.Redirect(w, r, newUrl, http.StatusSeeOther) http.Redirect(w, r, newUrl, http.StatusSeeOther)
default: default:
filePath := r.URL.Path filePath := r.URL.Path