Compare commits
3 Commits
cbf7218453
...
3ea2227a9f
Author | SHA1 | Date |
---|---|---|
Seednode | 3ea2227a9f | |
Seednode | b5d08b5b6d | |
Seednode | d7bc6e2451 |
18
README.md
|
@ -8,8 +8,6 @@ A new file will be selected if you open `/` directly, or if you click on any dis
|
||||||
|
|
||||||
Browser history is preserved, so you can always go back to any previously displayed media.
|
Browser history is preserved, so you can always go back to any previously displayed media.
|
||||||
|
|
||||||
Supported file types and extensions are listed in the corresponding source files in `formats/`.
|
|
||||||
|
|
||||||
Feature requests, code criticism, bug reports, general chit-chat, and unrelated angst accepted at `roulette@seedno.de`.
|
Feature requests, code criticism, bug reports, general chit-chat, and unrelated angst accepted at `roulette@seedno.de`.
|
||||||
|
|
||||||
Static binary builds available [here](https://cdn.seedno.de/builds/roulette).
|
Static binary builds available [here](https://cdn.seedno.de/builds/roulette).
|
||||||
|
@ -78,13 +76,17 @@ The cache can be regenerated at any time by accessing the `/clear_cache` endpoin
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
If the `-i|--index` flag is passed, four additional endpoints are registered.
|
## Info
|
||||||
|
|
||||||
|
If the `-i|--info` flag is passed, six additional endpoints are registered.
|
||||||
|
|
||||||
The first of these—`/html` and `/json`—return the contents of the index, in HTML and JSON formats respectively.
|
The first of these—`/html` and `/json`—return the contents of the index, in HTML and JSON formats respectively.
|
||||||
|
|
||||||
|
If `--page-length` is also set, these can be viewed in paginated form by appending `/n`, e.g. `/html/5` for the fifth page.
|
||||||
|
|
||||||
This can prove useful when confirming whether the index is generated successfully, or whether a given file is in the index.
|
This can prove useful when confirming whether the index is generated successfully, or whether a given file is in the index.
|
||||||
|
|
||||||
The other two endpoints—`/extensions` and `/mime_types`—return the registered file types.
|
The remaining four endpoints—`/available_extensions`, `/enabled_extensions`, `/available_mime_types` and `/enabled_mime_types`—return information about the registered file types.
|
||||||
|
|
||||||
## Statistics
|
## Statistics
|
||||||
|
|
||||||
|
@ -92,6 +94,8 @@ If the `--stats` flag is passed, an additional endpoint, `/stats`, is registered
|
||||||
|
|
||||||
When accessed, this endpoint returns a JSON document listing every file served, along with the number of times it has been served, its filesize, and timestamps of when it was served.
|
When accessed, this endpoint returns a JSON document listing every file served, along with the number of times it has been served, its filesize, and timestamps of when it was served.
|
||||||
|
|
||||||
|
If `--page-length` is also set, this can be viewed in paginated form by appending `/n`, e.g. `/stats/5` for the fifth page.
|
||||||
|
|
||||||
## Russian
|
## Russian
|
||||||
If the `--russian` flag is passed, everything functions exactly as you would expect.
|
If the `--russian` flag is passed, everything functions exactly as you would expect.
|
||||||
|
|
||||||
|
@ -111,7 +115,7 @@ Usage:
|
||||||
roulette <path> [path]... [flags]
|
roulette <path> [path]... [flags]
|
||||||
|
|
||||||
Flags:
|
Flags:
|
||||||
--all enable all supported file types
|
-a, --all enable all supported file types
|
||||||
--audio enable support for audio files
|
--audio enable support for audio files
|
||||||
-b, --bind string address to bind to (default "0.0.0.0")
|
-b, --bind string address to bind to (default "0.0.0.0")
|
||||||
-c, --cache generate directory cache at startup
|
-c, --cache generate directory cache at startup
|
||||||
|
@ -120,7 +124,7 @@ Flags:
|
||||||
--flash enable support for shockwave flash files (via ruffle.rs)
|
--flash enable support for shockwave flash files (via ruffle.rs)
|
||||||
-h, --help help for roulette
|
-h, --help help for roulette
|
||||||
--images enable support for image files
|
--images enable support for image files
|
||||||
-i, --index expose index endpoints
|
-i, --info expose informational endpoints
|
||||||
--maximum-files uint32 skip directories with file counts above this value (default 4294967295)
|
--maximum-files uint32 skip directories with file counts above this value (default 4294967295)
|
||||||
--minimum-files uint32 skip directories with file counts below this value (default 1)
|
--minimum-files uint32 skip directories with file counts below this value (default 1)
|
||||||
--page-length uint32 pagination length for statistics and debug pages
|
--page-length uint32 pagination length for statistics and debug pages
|
||||||
|
@ -133,7 +137,7 @@ Flags:
|
||||||
--stats expose stats endpoint
|
--stats expose stats endpoint
|
||||||
--stats-file string path to optional persistent stats file
|
--stats-file string path to optional persistent stats file
|
||||||
--text enable support for text files
|
--text enable support for text files
|
||||||
-v, --verbose log accessed files to stdout
|
-v, --verbose log accessed files and other information to stdout
|
||||||
-V, --version display version and exit
|
-V, --version display version and exit
|
||||||
--video enable support for video files
|
--video enable support for video files
|
||||||
```
|
```
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
/*
|
||||||
|
Copyright © 2023 Seednode <seednode@seedno.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/gob"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/julienschmidt/httprouter"
|
||||||
|
"github.com/klauspost/compress/zstd"
|
||||||
|
"seedno.de/seednode/roulette/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FileIndex struct {
|
||||||
|
mutex sync.RWMutex
|
||||||
|
list []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *FileIndex) Index() []string {
|
||||||
|
i.mutex.RLock()
|
||||||
|
val := i.list
|
||||||
|
i.mutex.RUnlock()
|
||||||
|
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *FileIndex) Remove(path string) {
|
||||||
|
i.mutex.RLock()
|
||||||
|
tempIndex := make([]string, len(i.list))
|
||||||
|
copy(tempIndex, i.list)
|
||||||
|
i.mutex.RUnlock()
|
||||||
|
|
||||||
|
var position int
|
||||||
|
|
||||||
|
for k, v := range tempIndex {
|
||||||
|
if path == v {
|
||||||
|
position = k
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tempIndex[position] = tempIndex[len(tempIndex)-1]
|
||||||
|
|
||||||
|
i.mutex.Lock()
|
||||||
|
i.list = make([]string, len(tempIndex)-1)
|
||||||
|
copy(i.list, tempIndex[:len(tempIndex)-1])
|
||||||
|
i.mutex.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *FileIndex) setIndex(val []string) {
|
||||||
|
i.mutex.Lock()
|
||||||
|
i.list = val
|
||||||
|
i.mutex.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *FileIndex) generateCache(args []string, formats *types.Types) {
|
||||||
|
i.mutex.Lock()
|
||||||
|
i.list = []string{}
|
||||||
|
i.mutex.Unlock()
|
||||||
|
|
||||||
|
fileList(args, &Filters{}, "", i, formats)
|
||||||
|
|
||||||
|
if Cache && CacheFile != "" {
|
||||||
|
i.Export(CacheFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *FileIndex) IsEmpty() bool {
|
||||||
|
i.mutex.RLock()
|
||||||
|
length := len(i.list)
|
||||||
|
i.mutex.RUnlock()
|
||||||
|
|
||||||
|
return length == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *FileIndex) Export(path string) error {
|
||||||
|
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
z, err := zstd.NewWriter(file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer z.Close()
|
||||||
|
|
||||||
|
enc := gob.NewEncoder(z)
|
||||||
|
|
||||||
|
i.mutex.RLock()
|
||||||
|
|
||||||
|
enc.Encode(&i.list)
|
||||||
|
|
||||||
|
i.mutex.RUnlock()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *FileIndex) Import(path string) error {
|
||||||
|
file, err := os.OpenFile(path, os.O_RDONLY, 0600)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
z, err := zstd.NewReader(file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer z.Close()
|
||||||
|
|
||||||
|
dec := gob.NewDecoder(z)
|
||||||
|
|
||||||
|
i.mutex.Lock()
|
||||||
|
|
||||||
|
err = dec.Decode(&i.list)
|
||||||
|
|
||||||
|
i.mutex.Unlock()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func serveCacheClear(args []string, index *FileIndex, formats *types.Types) httprouter.Handle {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||||
|
index.generateCache(args, formats)
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
|
|
||||||
|
w.Write([]byte("Ok"))
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,150 +5,20 @@ Copyright © 2023 Seednode <seednode@seedno.de>
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/gob"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"slices"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
"github.com/klauspost/compress/zstd"
|
|
||||||
"github.com/yosssi/gohtml"
|
"github.com/yosssi/gohtml"
|
||||||
"seedno.de/seednode/roulette/types"
|
"seedno.de/seednode/roulette/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FileIndex struct {
|
|
||||||
mutex sync.RWMutex
|
|
||||||
list []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *FileIndex) Index() []string {
|
|
||||||
i.mutex.RLock()
|
|
||||||
val := i.list
|
|
||||||
i.mutex.RUnlock()
|
|
||||||
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *FileIndex) Remove(path string) {
|
|
||||||
i.mutex.RLock()
|
|
||||||
tempIndex := make([]string, len(i.list))
|
|
||||||
copy(tempIndex, i.list)
|
|
||||||
i.mutex.RUnlock()
|
|
||||||
|
|
||||||
var position int
|
|
||||||
|
|
||||||
for k, v := range tempIndex {
|
|
||||||
if path == v {
|
|
||||||
position = k
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tempIndex[position] = tempIndex[len(tempIndex)-1]
|
|
||||||
|
|
||||||
i.mutex.Lock()
|
|
||||||
i.list = make([]string, len(tempIndex)-1)
|
|
||||||
copy(i.list, tempIndex[:len(tempIndex)-1])
|
|
||||||
i.mutex.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *FileIndex) setIndex(val []string) {
|
|
||||||
i.mutex.Lock()
|
|
||||||
i.list = val
|
|
||||||
i.mutex.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *FileIndex) generateCache(args []string, formats *types.Types) {
|
|
||||||
i.mutex.Lock()
|
|
||||||
i.list = []string{}
|
|
||||||
i.mutex.Unlock()
|
|
||||||
|
|
||||||
fileList(args, &Filters{}, "", i, formats)
|
|
||||||
|
|
||||||
if Cache && CacheFile != "" {
|
|
||||||
i.Export(CacheFile)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *FileIndex) IsEmpty() bool {
|
|
||||||
i.mutex.RLock()
|
|
||||||
length := len(i.list)
|
|
||||||
i.mutex.RUnlock()
|
|
||||||
|
|
||||||
return length == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *FileIndex) Export(path string) error {
|
|
||||||
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
z, err := zstd.NewWriter(file)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer z.Close()
|
|
||||||
|
|
||||||
enc := gob.NewEncoder(z)
|
|
||||||
|
|
||||||
i.mutex.RLock()
|
|
||||||
|
|
||||||
enc.Encode(&i.list)
|
|
||||||
|
|
||||||
i.mutex.RUnlock()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *FileIndex) Import(path string) error {
|
|
||||||
file, err := os.OpenFile(path, os.O_RDONLY, 0600)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
z, err := zstd.NewReader(file)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer z.Close()
|
|
||||||
|
|
||||||
dec := gob.NewDecoder(z)
|
|
||||||
|
|
||||||
i.mutex.Lock()
|
|
||||||
|
|
||||||
err = dec.Decode(&i.list)
|
|
||||||
|
|
||||||
i.mutex.Unlock()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func serveCacheClear(args []string, index *FileIndex, formats *types.Types) httprouter.Handle {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
||||||
index.generateCache(args, formats)
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/plain")
|
|
||||||
|
|
||||||
w.Write([]byte("Ok"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func serveIndexHtml(args []string, index *FileIndex, paginate bool) httprouter.Handle {
|
func serveIndexHtml(args []string, index *FileIndex, paginate bool) httprouter.Handle {
|
||||||
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||||
w.Header().Set("Content-Type", "text/html")
|
w.Header().Set("Content-Type", "text/html")
|
||||||
|
@ -318,30 +188,34 @@ func serveIndexJson(args []string, index *FileIndex) httprouter.Handle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveExtensions(formats *types.Types) httprouter.Handle {
|
func serveAvailableExtensions() httprouter.Handle {
|
||||||
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||||
w.Header().Set("Content-Type", "text/plain")
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
|
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
|
|
||||||
var output strings.Builder
|
response := []byte(types.SupportedFormats.GetExtensions())
|
||||||
|
|
||||||
extensions := make([]string, len(formats.Extensions))
|
w.Write(response)
|
||||||
|
|
||||||
i := 0
|
if Verbose {
|
||||||
|
fmt.Printf("%s | Served available extensions list (%s) to %s in %s\n",
|
||||||
for k := range formats.Extensions {
|
startTime.Format(LogDate),
|
||||||
extensions[i] = k
|
humanReadableSize(len(response)),
|
||||||
i++
|
realIP(r),
|
||||||
|
time.Since(startTime).Round(time.Microsecond),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
slices.Sort(extensions)
|
func serveEnabledExtensions(formats *types.Types) httprouter.Handle {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||||
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
|
|
||||||
for _, v := range extensions {
|
startTime := time.Now()
|
||||||
output.WriteString(v + "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
response := []byte(output.String())
|
response := []byte(formats.GetExtensions())
|
||||||
|
|
||||||
w.Write(response)
|
w.Write(response)
|
||||||
|
|
||||||
|
@ -356,30 +230,34 @@ func serveExtensions(formats *types.Types) httprouter.Handle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveMimeTypes(formats *types.Types) httprouter.Handle {
|
func serveAvailableMimeTypes() httprouter.Handle {
|
||||||
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||||
w.Header().Set("Content-Type", "text/plain")
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
|
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
|
|
||||||
var output strings.Builder
|
response := []byte(types.SupportedFormats.GetMimeTypes())
|
||||||
|
|
||||||
mimeTypes := make([]string, len(formats.MimeTypes))
|
w.Write(response)
|
||||||
|
|
||||||
i := 0
|
if Verbose {
|
||||||
|
fmt.Printf("%s | Served available MIME types list (%s) to %s in %s\n",
|
||||||
for k := range formats.MimeTypes {
|
startTime.Format(LogDate),
|
||||||
mimeTypes[i] = k
|
humanReadableSize(len(response)),
|
||||||
i++
|
realIP(r),
|
||||||
|
time.Since(startTime).Round(time.Microsecond),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
slices.Sort(mimeTypes)
|
func serveEnabledMimeTypes(formats *types.Types) httprouter.Handle {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||||
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
|
|
||||||
for _, v := range mimeTypes {
|
startTime := time.Now()
|
||||||
output.WriteString(v + "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
response := []byte(output.String())
|
response := []byte(formats.GetMimeTypes())
|
||||||
|
|
||||||
w.Write(response)
|
w.Write(response)
|
||||||
|
|
14
cmd/root.go
|
@ -12,7 +12,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ReleaseVersion string = "0.75.0"
|
ReleaseVersion string = "0.76.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -24,7 +24,7 @@ var (
|
||||||
Filtering bool
|
Filtering bool
|
||||||
Flash bool
|
Flash bool
|
||||||
Images bool
|
Images bool
|
||||||
Index bool
|
Info bool
|
||||||
MaximumFileCount uint32
|
MaximumFileCount uint32
|
||||||
MinimumFileCount uint32
|
MinimumFileCount uint32
|
||||||
PageLength uint32
|
PageLength uint32
|
||||||
|
@ -46,10 +46,6 @@ var (
|
||||||
Short: "Serves random media from the specified directories.",
|
Short: "Serves random media from the specified directories.",
|
||||||
Args: cobra.MinimumNArgs(1),
|
Args: cobra.MinimumNArgs(1),
|
||||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
if Index {
|
|
||||||
cmd.MarkFlagRequired("cache")
|
|
||||||
}
|
|
||||||
|
|
||||||
if RefreshInterval != "" {
|
if RefreshInterval != "" {
|
||||||
interval, err := time.ParseDuration(RefreshInterval)
|
interval, err := time.ParseDuration(RefreshInterval)
|
||||||
if err != nil || interval < 500*time.Millisecond {
|
if err != nil || interval < 500*time.Millisecond {
|
||||||
|
@ -78,7 +74,7 @@ func Execute() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.Flags().BoolVar(&All, "all", false, "enable all supported file types")
|
rootCmd.Flags().BoolVarP(&All, "all", "a", false, "enable all supported file types")
|
||||||
rootCmd.Flags().BoolVar(&Audio, "audio", false, "enable support for audio files")
|
rootCmd.Flags().BoolVar(&Audio, "audio", false, "enable support for audio files")
|
||||||
rootCmd.Flags().StringVarP(&Bind, "bind", "b", "0.0.0.0", "address to bind to")
|
rootCmd.Flags().StringVarP(&Bind, "bind", "b", "0.0.0.0", "address to bind to")
|
||||||
rootCmd.Flags().BoolVarP(&Cache, "cache", "c", false, "generate directory cache at startup")
|
rootCmd.Flags().BoolVarP(&Cache, "cache", "c", false, "generate directory cache at startup")
|
||||||
|
@ -86,7 +82,7 @@ func init() {
|
||||||
rootCmd.Flags().BoolVarP(&Filtering, "filter", "f", false, "enable filtering")
|
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(&Flash, "flash", false, "enable support for shockwave flash files (via ruffle.rs)")
|
||||||
rootCmd.Flags().BoolVar(&Images, "images", false, "enable support for image files")
|
rootCmd.Flags().BoolVar(&Images, "images", false, "enable support for image files")
|
||||||
rootCmd.Flags().BoolVarP(&Index, "index", "i", false, "expose index endpoints")
|
rootCmd.Flags().BoolVarP(&Info, "info", "i", false, "expose informational endpoints")
|
||||||
rootCmd.Flags().Uint32Var(&MaximumFileCount, "maximum-files", 1<<32-1, "skip directories with file counts above this value")
|
rootCmd.Flags().Uint32Var(&MaximumFileCount, "maximum-files", 1<<32-1, "skip directories with file counts above this value")
|
||||||
rootCmd.Flags().Uint32Var(&MinimumFileCount, "minimum-files", 1, "skip directories with file counts below this value")
|
rootCmd.Flags().Uint32Var(&MinimumFileCount, "minimum-files", 1, "skip directories with file counts below this value")
|
||||||
rootCmd.Flags().Uint32Var(&PageLength, "page-length", 0, "pagination length for statistics and debug pages")
|
rootCmd.Flags().Uint32Var(&PageLength, "page-length", 0, "pagination length for statistics and debug pages")
|
||||||
|
@ -99,7 +95,7 @@ func init() {
|
||||||
rootCmd.Flags().BoolVar(&Statistics, "stats", false, "expose stats endpoint")
|
rootCmd.Flags().BoolVar(&Statistics, "stats", false, "expose stats endpoint")
|
||||||
rootCmd.Flags().StringVar(&StatisticsFile, "stats-file", "", "path to optional persistent stats file")
|
rootCmd.Flags().StringVar(&StatisticsFile, "stats-file", "", "path to optional persistent stats file")
|
||||||
rootCmd.Flags().BoolVar(&Text, "text", false, "enable support for text files")
|
rootCmd.Flags().BoolVar(&Text, "text", false, "enable support for text files")
|
||||||
rootCmd.Flags().BoolVarP(&Verbose, "verbose", "v", false, "log accessed files to stdout")
|
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().BoolVarP(&Version, "version", "V", false, "display version and exit")
|
||||||
rootCmd.Flags().BoolVar(&Videos, "video", false, "enable support for video files")
|
rootCmd.Flags().BoolVar(&Videos, "video", false, "enable support for video files")
|
||||||
|
|
||||||
|
|
42
cmd/web.go
|
@ -27,6 +27,11 @@ import (
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
"github.com/yosssi/gohtml"
|
"github.com/yosssi/gohtml"
|
||||||
"seedno.de/seednode/roulette/types"
|
"seedno.de/seednode/roulette/types"
|
||||||
|
"seedno.de/seednode/roulette/types/audio"
|
||||||
|
"seedno.de/seednode/roulette/types/flash"
|
||||||
|
"seedno.de/seednode/roulette/types/images"
|
||||||
|
"seedno.de/seednode/roulette/types/text"
|
||||||
|
"seedno.de/seednode/roulette/types/video"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -317,25 +322,25 @@ func ServePage(args []string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if Audio || All {
|
if Audio || All {
|
||||||
formats.Add(types.Audio{})
|
formats.Add(audio.Format{})
|
||||||
}
|
}
|
||||||
|
|
||||||
if Flash || All {
|
if Flash || All {
|
||||||
formats.Add(types.Flash{})
|
formats.Add(flash.Format{})
|
||||||
}
|
}
|
||||||
|
|
||||||
if Text || All {
|
if Text || All {
|
||||||
formats.Add(types.Text{})
|
formats.Add(text.Format{})
|
||||||
}
|
}
|
||||||
|
|
||||||
if Videos || All {
|
if Videos || All {
|
||||||
formats.Add(types.Video{})
|
formats.Add(video.Format{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// enable image support if no other flags are passed, to retain backwards compatibility
|
// enable image support if no other flags are passed, to retain backwards compatibility
|
||||||
// to be replaced with rootCmd.MarkFlagsOneRequired on next spf13/cobra update
|
// to be replaced with rootCmd.MarkFlagsOneRequired on next spf13/cobra update
|
||||||
if Images || All || len(formats.Extensions) == 0 {
|
if Images || All || len(formats.Extensions) == 0 {
|
||||||
formats.Add(types.Images{})
|
formats.Add(images.Format{})
|
||||||
}
|
}
|
||||||
|
|
||||||
paths, err := normalizePaths(args, formats)
|
paths, err := normalizePaths(args, formats)
|
||||||
|
@ -408,20 +413,23 @@ func ServePage(args []string) error {
|
||||||
mux.GET("/clear_cache", serveCacheClear(args, index, formats))
|
mux.GET("/clear_cache", serveCacheClear(args, index, formats))
|
||||||
}
|
}
|
||||||
|
|
||||||
if Index {
|
if Info {
|
||||||
mux.GET("/html/", serveIndexHtml(args, index, false))
|
if Cache {
|
||||||
if PageLength != 0 {
|
mux.GET("/html/", serveIndexHtml(args, index, false))
|
||||||
mux.GET("/html/:page", serveIndexHtml(args, index, true))
|
if PageLength != 0 {
|
||||||
|
mux.GET("/html/:page", serveIndexHtml(args, index, true))
|
||||||
|
}
|
||||||
|
|
||||||
|
mux.GET("/json", serveIndexJson(args, index))
|
||||||
|
if PageLength != 0 {
|
||||||
|
mux.GET("/json/:page", serveIndexJson(args, index))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mux.GET("/json", serveIndexJson(args, index))
|
mux.GET("/available_extensions", serveAvailableExtensions())
|
||||||
if PageLength != 0 {
|
mux.GET("/enabled_extensions", serveEnabledExtensions(formats))
|
||||||
mux.GET("/json/:page", serveIndexJson(args, index))
|
mux.GET("/available_mime_types", serveAvailableMimeTypes())
|
||||||
}
|
mux.GET("/enabled_mime_types", serveEnabledMimeTypes(formats))
|
||||||
|
|
||||||
mux.GET("/extensions", serveExtensions(formats))
|
|
||||||
|
|
||||||
mux.GET("/mime_types", serveMimeTypes(formats))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if Profile {
|
if Profile {
|
||||||
|
|
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 96 KiB |