Compare commits
3 Commits
5dc218c60e
...
9844f4a2e1
Author | SHA1 | Date |
---|---|---|
Seednode | 9844f4a2e1 | |
Seednode | 9ae0aa60d3 | |
Seednode | 84c25310da |
|
@ -116,6 +116,7 @@ Flags:
|
||||||
--fallback serve files as application/octet-stream if no matching format is registered
|
--fallback serve files as application/octet-stream if no matching format is registered
|
||||||
-f, --filter enable filtering
|
-f, --filter enable filtering
|
||||||
--flash enable support for shockwave flash files (via ruffle.rs)
|
--flash enable support for shockwave flash files (via ruffle.rs)
|
||||||
|
--fun adds a bit of excitement to your day
|
||||||
--handlers display registered handlers (for debugging)
|
--handlers display registered handlers (for debugging)
|
||||||
-h, --help help for roulette
|
-h, --help help for roulette
|
||||||
--images enable support for image files
|
--images enable support for image files
|
||||||
|
@ -123,7 +124,7 @@ Flags:
|
||||||
--index-file string path to optional persistent index file
|
--index-file string path to optional persistent index file
|
||||||
-i, --info expose informational endpoints
|
-i, --info expose informational endpoints
|
||||||
--max-file-count int skip directories with file counts above this value (default 2147483647)
|
--max-file-count int skip directories with file counts above this value (default 2147483647)
|
||||||
--min-file-count int skip directories with file counts below this value (default 1)
|
--min-file-count int skip directories with file counts below this value
|
||||||
--page-length int pagination length for info pages
|
--page-length int pagination length for info pages
|
||||||
-p, --port int port to listen on (default 8080)
|
-p, --port int port to listen on (default 8080)
|
||||||
--prefix string root path for http handlers (for reverse proxying) (default "/")
|
--prefix string root path for http handlers (for reverse proxying) (default "/")
|
||||||
|
|
32
cmd/files.go
32
cmd/files.go
|
@ -72,21 +72,21 @@ func kill(path string, index *fileIndex) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFile(list []string, sortOrder string, regexes *regexes, formats *types.Types) (string, error) {
|
func newFile(list []string, sortOrder string, regexes *regexes, formats types.Types) (string, error) {
|
||||||
path, err := pickFile(list)
|
path, err := pickFile(list)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if sortOrder == "asc" || sortOrder == "desc" {
|
if sortOrder == "asc" || sortOrder == "desc" {
|
||||||
splitPath, length, err := split(path, regexes)
|
splitPath, err := split(path, regexes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case sortOrder == "asc":
|
case sortOrder == "asc":
|
||||||
splitPath.number = fmt.Sprintf("%0*d", length, 1)
|
splitPath.number = fmt.Sprintf("%0*d", len(splitPath.number), 1)
|
||||||
|
|
||||||
path, err = tryExtensions(splitPath, formats)
|
path, err = tryExtensions(splitPath, formats)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -118,8 +118,8 @@ func newFile(list []string, sortOrder string, regexes *regexes, formats *types.T
|
||||||
return path, nil
|
return path, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func nextFile(filePath, sortOrder string, regexes *regexes, formats *types.Types) (string, error) {
|
func nextFile(filePath, sortOrder string, regexes *regexes, formats types.Types) (string, error) {
|
||||||
splitPath, _, err := split(filePath, regexes)
|
splitPath, err := split(filePath, regexes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -141,10 +141,10 @@ func nextFile(filePath, sortOrder string, regexes *regexes, formats *types.Types
|
||||||
return path, err
|
return path, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func tryExtensions(splitPath *splitPath, formats *types.Types) (string, error) {
|
func tryExtensions(splitPath *splitPath, formats types.Types) (string, error) {
|
||||||
var path string
|
var path string
|
||||||
|
|
||||||
for extension := range formats.Extensions {
|
for extension := range formats {
|
||||||
path = fmt.Sprintf("%s%s%s", splitPath.base, splitPath.number, extension)
|
path = fmt.Sprintf("%s%s%s", splitPath.base, splitPath.number, extension)
|
||||||
|
|
||||||
exists, err := fileExists(path)
|
exists, err := fileExists(path)
|
||||||
|
@ -198,7 +198,7 @@ func pathIsValid(path string, paths []string) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasSupportedFiles(path string, formats *types.Types) (bool, error) {
|
func hasSupportedFiles(path string, formats types.Types) (bool, error) {
|
||||||
hasRegisteredFiles := make(chan bool, 1)
|
hasRegisteredFiles := make(chan bool, 1)
|
||||||
|
|
||||||
err := filepath.WalkDir(path, func(p string, info os.DirEntry, err error) error {
|
err := filepath.WalkDir(path, func(p string, info os.DirEntry, err error) error {
|
||||||
|
@ -229,7 +229,7 @@ func hasSupportedFiles(path string, formats *types.Types) (bool, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func walkPath(path string, fileChannel chan<- string, stats *scanStatsChannels, formats *types.Types) error {
|
func walkPath(path string, fileChannel chan<- string, stats *scanStatsChannels, formats types.Types) error {
|
||||||
errorChannel := make(chan error)
|
errorChannel := make(chan error)
|
||||||
done := make(chan bool, 1)
|
done := make(chan bool, 1)
|
||||||
|
|
||||||
|
@ -321,7 +321,7 @@ Poll:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func scanPaths(paths []string, sort string, index *fileIndex, formats *types.Types) ([]string, error) {
|
func scanPaths(paths []string, sort string, index *fileIndex, formats types.Types) ([]string, error) {
|
||||||
var list []string
|
var list []string
|
||||||
|
|
||||||
fileChannel := make(chan string)
|
fileChannel := make(chan string)
|
||||||
|
@ -375,13 +375,13 @@ Poll:
|
||||||
case path := <-fileChannel:
|
case path := <-fileChannel:
|
||||||
list = append(list, path)
|
list = append(list, path)
|
||||||
case stat := <-statsChannels.filesMatched:
|
case stat := <-statsChannels.filesMatched:
|
||||||
stats.filesMatched = stats.filesMatched + stat
|
stats.filesMatched += stat
|
||||||
case stat := <-statsChannels.filesSkipped:
|
case stat := <-statsChannels.filesSkipped:
|
||||||
stats.filesSkipped = stats.filesSkipped + stat
|
stats.filesSkipped += stat
|
||||||
case stat := <-statsChannels.directoriesMatched:
|
case stat := <-statsChannels.directoriesMatched:
|
||||||
stats.directoriesMatched = stats.directoriesMatched + stat
|
stats.directoriesMatched += stat
|
||||||
case stat := <-statsChannels.directoriesSkipped:
|
case stat := <-statsChannels.directoriesSkipped:
|
||||||
stats.directoriesSkipped = stats.directoriesSkipped + stat
|
stats.directoriesSkipped += stat
|
||||||
case err := <-errorChannel:
|
case err := <-errorChannel:
|
||||||
return []string{}, err
|
return []string{}, err
|
||||||
case <-done:
|
case <-done:
|
||||||
|
@ -409,7 +409,7 @@ Poll:
|
||||||
return list, nil
|
return list, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fileList(paths []string, filters *filters, sort string, index *fileIndex, formats *types.Types) ([]string, error) {
|
func fileList(paths []string, filters *filters, sort string, index *fileIndex, formats types.Types) ([]string, error) {
|
||||||
switch {
|
switch {
|
||||||
case Index && !index.isEmpty() && filters.isEmpty():
|
case Index && !index.isEmpty() && filters.isEmpty():
|
||||||
return index.List(), nil
|
return index.List(), nil
|
||||||
|
@ -493,7 +493,7 @@ func normalizePath(path string) (string, error) {
|
||||||
return absolutePath, nil
|
return absolutePath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validatePaths(args []string, formats *types.Types) ([]string, error) {
|
func validatePaths(args []string, formats types.Types) ([]string, error) {
|
||||||
var paths []string
|
var paths []string
|
||||||
|
|
||||||
for i := 0; i < len(args); i++ {
|
for i := 0; i < len(args); i++ {
|
||||||
|
|
16
cmd/index.go
16
cmd/index.go
|
@ -104,7 +104,10 @@ func (index *fileIndex) Export(path string) error {
|
||||||
enc := gob.NewEncoder(z)
|
enc := gob.NewEncoder(z)
|
||||||
|
|
||||||
index.mutex.RLock()
|
index.mutex.RLock()
|
||||||
enc.Encode(&index.list)
|
err = enc.Encode(&index.list)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
length := len(index.list)
|
length := len(index.list)
|
||||||
index.mutex.RUnlock()
|
index.mutex.RUnlock()
|
||||||
|
|
||||||
|
@ -139,12 +142,11 @@ func (index *fileIndex) Import(path string) error {
|
||||||
|
|
||||||
index.mutex.Lock()
|
index.mutex.Lock()
|
||||||
err = dec.Decode(&index.list)
|
err = dec.Decode(&index.list)
|
||||||
length := len(index.list)
|
|
||||||
index.mutex.Unlock()
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
length := len(index.list)
|
||||||
|
index.mutex.Unlock()
|
||||||
|
|
||||||
if Verbose {
|
if Verbose {
|
||||||
fmt.Printf("%s | INDEX: Imported %d entries from %s in %s\n",
|
fmt.Printf("%s | INDEX: Imported %d entries from %s in %s\n",
|
||||||
|
@ -158,7 +160,7 @@ func (index *fileIndex) Import(path string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveIndexRebuild(args []string, index *fileIndex, formats *types.Types, errorChannel chan<- error) httprouter.Handle {
|
func serveIndexRebuild(args []string, index *fileIndex, formats types.Types, errorChannel chan<- error) httprouter.Handle {
|
||||||
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||||
index.clear()
|
index.clear()
|
||||||
|
|
||||||
|
@ -175,13 +177,13 @@ func serveIndexRebuild(args []string, index *fileIndex, formats *types.Types, er
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func registerIndexHandlers(mux *httprouter.Router, args []string, index *fileIndex, formats *types.Types, errorChannel chan<- error) error {
|
func registerIndexHandlers(mux *httprouter.Router, args []string, index *fileIndex, formats types.Types, errorChannel chan<- error) error {
|
||||||
registerHandler(mux, Prefix+"/rebuild_index", serveIndexRebuild(args, index, formats, errorChannel))
|
registerHandler(mux, Prefix+"/rebuild_index", serveIndexRebuild(args, index, formats, errorChannel))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func importIndex(args []string, index *fileIndex, formats *types.Types) error {
|
func importIndex(args []string, index *fileIndex, formats types.Types) error {
|
||||||
skipIndex := false
|
skipIndex := false
|
||||||
|
|
||||||
if IndexFile != "" {
|
if IndexFile != "" {
|
||||||
|
|
65
cmd/info.go
65
cmd/info.go
|
@ -137,7 +137,7 @@ func serveIndexHtml(args []string, index *fileIndex, shouldPaginate bool) httpro
|
||||||
|
|
||||||
htmlBody.WriteString(`</table></body></html>`)
|
htmlBody.WriteString(`</table></body></html>`)
|
||||||
|
|
||||||
b, err := io.WriteString(w, gohtml.Format(htmlBody.String()))
|
length, err := io.WriteString(w, gohtml.Format(htmlBody.String()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -145,7 +145,7 @@ func serveIndexHtml(args []string, index *fileIndex, shouldPaginate bool) httpro
|
||||||
if Verbose {
|
if Verbose {
|
||||||
fmt.Printf("%s | SERVE: HTML index page (%s) to %s in %s\n",
|
fmt.Printf("%s | SERVE: HTML index page (%s) to %s in %s\n",
|
||||||
startTime.Format(logDate),
|
startTime.Format(logDate),
|
||||||
humanReadableSize(b),
|
humanReadableSize(length),
|
||||||
realIP(r),
|
realIP(r),
|
||||||
time.Since(startTime).Round(time.Microsecond),
|
time.Since(startTime).Round(time.Microsecond),
|
||||||
)
|
)
|
||||||
|
@ -195,12 +195,15 @@ func serveIndexJson(args []string, index *fileIndex, errorChannel chan<- error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Write(response)
|
written, err := w.Write(response)
|
||||||
|
if err != nil {
|
||||||
|
errorChannel <- err
|
||||||
|
}
|
||||||
|
|
||||||
if Verbose {
|
if Verbose {
|
||||||
fmt.Printf("%s | SERVE: JSON index page (%s) to %s in %s\n",
|
fmt.Printf("%s | SERVE: JSON index page (%s) to %s in %s\n",
|
||||||
startTime.Format(logDate),
|
startTime.Format(logDate),
|
||||||
humanReadableSize(len(response)),
|
humanReadableSize(written),
|
||||||
realIP(r),
|
realIP(r),
|
||||||
time.Since(startTime).Round(time.Microsecond),
|
time.Since(startTime).Round(time.Microsecond),
|
||||||
)
|
)
|
||||||
|
@ -208,20 +211,21 @@ func serveIndexJson(args []string, index *fileIndex, errorChannel chan<- error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveAvailableExtensions() httprouter.Handle {
|
func serveAvailableExtensions(errorChannel chan<- error) 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()
|
||||||
|
|
||||||
response := []byte(types.SupportedFormats.GetExtensions())
|
written, err := w.Write([]byte(types.SupportedFormats.GetExtensions()))
|
||||||
|
if err != nil {
|
||||||
w.Write(response)
|
errorChannel <- err
|
||||||
|
}
|
||||||
|
|
||||||
if Verbose {
|
if Verbose {
|
||||||
fmt.Printf("%s | SERVE: Available extension list (%s) to %s in %s\n",
|
fmt.Printf("%s | SERVE: Available extension list (%s) to %s in %s\n",
|
||||||
startTime.Format(logDate),
|
startTime.Format(logDate),
|
||||||
humanReadableSize(len(response)),
|
humanReadableSize(written),
|
||||||
realIP(r),
|
realIP(r),
|
||||||
time.Since(startTime).Round(time.Microsecond),
|
time.Since(startTime).Round(time.Microsecond),
|
||||||
)
|
)
|
||||||
|
@ -229,20 +233,21 @@ func serveAvailableExtensions() httprouter.Handle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveEnabledExtensions(formats *types.Types) httprouter.Handle {
|
func serveEnabledExtensions(formats types.Types, errorChannel chan<- error) 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()
|
||||||
|
|
||||||
response := []byte(formats.GetExtensions())
|
written, err := w.Write([]byte(formats.GetExtensions()))
|
||||||
|
if err != nil {
|
||||||
w.Write(response)
|
errorChannel <- err
|
||||||
|
}
|
||||||
|
|
||||||
if Verbose {
|
if Verbose {
|
||||||
fmt.Printf("%s | SERVE: Registered extension list (%s) to %s in %s\n",
|
fmt.Printf("%s | SERVE: Registered extension list (%s) to %s in %s\n",
|
||||||
startTime.Format(logDate),
|
startTime.Format(logDate),
|
||||||
humanReadableSize(len(response)),
|
humanReadableSize(written),
|
||||||
realIP(r),
|
realIP(r),
|
||||||
time.Since(startTime).Round(time.Microsecond),
|
time.Since(startTime).Round(time.Microsecond),
|
||||||
)
|
)
|
||||||
|
@ -250,20 +255,21 @@ func serveEnabledExtensions(formats *types.Types) httprouter.Handle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveAvailableMimeTypes() httprouter.Handle {
|
func serveAvailableMimeTypes(errorChannel chan<- error) 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()
|
||||||
|
|
||||||
response := []byte(types.SupportedFormats.GetMimeTypes())
|
written, err := w.Write([]byte(types.SupportedFormats.GetMimeTypes()))
|
||||||
|
if err != nil {
|
||||||
w.Write(response)
|
errorChannel <- err
|
||||||
|
}
|
||||||
|
|
||||||
if Verbose {
|
if Verbose {
|
||||||
fmt.Printf("%s | SERVE: Available MIME type list (%s) to %s in %s\n",
|
fmt.Printf("%s | SERVE: Available MIME type list (%s) to %s in %s\n",
|
||||||
startTime.Format(logDate),
|
startTime.Format(logDate),
|
||||||
humanReadableSize(len(response)),
|
humanReadableSize(written),
|
||||||
realIP(r),
|
realIP(r),
|
||||||
time.Since(startTime).Round(time.Microsecond),
|
time.Since(startTime).Round(time.Microsecond),
|
||||||
)
|
)
|
||||||
|
@ -271,20 +277,21 @@ func serveAvailableMimeTypes() httprouter.Handle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveEnabledMimeTypes(formats *types.Types) httprouter.Handle {
|
func serveEnabledMimeTypes(formats types.Types, errorChannel chan<- error) 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()
|
||||||
|
|
||||||
response := []byte(formats.GetMimeTypes())
|
written, err := w.Write([]byte(formats.GetMimeTypes()))
|
||||||
|
if err != nil {
|
||||||
w.Write(response)
|
errorChannel <- err
|
||||||
|
}
|
||||||
|
|
||||||
if Verbose {
|
if Verbose {
|
||||||
fmt.Printf("%s | SERVE: Registered MIME type list (%s) to %s in %s\n",
|
fmt.Printf("%s | SERVE: Registered MIME type list (%s) to %s in %s\n",
|
||||||
startTime.Format(logDate),
|
startTime.Format(logDate),
|
||||||
humanReadableSize(len(response)),
|
humanReadableSize(written),
|
||||||
realIP(r),
|
realIP(r),
|
||||||
time.Since(startTime).Round(time.Microsecond),
|
time.Since(startTime).Round(time.Microsecond),
|
||||||
)
|
)
|
||||||
|
@ -292,7 +299,7 @@ func serveEnabledMimeTypes(formats *types.Types) httprouter.Handle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func registerInfoHandlers(mux *httprouter.Router, args []string, index *fileIndex, formats *types.Types, errorChannel chan<- error) {
|
func registerInfoHandlers(mux *httprouter.Router, args []string, index *fileIndex, formats types.Types, errorChannel chan<- error) {
|
||||||
if Index {
|
if Index {
|
||||||
registerHandler(mux, Prefix+"/html", serveIndexHtml(args, index, false))
|
registerHandler(mux, Prefix+"/html", serveIndexHtml(args, index, false))
|
||||||
if PageLength != 0 {
|
if PageLength != 0 {
|
||||||
|
@ -305,8 +312,8 @@ func registerInfoHandlers(mux *httprouter.Router, args []string, index *fileInde
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
registerHandler(mux, Prefix+"/available_extensions", serveAvailableExtensions())
|
registerHandler(mux, Prefix+"/available_extensions", serveAvailableExtensions(errorChannel))
|
||||||
registerHandler(mux, Prefix+"/enabled_extensions", serveEnabledExtensions(formats))
|
registerHandler(mux, Prefix+"/enabled_extensions", serveEnabledExtensions(formats, errorChannel))
|
||||||
registerHandler(mux, Prefix+"/available_mime_types", serveAvailableMimeTypes())
|
registerHandler(mux, Prefix+"/available_mime_types", serveAvailableMimeTypes(errorChannel))
|
||||||
registerHandler(mux, Prefix+"/enabled_mime_types", serveEnabledMimeTypes(formats))
|
registerHandler(mux, Prefix+"/enabled_mime_types", serveEnabledMimeTypes(formats, errorChannel))
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ReleaseVersion string = "2.4.0"
|
ReleaseVersion string = "2.6.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -26,6 +26,7 @@ var (
|
||||||
Fallback bool
|
Fallback bool
|
||||||
Filtering bool
|
Filtering bool
|
||||||
Flash bool
|
Flash bool
|
||||||
|
Fun bool
|
||||||
Handlers bool
|
Handlers bool
|
||||||
Images bool
|
Images bool
|
||||||
Index bool
|
Index bool
|
||||||
|
@ -91,6 +92,7 @@ func init() {
|
||||||
rootCmd.Flags().BoolVar(&Fallback, "fallback", false, "serve files as application/octet-stream if no matching format is registered")
|
rootCmd.Flags().BoolVar(&Fallback, "fallback", false, "serve files as application/octet-stream if no matching format is registered")
|
||||||
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(&Fun, "fun", false, "adds a bit of excitement to your day")
|
||||||
rootCmd.Flags().BoolVar(&Handlers, "handlers", false, "display registered handlers (for debugging)")
|
rootCmd.Flags().BoolVar(&Handlers, "handlers", false, "display registered handlers (for debugging)")
|
||||||
rootCmd.Flags().BoolVar(&Images, "images", false, "enable support for image files")
|
rootCmd.Flags().BoolVar(&Images, "images", false, "enable support for image files")
|
||||||
rootCmd.Flags().BoolVar(&Index, "index", false, "generate index of supported file paths at startup")
|
rootCmd.Flags().BoolVar(&Index, "index", false, "generate index of supported file paths at startup")
|
||||||
|
|
28
cmd/sort.go
28
cmd/sort.go
|
@ -17,41 +17,35 @@ type splitPath struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (splitPath *splitPath) increment() {
|
func (splitPath *splitPath) increment() {
|
||||||
length := len(splitPath.number)
|
|
||||||
|
|
||||||
asInt, err := strconv.Atoi(splitPath.number)
|
asInt, err := strconv.Atoi(splitPath.number)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
splitPath.number = fmt.Sprintf("%0*d", length, asInt+1)
|
splitPath.number = fmt.Sprintf("%0*d", len(splitPath.number), asInt+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (splitPath *splitPath) decrement() {
|
func (splitPath *splitPath) decrement() {
|
||||||
length := len(splitPath.number)
|
|
||||||
|
|
||||||
asInt, err := strconv.Atoi(splitPath.number)
|
asInt, err := strconv.Atoi(splitPath.number)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
splitPath.number = fmt.Sprintf("%0*d", length, asInt-1)
|
splitPath.number = fmt.Sprintf("%0*d", len(splitPath.number), asInt-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func split(path string, regexes *regexes) (*splitPath, int, error) {
|
func split(path string, regexes *regexes) (*splitPath, error) {
|
||||||
p := splitPath{}
|
|
||||||
|
|
||||||
split := regexes.filename.FindAllStringSubmatch(path, -1)
|
split := regexes.filename.FindAllStringSubmatch(path, -1)
|
||||||
|
|
||||||
if len(split) < 1 || len(split[0]) < 3 {
|
if len(split) < 1 || len(split[0]) < 3 {
|
||||||
return &splitPath{}, 0, nil
|
return &splitPath{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
p.base = split[0][1]
|
p := &splitPath{
|
||||||
|
base: split[0][1],
|
||||||
p.number = split[0][2]
|
number: split[0][2],
|
||||||
|
extension: split[0][3],
|
||||||
p.extension = split[0][3]
|
}
|
||||||
|
|
||||||
return &p, len(p.number), nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
22
cmd/web.go
22
cmd/web.go
|
@ -153,7 +153,7 @@ func serveStaticFile(paths []string, index *fileIndex, errorChannel chan<- error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveRoot(paths []string, regexes *regexes, index *fileIndex, formats *types.Types, errorChannel chan<- error) httprouter.Handle {
|
func serveRoot(paths []string, regexes *regexes, index *fileIndex, formats types.Types, errorChannel chan<- error) httprouter.Handle {
|
||||||
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||||
refererUri, err := stripQueryParams(refererToUri(r.Referer()))
|
refererUri, err := stripQueryParams(refererToUri(r.Referer()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -236,7 +236,7 @@ func serveRoot(paths []string, regexes *regexes, index *fileIndex, formats *type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveMedia(paths []string, regexes *regexes, index *fileIndex, formats *types.Types, errorChannel chan<- error) httprouter.Handle {
|
func serveMedia(paths []string, regexes *regexes, index *fileIndex, formats types.Types, errorChannel chan<- error) httprouter.Handle {
|
||||||
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||||
filters := &filters{
|
filters := &filters{
|
||||||
included: splitQueryParams(r.URL.Query().Get("include"), regexes),
|
included: splitQueryParams(r.URL.Query().Get("include"), regexes),
|
||||||
|
@ -433,34 +433,32 @@ func ServePage(args []string) error {
|
||||||
return errors.New("invalid bind address provided")
|
return errors.New("invalid bind address provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
formats := &types.Types{
|
formats := make(types.Types)
|
||||||
Extensions: make(map[string]types.Type),
|
|
||||||
}
|
|
||||||
|
|
||||||
if Audio || All {
|
if Audio || All {
|
||||||
formats.Add(audio.Format{})
|
formats.Add(audio.Format{Fun: Fun})
|
||||||
}
|
}
|
||||||
|
|
||||||
if Code || All {
|
if Code || All {
|
||||||
formats.Add(code.Format{Theme: CodeTheme})
|
formats.Add(code.Format{Fun: Fun, Theme: CodeTheme})
|
||||||
}
|
}
|
||||||
|
|
||||||
if Flash || All {
|
if Flash || All {
|
||||||
formats.Add(flash.Format{})
|
formats.Add(flash.Format{Fun: Fun})
|
||||||
}
|
}
|
||||||
|
|
||||||
if Text || All {
|
if Text || All {
|
||||||
formats.Add(text.Format{})
|
formats.Add(text.Format{Fun: Fun})
|
||||||
}
|
}
|
||||||
|
|
||||||
if Videos || All {
|
if Videos || All {
|
||||||
formats.Add(video.Format{})
|
formats.Add(video.Format{Fun: Fun})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) == 0 {
|
||||||
formats.Add(images.Format{})
|
formats.Add(images.Format{Fun: Fun})
|
||||||
}
|
}
|
||||||
|
|
||||||
paths, err := validatePaths(args, formats)
|
paths, err := validatePaths(args, formats)
|
||||||
|
|
|
@ -11,7 +11,9 @@ import (
|
||||||
"seedno.de/seednode/roulette/types"
|
"seedno.de/seednode/roulette/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Format struct{}
|
type Format struct {
|
||||||
|
Fun bool
|
||||||
|
}
|
||||||
|
|
||||||
func (t Format) Css() string {
|
func (t Format) Css() string {
|
||||||
var css strings.Builder
|
var css strings.Builder
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Format struct {
|
type Format struct {
|
||||||
|
Fun bool
|
||||||
Theme string
|
Theme string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +57,9 @@ func (t Format) Css() string {
|
||||||
|
|
||||||
css.WriteString("html{height:100%;width:100%;}\n")
|
css.WriteString("html{height:100%;width:100%;}\n")
|
||||||
css.WriteString("a{bottom:0;left:0;position:absolute;right:0;top:0;margin:1rem;padding:0;height:99%;width:99%;color:inherit;text-decoration:none;}\n")
|
css.WriteString("a{bottom:0;left:0;position:absolute;right:0;top:0;margin:1rem;padding:0;height:99%;width:99%;color:inherit;text-decoration:none;}\n")
|
||||||
|
if t.Fun {
|
||||||
|
css.WriteString("body{font-family: \"Comic Sans MS\", cursive, \"Brush Script MT\", sans-serif;}\n")
|
||||||
|
}
|
||||||
|
|
||||||
return css.String()
|
return css.String()
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,9 @@ import (
|
||||||
"seedno.de/seednode/roulette/types"
|
"seedno.de/seednode/roulette/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Format struct{}
|
type Format struct {
|
||||||
|
Fun bool
|
||||||
|
}
|
||||||
|
|
||||||
func (t Format) Css() string {
|
func (t Format) Css() string {
|
||||||
var css strings.Builder
|
var css strings.Builder
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
_ "image/gif"
|
_ "image/gif"
|
||||||
_ "image/jpeg"
|
_ "image/jpeg"
|
||||||
_ "image/png"
|
_ "image/png"
|
||||||
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -24,7 +25,9 @@ type dimensions struct {
|
||||||
height int
|
height int
|
||||||
}
|
}
|
||||||
|
|
||||||
type Format struct{}
|
type Format struct {
|
||||||
|
Fun bool
|
||||||
|
}
|
||||||
|
|
||||||
func (t Format) Css() string {
|
func (t Format) Css() string {
|
||||||
var css strings.Builder
|
var css strings.Builder
|
||||||
|
@ -32,7 +35,17 @@ func (t Format) Css() string {
|
||||||
css.WriteString(`html,body{margin:0;padding:0;height:100%;}`)
|
css.WriteString(`html,body{margin:0;padding:0;height:100%;}`)
|
||||||
css.WriteString(`a{color:inherit;display:block;height:100%;width:100%;text-decoration:none;}`)
|
css.WriteString(`a{color:inherit;display:block;height:100%;width:100%;text-decoration:none;}`)
|
||||||
css.WriteString(`img{margin:auto;display:block;max-width:97%;max-height:97%;`)
|
css.WriteString(`img{margin:auto;display:block;max-width:97%;max-height:97%;`)
|
||||||
css.WriteString(`object-fit:scale-down;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);}`)
|
css.WriteString(`object-fit:scale-down;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)`)
|
||||||
|
if t.Fun {
|
||||||
|
rotate := rand.Intn(360)
|
||||||
|
|
||||||
|
css.WriteString(fmt.Sprintf(" rotate(%ddeg);", rotate))
|
||||||
|
css.WriteString(fmt.Sprintf("-ms-transform:rotate(%ddeg);", rotate))
|
||||||
|
css.WriteString(fmt.Sprintf("-webkit-transform:rotate(%ddeg);", rotate))
|
||||||
|
css.WriteString(fmt.Sprintf("-moz-transform:rotate(%ddeg);", rotate))
|
||||||
|
css.WriteString(fmt.Sprintf("-o-transform:rotate(%ddeg)", rotate))
|
||||||
|
}
|
||||||
|
css.WriteString(`;}`)
|
||||||
|
|
||||||
return css.String()
|
return css.String()
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,9 @@ import (
|
||||||
"seedno.de/seednode/roulette/types"
|
"seedno.de/seednode/roulette/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Format struct{}
|
type Format struct {
|
||||||
|
Fun bool
|
||||||
|
}
|
||||||
|
|
||||||
func (t Format) Css() string {
|
func (t Format) Css() string {
|
||||||
var css strings.Builder
|
var css strings.Builder
|
||||||
|
|
|
@ -10,35 +10,47 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var SupportedFormats = &Types{
|
var SupportedFormats = make(Types)
|
||||||
Extensions: make(map[string]Type),
|
|
||||||
}
|
|
||||||
|
|
||||||
type Type interface {
|
type Type interface {
|
||||||
|
// Returns either "inline" or "embed", depending on whether the file
|
||||||
|
// should be displayed inline (e.g. code) or embedded (e.g. images)
|
||||||
Type() string
|
Type() string
|
||||||
|
|
||||||
|
// Returns a CSS string used to format the corresponding page
|
||||||
Css() string
|
Css() string
|
||||||
|
|
||||||
|
// Returns an HTML <title> element for the specified file
|
||||||
Title(rootUrl, fileUri, filePath, fileName, prefix, mime string) (string, error)
|
Title(rootUrl, fileUri, filePath, fileName, prefix, mime string) (string, error)
|
||||||
|
|
||||||
|
// Returns an HTML <body> element used to display the specified file
|
||||||
Body(rootUrl, fileUri, filePath, fileName, prefix, mime string) (string, error)
|
Body(rootUrl, fileUri, filePath, fileName, prefix, mime string) (string, error)
|
||||||
|
|
||||||
|
// Returns a map of file extensions to MIME type strings.
|
||||||
Extensions() map[string]string
|
Extensions() map[string]string
|
||||||
MimeType(string) string
|
|
||||||
|
// Given a file extension, returns the corresponding MIME type,
|
||||||
|
// if one exists. Otherwise, returns an empty string.
|
||||||
|
MimeType(extension string) string
|
||||||
|
|
||||||
|
// Optional function used to validate whether a given file matches this format.
|
||||||
|
// If no validation checks are needed, this function should always return true.
|
||||||
Validate(filePath string) bool
|
Validate(filePath string) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Types struct {
|
type Types map[string]Type
|
||||||
Extensions map[string]Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Types) Add(format Type) {
|
func (t Types) Add(format Type) {
|
||||||
for k := range format.Extensions() {
|
for k := range format.Extensions() {
|
||||||
_, exists := t.Extensions[k]
|
_, exists := t[k]
|
||||||
if !exists {
|
if !exists {
|
||||||
t.Extensions[k] = format
|
t[k] = format
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Types) FileType(path string) Type {
|
func (t Types) FileType(path string) Type {
|
||||||
fileType, exists := t.Extensions[filepath.Ext(path)]
|
fileType, exists := t[filepath.Ext(path)]
|
||||||
if exists {
|
if exists {
|
||||||
return fileType
|
return fileType
|
||||||
}
|
}
|
||||||
|
@ -46,12 +58,12 @@ func (t *Types) FileType(path string) Type {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Types) Register(format Type) {
|
func (t Types) Register(format Type) {
|
||||||
t.Add(format)
|
t.Add(format)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Types) Validate(path string) bool {
|
func (t Types) Validate(path string) bool {
|
||||||
format, exists := t.Extensions[filepath.Ext(path)]
|
format, exists := t[filepath.Ext(path)]
|
||||||
if !exists {
|
if !exists {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -59,14 +71,14 @@ func (t *Types) Validate(path string) bool {
|
||||||
return format.Validate(path)
|
return format.Validate(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Types) GetExtensions() string {
|
func (t Types) GetExtensions() string {
|
||||||
var output strings.Builder
|
var output strings.Builder
|
||||||
|
|
||||||
extensions := make([]string, len(t.Extensions))
|
extensions := make([]string, len(t))
|
||||||
|
|
||||||
i := 0
|
i := 0
|
||||||
|
|
||||||
for k := range t.Extensions {
|
for k := range t {
|
||||||
extensions[i] = k
|
extensions[i] = k
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
@ -80,12 +92,12 @@ func (t *Types) GetExtensions() string {
|
||||||
return output.String()
|
return output.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Types) GetMimeTypes() string {
|
func (t Types) GetMimeTypes() string {
|
||||||
var output strings.Builder
|
var output strings.Builder
|
||||||
|
|
||||||
var mimeTypes []string
|
var mimeTypes []string
|
||||||
|
|
||||||
for _, j := range t.Extensions {
|
for _, j := range t {
|
||||||
extensions := j.Extensions()
|
extensions := j.Extensions()
|
||||||
for _, v := range extensions {
|
for _, v := range extensions {
|
||||||
mimeTypes = append(mimeTypes, v)
|
mimeTypes = append(mimeTypes, v)
|
||||||
|
|
|
@ -12,7 +12,9 @@ import (
|
||||||
"seedno.de/seednode/roulette/types"
|
"seedno.de/seednode/roulette/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Format struct{}
|
type Format struct {
|
||||||
|
Fun bool
|
||||||
|
}
|
||||||
|
|
||||||
func (t Format) Css() string {
|
func (t Format) Css() string {
|
||||||
var css strings.Builder
|
var css strings.Builder
|
||||||
|
|
Loading…
Reference in New Issue