# netgazet Tiny static-site generator for print-format PDFs (newsletters, magazines). Drop PDFs into `examples/`, run `main.py`, and get a browseable, mobile-friendly HTML/CSS archive in `output/`. ## What it does For every `*.pdf` in `examples/` it renders each page as a JPEG with poppler-utils (`pdftocairo`) and writes: - `output//page-NN.html` — one wrapper per page with prev/next navigation and a collapsed text-extract panel (from `pdftotext -layout`). - `output//index.html` — thumbnail grid for the issue. - `output/index.html` — root listing of all issues. - `output/styles.css` — single responsive stylesheet, no JavaScript. Layout fidelity (faithful to the print PDF) over text reflow; mobile responsiveness is via `img { max-width: 100% }` and CSS grid auto-fill. ## Requirements - Python ≥ 3.14 (see `.python-version`) - `poppler-utils` on `$PATH` (`pdftocairo`, `pdftotext`, `pdfinfo`): ```bash sudo apt install poppler-utils # Debian / Ubuntu brew install poppler # macOS ``` No third-party Python dependencies — `pyproject.toml` keeps `dependencies = []`. ## Usage ```bash python main.py # or: uv run python main.py ``` Then open `output/index.html` in a browser. Each run wipes and rebuilds `output//` for every PDF in `examples/`, so it's idempotent. ## Auto-convert: rebuild when a PDF is dropped in `examples/` Watch the folder with `inotifywait` (Linux; install `inotify-tools`): ```bash sudo apt install inotify-tools ``` Save next to `main.py` as `watch.sh`: ```bash #!/usr/bin/env bash set -euo pipefail cd "$(dirname "$0")" WATCH_DIR="${1:-examples}" echo "[watcher] watching $WATCH_DIR for new PDFs (Ctrl-C to stop)" inotifywait -m -q -e close_write,moved_to --format '%f' "$WATCH_DIR" \ | while read -r filename; do case "$filename" in *.pdf|*.PDF) echo "[watcher] $(date '+%H:%M:%S') new PDF: $filename — rebuilding" python main.py # Optional: push to your server right after rebuild # rsync -avz --delete output/ user@server:/var/www/netgazet/ ;; esac done ``` Make executable and run: ```bash chmod +x watch.sh ./watch.sh ``` The script rebuilds the **whole** site on every new PDF (~30 s for two 16-page issues). Fine for a handful of newsletters; for dozens, extend `main.py` to accept a single filename and only rebuild that issue plus the root index. On macOS, swap `inotifywait` for `fswatch -o "$WATCH_DIR" | while read; do ...; done`. ## Embedding in a WordPress page (iframe) Once `output/` is hosted somewhere (a vhost on your server, Cloudflare Pages, Netlify, etc.), embed it in any WordPress page or post: 1. In the block editor, add a **Custom HTML** block. 2. Paste: ```html ``` 3. Publish. Notes: - Use HTTPS for `src` if your WordPress site is on HTTPS — browsers block mixed content. - All navigation (issue → page → next page) stays inside the iframe, so the WordPress page doesn't reload. Don't add `target="_top"` to links in the generated HTML — that would break out of the frame. - `height: 85vh` works on desktop and most phones. For a fixed value use `height: 800px;` (or similar). - Cross-domain iframe embeds need no special config, **unless** the static host sends `X-Frame-Options: DENY` or `Content-Security-Policy: frame-ancestors 'none'`. Nginx/Caddy don't add these by default — only an issue if you explicitly enabled them. ### Subdomain vs subfolder (and auto-height) The iframe `src` can point at any reachable URL, including a **subdomain** such as `https://gazet.netwerk-antwerpen.be/`: ```html ``` That works out of the box (it's your own static files, so nothing blocks framing). Two things to know: - **HTTPS must match.** If WordPress is on `https://`, the subdomain must serve `https://` too, or the browser blocks it as mixed content. Static hosts and most shared hosting provide free Let's Encrypt certs — just enable it. - **A subdomain is a *different origin*** from the WordPress domain. That has one practical consequence: **cross-origin iframes can't auto-resize to their content height.** The browser won't let the parent page read the iframe's height, so the `postMessage` auto-height trick doesn't work. You get one of: | Hosting | URL example | Auto-height | |---|---|---| | Subdomain (different origin) | `gazet.netwerk-antwerpen.be` | ❌ — use a fixed height (`90vh` / `1200px`), accept inner scrollbars | | Subfolder (same origin) | `netwerk-antwerpen.be/gazet/` | ✅ — same-origin, `postMessage` auto-height works | Pick a **subfolder** only if seamless auto-resizing matters more than the cleaner subdomain URL. Otherwise a subdomain with a fixed `height` is the simplest setup. (The *Advanced iFrame Pro* plugin can do cross-domain auto-height too, but it needs a helper file dropped on the subdomain.)