almost full rewrite of the app; now based on streams
This commit is contained in:
parent
9db0a257c0
commit
2dcb96399d
10 changed files with 285 additions and 150 deletions
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
|
@ -10,8 +10,8 @@
|
||||||
"env":{
|
"env":{
|
||||||
"SLIDESHOW_ADDRESS": "0.0.0.0",
|
"SLIDESHOW_ADDRESS": "0.0.0.0",
|
||||||
"SLIDESHOW_PORT": "3000",
|
"SLIDESHOW_PORT": "3000",
|
||||||
"SLIDESHOW_DIRECTORY": "/home/velvettear/images",
|
"SLIDESHOW_DIRECTORY": "/mnt/images",
|
||||||
"SLIDESHOW_SCANINTERVAL": "10",
|
"SLIDESHOW_SCANINTERVAL": "600",
|
||||||
"SLIDESHOW_RESOLUTION": "600x1024",
|
"SLIDESHOW_RESOLUTION": "600x1024",
|
||||||
"SLIDESHOW_LOGLEVEL": "debug",
|
"SLIDESHOW_LOGLEVEL": "debug",
|
||||||
"SLIDESHOW_PALETTE_ALGORITHM": "wsm",
|
"SLIDESHOW_PALETTE_ALGORITHM": "wsm",
|
||||||
|
|
|
@ -22,7 +22,7 @@ configuration is entirely done via environment variables.
|
||||||
| SLIDESHOW_LOGLEVEL | "info" | the log level |
|
| SLIDESHOW_LOGLEVEL | "info" | the log level |
|
||||||
|
|
||||||
**note:**
|
**note:**
|
||||||
if `SLIDESHOW_RESOLUTION` is unset the images will served as they are (without any scaling).
|
if `SLIDESHOW_RESOLUTION` is unset or imagemagick's `convert` command is not in your `$PATH` the images will served as they are (without any scaling).
|
||||||
|
|
||||||
**available log levels:**
|
**available log levels:**
|
||||||
|
|
||||||
|
|
37
internal/api/response.go
Normal file
37
internal/api/response.go
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"git.velvettear.de/velvettear/loggo"
|
||||||
|
)
|
||||||
|
|
||||||
|
// struct for server responses
|
||||||
|
type response struct {
|
||||||
|
StatusCode int
|
||||||
|
Content interface{}
|
||||||
|
error error
|
||||||
|
}
|
||||||
|
|
||||||
|
// send a response
|
||||||
|
func (response *response) send(writer http.ResponseWriter) {
|
||||||
|
if response.StatusCode <= 0 {
|
||||||
|
if response.error != nil {
|
||||||
|
response.StatusCode = 500
|
||||||
|
} else {
|
||||||
|
response.StatusCode = 200
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if response.error != nil {
|
||||||
|
response.Content = response.error.Error()
|
||||||
|
}
|
||||||
|
data, error := json.Marshal(response)
|
||||||
|
if error != nil {
|
||||||
|
loggo.Error("encountered an error marshalling a json response", error.Error())
|
||||||
|
response.StatusCode = 500
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writer.WriteHeader(response.StatusCode)
|
||||||
|
writer.Write(data)
|
||||||
|
}
|
|
@ -1,9 +1,10 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.velvettear.de/velvettear/loggo"
|
"git.velvettear.de/velvettear/loggo"
|
||||||
"git.velvettear.de/velvettear/slideshow-api/internal"
|
"git.velvettear.de/velvettear/slideshow-api/internal"
|
||||||
|
@ -23,42 +24,47 @@ func Run() {
|
||||||
|
|
||||||
// register the handlers
|
// register the handlers
|
||||||
func registerHandlers() {
|
func registerHandlers() {
|
||||||
http.HandleFunc("/", handleImageRequest)
|
http.HandleFunc("/", serveRandomImageName)
|
||||||
|
http.HandleFunc("/image/", serveImage)
|
||||||
|
http.HandleFunc("/palette/", servePalette)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle the request to '/image'
|
// request url: '/' - serve the name of a random image
|
||||||
func handleImageRequest(writer http.ResponseWriter, request *http.Request) {
|
func serveRandomImageName(writer http.ResponseWriter, request *http.Request) {
|
||||||
if !internal.HasFoundImages() {
|
timestamp := time.Now().UnixMilli()
|
||||||
writer.WriteHeader(404)
|
var response response
|
||||||
return
|
response.Content, response.error = internal.GetRandomImage()
|
||||||
|
if response.error != nil {
|
||||||
|
response.StatusCode = 404
|
||||||
}
|
}
|
||||||
name, data, error := internal.GetRandomImage()
|
response.send(writer)
|
||||||
|
loggo.DebugTimed("served random image '"+response.Content.(string)+"'", timestamp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// request url: '/image' - serve an image
|
||||||
|
func serveImage(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
var response response
|
||||||
|
image, _ := strings.CutPrefix(request.URL.Path, "/image/")
|
||||||
|
image, error := internal.GetImagePath(image)
|
||||||
if error != nil {
|
if error != nil {
|
||||||
loggo.Error("encountered an error getting a random image", error.Error())
|
response.error = error
|
||||||
writer.WriteHeader(501)
|
response.StatusCode = 404
|
||||||
writer.Write([]byte("encountered an internal server error (" + error.Error() + ")\n"))
|
response.send(writer)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
palette, error := internal.GetColorPalette(data)
|
streamImage(writer, image)
|
||||||
|
}
|
||||||
|
|
||||||
|
// request url: '/palette' - serve the color palette of an image
|
||||||
|
func servePalette(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
var response response
|
||||||
|
image, _ := strings.CutPrefix(request.URL.Path, "/palette/")
|
||||||
|
image, error := internal.GetImagePath(image)
|
||||||
if error != nil {
|
if error != nil {
|
||||||
writer.WriteHeader(501)
|
response.error = error
|
||||||
writer.Write([]byte("encountered an internal server error (" + error.Error() + ")\n"))
|
response.StatusCode = 404
|
||||||
|
response.send(writer)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
bytes, error := json.Marshal(struct {
|
streamColorPalette(writer, image)
|
||||||
Name string
|
|
||||||
Palette string
|
|
||||||
Data []byte
|
|
||||||
}{
|
|
||||||
name,
|
|
||||||
palette,
|
|
||||||
data,
|
|
||||||
})
|
|
||||||
if error != nil {
|
|
||||||
loggo.Error("encountered an error marshalling the json response", error.Error())
|
|
||||||
writer.WriteHeader(501)
|
|
||||||
writer.Write([]byte("encountered an internal server error (" + error.Error() + ")\n"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
writer.Write(bytes)
|
|
||||||
}
|
}
|
||||||
|
|
124
internal/api/stream.go
Normal file
124
internal/api/stream.go
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.velvettear.de/velvettear/loggo"
|
||||||
|
"git.velvettear.de/velvettear/slideshow-api/internal"
|
||||||
|
"git.velvettear.de/velvettear/slideshow-api/internal/config"
|
||||||
|
color_thief "github.com/kennykarnama/color-thief"
|
||||||
|
)
|
||||||
|
|
||||||
|
// central streaming method for images
|
||||||
|
func streamImage(writer http.ResponseWriter, image string) {
|
||||||
|
if config.IsResolutionSet() {
|
||||||
|
streamScaledImage(writer, image)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
streamUnscaledImage(writer, image)
|
||||||
|
}
|
||||||
|
|
||||||
|
// stream a color palette
|
||||||
|
func streamColorPalette(writer http.ResponseWriter, image string) {
|
||||||
|
timestamp := time.Now().UnixMilli()
|
||||||
|
var response response
|
||||||
|
amount := config.PaletteColors
|
||||||
|
colors, error := color_thief.GetPaletteFromFile(image, amount, config.PaletteAlgorithm)
|
||||||
|
if error != nil {
|
||||||
|
loggo.Error("encountered an error getting the color palette from image '"+image+"'", error.Error())
|
||||||
|
response.error = error
|
||||||
|
response.send(writer)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var palette string
|
||||||
|
for index, color := range colors {
|
||||||
|
if index > 0 {
|
||||||
|
palette += "\n"
|
||||||
|
}
|
||||||
|
tmp := strconv.Itoa(index)
|
||||||
|
if len(tmp) < 2 {
|
||||||
|
tmp = "0" + tmp
|
||||||
|
}
|
||||||
|
tmp = "SLIDESHOW_COLOR" + tmp
|
||||||
|
palette += tmp + "=\"" + internal.RgbToHex(color) + "\""
|
||||||
|
}
|
||||||
|
data := []byte(palette)
|
||||||
|
writer.Write(data)
|
||||||
|
loggo.InfoTimed("successfully streamed color palette for image '"+image+"'", timestamp, "size: "+internal.FormatBytes(int64(len(data))))
|
||||||
|
}
|
||||||
|
|
||||||
|
// stream an unscaled image
|
||||||
|
func streamUnscaledImage(writer http.ResponseWriter, image string) {
|
||||||
|
timestamp := time.Now().UnixMilli()
|
||||||
|
var response response
|
||||||
|
file, error := os.Open(image)
|
||||||
|
if error != nil {
|
||||||
|
loggo.Error("encountered an error opening image '"+image+"' for streaming", error.Error())
|
||||||
|
response.error = error
|
||||||
|
response.send(writer)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
written, error := io.Copy(writer, file)
|
||||||
|
if error != nil {
|
||||||
|
loggo.Error("encountered an error piping image '"+image+"' to stream", error.Error())
|
||||||
|
response.error = error
|
||||||
|
response.send(writer)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
loggo.InfoTimed("successfully streamed image '"+image+"'", timestamp, "size: "+internal.FormatBytes(written))
|
||||||
|
}
|
||||||
|
|
||||||
|
// scale and stream an image
|
||||||
|
func streamScaledImage(writer http.ResponseWriter, image string) {
|
||||||
|
timestamp := time.Now().UnixMilli()
|
||||||
|
var response response
|
||||||
|
cmd := exec.Command("convert", image, "-resize", config.Resolution+"^", "-gravity", "center", "-extent", config.Resolution, "-")
|
||||||
|
stdout, stdoutError := cmd.StdoutPipe()
|
||||||
|
stderr, stderrError := cmd.StderrPipe()
|
||||||
|
cmd.Start()
|
||||||
|
if stdoutError != nil {
|
||||||
|
loggo.Error("enountered an error opening imagemagicks's stdout pipe", stdoutError.Error())
|
||||||
|
response.error = stdoutError
|
||||||
|
response.send(writer)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if stderrError != nil {
|
||||||
|
loggo.Error("enountered an error opening imagemagicks's stderr pipe", stderrError.Error())
|
||||||
|
response.error = stderrError
|
||||||
|
response.send(writer)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
written, copyError := io.Copy(writer, stdout)
|
||||||
|
if copyError != nil {
|
||||||
|
loggo.Error("enountered an error piping imagemagicks's output to the stream", copyError.Error())
|
||||||
|
response.error = copyError
|
||||||
|
response.send(writer)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if written == 0 {
|
||||||
|
errorBytes, stderrError := io.ReadAll(stderr)
|
||||||
|
if stderrError != nil {
|
||||||
|
loggo.Error("enountered an error reading imagemagicks's stderr", stderrError.Error())
|
||||||
|
response.error = stderrError
|
||||||
|
response.send(writer)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(errorBytes) > 0 {
|
||||||
|
error := errors.New(strings.TrimSpace(string(errorBytes)))
|
||||||
|
loggo.Error("enountered an error executing imagemagick", error.Error())
|
||||||
|
response.error = error
|
||||||
|
response.send(writer)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmd.Wait()
|
||||||
|
loggo.InfoTimed("successfully streamed scaled image '"+image+"'", timestamp, "size: "+internal.FormatBytes(written), "resolution: "+config.Resolution)
|
||||||
|
}
|
|
@ -1,44 +0,0 @@
|
||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"image/color"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// the internally pre buffered (and scaled) image
|
|
||||||
var cachedImage []byte
|
|
||||||
|
|
||||||
// the internally pre buffered color palette
|
|
||||||
var cachedPalette []byte
|
|
||||||
|
|
||||||
// cache an image
|
|
||||||
func cacheImage(image []byte) {
|
|
||||||
cachedImage = image
|
|
||||||
}
|
|
||||||
|
|
||||||
// cache a color palette
|
|
||||||
func cachePalette(colors []color.Color) {
|
|
||||||
var palette string
|
|
||||||
for index, color := range colors {
|
|
||||||
if index > 0 {
|
|
||||||
palette += "\n"
|
|
||||||
}
|
|
||||||
tmp := strconv.Itoa(index)
|
|
||||||
if len(tmp) < 2 {
|
|
||||||
tmp = "0" + tmp
|
|
||||||
}
|
|
||||||
tmp = "SLIDESHOW_COLOR" + tmp
|
|
||||||
palette += tmp + "=\"" + rgbToHex(color) + "\""
|
|
||||||
}
|
|
||||||
cachedPalette = []byte(palette)
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if an image is cached
|
|
||||||
func hasCachedImage() bool {
|
|
||||||
return len(cachedImage) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if a color palette is cached
|
|
||||||
func hasCachedColorPalette() bool {
|
|
||||||
return len(cachedPalette) > 0
|
|
||||||
}
|
|
|
@ -2,6 +2,7 @@ package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -16,6 +17,7 @@ var ScanInterval time.Duration
|
||||||
var Resolution string
|
var Resolution string
|
||||||
var PaletteAlgorithm int
|
var PaletteAlgorithm int
|
||||||
var PaletteColors int
|
var PaletteColors int
|
||||||
|
var BufferSize int
|
||||||
|
|
||||||
// initialize the config
|
// initialize the config
|
||||||
func Initialize() {
|
func Initialize() {
|
||||||
|
@ -72,6 +74,25 @@ func Initialize() {
|
||||||
tmpInt = 16
|
tmpInt = 16
|
||||||
}
|
}
|
||||||
PaletteColors = tmpInt
|
PaletteColors = tmpInt
|
||||||
|
tmpInt, _ = strconv.Atoi(os.Getenv("SLIDESHOW_BUFFERSIZE"))
|
||||||
|
if tmpInt <= 0 {
|
||||||
|
tmpInt = 4096
|
||||||
|
}
|
||||||
|
BufferSize = tmpInt
|
||||||
|
if IsResolutionSet() {
|
||||||
|
checkForConvert()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if 'convert' is available
|
||||||
|
func checkForConvert() {
|
||||||
|
cmd := exec.Command("convert")
|
||||||
|
error := cmd.Run()
|
||||||
|
if error == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Resolution = ""
|
||||||
|
loggo.Warning("could not find imagemagick's 'convert' command, no scaling will be done", error.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if a resolution has been specified
|
// check if a resolution has been specified
|
||||||
|
|
27
internal/formatter.go
Normal file
27
internal/formatter.go
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"image/color"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// format bytes
|
||||||
|
func FormatBytes(bytes int64) string {
|
||||||
|
value := float64(bytes)
|
||||||
|
unit := "bytes"
|
||||||
|
if bytes > 1000000 {
|
||||||
|
value = value / 1000000
|
||||||
|
unit = "mega" + unit
|
||||||
|
} else if bytes > 1000 {
|
||||||
|
value = value / 1000
|
||||||
|
unit = "kilo" + unit
|
||||||
|
}
|
||||||
|
return strconv.FormatFloat(value, 'f', 2, 64) + " " + unit
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse rgb color values to a hex hex
|
||||||
|
func RgbToHex(color color.Color) string {
|
||||||
|
r, g, b, _ := color.RGBA()
|
||||||
|
return fmt.Sprintf("#%02x%02x%02x", uint8(r>>8), uint8(g>>8), uint8(b>>8))
|
||||||
|
}
|
|
@ -1,43 +0,0 @@
|
||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.velvettear.de/velvettear/loggo"
|
|
||||||
"git.velvettear.de/velvettear/slideshow-api/internal/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
// scale an image
|
|
||||||
func ScaleImage(image string) ([]byte, error) {
|
|
||||||
timestamp := time.Now().UnixMilli()
|
|
||||||
cmd := exec.Command("convert", image, "-resize", config.Resolution+"^", "-gravity", "center", "-extent", config.Resolution, "-")
|
|
||||||
stdout, stdoutError := cmd.StdoutPipe()
|
|
||||||
stderr, stderrError := cmd.StderrPipe()
|
|
||||||
var data []byte
|
|
||||||
cmd.Start()
|
|
||||||
if stdoutError != nil {
|
|
||||||
return data, stdoutError
|
|
||||||
}
|
|
||||||
if stderrError != nil {
|
|
||||||
return data, stdoutError
|
|
||||||
}
|
|
||||||
data, stdoutError = io.ReadAll(stdout)
|
|
||||||
if stdoutError != nil {
|
|
||||||
return data, stdoutError
|
|
||||||
}
|
|
||||||
errorBytes, stderrError := io.ReadAll(stderr)
|
|
||||||
if stderrError != nil {
|
|
||||||
return data, stdoutError
|
|
||||||
}
|
|
||||||
cmd.Wait()
|
|
||||||
errorMessage := strings.TrimSpace(string(errorBytes))
|
|
||||||
if len(errorMessage) > 0 {
|
|
||||||
return data, errors.New(errorMessage)
|
|
||||||
}
|
|
||||||
loggo.DebugTimed("successfully scaled image", timestamp, "image: "+image, "resolution: "+config.Resolution)
|
|
||||||
return data, nil
|
|
||||||
}
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -14,17 +13,18 @@ import (
|
||||||
"git.velvettear.de/velvettear/slideshow-api/internal/config"
|
"git.velvettear.de/velvettear/slideshow-api/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// slice of images
|
// map of images
|
||||||
var images []string
|
var images map[string]string
|
||||||
|
|
||||||
// temporary slice of images
|
// temporary map of images
|
||||||
var tmpImages []string
|
var tmpImages map[string]string
|
||||||
|
|
||||||
// Scan the specified directory
|
// Scan the specified directory
|
||||||
func Scan() {
|
func Scan() {
|
||||||
timestamp := time.Now()
|
timestamp := time.Now()
|
||||||
directory := config.Directory
|
directory := config.Directory
|
||||||
loggo.Info("scanning directory for images and subdirectories...", "interval: "+strconv.FormatFloat(config.ScanInterval.Seconds(), 'f', 0, 64)+" seconds", "directory: "+directory)
|
loggo.Info("scanning directory for images and subdirectories...", "interval: "+strconv.FormatFloat(config.ScanInterval.Seconds(), 'f', 0, 64)+" seconds", "directory: "+directory)
|
||||||
|
tmpImages = make(map[string]string)
|
||||||
filepath.WalkDir(directory, checkDirectory)
|
filepath.WalkDir(directory, checkDirectory)
|
||||||
images = tmpImages
|
images = tmpImages
|
||||||
tmpImages = nil
|
tmpImages = nil
|
||||||
|
@ -32,26 +32,33 @@ func Scan() {
|
||||||
go scheduleRescan()
|
go scheduleRescan()
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if images has been found
|
// get a random image
|
||||||
func HasFoundImages() bool {
|
func GetRandomImage() (string, error) {
|
||||||
return len(images) > 0
|
if len(images) == 0 {
|
||||||
|
return "", errors.New("no images have been found in directory '" + config.Directory + "'")
|
||||||
|
}
|
||||||
|
random := rand.Intn(len(images))
|
||||||
|
index := 0
|
||||||
|
for key := range images {
|
||||||
|
if index == random {
|
||||||
|
return key, nil
|
||||||
|
}
|
||||||
|
index++
|
||||||
|
}
|
||||||
|
return "", errors.New("could not find a random image with index '" + strconv.Itoa(random) + "'")
|
||||||
}
|
}
|
||||||
|
|
||||||
// get a random image
|
// get the path of an image by name
|
||||||
func GetRandomImage() (string, []byte, error) {
|
func GetImagePath(name string) (string, error) {
|
||||||
var name string
|
var path string
|
||||||
var data []byte
|
if len(name) == 0 {
|
||||||
var error error
|
return path, errors.New("no image name provided")
|
||||||
if len(images) == 0 {
|
|
||||||
return name, data, errors.New("no images have been found")
|
|
||||||
}
|
}
|
||||||
image := images[rand.Intn(len(images))]
|
image := images[name]
|
||||||
if config.IsResolutionSet() {
|
if len(image) == 0 {
|
||||||
data, error = ScaleImage(image)
|
return path, errors.New("could not find image '" + name + "' in internal map")
|
||||||
} else {
|
|
||||||
data, error = os.ReadFile(image)
|
|
||||||
}
|
}
|
||||||
return image, data, error
|
return image, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// sleep the specified interval and then trigger a rescan of the specified directory
|
// sleep the specified interval and then trigger a rescan of the specified directory
|
||||||
|
@ -61,7 +68,7 @@ func scheduleRescan() {
|
||||||
Scan()
|
Scan()
|
||||||
}
|
}
|
||||||
|
|
||||||
// add image files to the slice of images and subdirectoies to the watcher
|
// add image files to the map of images
|
||||||
func checkDirectory(path string, dir fs.DirEntry, err error) error {
|
func checkDirectory(path string, dir fs.DirEntry, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -69,8 +76,8 @@ func checkDirectory(path string, dir fs.DirEntry, err error) error {
|
||||||
if dir.IsDir() || !isImage(path) {
|
if dir.IsDir() || !isImage(path) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
tmpImages = append(tmpImages, path)
|
tmpImages[filepath.Base(path)] = path
|
||||||
loggo.Debug("added image to temporary slice of images", path)
|
loggo.Debug("added image to temporary map of images", path)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue