Also available on Github: https://github.com/Seednode/roulette
Go to file
seednode 459cb9df0d Bump version number to 8.8.2 as an example 2024-05-15 13:27:19 -04:00
cmd Bump version number to 8.8.2 as an example 2024-05-15 13:27:19 -04:00
docker Build using local source files instead of git cloning; do not strip or upx-compress the debug binary 2024-02-21 07:50:29 -06:00
types All arguments are now at most two hyphenated words 2024-02-06 16:10:06 -06:00
vendor Updated transitive dependencies 2024-05-13 09:56:40 -04:00
.gitignore Initial commit 2022-09-08 10:12:06 -05:00
LICENSE Update release year 2024-01-14 12:39:14 -06:00
README.md Replace 'container' with 'image' for consistency 2024-02-21 07:58:38 -06:00
build-docker.sh Build using local source files instead of git cloning; do not strip or upx-compress the debug binary 2024-02-21 07:50:29 -06:00
build.sh Bump Go version to 1.22; remove openbsd/mips builds 2024-02-07 11:44:30 -06:00
default.pgo Update PGO profile 2024-02-08 21:05:48 -06:00
go.mod Updated transitive dependencies 2024-05-13 09:56:40 -04:00
go.sum Updated transitive dependencies 2024-05-13 09:56:40 -04:00
main.go Update release year 2024-01-14 12:39:14 -06:00

README.md

About

Sometimes, you just need a way to randomly display media from your filesystem.

Simply point this tool at one or more directories, and then open the specified port (default 8080) in your browser.

A new file will be selected if you open / directly, or if you click on any displayed files.

Browser history is preserved, so you can always go back to any previously displayed media.

Feature requests, code criticism, bug reports, general chit-chat, and unrelated angst accepted at roulette@seedno.de.

Static binary builds available here.

I only test the linux/amd64, linux/arm64, and windows/amd64 builds, the rest are all best-effort™.

x86_64 and ARM Docker images of latest version: oci.seedno.de/seednode/roulette:latest.

Dockerfile available here.

An example instance with most features enabled can be found here.

Admin prefix

You can restrict access to certain functionality (the REST API and profiling endpoints) by prepending a secret string to the paths.

For example, providing the --admin-prefix=abc123 flag will register the index rebuild path as /abc123/index/rebuild.

The restricted paths are:

  • /debug/pprof/allocs
  • /debug/pprof/block
  • /debug/pprof/cmdline
  • /debug/pprof/goroutine
  • /debug/pprof/heap
  • /debug/pprof/mutex
  • /debug/pprof/profile
  • /debug/pprof/symbol
  • /debug/pprof/threadcreate
  • /debug/pprof/trace
  • /extensions/available
  • /extensions/enabled
  • /index/
  • /index/rebuild
  • /types/available
  • /types/enabled

While this might thwart very basic attacks, the proper solution for most use cases would likely be to add authentication via a reverse proxy.

API

If the --api flag is passed, a number of REST endpoints are registered.

The first of these—/index/—responds to GET requests with the contents of the index, in JSON format.

The second—/index/rebuild—responds to POST requests by rebuilding 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 respond to GET requests with information about the registered file types:

  • /extensions/available
  • /extensions/enabled
  • /types/available
  • /types/enabled

Filtering

You can provide a comma-delimited string of alphanumeric patterns to match via the include= query parameter, assuming the -f|--filter flag is enabled.

Only filenames matching one or more of the patterns will be served.

You can also provide a comma-delimited string of alphanumeric patterns to exclude, via the exclude= query parameter.

Filenames matching any of these patterns will not be served.

You can combine these two parameters, with exclusions taking priority over inclusions.

Both filtering parameters ignore the file extension and full path; they only compare against the bare filename.

Ignoring directories

If the --ignore <filename> flag is passed, any directory containing a file with the specified name will be skipped during the scanning stage.

Indexing

If the -i|--index flag is passed, all specified paths will be indexed on start.

This will slightly increase the delay before the application begins responding to requests, but should significantly speed up subsequent requests.

Automatic index rebuilds can be enabled via the --index-interval <duration> flag, which accepts time.Duration strings.

If --index-file <filename> is set, the index will be loaded from the specified file on start, and written to the file whenever it is re-generated.

The index file consists of zstd-compressed gobs.

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.

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.

Supported units are ns, us/µs, ms, s, m, and h.

Russian

If the --russian flag is passed, everything functions exactly as you would expect.

That is, files will be deleted after being served. This is not a joke, you will lose data.

This uses os.Remove() and checks to ensure the specified file is inside one of the paths passed to roulette.

That said, this has not been tested to any real extent, so only pass this flag on systems you don't care about.

Enjoy!

Sorting

You can specify a sorting direction via the sort= query parameter, assuming the -s|--sort flag is enabled.

A value of sort=asc means files will be served in ascending order (lowest-numbered to highest).

If a file exists with a numbered suffix one higher than the currently displayed file, it will be served next.

A value of sort=desc means files will be served in descending order (highest-numbered to lowest).

If a file exists with a numbered suffix one lower than the currently displayed file, it will be served next.

In either case, if no sequential file is found, a new random one will be chosen.

For sort=asc, the lowest-numbered file matching a given name will be served first.

For sort=desc, the highest-numbered file will be served instead.

If any other (or no) value is provided, the selected file will be random.

Note: These options require sequentially-numbered files matching the following pattern: filename[0-9]*.extension.

Themes

The --code handler provides syntax highlighting via alecthomas/chroma.

Any supported theme can be passed via the --code-theme flag.

By default, solarized-dark256 is used.

Usage output

Serves random media from the specified directories.

Usage:
  roulette <path> [path]... [flags]

Flags:
      --admin-prefix string     string to prepend to administrative paths
  -a, --all                     enable all supported file types
      --allow-empty             allow specifying paths containing no supported files
      --api                     expose REST API
      --audio                   enable support for audio files
  -b, --bind string             address to bind to (default "0.0.0.0")
      --case-insensitive        use case-insensitive matching for filters
      --code                    enable support for source code files
      --code-theme string       theme for source code syntax highlighting (default "solarized-dark256")
      --concurrency int         maximum concurrency for scan threads (default 1024)
  -d, --debug                   log file permission errors instead of simply skipping the files
      --error-exit              shut down webserver on error, instead of just printing error
      --fallback                serve files as application/octet-stream if no matching format is registered
  -f, --filter                  enable filtering
      --flash                   enable support for shockwave flash files (via ruffle.rs)
      --fun                     add a bit of excitement to your day
  -h, --help                    help for roulette
      --ignore string           filename used to indicate directory should be skipped
      --images                  enable support for image files
  -i, --index                   generate index of supported file paths at startup
      --index-file string       path to optional persistent index file
      --index-interval string   interval at which to regenerate index (e.g. "5m" or "1h")
      --max-files int           skip directories with file counts above this value (default 2147483647)
      --min-files int           skip directories with file counts below this value
      --no-buttons              disable first/prev/next/last buttons
  -p, --port int                port to listen on (default 8080)
      --prefix string           root path for http handlers (for reverse proxying) (default "/")
      --profile                 register net/http/pprof handlers
  -r, --recursive               recurse into subdirectories
      --refresh                 enable automatic page refresh via query parameter
      --russian                 remove selected images after serving
  -s, --sort                    enable sorting
      --text                    enable support for text files
  -v, --verbose                 log accessed files and other information to stdout
  -V, --version                 display version and exit
      --video                   enable support for video files

Building the Docker image

From inside the cloned repository, build the image using the following command:

REGISTRY=<registry url> LATEST=yes TAG=alpine ./build-docker.sh