Added sorting options (ascending, descending, defaults to random)
This commit is contained in:
parent
7f27050595
commit
0d9e74fbca
15
README.md
15
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.
|
||||
|
|
132
cmd/files.go
132
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
|
||||
}
|
||||
|
||||
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())
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var Version = "0.12.5"
|
||||
var Version = "0.13.0"
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(versionCmd)
|
||||
|
|
67
cmd/web.go
67
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
|
||||
|
|
Loading…
Reference in New Issue