From 0d9e74fbca78c4830a624635a9fad4ad5890ca02 Mon Sep 17 00:00:00 2001 From: Seednode Date: Tue, 18 Oct 2022 13:42:32 -0500 Subject: [PATCH] Added sorting options (ascending, descending, defaults to random) --- README.md | 15 ------ cmd/files.go | 134 +++++++++++++++++++++++++++++++++---------------- cmd/version.go | 2 +- cmd/web.go | 67 +++++++++++++++++++++---- 4 files changed, 150 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index 7468a69..d00f206 100644 --- a/README.md +++ b/README.md @@ -10,20 +10,6 @@ Browser history is preserved, so you can always go back to any previously displa Builds available [here](https://cdn.seedno.de/builds/roulette). -## [-s, --successive] - -This option is tailored specifically for my own use case. - -When loading a new image, it checks for a sequentially-numbered file in the same directory. - -For example, let's say `/mnt/photos/MyVacation001.jpg` is being displayed. - -If you click on the image, `roulette` will attempt to display `/mnt/photos/MyVacation002.jpg`. - -If that matching file is not found, it will select a random file as usual. - -The expected format is `filename###.extension`. - ## Usage output ``` Usage: @@ -40,7 +26,6 @@ Flags: -h, --help help for roulette -p, --port int port to listen on (default 8080) -r, --recursive recurse into subdirectories - -s, --successive load the next sequential file, if possible -v, --verbose log accessed files to stdout Use "roulette [command] --help" for more information about a command. diff --git a/cmd/files.go b/cmd/files.go index 38670ed..8d92e2b 100644 --- a/cmd/files.go +++ b/cmd/files.go @@ -52,17 +52,45 @@ func getFirstFile(path string) (string, error) { number := 1 extension := split[0][3] - fileName := fmt.Sprintf("%v%.3d%v", base, number, extension) - - nextFile, err := nextFileExists(fileName) + fileName, err := tryExtensions(base, number, extension) if err != nil { return "", err } - if !nextFile { + return fileName, nil +} + +func getLastFile(path string) (string, error) { + re := regexp.MustCompile(`(.+)([0-9]{3})(\..+)`) + + split := re.FindAllStringSubmatch(path, -1) + + if len(split) < 1 || len(split[0]) < 3 { return "", nil } + base := split[0][1] + number := 1 + extension := split[0][3] + + var fileName string + var err error + + for { + fileName, err = tryExtensions(base, number, extension) + if err != nil { + return "", err + } + + if fileName == "" { + fileName, err = tryExtensions(base, number-1, extension) + + break + } + + number = number + 1 + } + return fileName, nil } @@ -82,20 +110,69 @@ func getNextFile(path string) (string, error) { } extension := split[0][3] - incremented := number + 1 - - fileName := fmt.Sprintf("%v%.3d%v", base, incremented, extension) - - nextFile, err := nextFileExists(fileName) + fileName, err := tryExtensions(base, number+1, extension) if err != nil { return "", err } - if !nextFile { + return fileName, err +} + +func getPreviousFile(path string) (string, error) { + re := regexp.MustCompile(`(.+)([0-9]{3})(\..+)`) + + split := re.FindAllStringSubmatch(path, -1) + + if len(split) < 1 || len(split[0]) < 3 { return "", nil } - return fileName, nil + base := split[0][1] + number, err := strconv.Atoi(split[0][2]) + if err != nil { + return "", err + } + extension := split[0][3] + + fileName, err := tryExtensions(base, number-1, extension) + if err != nil { + return "", err + } + + return fileName, err +} + +func tryExtensions(base string, number int, extension string) (string, error) { + extensions := [6]string{extension, ".jpg", ".jpeg", ".png", ".gif", ".webp"} + + var fileName string + + for _, i := range extensions { + fileName = fmt.Sprintf("%v%.3d%v", base, number, i) + + exists, err := fileExists(fileName) + if err != nil { + return "", err + } + + if exists { + return fileName, nil + } + } + + return "", nil +} + +func fileExists(path string) (bool, error) { + _, err := os.Stat(path) + switch { + case err == nil: + return true, nil + case errors.Is(err, os.ErrNotExist): + return false, nil + default: + return false, err + } } func pathIsValid(filePath string, paths []string) bool { @@ -116,33 +193,6 @@ func pathIsValid(filePath string, paths []string) bool { return true } -func fileExists(filePath string) (bool, error) { - _, err := os.Stat(filePath) - if errors.Is(err, os.ErrNotExist) { - if Verbose { - fmt.Printf("%v Failed to serve non-existent file: %v\n", time.Now().Format(LOGDATE), filePath) - } - - return false, nil - } else if !errors.Is(err, os.ErrNotExist) && err != nil { - return false, err - } - - return true, nil -} - -func nextFileExists(path string) (bool, error) { - _, err := os.Stat(path) - switch { - case err == nil: - return true, nil - case errors.Is(err, os.ErrNotExist): - return false, nil - default: - return false, err - } -} - func isImage(path string) (bool, error) { file, err := os.Open(path) if err != nil { @@ -219,7 +269,7 @@ func prepareDirectory(directory []string) []string { } } -func prepareDirectories(m map[string][]string, successive string) []string { +func prepareDirectories(m map[string][]string, sorting string) []string { directories := []string{} keys := make([]string, len(m)) @@ -230,7 +280,7 @@ func prepareDirectories(m map[string][]string, successive string) []string { i++ } - if successive != "" { + if sorting == "asc" || sorting == "desc" { for i := 0; i < len(keys); i++ { directories = append(directories, prepareDirectory(m[keys[i]])...) } @@ -243,13 +293,13 @@ func prepareDirectories(m map[string][]string, successive string) []string { return directories } -func pickFile(args []string, filter, successive string) (string, error) { +func pickFile(args []string, filter, sorting string) (string, error) { fileMap, err := getFileList(args, filter) if err != nil { return "", err } - fileList := prepareDirectories(fileMap, successive) + fileList := prepareDirectories(fileMap, sorting) rand.Seed(time.Now().UnixNano()) diff --git a/cmd/version.go b/cmd/version.go index f44abfe..e4ff936 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -10,7 +10,7 @@ import ( "github.com/spf13/cobra" ) -var Version = "0.12.5" +var Version = "0.13.0" func init() { rootCmd.AddCommand(versionCmd) diff --git a/cmd/web.go b/cmd/web.go index 02164a3..abb0ea9 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -142,10 +142,10 @@ func serveHtmlHandler(paths []string) appHandler { } filter := r.URL.Query().Get("f") - successive := r.URL.Query().Get("s") + sorting := r.URL.Query().Get("s") switch { - case r.URL.Path == "/" && successive == "true" && refererUri != "": + case r.URL.Path == "/" && sorting == "asc" && refererUri != "": query, err := url.QueryUnescape(refererUri) if err != nil { return err @@ -157,7 +157,7 @@ func serveHtmlHandler(paths []string) appHandler { } if filePath == "" { - filePath, err = pickFile(paths, filter, successive) + filePath, err = pickFile(paths, filter, sorting) switch { case err != nil && err == ErrNoImagesFound: http.NotFound(w, r) @@ -173,10 +173,10 @@ func serveHtmlHandler(paths []string) appHandler { } } - newUrl := fmt.Sprintf("%v%v?f=%v&s=%v", r.URL.Host, filePath, filter, successive) + newUrl := fmt.Sprintf("%v%v?f=%v&s=%v", r.URL.Host, filePath, filter, sorting) http.Redirect(w, r, newUrl, http.StatusSeeOther) - case r.URL.Path == "/" && successive == "true" && refererUri == "": - filePath, err := pickFile(paths, filter, successive) + case r.URL.Path == "/" && sorting == "asc" && refererUri == "": + filePath, err := pickFile(paths, filter, sorting) if err != nil && err == ErrNoImagesFound { http.NotFound(w, r) @@ -190,10 +190,40 @@ func serveHtmlHandler(paths []string) appHandler { return err } - newUrl := fmt.Sprintf("%v%v?f=%v&s=%v", r.URL.Host, filePath, filter, successive) + newUrl := fmt.Sprintf("%v%v?f=%v&s=%v", r.URL.Host, filePath, filter, sorting) http.Redirect(w, r, newUrl, http.StatusSeeOther) - case r.URL.Path == "/": - filePath, err := pickFile(paths, filter, successive) + case r.URL.Path == "/" && sorting == "desc" && refererUri != "": + query, err := url.QueryUnescape(refererUri) + if err != nil { + return err + } + + filePath, err := getPreviousFile(query) + if err != nil { + return err + } + + if filePath == "" { + filePath, err = pickFile(paths, filter, sorting) + switch { + case err != nil && err == ErrNoImagesFound: + http.NotFound(w, r) + + return nil + case err != nil: + return err + } + + filePath, err = getLastFile(filePath) + if err != nil { + return err + } + } + + newUrl := fmt.Sprintf("%v%v?f=%v&s=%v", r.URL.Host, filePath, filter, sorting) + http.Redirect(w, r, newUrl, http.StatusSeeOther) + case r.URL.Path == "/" && sorting == "desc" && refererUri == "": + filePath, err := pickFile(paths, filter, sorting) if err != nil && err == ErrNoImagesFound { http.NotFound(w, r) @@ -202,7 +232,24 @@ func serveHtmlHandler(paths []string) appHandler { return err } - newUrl := fmt.Sprintf("%v%v?f=%v&s=%v", r.URL.Host, filePath, filter, successive) + filePath, err = getLastFile(filePath) + if err != nil { + return err + } + + newUrl := fmt.Sprintf("%v%v?f=%v&s=%v", r.URL.Host, filePath, filter, sorting) + http.Redirect(w, r, newUrl, http.StatusSeeOther) + case r.URL.Path == "/": + filePath, err := pickFile(paths, filter, sorting) + if err != nil && err == ErrNoImagesFound { + http.NotFound(w, r) + + return nil + } else if err != nil { + return err + } + + newUrl := fmt.Sprintf("%v%v?f=%v&s=%v", r.URL.Host, filePath, filter, sorting) http.Redirect(w, r, newUrl, http.StatusSeeOther) default: filePath := r.URL.Path