made image icons cached and show in index
sophuwu sophie@skisiel.com
Thu, 27 Mar 2025 00:54:10 +0100
7 files changed,
264 insertions(+),
38 deletions(-)
M
config/config.go
→
config/config.go
@@ -1,6 +1,7 @@
package config import ( + "fmt" "os" "strings" )@@ -11,12 +12,31 @@ var HttpDir string
var Port string var Addr string +func checkAbs(path string) bool { + if len(path) < 2 || path[0] != '/' { + return false + } + return true +} + +func checkDir(path string) bool { + if st, err := os.Stat(path); err == nil && st.IsDir() { + return true + } + return false +} + +func checkAbsDir(path string) bool { + return checkAbs(path) && checkDir(path) +} + func Get() { OtpPath = strings.TrimSpace(os.Getenv("OTP_PATH")) DbPath = strings.TrimSpace(os.Getenv("DB_PATH")) HttpDir = strings.TrimSpace(os.Getenv("HTTP_DIR")) - if HttpDir == "" { - HttpDir = "." + if !checkAbs(DbPath) || !checkAbs(OtpPath) || !checkAbsDir(HttpDir) { + fmt.Println("Please set the environment variables OTP_PATH, DB_PATH and HTTP_DIR to absolute paths.") + os.Exit(1) } Port = strings.TrimSpace(os.Getenv("PORT")) if Port == "" {@@ -26,4 +46,5 @@ Addr = strings.TrimSpace(os.Getenv("ADDR"))
if Addr == "" { Addr = "127.0.0.1" } + }
M
go.mod
→
go.mod
@@ -1,13 +1,18 @@
-module sophuwu.site/cdn +module git.sophuwu.com/cdn + +go 1.23.0 -go 1.22.2 +toolchain go1.24.1 -require go.etcd.io/bbolt v1.3.11 +require ( + github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 + github.com/pquerna/otp v1.4.0 + go.etcd.io/bbolt v1.3.11 + golang.org/x/image v0.25.0 +) require ( - github.com/blang/vfs v1.0.0 // indirect + github.com/asdine/storm/v3 v3.2.1 // indirect github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect - github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect - github.com/pquerna/otp v1.4.0 // indirect golang.org/x/sys v0.4.0 // indirect )
M
go.sum
→
go.sum
@@ -1,10 +1,18 @@
-github.com/blang/vfs v1.0.0 h1:AUZUgulCDzbaNjTRWEP45X7m/J10brAptZpSRKRZBZc= -github.com/blang/vfs v1.0.0/go.mod h1:jjuNUc/IKcRNNWC9NUCvz4fR9PZLPIKxEygtPs/4tSI= +github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/Sereal/Sereal v0.0.0-20190618215532-0b8ac451a863/go.mod h1:D0JMgToj/WdxCgd30Kc1UcA9E+WdZoJqeVOuYW7iTBM= +github.com/asdine/storm/v3 v3.2.1 h1:I5AqhkPK6nBZ/qJXySdI7ot5BlXSZ7qvDY1zAn5ZJac= +github.com/asdine/storm/v3 v3.2.1/go.mod h1:LEpXwGt4pIqrE/XcTvCnZHT5MgZCV6Ub9q7yQzOFWr0= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=@@ -12,14 +20,29 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg= github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= +go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0= go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ= +golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20191105084925-a882066a44e0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
M
html/filelabel.html
→
html/filelabel.html
@@ -2,9 +2,9 @@ {{ define "filelabel" }}
<a href="{{ .Url }}"> <div class="filelabel"> <span class="icon">{{ .Icon }}</span> - <span>{{ .Name }}</span> + <span class="file-name">{{ .Name }}</span> <span class="right">{{ .Size }}</span> - <span class="right" title="{{ .Mod.Full }}">{{ .Mod.Short }}</span> + <span class="right mod-time" title="{{ .Mod.Full }}">{{ .Mod.Short }}</span> </div> </a> {{ end }}
M
html/index.html
→
html/index.html
@@ -12,6 +12,40 @@ <title>Error</title>
{{ end }} {{ end }} <meta name="viewport" content="width=device-width, initial-scale=1"> + <script> + function fileExt(url) { + let i = url.toString().toLowerCase().lastIndexOf("."); + if (i === -1) { + return ""; + } + return url.toString().toLowerCase().substring(url.toString().lastIndexOf(".")); + } + const imgExts = [".jpg", ".jpeg", ".png", ".gif", ".webp"]; + var dirPath = "{{ .Path }}"; + if (!dirPath.endsWith("/")) { + dirPath += "/"; + } + function IconCheck(elem) { + let icon = elem.querySelector(".icon"); + if (icon.innerText === "F") { + return; + } + let url = elem.querySelector(".file-name").innerText; + let ext = fileExt(url); + if (imgExts.includes(ext)) { + let mod = elem.querySelector(".mod-time").title.replaceAll(" ", "_").replaceAll(":", "_"); + url = dirPath + url; + icon.innerHTML = "<img src='"+url+".png?icon=" + url + "&mod="+ mod +"' alt='f'/>"; + } else if (ext === ".mp4") { + icon.innerText = "v"; + } + } + document.addEventListener("DOMContentLoaded", function() { + document.querySelectorAll(".filelabel").forEach(filelement => { + IconCheck(filelement); + }); + }); + </script> <style> :root{ color:white;@@ -65,11 +99,17 @@ .right{text-align: right;}
@font-face{ font-family: "sophuwuicons"; - src: url("data:font/ttf;base64,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") format("truetype"); + src: url("data:font/ttf;base64,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") format("truetype"); } .icon { font-family: "sophuwuicons"; font-size: 2rem; +} +.icon > img { + max-width: 2rem; + max-height: 2rem; + width: auto; + height: auto; } </style> </head>
A
imgconv/imgconv.go
@@ -0,0 +1,89 @@
+package imgconv + +import ( + "bytes" + "fmt" + "github.com/nfnt/resize" + "image/gif" + "strings" + + // "gocv.io/x/gocv" + "golang.org/x/image/webp" + "image" + "image/jpeg" + "image/png" + "io" + "path/filepath" +) + +// ffmpeg -i file.mp4 -vf "select='eq(n\,20)+eq(n\,40)+eq(n\,60)+eq(n\,80)'" -vsync 0 frame%d.png + +func scaleEncode(img image.Image) ([]byte, error) { + var w, h uint + aspect := float64(img.Bounds().Dx()) / float64(img.Bounds().Dy()) + if aspect > 1 { + w = 128 + h = uint(float64(w) / aspect) + } else { + h = 128 + w = uint(float64(h) * aspect) + } + img = resize.Resize(w, h, img, resize.NearestNeighbor) + var buf bytes.Buffer + err := png.Encode(&buf, img) + if err != nil { + return nil, fmt.Errorf("failed to encode image to PNG: %v", err) + } + return buf.Bytes(), nil +} + +func Media2Icon(path string, file io.Reader) ([]byte, error) { + var img image.Image + var err error + switch strings.ToLower(filepath.Ext(path)) { + case ".jpg", ".jpeg": + img, err = jpeg.Decode(file) + break + case ".png": + img, err = png.Decode(file) + break + case ".webp": + img, err = webp.Decode(file) + break + case ".gif": + img, err = gif.Decode(file) + break + default: + err = fmt.Errorf("unsupported image format: %s", filepath.Ext(path)) + } + if err != nil { + return nil, fmt.Errorf("error decoding image: %v", err) + } + return scaleEncode(img) +} + +/* +func getFirstFrameAsPNGBytes(videoPath string) ([]byte, error) { + // Open the video file + video, err := gocv.VideoCaptureFile(videoPath) + if err != nil { + return nil, fmt.Errorf("error opening video: %v", err) + } + img := gocv.NewMat() + ok := video.Read(&img) + + if !ok || img.Empty() { + img.Close() + video.Close() + return nil, fmt.Errorf("failed to read the first frame") + } + + imgImg, err := img.ToImage() + img.Close() + video.Close() + if err != nil { + return nil, fmt.Errorf("failed to convert frame to image: %v", err) + } + return scaleEncode(imgImg) +} +*/
M
main.go
→
main.go
@@ -2,7 +2,13 @@ package main
import ( "embed" + "errors" "fmt" + "git.sophuwu.com/cdn/config" + "git.sophuwu.com/cdn/imgconv" + "github.com/asdine/storm/v3" + "go.etcd.io/bbolt" + "io/fs" "time"@@ -68,7 +74,7 @@
func (t *TemplateData) add(a DirEntry, size int64, dir bool) { if dir { a.Size = func() string { - n, e := os.ReadDir(filepath.Join(Config.HTTPDir, a.Url)) + n, e := os.ReadDir(filepath.Join(config.HttpDir, a.Url)) if e == nil { return fmt.Sprintf("%d items", len(n)) }@@ -109,14 +115,69 @@ func FillError(w io.Writer, err error, code int) bool {
if err == nil { return false } + fmt.Fprintf(os.Stderr, "error: %s\n", err) _ = Temp.ExecuteTemplate(w, "index", map[string]string{ "Error": fmt.Sprintf("%d: %s", code, HttpCodes[code]), }) return true } +type ImgIcon struct { + ImgPath string `storm:"id"` + ModTime string + PngData []byte +} + func customFileServer(root http.Dir) http.Handler { + iconFunc := func(w http.ResponseWriter, r *http.Request) { + qq := r.URL.Query() + var icon ImgIcon + if qq.Get("icon") == "" || qq.Get("mod") == "" { + FillError(w, fmt.Errorf("icon or mod not found"), 400) + return + } + err := DB.One("ImgPath", qq.Get("icon"), &icon) + if err != nil || icon.ModTime != qq.Get("mod") { + fn := DB.Update + if errors.Is(err, storm.ErrNotFound) { + fn = DB.Save + } + icon.ImgPath = qq.Get("icon") + icon.ModTime = qq.Get("mod") + var f http.File + f, err = root.Open(icon.ImgPath) + if FillError(w, err, 404) { + return + } + var fi fs.FileInfo + fi, err = f.Stat() + if err == nil && fi.IsDir() { + err = fmt.Errorf("icon is dir") + } + if FillError(w, err, 400) { + f.Close() + return + } + icon.PngData, err = imgconv.Media2Icon(icon.ImgPath, f) + f.Close() + if FillError(w, err, 404) { + return + } + err = fn(&icon) + if FillError(w, err, 500) { + return + } + } + w.Header().Set("Content-Type", "image/png") + w.WriteHeader(200) + w.Write(icon.PngData) + } + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Query().Has("icon") { + iconFunc(w, r) + return + } upath := r.URL.Path f, err := root.Open(upath) if FillError(w, err, 404) {@@ -152,39 +213,26 @@ http.FileServer(root).ServeHTTP(w, r)
}) } +var DB *storm.DB + func main() { // Fs := os.DirFS(Config.HTTPDir) - http.Handle("/", customFileServer(http.Dir(Config.HTTPDir))) + http.Handle("/", customFileServer(http.Dir(config.HttpDir))) // http.Handle("/", http.StripPrefix("/", FileServer(http.Dir(Config.HTTPDir)))) - http.ListenAndServe(Config.Listen, nil) + http.ListenAndServe(config.Addr+":"+config.Port, nil) -} - -var Config struct { - HTTPDir string - Listen string } func init() { Temp = template.Must(template.ParseFS(embedHtml, "html/*")) - - httpdir := os.Getenv("HTTP_DIR") - if httpdir == "" { - httpdir = "." - } - Config.HTTPDir, _ = filepath.Abs(httpdir) - - Config.Listen = os.Getenv("ADDR") - if Config.Listen == "" { - Config.Listen = "127.0.0.1" - } - Config.Listen += ":" - n := len(Config.Listen) - Config.Listen += os.Getenv("PORT") - if len(Config.Listen) == n { - Config.Listen += "8844" + config.Get() + db, err := storm.Open(config.DbPath, storm.BoltOptions(0600, &bbolt.Options{Timeout: 1 * time.Second})) + if err != nil { + fmt.Println("Failed to open database:", err) + os.Exit(1) } - + db.Init(&ImgIcon{}) + DB = db }