Compare commits

..

No commits in common. "ba827430bb6fa57ff33c5ed0db8264680ece4162" and "76b4053240be22a5571fdd039209915436a6ee65" have entirely different histories.

7 changed files with 129 additions and 80 deletions

View File

@ -24,6 +24,8 @@ If the `-c|--cache` flag is passed, the indices of all specified paths will be c
This will slightly increase the delay before the application begins responding to requests, but should significantly speed up subsequent requests.
If any `include=`/`exclude=` filters are specified in a given request, the cache will be bypassed for that specific request.
The cache can be regenerated at any time by accessing the `/clear_cache` endpoint.
If `--cache-file` is set, the cache will be loaded from the specified file on start, and written to the file whenever it is re-generated.
@ -118,7 +120,6 @@ Flags:
-c, --cache generate directory cache at startup
--cache-file string path to optional persistent cache file
--code enable support for source code files
--code-theme string theme for source code syntax highlighting (default "solarized-dark256")
-f, --filter enable filtering
--flash enable support for shockwave flash files (via ruffle.rs)
--handlers display registered handlers (for debugging)
@ -136,6 +137,7 @@ Flags:
--russian remove selected images after serving
-s, --sort enable sorting
--text enable support for text files
--theme string theme for source code syntax highlighting (default "solarized-dark256")
-v, --verbose log accessed files and other information to stdout
-V, --version display version and exit
--video enable support for video files

View File

