Compare commits

..

3 Commits

15 changed files with 86 additions and 63 deletions

View File

@ -35,25 +35,27 @@ 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 `/rebuild_index` endpoint. The index can be regenerated at any time by accessing the `/index/rebuild` 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—`/html` and `/json`—return the contents of the index, in HTML and JSON formats respectively. The first of these—`/index/html` and `/index/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. 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.
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—`/available_extensions`, `/enabled_extensions`, `/available_mime_types` and `/enabled_mime_types`—return information about the registered file types. The remaining four endpoints—`/extensions/available`, `/extensions/enabled`, `/types/available` and `/types/enabled`—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. Pressing Space will pause automatic refreshing until the page is manually refreshed or a new page is loaded. This can be used to generate a sort of slideshow of files in any browser with Javascript support.
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,13 +27,6 @@ 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+"/rebuild_index", serveIndexRebuild(args, index, formats, errorChannel)) registerHandler(mux, Prefix+"/index/rebuild", 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 serveAvailableMimeTypes(errorChannel chan<- error) httprouter.Handle { func serveAvailableMediaTypes(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.GetMimeTypes())) written, err := w.Write([]byte(types.SupportedFormats.GetMediaTypes()))
if err != nil { if err != nil {
errorChannel <- err 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 media 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 serveAvailableMimeTypes(errorChannel chan<- error) httprouter.Handle {
} }
} }
func serveEnabledMimeTypes(formats types.Types, errorChannel chan<- error) httprouter.Handle { func serveEnabledMediaTypes(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.GetMimeTypes())) written, err := w.Write([]byte(formats.GetMediaTypes()))
if err != nil { if err != nil {
errorChannel <- err 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 media 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 serveEnabledMimeTypes(formats types.Types, errorChannel chan<- error) httpr
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+"/index/html", serveIndexHtml(args, index, false))
if PageLength != 0 { if PageLength != 0 {
registerHandler(mux, Prefix+"/html/:page", serveIndexHtml(args, index, true)) registerHandler(mux, Prefix+"/index/html/:page", serveIndexHtml(args, index, true))
} }
registerHandler(mux, Prefix+"/json", serveIndexJson(args, index, errorChannel)) registerHandler(mux, Prefix+"/index/json", serveIndexJson(args, index, errorChannel))
if PageLength != 0 { if PageLength != 0 {
registerHandler(mux, Prefix+"/json/:page", serveIndexJson(args, index, errorChannel)) registerHandler(mux, Prefix+"/index/json/:page", serveIndexJson(args, index, errorChannel))
} }
} }
registerHandler(mux, Prefix+"/available_extensions", serveAvailableExtensions(errorChannel)) registerHandler(mux, Prefix+"/extensions/available", serveAvailableExtensions(errorChannel))
registerHandler(mux, Prefix+"/enabled_extensions", serveEnabledExtensions(formats, errorChannel)) registerHandler(mux, Prefix+"/extensions/enabled", serveEnabledExtensions(formats, errorChannel))
registerHandler(mux, Prefix+"/available_mime_types", serveAvailableMimeTypes(errorChannel)) registerHandler(mux, Prefix+"/types/available", serveAvailableMediaTypes(errorChannel))
registerHandler(mux, Prefix+"/enabled_mime_types", serveEnabledMimeTypes(formats, errorChannel)) registerHandler(mux, Prefix+"/types/enabled", serveEnabledMediaTypes(formats, errorChannel))
} }

46
cmd/refresh.go Normal file
View File

@ -0,0 +1,46 @@
/*
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 = "2.8.0" ReleaseVersion string = "3.0.0"
) )
var ( var (

View File

@ -10,24 +10,8 @@ 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
} }
mimeType := format.MimeType(path) mediaType := format.MediaType(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, mimeType) title, err := format.Title(rootUrl, fileUri, path, fileName, Prefix, mediaType)
if err != nil { if err != nil {
errorChannel <- err errorChannel <- err
@ -325,12 +325,10 @@ 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(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>", htmlBody.WriteString(refreshFunction(rootUrl, refreshTimer))
rootUrl,
refreshTimer))
} }
body, err := format.Body(rootUrl, fileUri, path, fileName, Prefix, mimeType) body, err := format.Body(rootUrl, fileUri, path, fileName, Prefix, mediaType)
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) MimeType(extension string) string { func (t Format) MediaType(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) MimeType(extension string) string { func (t Format) MediaType(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) MimeType(extension string) string { func (t Format) MediaType(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) MimeType(extension string) string { func (t Format) MediaType(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) MimeType(extension string) string { func (t Format) MediaType(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.
MimeType(extension string) string MediaType(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) GetMimeTypes() string { func (t Types) GetMediaTypes() string {
var output strings.Builder var output strings.Builder
var mimeTypes []string var mediaTypes []string
for _, j := range t { for _, j := range t {
extensions := j.Extensions() extensions := j.Extensions()
for _, v := range extensions { for _, v := range extensions {
mimeTypes = append(mimeTypes, v) mediaTypes = append(mediaTypes, v)
} }
} }
mimeTypes = removeDuplicateStr(mimeTypes) mediaTypes = removeDuplicateStr(mediaTypes)
slices.Sort(mimeTypes) slices.Sort(mediaTypes)
for _, v := range mimeTypes { for _, v := range mediaTypes {
output.WriteString(v + "\n") output.WriteString(v + "\n")
} }

View File

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