diff --git a/README.md b/README.md index cc46419..c70037f 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ Available Commands: version Print version Flags: + -c, --cache only scan directories once, at startup -f, --filter enable filtering via query parameters -h, --help help for roulette -p, --port uint16 port to listen on (default 8080) diff --git a/cmd/files.go b/cmd/files.go index 85d91ae..ff1b428 100644 --- a/cmd/files.go +++ b/cmd/files.go @@ -105,12 +105,26 @@ func preparePath(path string) string { return path } -func appendPath(directory, path string, files *Files, stats *Stats) { +func appendPath(directory, path string, files *Files, stats *Stats) error { + // If caching, check for valid images here, to speed up future pickFile() calls + if Cache { + image, err := isImage(path) + if err != nil { + return err + } + + if !image { + return nil + } + } + files.Mutex.Lock() files.List[directory] = append(files.List[directory], path) files.Mutex.Unlock() stats.IncrementFilesMatched() + + return nil } func appendPaths(path string, files *Files, filters *Filters, stats *Stats) error { @@ -142,7 +156,10 @@ func appendPaths(path string, files *Files, filters *Filters, stats *Stats) erro filename, filters.Includes[i], ) { - appendPath(directory, path, files, stats) + err := appendPath(directory, path, files, stats) + if err != nil { + return err + } return nil } @@ -153,7 +170,10 @@ func appendPaths(path string, files *Files, filters *Filters, stats *Stats) erro return nil } - appendPath(directory, path, files, stats) + err = appendPath(directory, path, files, stats) + if err != nil { + return err + } return nil } @@ -418,45 +438,61 @@ func prepareDirectories(files *Files, sort string) []string { return directories } -func pickFile(args []string, filters *Filters, sort string) (string, error) { - files := Files{} - files.List = make(map[string][]string) +func pickFile(args []string, filters *Filters, sort string, fileCache *[]string) (string, error) { + var fileList []string - stats := Stats{} + if Cache && len(*fileCache) != 0 { + fileList = *fileCache + } else { + files := Files{} + files.List = make(map[string][]string) - concurrency := Concurrency{} - concurrency.DirectoryScans = make(chan int, maxDirectoryScans) - concurrency.FileScans = make(chan int, maxFileScans) + stats := Stats{} - startTime := time.Now() - getFileList(args, &files, filters, &stats, &concurrency) - runTime := time.Since(startTime) + concurrency := Concurrency{} + concurrency.DirectoryScans = make(chan int, maxDirectoryScans) + concurrency.FileScans = make(chan int, maxFileScans) - if Verbose { - fmt.Printf("%v | Scanned %v/%v files across %v directories in %v\n", - time.Now().Format(LOGDATE), - stats.GetFilesMatched(), - stats.GetFilesTotal(), - stats.GetDirectoriesMatched(), - runTime, - ) + startTime := time.Now() + getFileList(args, &files, filters, &stats, &concurrency) + runTime := time.Since(startTime) + + if Verbose { + fmt.Printf("%v | Scanned %v/%v files across %v directories in %v\n", + time.Now().Format(LOGDATE), + stats.GetFilesMatched(), + stats.GetFilesTotal(), + stats.GetDirectoriesMatched(), + runTime, + ) + } + + fileList = prepareDirectories(&files, sort) + + if Cache { + *fileCache = append(*fileCache, fileList...) + } } - fileList := prepareDirectories(&files, sort) - rand.Seed(time.Now().UnixNano()) rand.Shuffle(len(fileList), func(i, j int) { fileList[i], fileList[j] = fileList[j], fileList[i] }) for i := 0; i < len(fileList); i++ { filePath := fileList[i] - isImage, err := isImage(filePath) - if err != nil { - return "", err + + // If not caching, check for valid images just before serving, to speed up scanning + if !Cache { + isImage, err := isImage(filePath) + if err != nil { + return "", err + } + + if isImage { + return filePath, nil + } } - if isImage { - return filePath, nil - } + return filePath, nil } return "", ErrNoImagesFound diff --git a/cmd/root.go b/cmd/root.go index e9fe99a..444cdf4 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -24,6 +24,7 @@ type Concurrency struct { FileScans chan int } +var Cache bool var Filter bool var Port uint16 var Recursive bool @@ -51,6 +52,7 @@ func Execute() { } func init() { + rootCmd.Flags().BoolVarP(&Cache, "cache", "c", false, "only scan directories once, at startup") 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().BoolVarP(&Recursive, "recursive", "r", false, "recurse into subdirectories") diff --git a/cmd/version.go b/cmd/version.go index 0edc62d..805e184 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -10,7 +10,7 @@ import ( "github.com/spf13/cobra" ) -var Version = "0.18.4" +var Version = "0.19.0" func init() { rootCmd.AddCommand(versionCmd) diff --git a/cmd/web.go b/cmd/web.go index 4b0a782..75a45dd 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -241,7 +241,7 @@ func serveStaticFileHandler(paths []string) appHandler { } } -func serveHtmlHandler(paths []string, re regexp.Regexp) appHandler { +func serveHtmlHandler(paths []string, re regexp.Regexp, fileCache *[]string) appHandler { return func(w http.ResponseWriter, r *http.Request) error { refererUri, err := stripQueryParams(refererToUri(r.Referer())) if err != nil { @@ -279,7 +279,7 @@ func serveHtmlHandler(paths []string, re regexp.Regexp) appHandler { } if filePath == "" { - filePath, err = pickFile(paths, &filters, sortOrder) + filePath, err = pickFile(paths, &filters, sortOrder, fileCache) switch { case err != nil && err == ErrNoImagesFound: http.NotFound(w, r) @@ -307,7 +307,7 @@ func serveHtmlHandler(paths []string, re regexp.Regexp) appHandler { ) http.Redirect(w, r, newUrl, RedirectStatusCode) case r.URL.Path == "/" && sortOrder == "asc" && refererUri == "": - filePath, err := pickFile(paths, &filters, sortOrder) + filePath, err := pickFile(paths, &filters, sortOrder, fileCache) if err != nil && err == ErrNoImagesFound { http.NotFound(w, r) @@ -349,7 +349,7 @@ func serveHtmlHandler(paths []string, re regexp.Regexp) appHandler { } if filePath == "" { - filePath, err = pickFile(paths, &filters, sortOrder) + filePath, err = pickFile(paths, &filters, sortOrder, fileCache) switch { case err != nil && err == ErrNoImagesFound: http.NotFound(w, r) @@ -377,7 +377,7 @@ func serveHtmlHandler(paths []string, re regexp.Regexp) appHandler { ) http.Redirect(w, r, newUrl, RedirectStatusCode) case r.URL.Path == "/" && sortOrder == "desc" && refererUri == "": - filePath, err := pickFile(paths, &filters, sortOrder) + filePath, err := pickFile(paths, &filters, sortOrder, fileCache) if err != nil && err == ErrNoImagesFound { http.NotFound(w, r) @@ -404,7 +404,7 @@ func serveHtmlHandler(paths []string, re regexp.Regexp) appHandler { fmt.Printf("New URL is %v\n", newUrl) http.Redirect(w, r, newUrl, RedirectStatusCode) case r.URL.Path == "/": - filePath, err := pickFile(paths, &filters, sortOrder) + filePath, err := pickFile(paths, &filters, sortOrder, fileCache) if err != nil && err == ErrNoImagesFound { http.NotFound(w, r) @@ -469,7 +469,9 @@ func ServePage(args []string) error { re := regexp.MustCompile(`(.+)([0-9]{3})(\..+)`) - http.Handle("/", serveHtmlHandler(paths, *re)) + fileCache := []string{} + + http.Handle("/", serveHtmlHandler(paths, *re, &fileCache)) http.Handle(PREFIX+"/", http.StripPrefix(PREFIX, serveStaticFileHandler(paths))) http.HandleFunc("/favicon.ico", doNothing)