@ -22,8 +22,7 @@ type fileCache struct {
func (cache *fileCache) List() []string {
cache.mutex.RLock()
val := make([]string, len(cache.list))
copy(val, cache.list)
val := cache.list
cache.mutex.RUnlock()
return val
@ -54,15 +53,8 @@ func (cache *fileCache) remove(path string) {
}
func (cache *fileCache) set(val []string) {
length := len(val)
if length < 1 {
return
}
cache.mutex.Lock()
cache.list = make([]string, length)
copy(cache.list, val)
cache.list = val
cache.mutex.Unlock()
}

View File

@ -43,12 +43,12 @@ type concurrency struct {
type files struct {
mutex sync.RWMutex
list []string
list map[string][]string
}
func (f *files) append(path string) {
func (f *files) append(directory, path string) {
f.mutex.Lock()
f.list = append(f.list, path)
f.list[directory] = append(f.list[directory], path)
f.mutex.Unlock()
}
@ -99,6 +99,63 @@ func preparePath(path string) string {
return mediaPrefix + path
}
func appendPath(directory, path string, files *files, stats *scanStats, formats *types.Types) {
if !formats.Validate(path) {
stats.filesSkipped.Add(1)
return
}
files.append(directory, path)
stats.filesMatched.Add(1)
}
func appendPaths(path string, files *files, filters *filters, stats *scanStats, formats *types.Types) error {
absolutePath, err := filepath.Abs(path)
if err != nil {
return err
}
directory, filename := filepath.Split(absolutePath)
filename = strings.ToLower(filename)
if filters.hasExcludes() {
for i := 0; i < len(filters.excluded); i++ {
if strings.Contains(
filename,
filters.excluded[i],
) {
stats.filesSkipped.Add(1)
return nil
}
}
}
if filters.hasIncludes() {
for i := 0; i < len(filters.included); i++ {
if strings.Contains(
filename,
filters.included[i],
) {
appendPath(directory, path, files, stats, formats)
return nil
}
}
stats.filesSkipped.Add(1)
return nil
}
appendPath(directory, path, files, stats, formats)
return nil
}
func newFile(paths []string, filters *filters, sortOrder string, regexes *regexes, cache *fileCache, formats *types.Types) (string, error) {
path, err := pickFile(paths, filters, sortOrder, cache, formats)
if err != nil {
@ -294,7 +351,7 @@ func pathCount(path string) (uint32, uint32, error) {
return files, directories, nil
}
func scanPath(path string, files *files, stats *scanStats, concurrency *concurrency, formats *types.Types) error {
func scanPath(path string, files *files, filters *filters, stats *scanStats, concurrency *concurrency, formats *types.Types) error {
var wg sync.WaitGroup
err := filepath.WalkDir(path, func(p string, info os.DirEntry, err error) error {
@ -321,15 +378,10 @@ func scanPath(path string, files *files, stats *scanStats, concurrency *concurre
fmt.Println(err)
}
if !formats.Validate(path) {
stats.filesSkipped.Add(1)
return
err = appendPaths(path, files, filters, stats, formats)
if err != nil {
fmt.Println(err)
}
files.append(path)
stats.filesMatched.Add(1)
}()
case info.IsDir():
files, directories, err := pathCount(p)
@ -360,10 +412,16 @@ func scanPath(path string, files *files, stats *scanStats, concurrency *concurre
return nil
}
func scanPaths(paths []string, sort string, cache *fileCache, formats *types.Types) []string {
func fileList(paths []string, filters *filters, sort string, cache *fileCache, formats *types.Types) ([]string, bool) {
if Cache && filters.isEmpty() && !cache.isEmpty() {
return cache.List(), true
}
var fileList []string
files := &files{
mutex: sync.RWMutex{},
list: []string{},
list: make(map[string][]string),
}
stats := &scanStats{
@ -393,7 +451,7 @@ func scanPaths(paths []string, sort string, cache *fileCache, formats *types.Typ
wg.Done()
}()
err := scanPath(paths[i], files, stats, concurrency, formats)
err := scanPath(paths[i], files, filters, stats, concurrency, formats)
if err != nil {
fmt.Println(err)
}
@ -402,9 +460,10 @@ func scanPaths(paths []string, sort string, cache *fileCache, formats *types.Typ
wg.Wait()
fileList = prepareDirectories(files, sort)
if stats.filesMatched.Load() < 1 {
fmt.Println("No files matched")
return []string{}
return []string{}, false
}
if Verbose {
@ -418,32 +477,35 @@ func scanPaths(paths []string, sort string, cache *fileCache, formats *types.Typ
)
}
return files.list
if Cache && filters.isEmpty() {
cache.set(fileList)
}
return fileList, false
}
func fileList(paths []string, filters *filters, sort string, cache *fileCache, formats *types.Types) []string {
switch {
case Cache && !cache.isEmpty() && filters.isEmpty():
return cache.List()
case Cache && !cache.isEmpty() && !filters.isEmpty():
return filters.apply(cache.List())
case Cache && cache.isEmpty() && !filters.isEmpty():
cache.set(scanPaths(paths, sort, cache, formats))
return filters.apply(cache.List())
case Cache && cache.isEmpty() && filters.isEmpty():
cache.set(scanPaths(paths, sort, cache, formats))
return cache.List()
case !Cache && !filters.isEmpty():
return filters.apply(scanPaths(paths, sort, cache, formats))
default:
return scanPaths(paths, sort, cache, formats)
func prepareDirectories(files *files, sort string) []string {
directories := []string{}
keys := make([]string, len(files.list))
i := 0
for k := range files.list {
keys[i] = k
i++
}
for i := 0; i < len(keys); i++ {
directories = append(directories, files.list[keys[i]]...)
}
return directories
}
func pickFile(args []string, filters *filters, sort string, cache *fileCache, formats *types.Types) (string, error) {
list := fileList(args, filters, sort, cache, formats)
fileList, fromCache := fileList(args, filters, sort, cache, formats)
fileCount := len(list)
fileCount := len(fileList)
if fileCount < 1 {
return "", ErrNoMediaFound
@ -459,7 +521,27 @@ func pickFile(args []string, filters *filters, sort string, cache *fileCache, fo
return "", err
}
return list[val], nil
for i := 0; i < fileCount; i++ {
switch {
case val >= fileCount:
val = 0
case val < fileCount-1:
val++
}
path := fileList[val]
switch {
case !fromCache && formats.Validate(path):
return path, nil
case !fromCache:
continue
default:
return path, nil
}
}
return "", ErrNoMediaFound
}
func normalizePath(path string) (string, error) {

View File

@ -4,10 +4,7 @@ Copyright © 2023 Seednode <seednode@seedno.de>
package cmd
import (
"slices"
"strings"
)
import "strings"
type filters struct {
included []string
@ -33,27 +30,3 @@ func (filters *filters) hasExcludes() bool {
func (filters *filters) excludes() string {
return strings.Join(filters.excluded, ",")
}
func (filters *filters) apply(fileList []string) []string {
result := make([]string, len(fileList))
copy(result, fileList)
if filters.hasExcludes() {
for _, exclude := range filters.excluded {
result = slices.DeleteFunc(fileList, func(s string) bool {
return strings.Contains(strings.ToLower(s), strings.ToLower(exclude))
})
}
}
if filters.hasIncludes() {
for _, include := range filters.included {
result = slices.DeleteFunc(fileList, func(s string) bool {
return !strings.Contains(strings.ToLower(s), strings.ToLower(include))
})
}
}
return result
}

View File

@ -11,7 +11,7 @@ import (
)
const (
ReleaseVersion string = "0.87.0"
ReleaseVersion string = "0.85.1"
)
var (
@ -21,7 +21,6 @@ var (
Cache bool
CacheFile string
Code bool
CodeTheme string
Filtering bool
Flash bool
Handlers bool
@ -38,6 +37,7 @@ var (
Russian bool
Sorting bool
Text bool
Theme string
Verbose bool
Version bool
Videos bool
@ -71,7 +71,6 @@ func init() {
rootCmd.Flags().BoolVarP(&Cache, "cache", "c", false, "generate directory cache at startup")
rootCmd.Flags().StringVar(&CacheFile, "cache-file", "", "path to optional persistent cache file")
rootCmd.Flags().BoolVar(&Code, "code", false, "enable support for source code files")
rootCmd.Flags().StringVar(&CodeTheme, "code-theme", "solarized-dark256", "theme for source code syntax highlighting")
rootCmd.Flags().BoolVarP(&Filtering, "filter", "f", false, "enable filtering")
rootCmd.Flags().BoolVar(&Flash, "flash", false, "enable support for shockwave flash files (via ruffle.rs)")
rootCmd.Flags().BoolVar(&Handlers, "handlers", false, "display registered handlers (for debugging)")
@ -88,6 +87,7 @@ func init() {
rootCmd.Flags().BoolVar(&Russian, "russian", false, "remove selected images after serving")
rootCmd.Flags().BoolVarP(&Sorting, "sort", "s", false, "enable sorting")
rootCmd.Flags().BoolVar(&Text, "text", false, "enable support for text files")
rootCmd.Flags().StringVar(&Theme, "theme", "solarized-dark256", "theme for source code syntax highlighting")
rootCmd.Flags().BoolVarP(&Verbose, "verbose", "v", false, "log accessed files and other information to stdout")
rootCmd.Flags().BoolVarP(&Version, "version", "V", false, "display version and exit")
rootCmd.Flags().BoolVar(&Videos, "video", false, "enable support for video files")

View File

@ -331,7 +331,7 @@ func ServePage(args []string) error {
}
if Code || All {
formats.Add(code.New(CodeTheme))
formats.Add(code.New(Theme))
}
if Flash || All {

Binary file not shown.