Not your usual local magazine/book/comic reader.
Magz makes reading local magazines, books, or comics effortless β no internet required. It runs a lightweight Go-based local server that scans your library directories, caches metadata using SQLite, and serves a simple web app UI for browsing and reading right in your browser.
- π Auto-detects and catalogs your local magazine/book folders
- πΌοΈ Displays pages directly in a browser-based reader
- π Auto-refreshes your library every few minutes
- β‘ Fast and portable β just a single Go binary
- πΏ Uses SQLite for local caching
- π§© Nix shell for easy development and reproducibility
/home/n/Books/ < (Books is a new Directory in my case)
βββ Death to Pachuco < (Magazine/Comic Category ie., Directory name)
βΒ Β βββ Death to Pachuco 001.cbz < (Magazine/Comic Title ie., Exact filename - Death to Pachuco 001)
βββ Misc < (Magazine/Comic Category)
βΒ Β βββ My Own Comic < (Magazine/Comic Title ie., Exact filename)
βΒ Β βββ 001.png
βΒ Β βββ 002.png
βΒ Β βββ *.png
βββ Playboy < (Magazine/Comic Category ie., Directory name)
βΒ Β βββ Best Ones So far < (Magazine/Comic Title ie., Exact filename)
βΒ Β βββ 183887_001.jpg
βΒ Β βββ 183887_002.jpg
βΒ Β βββ 183887_003.jpg
βΒ Β βββ*.jpg
βββ Batman < (Magazine/Comic Category ie., Directory name)
βββ Batman #1 (1940-2011).cbr < (Magazine/Comic Title ie., Exact filename)- Go 1.22+
- Any system Go runs on (Linux, macOS, Windows, etc.)
- (Optional) Nix for reproducible development environments
git clone https://github.com/2hexed/magz.git
cd magz
# Build the binary
go build -o magz
# Create your config file
cp magz.config.example.json magz.config.jsonThen, edit magz.config.json to match your setup.
If you use Nix, you can instantly enter a ready-to-go environment:
nix-shellInside the shell, youβll see a welcome message and have access to these helper commands:
| Command | Description |
|---|---|
first-time-running |
Initializes Go module, installs dependencies |
buildbin |
Builds the magz binary |
fmtfiles |
Formats Go, Nix, JSON, HTML, JS, and Markdown files |
prjcleanup |
TODO
Magz implements several security measures:
- Path Validation: All file access is validated against configured library paths
- Query Parameter Sanitization: URL parameters are properly escaped
- No Directory Listing: Only explicitly cataloged content is accessible
- Read-Only Access: The application only reads files, never writes or modifies them
- Connection Timeouts: HTTP server has configured timeouts to prevent resource exhaustion
- Run Magz on localhost only (don't expose to the internet without proper authentication)
- Use specific library paths rather than root directories
- Keep your Go version updated for security patches
- Regularly review your library paths configuration
Magz uses a single config file named magz.config.json in the project root. (Example file - magz.config.example.json is included in the project for users)
Configuration Parameters:
| Key | Type | Description |
|---|---|---|
Port |
integer | Port for the local server |
AutoRefreshInterval |
integer | Minutes between automatic rescans |
LibraryPaths |
array | List of library directories containing magazines/books |
CacheDB |
string | SQLite cache database file name |
MaxThumbnailSize |
int | Maximum dimension for thumbnails in pixels |
LogLevel |
string | Logging verbosity - "info" or "debug" |
After building, You can override config values with environment variables:
export MAGZ_PORT=8090
export MAGZ_LOG_LEVEL=debug
./magzYouβll see something like:
π Magz running at http://localhost:8082
Then open your browser and visit that address.
Magz will:
- Scan your library paths for readable folders
- Cache metadata (title, category, cover, etc.)
- Serve the
public/web app for browsing and reading
𧦠The web app is static (no build needed) and lives in public/.
It provides a minimal, clean reader interface.
Ctrl/Cmd + K- Focus search boxEscape- Clear searchEnter- Open selected magazine
Arrow Left/Arrow Right- Navigate pagesEscape- Return to library- Touch/swipe gestures on mobile devices
If your library doesn't show new content:
- Check the log output for scan errors
- Verify file permissions on library directories
- Manually trigger a rescan by restarting the server
- Check that file extensions are supported (.jpg, .jpeg, .png, .webp, .avif, .gif)
If the application is slow:
- Reduce
MaxThumbnailSizein config (try 300 or 250) - Increase
AutoRefreshIntervalto scan less frequently - Check database size - consider deleting and rebuilding cache
- Ensure library paths are on fast storage (SSD preferred)
If covers aren't displaying:
- Check that cover images are valid formats
- Look for error messages in logs (run with LogLevel: "debug")
- Try deleting the cache database to force regeneration
- Verify image file permissions
- SSD Storage: Use SSD for both library and cache database
- Thumbnail Size: Smaller thumbnails = faster loading (but lower quality)
- Library Organization: Organize files in subdirectories by category
- Archive Format: CBZ (zip) is faster than CBR (rar) for extraction
- Concurrent Access: The app handles multiple users but performance may degrade with many simultaneous readers
go test -v ./...# Linux
GOOS=linux GOARCH=amd64 go build -o magz-linux
# macOS
GOOS=darwin GOARCH=amd64 go build -o magz-macos
# Windows
GOOS=windows GOARCH=amd64 go build -o magz.exeUse air for hot reloading:
go install github.com/cosmtrek/air@latest
airMagz exposes a small set of REST endpoints used by the web app, which can also be accessed manually or via other tools.
curl http://localhost:8082/api/healthExample Response:
{
"status": "ok",
"version": "1.0.0",
"uptime": "2h30m15s"
}Returns all cached library entries.
Example Response:
[
{
"id": 1,
"category": "Comics",
"title": "Spiderverse Vol 1",
"path": "/home/n/Books/Comics/Spiderverse Vol 1",
"cover": "COVER TYPE",
"coverData": "data:image/jpeg;base64,/9j/2..",
"lastModified": "2025-11-12T14:03:22Z"
}
]Returns all image pages for a specific library item.
Example:
GET /api/pages?id=1
Response:
[
"/home/n/Books/Comics/Spiderverse Vol 1/page1.jpg",
"/home/n/Books/Comics/Spiderverse Vol 1/page2.jpg"
]Serves a specific image file directly from disk.
Example:
GET /media?path=/home/n/Books/Comics/Spiderverse Vol 1/page1.jpg
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Format your code using
fmtfiles(in Nix shell) - Commit your changes with descriptive messages
- Push to your branch
- Open a Pull Request
Please include:
- Clear description of changes
- Any new dependencies
- Updated documentation if needed
- Tests for new features
| Status | Feature |
|---|---|
| OK | Interval-based library refresh |
| TODO | In-browser reading progress tracking |
| OK | UI themes and dark mode |
| TODO | Optional metadata editing and tagging |
| OK | Comic archive support |
| TODO | Systemd unit and Docker file |