diff --git a/README.md b/README.md index 8bed2d5..279b37d 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ ## About -Sometimes, you just need a way to randomly display images from your filesystem. +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 image will be selected if you open `/` directly, or if you click on any displayed image. +A new file will be selected if you open `/` directly, or if you click on any displayed media. -Browser history is preserved, so you can always go back to any previously displayed image. +Browser history is preserved, so you can always go back to any previously displayed media. -Supported file types and extensions are `bmp`, `gif`, `jp[e]g`, `png`, and `webp`. +Supported file types and extensions are `bmp`, `gif`, `jp[e]g`, `png`, `webp`, `mp4`, `ogv`, and `webm`. Feature requests, code criticism, bug reports, general chit-chat, and unrelated angst accepted at `roulette@seedno.de`. @@ -60,7 +60,7 @@ Note: These patterns require sequentially-numbered files matching the following If a positive-value `refresh=` query parameter is provided, the page will reload after that interval. -This can be used to generate a sort of slideshow of images. +This can be used to generate a sort of slideshow of files. Supported units are `ns`, `us`/`µs`, `ms`, `s`, `m`, and `h`. diff --git a/cmd/files.go b/cmd/files.go index c48e7d4..8a18c6e 100644 --- a/cmd/files.go +++ b/cmd/files.go @@ -43,7 +43,7 @@ type Concurrency struct { var ( ErrNoImagesFound = fmt.Errorf("no supported image formats found which match all criteria") - Extensions = [6]string{".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp"} + Extensions = [9]string{".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp", ".mp4", ".ogv", ".webm"} ) type Dimensions struct { @@ -168,12 +168,12 @@ func preparePath(path string) string { func appendPath(directory, path string, files *Files, stats *ScanStats, shouldCache bool) error { if shouldCache { - image, err := isImage(path) + image, video, err := isSupportedFileType(path) if err != nil { return err } - if !image { + if !(image || video) { return nil } } @@ -382,20 +382,27 @@ func pathIsValid(filePath string, paths []string) bool { } } -func isImage(path string) (bool, error) { +func isSupportedFileType(path string) (bool, bool, error) { file, err := os.Open(path) switch { case errors.Is(err, os.ErrNotExist): - return false, nil + return false, false, nil case err != nil: - return false, err + return false, false, err } defer file.Close() head := make([]byte, 261) file.Read(head) - return filetype.IsImage(head), nil + switch { + case filetype.IsImage(head): + return true, false, nil + case filetype.IsVideo(head): + return false, true, nil + default: + return false, false, nil + } } func pathHasSupportedFiles(path string) (bool, error) { @@ -410,12 +417,12 @@ func pathHasSupportedFiles(path string) (bool, error) { case !recursive && info.IsDir() && p != path: return filepath.SkipDir case !info.IsDir(): - image, err := isImage(p) + image, video, err := isSupportedFileType(p) if err != nil { return err } - if image { + if image || video { hasSupportedFiles <- true return filepath.SkipAll } @@ -609,12 +616,12 @@ func pickFile(args []string, filters *Filters, sort string, index *Index) (strin filePath := fileList[r] if !fromCache { - isImage, err := isImage(filePath) + image, video, err := isSupportedFileType(filePath) if err != nil { return "", err } - if isImage { + if image || video { return filePath, nil } diff --git a/cmd/version.go b/cmd/version.go index a02868c..b6eac66 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -10,7 +10,7 @@ import ( "github.com/spf13/cobra" ) -var Version = "0.44.0" +var Version = "0.45.0" func init() { rootCmd.AddCommand(versionCmd) diff --git a/cmd/web.go b/cmd/web.go index 0802f5f..2af808d 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -751,21 +751,26 @@ func serveImage(paths []string, Regexes *Regexes, index *Index) http.HandlerFunc return } - image, err := isImage(filePath) + image, video, err := isSupportedFileType(filePath) if err != nil { fmt.Println(err) return } - if !image { + + if !(image || video) { notFound(w, r, filePath) return } - dimensions, err := imageDimensions(filePath) - if err != nil { - fmt.Println(err) - return + var dimensions *Dimensions + + if image { + dimensions, err = imageDimensions(filePath) + if err != nil { + fmt.Println(err) + return + } } fileName := filepath.Base(filePath) @@ -782,24 +787,38 @@ func serveImage(paths []string, Regexes *Regexes, index *Index) http.HandlerFunc htmlBody.WriteString(``) htmlBody.WriteString(``) - htmlBody.WriteString(fmt.Sprintf(`%s (%dx%d)`, - fileName, - dimensions.width, - dimensions.height)) + switch { + case image: + htmlBody.WriteString(fmt.Sprintf(`%s (%dx%d)`, + fileName, + dimensions.width, + dimensions.height)) + case video: + htmlBody.WriteString(fmt.Sprintf(`%s`, + fileName)) + } htmlBody.WriteString(``) if refreshInterval != "0ms" { htmlBody.WriteString(fmt.Sprintf("", queryParams, refreshTimer)) } - htmlBody.WriteString(fmt.Sprintf(`Roulette selected: %s`, - queryParams, - generateFilePath(filePath), - dimensions.width, - dimensions.height, - fileName)) + switch { + case image: + htmlBody.WriteString(fmt.Sprintf(`Roulette selected: %s`, + queryParams, + generateFilePath(filePath), + dimensions.width, + dimensions.height, + fileName)) + case video: + htmlBody.WriteString(fmt.Sprintf(``, + queryParams, + generateFilePath(filePath), + fileName)) + } htmlBody.WriteString(``) _, err = io.WriteString(w, gohtml.Format(htmlBody.String()))