Compare commits
No commits in common. "05a17238051162636fa7f074590e38f2d4551243" and "44b287478094b0ecfe45a493175c77ac336a4f85" have entirely different histories.
05a1723805
...
44b2874780
10 changed files with 11 additions and 347 deletions
|
|
@ -2,15 +2,11 @@
|
||||||
.git
|
.git
|
||||||
.gitignore
|
.gitignore
|
||||||
.gitattributes
|
.gitattributes
|
||||||
scripts-bash
|
bash-scripts
|
||||||
scripts-go
|
|
||||||
Containerfile
|
Containerfile
|
||||||
Containerfile.build
|
|
||||||
binaries
|
|
||||||
README.md
|
README.md
|
||||||
xml-template
|
xml-template
|
||||||
cache
|
cache
|
||||||
etc
|
etc
|
||||||
library
|
library
|
||||||
watch
|
watch
|
||||||
releases
|
|
||||||
|
|
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -7,5 +7,3 @@ cache
|
||||||
library
|
library
|
||||||
etc
|
etc
|
||||||
watch
|
watch
|
||||||
binaries
|
|
||||||
releases
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ RUN CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build \
|
||||||
-a \
|
-a \
|
||||||
-ldflags="-s -w -linkmode external -extldflags '-static' -X main.GOMEMLIMIT=512MiB -X runtime.defaultGOGC=50" \
|
-ldflags="-s -w -linkmode external -extldflags '-static' -X main.GOMEMLIMIT=512MiB -X runtime.defaultGOGC=50" \
|
||||||
-trimpath \
|
-trimpath \
|
||||||
-o bin/main ./app/gopherbook
|
-o bin/main app/gopherbook/main.go
|
||||||
RUN upx --best --ultra-brute bin/main
|
RUN upx --best --ultra-brute bin/main
|
||||||
RUN chmod +x bin/main
|
RUN chmod +x bin/main
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
# Multi-platform build container for Gopherbook
|
|
||||||
FROM golang:alpine AS builder
|
|
||||||
|
|
||||||
RUN apk add --no-cache \
|
|
||||||
musl-dev \
|
|
||||||
gcc \
|
|
||||||
g++ \
|
|
||||||
mingw-w64-gcc \
|
|
||||||
wget \
|
|
||||||
xz \
|
|
||||||
git
|
|
||||||
|
|
||||||
# Install UPX for binary compression
|
|
||||||
RUN wget https://github.com/upx/upx/releases/download/v5.0.2/upx-5.0.2-amd64_linux.tar.xz && \
|
|
||||||
tar -xf upx-5.0.2-amd64_linux.tar.xz && \
|
|
||||||
mv upx-5.0.2-amd64_linux/upx /usr/local/bin/upx && \
|
|
||||||
rm -r upx-5.0.2-amd64_linux upx-5.0.2-amd64_linux.tar.xz
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY go.mod go.sum ./
|
|
||||||
RUN go mod download
|
|
||||||
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Build Linux binary
|
|
||||||
RUN echo "Building Linux binary..." && \
|
|
||||||
CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build \
|
|
||||||
-a \
|
|
||||||
-ldflags="-s -w -linkmode external -extldflags '-static'" \
|
|
||||||
-trimpath \
|
|
||||||
-o bin/gopherbook-linux ./app/gopherbook && \
|
|
||||||
upx --best --ultra-brute bin/gopherbook-linux && \
|
|
||||||
chmod +x bin/gopherbook-linux
|
|
||||||
|
|
||||||
# Build Windows binary
|
|
||||||
RUN echo "Building Windows binary..." && \
|
|
||||||
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
|
|
||||||
|
|
||||||
# Verify binaries were created
|
|
||||||
RUN ls -lh bin/ && \
|
|
||||||
echo "Build complete!" && \
|
|
||||||
echo "Linux binary size: $(du -h bin/gopherbook-linux | cut -f1)" && \
|
|
||||||
echo "Windows binary size: $(du -h bin/gopherbook-windows.exe | cut -f1)"
|
|
||||||
|
|
||||||
# Keep the builder stage as the final stage so we can copy files out
|
|
||||||
FROM builder
|
|
||||||
2
Makefile
2
Makefile
|
|
@ -1,5 +1,5 @@
|
||||||
build:
|
build:
|
||||||
go build -o bin/main ./app/gopherbook
|
go build -o bin/main app/gopherbook/main.go
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf watch etc library cache
|
rm -rf watch etc library cache
|
||||||
|
|
|
||||||
|
|
@ -78,15 +78,6 @@ Then open http://localhost:12010 in your browser.
|
||||||
./etc/admin.json ← admin settings (registration toggle)
|
./etc/admin.json ← admin settings (registration toggle)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Environment Variables
|
|
||||||
Can be used to set where everything is stored with:
|
|
||||||
```
|
|
||||||
GOPHERBOOK_LIBRARY=$HOME/.config/gopherbook/library
|
|
||||||
GOPHERBOOK_CACHE=$HOME/.config/gopherbook/covers
|
|
||||||
GOPHERBOOK_ETC=$HOME/.config/gopherbook/etc
|
|
||||||
GOPHERBOOK_WATCH=$HOME/.config/gopherbook/watch
|
|
||||||
```
|
|
||||||
|
|
||||||
## Watch folder for bulk imports
|
## Watch folder for bulk imports
|
||||||
|
|
||||||
Gopherbook includes an automatic watch folder system that makes bulk importing comics effortless:
|
Gopherbook includes an automatic watch folder system that makes bulk importing comics effortless:
|
||||||
|
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
baseLibraryPath string
|
|
||||||
baseCachePath string
|
|
||||||
baseEtcPath string
|
|
||||||
baseWatchPath string
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// Store the base paths (before user-specific paths are added)
|
|
||||||
baseLibraryPath = libraryPath
|
|
||||||
baseCachePath = cachePath
|
|
||||||
baseEtcPath = etcPath
|
|
||||||
baseWatchPath = watchPath
|
|
||||||
|
|
||||||
// Override from environment variables if set
|
|
||||||
if env := os.Getenv("GOPHERBOOK_LIBRARY"); env != "" {
|
|
||||||
baseLibraryPath = filepath.Clean(env)
|
|
||||||
libraryPath = baseLibraryPath
|
|
||||||
}
|
|
||||||
if env := os.Getenv("GOPHERBOOK_CACHE"); env != "" {
|
|
||||||
baseCachePath = filepath.Clean(env)
|
|
||||||
cachePath = baseCachePath
|
|
||||||
}
|
|
||||||
if env := os.Getenv("GOPHERBOOK_ETC"); env != "" {
|
|
||||||
baseEtcPath = filepath.Clean(env)
|
|
||||||
etcPath = baseEtcPath
|
|
||||||
}
|
|
||||||
if env := os.Getenv("GOPHERBOOK_WATCH"); env != "" {
|
|
||||||
baseWatchPath = filepath.Clean(env)
|
|
||||||
watchPath = baseWatchPath
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -544,8 +544,8 @@ func handleLogin(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
currentUser = req.Username
|
currentUser = req.Username
|
||||||
key := deriveKey(req.Password)
|
key := deriveKey(req.Password)
|
||||||
libraryPath = filepath.Join(baseLibraryPath, currentUser)
|
libraryPath = filepath.Join("./library", currentUser)
|
||||||
cachePath = filepath.Join(baseCachePath, currentUser)
|
cachePath = filepath.Join("./cache/covers", currentUser)
|
||||||
os.MkdirAll(filepath.Join(libraryPath, "Unorganized"), 0755)
|
os.MkdirAll(filepath.Join(libraryPath, "Unorganized"), 0755)
|
||||||
os.MkdirAll(cachePath, 0755)
|
os.MkdirAll(cachePath, 0755)
|
||||||
|
|
||||||
|
|
@ -599,8 +599,8 @@ func handleLogout(w http.ResponseWriter, r *http.Request) {
|
||||||
passwordsMutex.Unlock()
|
passwordsMutex.Unlock()
|
||||||
currentEncryptionKey = nil
|
currentEncryptionKey = nil
|
||||||
currentUser = ""
|
currentUser = ""
|
||||||
libraryPath = baseLibraryPath
|
libraryPath = "./library"
|
||||||
cachePath = baseCachePath
|
cachePath = "./cache/covers"
|
||||||
|
|
||||||
http.SetCookie(w, &http.Cookie{
|
http.SetCookie(w, &http.Cookie{
|
||||||
Name: "session",
|
Name: "session",
|
||||||
|
|
@ -2697,16 +2697,9 @@ func authMiddleware(next http.HandlerFunc) http.HandlerFunc {
|
||||||
next(w, r)
|
next(w, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func getUsersPath() string {
|
|
||||||
return filepath.Join(etcPath, "users.json")
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAdminPath() string {
|
|
||||||
return filepath.Join(etcPath, "admin.json")
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadUsers() {
|
func loadUsers() {
|
||||||
data, err := os.ReadFile(getUsersPath())
|
data, err := os.ReadFile("etc/users.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -2714,7 +2707,7 @@ func loadUsers() {
|
||||||
log.Printf("Error unmarshaling users: %v", err)
|
log.Printf("Error unmarshaling users: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
adminData, err := os.ReadFile(getAdminPath())
|
adminData, err := os.ReadFile("etc/admin.json")
|
||||||
if err == nil && len(adminData) > 0 {
|
if err == nil && len(adminData) > 0 {
|
||||||
var adminConfig struct{ RegistrationEnabled bool }
|
var adminConfig struct{ RegistrationEnabled bool }
|
||||||
if err := json.Unmarshal(adminData, &adminConfig); err == nil {
|
if err := json.Unmarshal(adminData, &adminConfig); err == nil {
|
||||||
|
|
@ -2725,13 +2718,13 @@ func loadUsers() {
|
||||||
|
|
||||||
func saveUsers() {
|
func saveUsers() {
|
||||||
data, _ := json.MarshalIndent(users, "", " ")
|
data, _ := json.MarshalIndent(users, "", " ")
|
||||||
os.WriteFile(getUsersPath(), data, 0644)
|
os.WriteFile("etc/users.json", data, 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveAdminConfig() {
|
func saveAdminConfig() {
|
||||||
config := struct{ RegistrationEnabled bool }{RegistrationEnabled: registrationEnabled}
|
config := struct{ RegistrationEnabled bool }{RegistrationEnabled: registrationEnabled}
|
||||||
data, _ := json.MarshalIndent(config, "", " ")
|
data, _ := json.MarshalIndent(config, "", " ")
|
||||||
os.WriteFile(getAdminPath(), data, 0644)
|
os.WriteFile("etc/admin.json", data, 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadTags() {
|
func loadTags() {
|
||||||
|
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
IMAGE_NAME="localhost/gopherbook-builder:latest"
|
|
||||||
CONTAINER_NAME="gopherbook-builder-tmp"
|
|
||||||
OUTPUT_DIR="./binaries"
|
|
||||||
|
|
||||||
echo "=== Building cross-compilation container ==="
|
|
||||||
podman build --force-rm -t "$IMAGE_NAME" -f Containerfile.build .
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "Image build failed. Exiting."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "=== Creating temporary container ==="
|
|
||||||
podman create --name "$CONTAINER_NAME" "$IMAGE_NAME"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "=== Creating output directory ==="
|
|
||||||
mkdir -p "$OUTPUT_DIR"
|
|
||||||
rm -f "$OUTPUT_DIR"/*
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "=== Extracting Linux binary ==="
|
|
||||||
podman cp "$CONTAINER_NAME:/app/bin/gopherbook-linux" "$OUTPUT_DIR/gopherbook-linux"
|
|
||||||
chmod +x "$OUTPUT_DIR/gopherbook-linux"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "=== Extracting Windows binary ==="
|
|
||||||
podman cp "$CONTAINER_NAME:/app/bin/gopherbook-windows.exe" "$OUTPUT_DIR/gopherbook-windows.exe"
|
|
||||||
chmod +x "$OUTPUT_DIR/gopherbook-windows.exe"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "=== Cleaning up temporary container ==="
|
|
||||||
podman rm "$CONTAINER_NAME"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "=== Build complete! ==="
|
|
||||||
echo "Binaries are in: $OUTPUT_DIR/"
|
|
||||||
ls -lh "$OUTPUT_DIR/"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "=== Binary sizes ==="
|
|
||||||
du -h "$OUTPUT_DIR"/*
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "=== Cleaning up builder image ==="
|
|
||||||
podman rmi "$IMAGE_NAME"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "✓ Done! Your binaries are ready:"
|
|
||||||
echo " • Linux: $OUTPUT_DIR/gopherbook-linux"
|
|
||||||
echo " • Windows: $OUTPUT_DIR/gopherbook-windows.exe"
|
|
||||||
echo ""
|
|
||||||
echo "To run the Linux binary:"
|
|
||||||
echo " $OUTPUT_DIR/gopherbook-linux"
|
|
||||||
echo ""
|
|
||||||
echo "To test the Windows binary (requires wine):"
|
|
||||||
echo " wine $OUTPUT_DIR/gopherbook-windows.exe"
|
|
||||||
|
|
@ -1,161 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
VERSION="${1:-v1.1.000}"
|
|
||||||
RELEASE_DIR="./releases"
|
|
||||||
BINARIES_DIR="./binaries"
|
|
||||||
|
|
||||||
echo "=== Packaging Gopherbook $VERSION ==="
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Create release directory
|
|
||||||
mkdir -p "$RELEASE_DIR"
|
|
||||||
|
|
||||||
# Clean old releases for this version
|
|
||||||
rm -f "$RELEASE_DIR"/gopherbook-$VERSION-*
|
|
||||||
|
|
||||||
# Check if binaries exist
|
|
||||||
if [ ! -f "$BINARIES_DIR/gopherbook-linux" ] || [ ! -f "$BINARIES_DIR/gopherbook-windows.exe" ]; then
|
|
||||||
echo "Error: Binaries not found. Run ./build-and-extract.sh first."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "=== Creating README.txt ==="
|
|
||||||
cat > /tmp/README.txt << 'EOF'
|
|
||||||
Gopherbook - Comic Book Reader (CBZ/CBT)
|
|
||||||
=========================================
|
|
||||||
|
|
||||||
Quick Start:
|
|
||||||
------------
|
|
||||||
1. Run the gopherbook executable
|
|
||||||
2. Open your browser to http://localhost:8080
|
|
||||||
3. Register a new user account
|
|
||||||
4. Upload your CBZ/CBT comic files
|
|
||||||
|
|
||||||
Features:
|
|
||||||
---------
|
|
||||||
• Supports CBZ (ZIP) and CBT (TAR) formats
|
|
||||||
• Password-protected archives
|
|
||||||
• Tag management and filtering
|
|
||||||
• Bookmark pages
|
|
||||||
• Auto-organize by artist and story arc
|
|
||||||
• Watch folder for automatic imports
|
|
||||||
• Multi-user support with admin controls
|
|
||||||
|
|
||||||
Watch Folder:
|
|
||||||
-------------
|
|
||||||
Place CBZ/CBT files in the ./watch/<username>/ directory
|
|
||||||
and they will be automatically imported to your library.
|
|
||||||
|
|
||||||
Directory Structure:
|
|
||||||
--------------------
|
|
||||||
./library/ - Your comic library (per user)
|
|
||||||
./cache/ - Cover image cache
|
|
||||||
./etc/ - User data and settings
|
|
||||||
./watch/ - Watch folders for auto-import
|
|
||||||
|
|
||||||
Default Port: 8080
|
|
||||||
|
|
||||||
For more information, visit:
|
|
||||||
https://github.com/riomoo/gopherbook
|
|
||||||
https://codeberg.org/riomoo/gofudge
|
|
||||||
https://gitgud.io/riomoo/gopherbook
|
|
||||||
|
|
||||||
EOF
|
|
||||||
|
|
||||||
echo "=== Creating Linux package ==="
|
|
||||||
LINUX_DIR="/tmp/gopherbook-linux"
|
|
||||||
rm -rf "$LINUX_DIR"
|
|
||||||
mkdir -p "$LINUX_DIR"
|
|
||||||
|
|
||||||
# Copy Linux binary
|
|
||||||
cp "$BINARIES_DIR/gopherbook-linux" "$LINUX_DIR/gopherbook"
|
|
||||||
chmod +x "$LINUX_DIR/gopherbook"
|
|
||||||
|
|
||||||
# Copy documentation
|
|
||||||
cp /tmp/README.txt "$LINUX_DIR/"
|
|
||||||
|
|
||||||
# Create run script
|
|
||||||
cat > "$LINUX_DIR/run.sh" << 'EOF'
|
|
||||||
#!/bin/bash
|
|
||||||
echo "Starting Gopherbook..."
|
|
||||||
echo "Open your browser to: http://localhost:8080"
|
|
||||||
echo "Press Ctrl+C to stop"
|
|
||||||
echo ""
|
|
||||||
./gopherbook
|
|
||||||
EOF
|
|
||||||
chmod +x "$LINUX_DIR/run.sh"
|
|
||||||
|
|
||||||
# Package Linux
|
|
||||||
cd /tmp
|
|
||||||
tar -czf "$LINUX_DIR.tar.gz" gopherbook-linux/
|
|
||||||
cd - > /dev/null
|
|
||||||
mv "/tmp/gopherbook-linux.tar.gz" "$RELEASE_DIR/gopherbook-$VERSION-linux-amd64.tar.gz"
|
|
||||||
rm -rf "$LINUX_DIR"
|
|
||||||
|
|
||||||
echo "✓ Linux package created"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "=== Creating Windows package ==="
|
|
||||||
WINDOWS_DIR="/tmp/gopherbook-windows"
|
|
||||||
rm -rf "$WINDOWS_DIR"
|
|
||||||
mkdir -p "$WINDOWS_DIR"
|
|
||||||
|
|
||||||
# Copy Windows binary
|
|
||||||
cp "$BINARIES_DIR/gopherbook-windows.exe" "$WINDOWS_DIR/gopherbook.exe"
|
|
||||||
|
|
||||||
# Copy documentation (Windows line endings)
|
|
||||||
unix2dos < /tmp/README.txt > "$WINDOWS_DIR/README.txt" 2>/dev/null || cp /tmp/README.txt "$WINDOWS_DIR/README.txt"
|
|
||||||
|
|
||||||
# Create batch file
|
|
||||||
cat > "$WINDOWS_DIR/run.bat" << 'EOF'
|
|
||||||
@echo off
|
|
||||||
echo Starting Gopherbook...
|
|
||||||
echo Open your browser to: http://localhost:8080
|
|
||||||
echo Press Ctrl+C to stop
|
|
||||||
echo.
|
|
||||||
gopherbook.exe
|
|
||||||
pause
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Create PowerShell script
|
|
||||||
cat > "$WINDOWS_DIR/run.ps1" << 'EOF'
|
|
||||||
Write-Host "Starting Gopherbook..." -ForegroundColor Green
|
|
||||||
Write-Host "Open your browser to: http://localhost:8080" -ForegroundColor Cyan
|
|
||||||
Write-Host "Press Ctrl+C to stop" -ForegroundColor Yellow
|
|
||||||
Write-Host ""
|
|
||||||
.\gopherbook.exe
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Package Windows
|
|
||||||
cd /tmp
|
|
||||||
zip -q -r "$WINDOWS_DIR.zip" gopherbook-windows/
|
|
||||||
cd - > /dev/null
|
|
||||||
mv "/tmp/gopherbook-windows.zip" "$RELEASE_DIR/gopherbook-$VERSION-windows-amd64.zip"
|
|
||||||
rm -rf "$WINDOWS_DIR"
|
|
||||||
|
|
||||||
echo "✓ Windows package created"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "=== Creating checksums ==="
|
|
||||||
cd "$RELEASE_DIR"
|
|
||||||
sha256sum gopherbook-$VERSION-*.tar.gz gopherbook-$VERSION-*.zip > gopherbook-$VERSION-checksums.txt
|
|
||||||
cd - > /dev/null
|
|
||||||
|
|
||||||
echo "✓ Checksums created"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "=== Release packages ready! ==="
|
|
||||||
echo ""
|
|
||||||
ls -lh "$RELEASE_DIR"/gopherbook-$VERSION-*
|
|
||||||
echo ""
|
|
||||||
echo "Release files:"
|
|
||||||
echo " • $RELEASE_DIR/gopherbook-$VERSION-linux-amd64.tar.gz"
|
|
||||||
echo " • $RELEASE_DIR/gopherbook-$VERSION-windows-amd64.zip"
|
|
||||||
echo " • $RELEASE_DIR/gopherbook-$VERSION-checksums.txt"
|
|
||||||
echo ""
|
|
||||||
echo "Upload these files to GitHub Releases!"
|
|
||||||
|
|
||||||
# Cleanup
|
|
||||||
rm -f /tmp/README.txt
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue