arnefandCopilot 2399d8a5a6 Add in-browser EPUB reader (no JavaScript)
- internal/library/reader.go: new Chapter type and Service.ReadChapter/
  ChapterAsset. Parses the EPUB spine, extracts and sanitizes each
  chapter's <body> HTML using golang.org/x/net/html:
  - strips <script>, <style>, <link>, <iframe>, <object>, <embed>,
    <form>, <meta>, <base>, <audio>, <video>, <noscript> and any
    on*-event-handler attributes
  - rewrites relative <img>/xlink:href asset references to
    /read/{id}/asset/{path}
  - rewrites internal chapter links to /read/{id}/{spineIndex},
    neutralizes javascript: hrefs, leaves external links untouched
  - refactored CoverBytes to share the new findEPUBPath helper
- internal/web/handlers.go: GET /read/{id}/{idx} renders a chapter page
  with prev/next navigation; GET /read/{id}/asset/{path...} serves
  embedded chapter assets (images) with a size cap, mirroring the
  existing cover-image guard
- views/pages.templ: new ReaderPage component (renders sanitized HTML
  via templ.Raw); BookPage gets an "Im Browser lesen" button next to
  the existing download button; templ regenerated
- static/styles.css: reader typography/layout, prev/next nav styling
- go.mod/go.sum: golang.org/x/net/html promoted to a direct dependency
- README: documents the new in-browser reader feature

Verified end-to-end with a hand-built test EPUB (spine ordering,
metadata, script/style stripping, event-handler stripping, chapter
link rewriting, image asset rewriting, javascript: neutralization,
external link passthrough, out-of-range chapter handling, and
path-traversal guard on chapter assets); test file removed afterwards
per repo convention (no test suite checked in yet).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-08-15 16:17:16 +02:00
2026-08-15 11:50:27 +02:00

eBook Library (Go + templ)

Minimalistische eBook-Bibliothek für den Tolino-Webbrowser.

Features (MVP)

  • Listet EPUB-Dateien aus books/
  • Detailseite pro Buch
  • Im Browser lesen (serverseitig gerenderte Kapitel, kein JavaScript nötig)
  • Download-Link pro Buch (für Tolino)
  • Schlichtes, kontrastreiches UI ohne JavaScript-Abhängigkeit
  • Login-Pflicht (Session-Cookie, 30 Tage)
  • Optionaler Buch-Upload für berechtigte Benutzer

Voraussetzungen

Templ CLI installieren:

go install github.com/a-h/templ/cmd/templ@latest

Start

  1. Abhängigkeiten laden:
go mod tidy
  1. Templates generieren:
templ generate
  1. Ersten Benutzer anlegen:
go run ./cmd/admin user add <benutzername>
# mit Upload-Recht:
go run ./cmd/admin user add <benutzername> --upload
  1. Server starten:
go run ./cmd/server
  1. Browser öffnen:
  • http://localhost:8080

Bücher hinzufügen

Lege deine EPUB-Dateien in den Ordner books/.

Alternativ können Benutzer mit Upload-Recht Bücher direkt im Browser hochladen.

Benutzerverwaltung (CLI)

Rollen (aufsteigend): readeruploaderadmin

go run ./cmd/admin user add <name> [--role reader|uploader|admin]
go run ./cmd/admin user list
go run ./cmd/admin user delete <name>
go run ./cmd/admin user set-role <name> <reader|uploader|admin>

Docker / docker-compose Deployment

Beispiel docker-compose.yml:

version: '3'

networks:
  web:
    external: true

services:
  app:
    image: git.arnef.de/arnef/ebooks:latest
    restart: always
    networks:
      - web
    volumes:
      - ./data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    labels:
      traefik.enable: 'true'
      traefik.http.routers.ebooks.rule: Host(`books.arnef.de`)
      traefik.http.routers.ebooks.entrypoints: websecure
      traefik.http.routers.ebooks.tls.certresolver: letsencrypt
      traefik.http.services.ebooks.loadbalancer.server.port: 8080

Der Container läuft als nicht-root Benutzer ebooks (UID 100, GID 101). BOOKS_DIR (/data/books) und USERS_DB (/data/users.db) liegen im Volume ./data. Der Server legt BOOKS_DIR beim Start automatisch an, falls es fehlt — gehört das Host-Verzeichnis ./data aber nicht dem passenden UID/GID, schlägt das Anlegen fehl bzw. users.db kann nicht geöffnet werden (unable to open database file) und Uploads schlagen mit "Datei konnte nicht gespeichert werden" fehl.

  1. Datenverzeichnis anlegen und Rechte setzen:
mkdir -p data
sudo chown -R 100:101 data
  1. Container starten:
docker compose up -d
  1. Ersten Benutzer über die im Image enthaltene Admin-CLI anlegen (der Server muss dafür nicht gestoppt werden, --role admin empfohlen für den ersten Account):
docker compose exec app /app/admin user add <name> --role admin
docker compose exec app /app/admin user list

USERS_DB ist im Image bereits auf /data/users.db gesetzt, daher ist kein zusätzlicher Parameter nötig.

Konfiguration

Umgebungsvariablen:

Variable Standard Beschreibung
ADDR :8080 Listen-Adresse des Servers
BOOKS_DIR books Verzeichnis mit Büchern
USERS_DB users.db Pfad zur SQLite-Benutzerdatenbank
S
Description
No description provided
Readme
141 KiB
Languages
Go 77.7%
templ 11.8%
CSS 8.5%
Dockerfile 2%