Compare commits

..

No commits in common. "81d7e60d0c89589eac0e80722c624e46b6d5b1b8" and "f36c0cc999617f1421a6b40c60b8a9e5ec11ff31" have entirely different histories.

15 changed files with 63 additions and 86 deletions

View File

@ -35,27 +35,25 @@ If the `-i|--indexing` flag is passed, all specified paths will be indexed on st
This will slightly increase the delay before the application begins responding to requests, but should significantly speed up subsequent requests. This will slightly increase the delay before the application begins responding to requests, but should significantly speed up subsequent requests.
The index can be regenerated at any time by accessing the `/index/rebuild` endpoint. The index can be regenerated at any time by accessing the `/rebuild_index` endpoint.
If `--index-file` is set, the index will be loaded from the specified file on start, and written to the file whenever it is re-generated. If `--index-file` is set, the index will be loaded from the specified file on start, and written to the file whenever it is re-generated.
## Info ## Info
If the `-i|--info` flag is passed, six additional endpoints are registered. If the `-i|--info` flag is passed, six additional endpoints are registered.
The first of these—`/index/html` and `/index/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 a page number, e.g. `/index/html/5` for the fifth page. 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 remaining four endpoints—`/extensions/available`, `/extensions/enabled`, `/types/available` and `/types/enabled`—return information about 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.
## Refresh ## Refresh
If the `--refresh` flag is passed and a positive-value `refresh=<integer><unit>` query parameter is provided, the page will reload after that interval. If the `--refresh` flag is passed and a positive-value `refresh=<integer><unit>` query parameter is provided, the page will reload after that interval.
This can be used to generate a sort of slideshow of files in any browser with Javascript support. This can be used to generate a sort of slideshow of files. Pressing Space will pause automatic refreshing until the page is manually refreshed or a new page is loaded.
Pressing Spacebar will pause automatic refreshing until Spacebar is pressed again, the page is manually refreshed, or a new page is loaded.
Minimum accepted value is 500ms, as anything lower seems to cause inconsistent behavior. This might be changed in a future release. Minimum accepted value is 500ms, as anything lower seems to cause inconsistent behavior. This might be changed in a future release.

View File

@ -27,6 +27,13 @@ type regexes struct {
filename *regexp.Regexp filename *regexp.Regexp
} }
// type scanStats struct {
// filesMatched int
// filesSkipped int
// directoriesMatched int
// directoriesSkipped int
// }
type scanStatsChannels struct { type scanStatsChannels struct {
filesMatched chan int filesMatched chan int
filesSkipped chan int filesSkipped chan int

View File

@ -178,7 +178,7 @@ func serveIndexRebuild(args []string, index *fileIndex, formats types.Types, err
} }
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+"/index/rebuild", serveIndexRebuild(args, index, formats, errorChannel)) registerHandler(mux, Prefix+"/rebuild_index", serveIndexRebuild(args, index, formats, errorChannel))
return nil return nil
} }

View File

@ -255,19 +255,19 @@ func serveEnabledExtensions(formats types.Types, errorChannel chan<- error) http
} }
} }
func serveAvailableMediaTypes(errorChannel chan<- error) 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()
written, err := w.Write([]byte(types.SupportedFormats.GetMediaTypes())) written, err := w.Write([]byte(types.SupportedFormats.GetMimeTypes()))
if err != nil { if err != nil {
errorChannel <- err errorChannel <- err
} }
if Verbose { if Verbose {
fmt.Printf("%s | SERVE: Available media 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(written), humanReadableSize(written),
realIP(r), realIP(r),
@ -277,19 +277,19 @@ func serveAvailableMediaTypes(errorChannel chan<- error) httprouter.Handle {
} }
} }
func serveEnabledMediaTypes(formats types.Types, errorChannel chan<- error) 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()
written, err := w.Write([]byte(formats.GetMediaTypes())) written, err := w.Write([]byte(formats.GetMimeTypes()))
if err != nil { if err != nil {
errorChannel <- err errorChannel <- err
} }
if Verbose { if Verbose {
fmt.Printf("%s | SERVE: Registered media 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(written), humanReadableSize(written),
realIP(r), realIP(r),
@ -301,19 +301,19 @@ func serveEnabledMediaTypes(formats types.Types, errorChannel chan<- error) http
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+"/index/html", serveIndexHtml(args, index, false)) registerHandler(mux, Prefix+"/html", serveIndexHtml(args, index, false))
if PageLength != 0 { if PageLength != 0 {
registerHandler(mux, Prefix+"/index/html/:page", serveIndexHtml(args, index, true)) registerHandler(mux, Prefix+"/html/:page", serveIndexHtml(args, index, true))
} }
registerHandler(mux, Prefix+"/index/json", serveIndexJson(args, index, errorChannel)) registerHandler(mux, Prefix+"/json", serveIndexJson(args, index, errorChannel))
if PageLength != 0 { if PageLength != 0 {
registerHandler(mux, Prefix+"/index/json/:page", serveIndexJson(args, index, errorChannel)) registerHandler(mux, Prefix+"/json/:page", serveIndexJson(args, index, errorChannel))
} }
} }
registerHandler(mux, Prefix+"/extensions/available", serveAvailableExtensions(errorChannel)) registerHandler(mux, Prefix+"/available_extensions", serveAvailableExtensions(errorChannel))
registerHandler(mux, Prefix+"/extensions/enabled", serveEnabledExtensions(formats, errorChannel)) registerHandler(mux, Prefix+"/enabled_extensions", serveEnabledExtensions(formats, errorChannel))
registerHandler(mux, Prefix+"/types/available", serveAvailableMediaTypes(errorChannel)) registerHandler(mux, Prefix+"/available_mime_types", serveAvailableMimeTypes(errorChannel))
registerHandler(mux, Prefix+"/types/enabled", serveEnabledMediaTypes(formats, errorChannel)) registerHandler(mux, Prefix+"/enabled_mime_types", serveEnabledMimeTypes(formats, errorChannel))
} }

View File

@ -1,46 +0,0 @@
/*
Copyright © 2023 Seednode <seednode@seedno.de>
*/
package cmd
import (
"fmt"
"net/http"
"strings"
"time"
)
func refreshInterval(r *http.Request) (int64, string) {
interval := r.URL.Query().Get("refresh")
duration, err := time.ParseDuration(interval)
switch {
case err != nil || duration == 0 || !Refresh:
return 0, "0ms"
case duration < 500*time.Millisecond:
return 500, "500ms"
default:
return duration.Milliseconds(), interval
}
}
func refreshFunction(rootUrl string, refreshTimer int64) string {
var htmlBody strings.Builder
htmlBody.WriteString(fmt.Sprintf("<script>window.onload = function(){ clear = setInterval(function() {window.location.href = '%s';}, %d)};",
rootUrl,
refreshTimer))
htmlBody.WriteString("document.body.onkeyup = function(e) { ")
htmlBody.WriteString(`if (e.key == " " || e.code == "Space" || e.keyCode == 32) { `)
htmlBody.WriteString(`if (typeof clear !== 'undefined') {`)
htmlBody.WriteString(`clearInterval(clear); delete clear;`)
htmlBody.WriteString(`} else {`)
htmlBody.WriteString(fmt.Sprintf("clear = setInterval(function(){window.location.href = '%s';}, %d);}}}",
rootUrl,
refreshTimer))
htmlBody.WriteString(`</script>`)
return htmlBody.String()
}

View File

@ -12,7 +12,7 @@ import (
) )
const ( const (
ReleaseVersion string = "3.0.0" ReleaseVersion string = "2.8.0"
) )
var ( var (

View File

@ -10,8 +10,24 @@ import (
"net/url" "net/url"
"runtime" "runtime"
"strings" "strings"
"time"
) )
func refreshInterval(r *http.Request) (int64, string) {
interval := r.URL.Query().Get("refresh")
duration, err := time.ParseDuration(interval)
switch {
case err != nil || duration == 0 || !Refresh:
return 0, "0ms"
case duration < 500*time.Millisecond:
return 500, "500ms"
default:
return duration.Milliseconds(), interval
}
}
func sortOrder(r *http.Request) string { func sortOrder(r *http.Request) string {
sortOrder := r.URL.Query().Get("sort") sortOrder := r.URL.Query().Get("sort")
if sortOrder == "asc" || sortOrder == "desc" { if sortOrder == "asc" || sortOrder == "desc" {

View File

@ -297,7 +297,7 @@ func serveMedia(paths []string, regexes *regexes, index *fileIndex, formats type
return return
} }
mediaType := format.MediaType(path) mimeType := format.MimeType(path)
fileUri := Prefix + generateFileUri(path) fileUri := Prefix + generateFileUri(path)
@ -314,7 +314,7 @@ func serveMedia(paths []string, regexes *regexes, index *fileIndex, formats type
htmlBody.WriteString(faviconHtml) htmlBody.WriteString(faviconHtml)
htmlBody.WriteString(fmt.Sprintf(`<style>%s</style>`, format.Css())) htmlBody.WriteString(fmt.Sprintf(`<style>%s</style>`, format.Css()))
title, err := format.Title(rootUrl, fileUri, path, fileName, Prefix, mediaType) title, err := format.Title(rootUrl, fileUri, path, fileName, Prefix, mimeType)
if err != nil { if err != nil {
errorChannel <- err errorChannel <- err
@ -325,10 +325,12 @@ func serveMedia(paths []string, regexes *regexes, index *fileIndex, formats type
htmlBody.WriteString(title) htmlBody.WriteString(title)
htmlBody.WriteString(`</head><body>`) htmlBody.WriteString(`</head><body>`)
if refreshInterval != "0ms" { if refreshInterval != "0ms" {
htmlBody.WriteString(refreshFunction(rootUrl, refreshTimer)) htmlBody.WriteString(fmt.Sprintf("<script>window.onload = function(){clear = setInterval(function(){window.location.href = '%s';}, %d); document.body.onkeyup = function(e) { if (e.key == \"\" || e.code == \"Space\" || e.keyCode == 32){clearInterval(clear)}}};</script>",
rootUrl,
refreshTimer))
} }
body, err := format.Body(rootUrl, fileUri, path, fileName, Prefix, mediaType) body, err := format.Body(rootUrl, fileUri, path, fileName, Prefix, mimeType)
if err != nil { if err != nil {
errorChannel <- err errorChannel <- err

View File

@ -44,7 +44,7 @@ func (t Format) Extensions() map[string]string {
} }
} }
func (t Format) MediaType(extension string) string { func (t Format) MimeType(extension string) string {
extensions := t.Extensions() extensions := t.Extensions()
value, exists := extensions[extension] value, exists := extensions[extension]

View File

@ -210,7 +210,7 @@ func (t Format) Extensions() map[string]string {
} }
} }
func (t Format) MediaType(extension string) string { func (t Format) MimeType(extension string) string {
extensions := t.Extensions() extensions := t.Extensions()
value, exists := extensions[extension] value, exists := extensions[extension]

View File

@ -43,7 +43,7 @@ func (t Format) Extensions() map[string]string {
} }
} }
func (t Format) MediaType(extension string) string { func (t Format) MimeType(extension string) string {
extensions := t.Extensions() extensions := t.Extensions()
value, exists := extensions[extension] value, exists := extensions[extension]

View File

@ -97,7 +97,7 @@ func (t Format) Validate(filePath string) bool {
return true return true
} }
func (t Format) MediaType(extension string) string { func (t Format) MimeType(extension string) string {
extensions := t.Extensions() extensions := t.Extensions()
value, exists := extensions[extension] value, exists := extensions[extension]

View File

@ -51,7 +51,7 @@ func (t Format) Extensions() map[string]string {
} }
} }
func (t Format) MediaType(extension string) string { func (t Format) MimeType(extension string) string {
extensions := t.Extensions() extensions := t.Extensions()
value, exists := extensions[extension] value, exists := extensions[extension]

View File

@ -31,7 +31,7 @@ type Type interface {
// Given a file extension, returns the corresponding MIME type, // Given a file extension, returns the corresponding MIME type,
// if one exists. Otherwise, returns an empty string. // if one exists. Otherwise, returns an empty string.
MediaType(extension string) string MimeType(extension string) string
// Optional function used to validate whether a given file matches this format. // Optional function used to validate whether a given file matches this format.
// If no validation checks are needed, this function should always return true. // If no validation checks are needed, this function should always return true.
@ -92,23 +92,23 @@ func (t Types) GetExtensions() string {
return output.String() return output.String()
} }
func (t Types) GetMediaTypes() string { func (t Types) GetMimeTypes() string {
var output strings.Builder var output strings.Builder
var mediaTypes []string var mimeTypes []string
for _, j := range t { for _, j := range t {
extensions := j.Extensions() extensions := j.Extensions()
for _, v := range extensions { for _, v := range extensions {
mediaTypes = append(mediaTypes, v) mimeTypes = append(mimeTypes, v)
} }
} }
mediaTypes = removeDuplicateStr(mediaTypes) mimeTypes = removeDuplicateStr(mimeTypes)
slices.Sort(mediaTypes) slices.Sort(mimeTypes)
for _, v := range mediaTypes { for _, v := range mimeTypes {
output.WriteString(v + "\n") output.WriteString(v + "\n")
} }

View File

@ -48,7 +48,7 @@ func (t Format) Extensions() map[string]string {
} }
} }
func (t Format) MediaType(path string) string { func (t Format) MimeType(path string) string {
extensions := t.Extensions() extensions := t.Extensions()
extension := filepath.Ext(path) extension := filepath.Ext(path)