Compare commits
No commits in common. "a87d9a26fd0bf9475ed3653f812d7379644b5b78" and "9274162b4b245c744578e6c199ea2f11782385b9" have entirely different histories.
a87d9a26fd
...
9274162b4b
|
@ -116,12 +116,11 @@ Flags:
|
||||||
--case-sensitive use case-sensitive matching for filters
|
--case-sensitive use case-sensitive matching for filters
|
||||||
--code enable support for source code files
|
--code enable support for source code files
|
||||||
--code-theme string theme for source code syntax highlighting (default "solarized-dark256")
|
--code-theme string theme for source code syntax highlighting (default "solarized-dark256")
|
||||||
--disable-buttons disable first/prev/next/last buttons
|
|
||||||
--exit-on-error shut down webserver on error, instead of just printing the error
|
--exit-on-error shut down webserver on error, instead of just printing the error
|
||||||
--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 add a bit of excitement to your day
|
--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
|
||||||
|
|
|
@ -87,7 +87,7 @@ func newFile(list []string, sortOrder string, regexes *regexes, formats types.Ty
|
||||||
}
|
}
|
||||||
case sortOrder == "desc":
|
case sortOrder == "desc":
|
||||||
for {
|
for {
|
||||||
splitPath.number = splitPath.increment()
|
splitPath.increment()
|
||||||
|
|
||||||
path, err = tryExtensions(splitPath, formats)
|
path, err = tryExtensions(splitPath, formats)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -95,7 +95,7 @@ func newFile(list []string, sortOrder string, regexes *regexes, formats types.Ty
|
||||||
}
|
}
|
||||||
|
|
||||||
if path == "" {
|
if path == "" {
|
||||||
splitPath.number = splitPath.decrement()
|
splitPath.decrement()
|
||||||
|
|
||||||
path, err = tryExtensions(splitPath, formats)
|
path, err = tryExtensions(splitPath, formats)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -119,9 +119,9 @@ func nextFile(filePath, sortOrder string, regexes *regexes, formats types.Types)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case sortOrder == "asc":
|
case sortOrder == "asc":
|
||||||
splitPath.number = splitPath.increment()
|
splitPath.increment()
|
||||||
case sortOrder == "desc":
|
case sortOrder == "desc":
|
||||||
splitPath.number = splitPath.decrement()
|
splitPath.decrement()
|
||||||
default:
|
default:
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -186,15 +186,13 @@ func registerIndexHandlers(mux *httprouter.Router, args []string, index *fileInd
|
||||||
func importIndex(args []string, index *fileIndex, formats types.Types) error {
|
func importIndex(args []string, index *fileIndex, formats types.Types) error {
|
||||||
if IndexFile != "" {
|
if IndexFile != "" {
|
||||||
err := index.Import(IndexFile)
|
err := index.Import(IndexFile)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := fileList(args, &filters{}, "", index, formats)
|
_, err := fileList(args, &filters{}, "", index, formats)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
10
cmd/info.go
10
cmd/info.go
|
@ -19,7 +19,7 @@ import (
|
||||||
"seedno.de/seednode/roulette/types"
|
"seedno.de/seednode/roulette/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func paginateIndex(page int, fileCount int, ending bool) string {
|
func paginate(page int, fileCount int, ending bool) string {
|
||||||
var html strings.Builder
|
var html strings.Builder
|
||||||
|
|
||||||
var firstPage int = 1
|
var firstPage int = 1
|
||||||
|
@ -120,8 +120,8 @@ func serveIndexHtml(args []string, index *fileIndex, shouldPaginate bool) httpro
|
||||||
htmlBody.WriteString(`table,td,tr{border:none;}td{border-bottom:1px solid black;}td{white-space:nowrap;padding:.5em}</style>`)
|
htmlBody.WriteString(`table,td,tr{border:none;}td{border-bottom:1px solid black;}td{white-space:nowrap;padding:.5em}</style>`)
|
||||||
htmlBody.WriteString(fmt.Sprintf("<title>Index contains %d files</title></head><body><table>", fileCount))
|
htmlBody.WriteString(fmt.Sprintf("<title>Index contains %d files</title></head><body><table>", fileCount))
|
||||||
|
|
||||||
if shouldPaginate && !DisableButtons {
|
if shouldPaginate {
|
||||||
htmlBody.WriteString(paginateIndex(page, fileCount, false))
|
htmlBody.WriteString(paginate(page, fileCount, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(indexDump) > 0 {
|
if len(indexDump) > 0 {
|
||||||
|
@ -135,8 +135,8 @@ func serveIndexHtml(args []string, index *fileIndex, shouldPaginate bool) httpro
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if shouldPaginate && !DisableButtons {
|
if shouldPaginate {
|
||||||
htmlBody.WriteString(paginateIndex(page, fileCount, true))
|
htmlBody.WriteString(paginate(page, fileCount, true))
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlBody.WriteString(`</table></body></html>`)
|
htmlBody.WriteString(`</table></body></html>`)
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ReleaseVersion string = "3.1.0"
|
ReleaseVersion string = "3.0.2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -22,7 +22,6 @@ var (
|
||||||
CaseSensitive bool
|
CaseSensitive bool
|
||||||
Code bool
|
Code bool
|
||||||
CodeTheme string
|
CodeTheme string
|
||||||
DisableButtons bool
|
|
||||||
ExitOnError bool
|
ExitOnError bool
|
||||||
Fallback bool
|
Fallback bool
|
||||||
Filtering bool
|
Filtering bool
|
||||||
|
@ -89,7 +88,6 @@ func init() {
|
||||||
rootCmd.Flags().BoolVar(&CaseSensitive, "case-sensitive", false, "use case-sensitive matching for filters")
|
rootCmd.Flags().BoolVar(&CaseSensitive, "case-sensitive", false, "use case-sensitive matching for filters")
|
||||||
rootCmd.Flags().BoolVar(&Code, "code", false, "enable support for source code files")
|
rootCmd.Flags().BoolVar(&Code, "code", false, "enable support for source code files")
|
||||||
rootCmd.Flags().StringVar(&CodeTheme, "code-theme", "solarized-dark256", "theme for source code syntax highlighting")
|
rootCmd.Flags().StringVar(&CodeTheme, "code-theme", "solarized-dark256", "theme for source code syntax highlighting")
|
||||||
rootCmd.Flags().BoolVar(&DisableButtons, "disable-buttons", false, "disable first/prev/next/last buttons")
|
|
||||||
rootCmd.Flags().BoolVar(&ExitOnError, "exit-on-error", false, "shut down webserver on error, instead of just printing the error")
|
rootCmd.Flags().BoolVar(&ExitOnError, "exit-on-error", false, "shut down webserver on error, instead of just printing the error")
|
||||||
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")
|
||||||
|
|
139
cmd/sort.go
139
cmd/sort.go
|
@ -6,12 +6,8 @@ package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"seedno.de/seednode/roulette/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type splitPath struct {
|
type splitPath struct {
|
||||||
|
@ -20,22 +16,22 @@ type splitPath struct {
|
||||||
extension string
|
extension string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (splitPath *splitPath) increment() string {
|
func (splitPath *splitPath) increment() {
|
||||||
asInt, err := strconv.Atoi(splitPath.number)
|
asInt, err := strconv.Atoi(splitPath.number)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("%0*d", len(splitPath.number), asInt+1)
|
splitPath.number = fmt.Sprintf("%0*d", len(splitPath.number), asInt+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (splitPath *splitPath) decrement() string {
|
func (splitPath *splitPath) decrement() {
|
||||||
asInt, err := strconv.Atoi(splitPath.number)
|
asInt, err := strconv.Atoi(splitPath.number)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("%0*d", len(splitPath.number), asInt-1)
|
splitPath.number = fmt.Sprintf("%0*d", len(splitPath.number), asInt-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func split(path string, regexes *regexes) (*splitPath, error) {
|
func split(path string, regexes *regexes) (*splitPath, error) {
|
||||||
|
@ -53,126 +49,3 @@ func split(path string, regexes *regexes) (*splitPath, error) {
|
||||||
|
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRange(path string, regexes *regexes, index *fileIndex) (string, string, error) {
|
|
||||||
splitPath, err := split(path, regexes)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
list := index.List()
|
|
||||||
|
|
||||||
sort.Slice(list, func(i, j int) bool {
|
|
||||||
return list[i] <= list[j]
|
|
||||||
})
|
|
||||||
|
|
||||||
var first, last, previous string
|
|
||||||
|
|
||||||
Loop:
|
|
||||||
for _, val := range list {
|
|
||||||
splitVal, err := split(val, regexes)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case splitVal.base == splitPath.base && first == "":
|
|
||||||
first = val
|
|
||||||
case splitVal.base != splitPath.base && first != "":
|
|
||||||
last = previous
|
|
||||||
|
|
||||||
break Loop
|
|
||||||
}
|
|
||||||
|
|
||||||
previous = val
|
|
||||||
}
|
|
||||||
|
|
||||||
return first, last, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func paginateSorted(path, first, last, queryParams string, regexes *regexes, formats types.Types) (string, error) {
|
|
||||||
split, err := split(path, regexes)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
var firstStatus, prevStatus, nextStatus, lastStatus string = "", "", "", ""
|
|
||||||
|
|
||||||
if path <= first {
|
|
||||||
firstStatus = " disabled"
|
|
||||||
prevStatus = " disabled"
|
|
||||||
}
|
|
||||||
|
|
||||||
if path >= last {
|
|
||||||
nextStatus = " disabled"
|
|
||||||
lastStatus = " disabled"
|
|
||||||
}
|
|
||||||
|
|
||||||
prevPath := &splitPath{
|
|
||||||
base: split.base,
|
|
||||||
number: split.decrement(),
|
|
||||||
extension: split.extension,
|
|
||||||
}
|
|
||||||
|
|
||||||
prevPage, err := tryExtensions(prevPath, formats)
|
|
||||||
switch {
|
|
||||||
case err != nil:
|
|
||||||
return "", err
|
|
||||||
case prevPage == "":
|
|
||||||
prevStatus = " disabled"
|
|
||||||
case prevPage < first:
|
|
||||||
prevPage = first
|
|
||||||
}
|
|
||||||
|
|
||||||
nextPath := &splitPath{
|
|
||||||
base: split.base,
|
|
||||||
number: split.increment(),
|
|
||||||
extension: split.extension,
|
|
||||||
}
|
|
||||||
|
|
||||||
nextPage, err := tryExtensions(nextPath, formats)
|
|
||||||
switch {
|
|
||||||
case err != nil:
|
|
||||||
return "", err
|
|
||||||
case nextPage == "":
|
|
||||||
nextStatus = " disabled"
|
|
||||||
case nextPage > last:
|
|
||||||
nextPage = last
|
|
||||||
}
|
|
||||||
|
|
||||||
var html strings.Builder
|
|
||||||
|
|
||||||
html.WriteString(`<table style="margin-left:auto;margin-right:auto;"><tr><td>`)
|
|
||||||
|
|
||||||
html.WriteString(fmt.Sprintf(`<button onclick="window.location.href = '%s%s%s%s';"%s>First</button>`,
|
|
||||||
Prefix,
|
|
||||||
mediaPrefix,
|
|
||||||
first,
|
|
||||||
queryParams,
|
|
||||||
firstStatus))
|
|
||||||
|
|
||||||
html.WriteString(fmt.Sprintf(`<button onclick="window.location.href = '%s%s%s%s';"%s>Prev</button>`,
|
|
||||||
Prefix,
|
|
||||||
mediaPrefix,
|
|
||||||
prevPage,
|
|
||||||
queryParams,
|
|
||||||
prevStatus))
|
|
||||||
|
|
||||||
html.WriteString(fmt.Sprintf(`<button onclick="window.location.href = '%s%s%s%s';"%s>Next</button>`,
|
|
||||||
Prefix,
|
|
||||||
mediaPrefix,
|
|
||||||
nextPage,
|
|
||||||
queryParams,
|
|
||||||
nextStatus))
|
|
||||||
|
|
||||||
html.WriteString(fmt.Sprintf(`<button onclick="window.location.href = '%s%s%s%s';"%s>Last</button>`,
|
|
||||||
Prefix,
|
|
||||||
mediaPrefix,
|
|
||||||
last,
|
|
||||||
queryParams,
|
|
||||||
lastStatus))
|
|
||||||
|
|
||||||
html.WriteString("</td></tr></table>")
|
|
||||||
|
|
||||||
return html.String(), nil
|
|
||||||
}
|
|
||||||
|
|
34
cmd/web.go
34
cmd/web.go
|
@ -307,9 +307,7 @@ func serveMedia(paths []string, regexes *regexes, index *fileIndex, formats type
|
||||||
|
|
||||||
refreshTimer, refreshInterval := refreshInterval(r)
|
refreshTimer, refreshInterval := refreshInterval(r)
|
||||||
|
|
||||||
queryParams := generateQueryParams(filters, sortOrder, refreshInterval)
|
rootUrl := Prefix + "/" + generateQueryParams(filters, sortOrder, refreshInterval)
|
||||||
|
|
||||||
rootUrl := Prefix + "/" + queryParams
|
|
||||||
|
|
||||||
var htmlBody strings.Builder
|
var htmlBody strings.Builder
|
||||||
htmlBody.WriteString(`<!DOCTYPE html><html class="bg" lang="en"><head>`)
|
htmlBody.WriteString(`<!DOCTYPE html><html class="bg" lang="en"><head>`)
|
||||||
|
@ -326,33 +324,6 @@ func serveMedia(paths []string, regexes *regexes, index *fileIndex, formats type
|
||||||
}
|
}
|
||||||
htmlBody.WriteString(title)
|
htmlBody.WriteString(title)
|
||||||
htmlBody.WriteString(`</head><body>`)
|
htmlBody.WriteString(`</head><body>`)
|
||||||
|
|
||||||
var first, last string
|
|
||||||
|
|
||||||
if Index && sortOrder != "" {
|
|
||||||
first, last, err = getRange(path, regexes, index)
|
|
||||||
if err != nil {
|
|
||||||
errorChannel <- err
|
|
||||||
|
|
||||||
serverError(w, r, nil)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if Index && !DisableButtons && sortOrder != "" {
|
|
||||||
paginate, err := paginateSorted(path, first, last, queryParams, regexes, formats)
|
|
||||||
if err != nil {
|
|
||||||
errorChannel <- err
|
|
||||||
|
|
||||||
serverError(w, r, nil)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
htmlBody.WriteString(paginate)
|
|
||||||
}
|
|
||||||
|
|
||||||
if refreshInterval != "0ms" {
|
if refreshInterval != "0ms" {
|
||||||
htmlBody.WriteString(refreshFunction(rootUrl, refreshTimer))
|
htmlBody.WriteString(refreshFunction(rootUrl, refreshTimer))
|
||||||
}
|
}
|
||||||
|
@ -366,7 +337,6 @@ func serveMedia(paths []string, regexes *regexes, index *fileIndex, formats type
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
htmlBody.WriteString(body)
|
htmlBody.WriteString(body)
|
||||||
|
|
||||||
htmlBody.WriteString(`</body></html>`)
|
htmlBody.WriteString(`</body></html>`)
|
||||||
|
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
|
@ -486,7 +456,7 @@ func ServePage(args []string) error {
|
||||||
// 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) == 0 {
|
if Images || All || len(formats) == 0 {
|
||||||
formats.Add(images.Format{DisableButtons: DisableButtons, Fun: Fun})
|
formats.Add(images.Format{Fun: Fun})
|
||||||
}
|
}
|
||||||
|
|
||||||
paths, err := validatePaths(args, formats)
|
paths, err := validatePaths(args, formats)
|
||||||
|
|
|
@ -26,7 +26,6 @@ type dimensions struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Format struct {
|
type Format struct {
|
||||||
DisableButtons bool
|
|
||||||
Fun bool
|
Fun bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,13 +33,7 @@ func (t Format) Css() string {
|
||||||
var css strings.Builder
|
var css strings.Builder
|
||||||
|
|
||||||
css.WriteString(`html,body{margin:0;padding:0;height:100%;}`)
|
css.WriteString(`html,body{margin:0;padding:0;height:100%;}`)
|
||||||
|
|
||||||
if t.DisableButtons {
|
|
||||||
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;}`)
|
||||||
} else {
|
|
||||||
css.WriteString(`a{color:inherit;display:block;height:97%;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 {
|
if t.Fun {
|
||||||
|
|
Loading…
Reference in New Issue