diff --git a/Containerfile.build b/Containerfile.build
index f9fab6a..7747181 100644
--- a/Containerfile.build
+++ b/Containerfile.build
@@ -35,12 +35,15 @@ RUN echo "Building Linux binary..." && \
# Build Windows binary
RUN echo "Building Windows binary..." && \
+ echo 'IDI_ICON1 ICON "./app/gopherbook/static/images/favicon/favicon.ico"' > gopherbook.rc && \
+ x86_64-w64-mingw32-windres gopherbook.rc -o ./app/gopherbook/gopherbook.syso && \
CGO_ENABLED=1 GOOS=windows GOARCH=amd64 CC=x86_64-w64-mingw32-gcc go build \
-a \
-ldflags="-s -w" \
-trimpath \
-o bin/gopherbook-windows.exe ./app/gopherbook && \
- upx --best --ultra-brute bin/gopherbook-windows.exe
+ upx --best --ultra-brute bin/gopherbook-windows.exe && \
+ rm ./app/gopherbook/gopherbook.syso gopherbook.rc
# Verify binaries were created
RUN ls -lh bin/ && \
diff --git a/Makefile b/Makefile
index 11a28fe..797294d 100644
--- a/Makefile
+++ b/Makefile
@@ -2,4 +2,4 @@ build:
go build -o bin/main ./app/gopherbook
clean:
- rm -rf watch etc library cache
+ rm -rf watch etc library cache binaries releases
diff --git a/README.md b/README.md
index 2766fdc..007a519 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,21 @@
-# Gopherbook – Self-Hosted Comic Library & CBZ/CBT Reader
+
+
+
+
+
+
+
+
+## Self-Hosted Comic Library & CBZ/CBT Reader
Gopherbook is a lightweight, single-binary, self-hosted web comic reader and library manager written in Go.
It is designed for people who want full control over their digital comic collection (CBZ/CBT files), including support for password-protected/encrypted archives, per-user libraries, tagging, automatic organization, and a clean modern reader.
+
+
## License
-[](LICENSE)
+[](LICENSE)
## Features
@@ -186,6 +196,10 @@ Pull requests are welcome! Especially:
Please open an issue first for bigger changes.
+## If you'd like to know about the new mascot Vinny
+
+- Check the [Wiki](/riomoo/gopherbook/wiki/Meet-Vinny.md)!
+
## Thanks / Credits
- yeka/zip – password-protected ZIP support in pure Go
diff --git a/app/gopherbook/main.go b/app/gopherbook/main.go
index 7ed7bae..9db9fd1 100644
--- a/app/gopherbook/main.go
+++ b/app/gopherbook/main.go
@@ -21,6 +21,7 @@ import (
"regexp"
"sort"
"strings"
+ "io/fs"
"sync"
"time"
"runtime"
@@ -39,6 +40,9 @@ import (
//go:embed templates/index.html
var templateFS embed.FS
+//go:embed all:static
+var staticFS embed.FS
+
// ComicInfo represents the standard ComicInfo.xml metadata
type ComicInfo struct {
XMLName xml.Name `xml:"ComicInfo"`
@@ -135,6 +139,14 @@ func main() {
loadUsers()
initWatchFolders()
+ // Create static sub-filesystem once
+ staticSubFS, err := fs.Sub(staticFS, "static")
+ if err != nil {
+ log.Fatal(fmt.Errorf("failed to create static sub-filesystem: %w", err))
+ }
+
+ // Create handlers once and reuse
+ staticHandler := http.FileServer(http.FS(staticSubFS))
http.HandleFunc("/api/register", handleRegister)
http.HandleFunc("/api/login", handleLogin)
@@ -154,6 +166,7 @@ func main() {
http.HandleFunc("/api/admin/delete-comic/", authMiddleware(handleDeleteComic))
http.HandleFunc("/api/watch-folder", authMiddleware(handleWatchFolder))
http.HandleFunc("/", serveUI)
+ http.Handle("/static/", http.StripPrefix("/static/", staticHandler))
go func() {
for {
@@ -1599,7 +1612,7 @@ func saveJPEG(img image.Image, path string) error {
defer out.Close()
// Lower quality = smaller memory footprint during encoding
- err = jpeg.Encode(out, img, &jpeg.Options{Quality: 70})
+ err = jpeg.Encode(out, img, &jpeg.Options{Quality: 85})
img = nil
runtime.GC()
@@ -1643,7 +1656,7 @@ func handleTags(w http.ResponseWriter, r *http.Request) {
}
if req.Color == "" {
- req.Color = "#1f6feb"
+ req.Color = "#446B6E"
}
tagsMutex.Lock()
@@ -1832,7 +1845,7 @@ func handleTryKnownPasswords(w http.ResponseWriter, r *http.Request) {
tagData.Count++
tags[tag] = tagData
} else {
- tags[tag] = Tag{Name: tag, Color: "#1f6feb", Count: 1}
+ tags[tag] = Tag{Name: tag, Color: "#446B6E", Count: 1}
}
}
tagsMutex.Unlock()
@@ -1947,7 +1960,7 @@ func handleSetPassword(w http.ResponseWriter, r *http.Request) {
tagData.Count++
tags[tag] = tagData
} else {
- tags[tag] = Tag{Name: tag, Color: "#1f6feb", Count: 1}
+ tags[tag] = Tag{Name: tag, Color: "#446B6E", Count: 1}
}
}
tagsMutex.Unlock()
@@ -2419,7 +2432,7 @@ func processComic(filePath, filename string, modTime time.Time) Comic {
tagData.Count++
tags[tag] = tagData
} else {
- tags[tag] = Tag{Name: tag, Color: "#1f6feb", Count: 1}
+ tags[tag] = Tag{Name: tag, Color: "#446B6E", Count: 1}
}
}
tagsMutex.Unlock()
@@ -2481,7 +2494,7 @@ func loadComicMetadataLazy(comicID string) error {
tagData.Count++
tags[tag] = tagData
} else {
- tags[tag] = Tag{Name: tag, Color: "#1f6feb", Count: 1}
+ tags[tag] = Tag{Name: tag, Color: "#446B6E", Count: 1}
}
}
tagsMutex.Unlock()
diff --git a/app/gopherbook/static/images/favicon/favicon.ico b/app/gopherbook/static/images/favicon/favicon.ico
new file mode 100644
index 0000000..c9b5b45
--- /dev/null
+++ b/app/gopherbook/static/images/favicon/favicon.ico
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8202e8bb8e72d5a050ec53a218fc7bf9eb0c19c0ce185792788ad56be29f2a25
+size 443814
diff --git a/app/gopherbook/static/images/pngs/CutePose2.png b/app/gopherbook/static/images/pngs/CutePose2.png
new file mode 100644
index 0000000..98cd9d1
--- /dev/null
+++ b/app/gopherbook/static/images/pngs/CutePose2.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e98f5d51fbb1fc335f7640b295e2b6f65eb724bde94e6f760bda277492ce10cd
+size 334430
diff --git a/app/gopherbook/static/images/pngs/LogoPose2.png b/app/gopherbook/static/images/pngs/LogoPose2.png
new file mode 100644
index 0000000..00ba2bf
--- /dev/null
+++ b/app/gopherbook/static/images/pngs/LogoPose2.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:84533cde26dfe5455f5e0850a0ea124619eba48b12faaa8461fa115f6ec91fd4
+size 257580
diff --git a/app/gopherbook/templates/index.html b/app/gopherbook/templates/index.html
index a501978..f2408ce 100644
--- a/app/gopherbook/templates/index.html
+++ b/app/gopherbook/templates/index.html
@@ -3,6 +3,7 @@
+
Gopherbook