reader

command module
v0.0.0-...-8f85068 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 13, 2026 License: BSD-3-Clause Imports: 19 Imported by: 0

README

go-reddit/reader

A native macOS Reddit reader whose entire UI is drawn by go-widgets — compiled to WebAssembly, blitted into a <canvas>, and hosted in a WKWebView that is opened from Go with zero cgo (CGO_ENABLED=0).

go-reddit reader

What it is

┌─ "Reddit Reader.app"  (pure Go, CGO=0, self-contained) ───────────────┐
│                                                                        │
│   internal/ui        go-widgets toolkit renders the feed → RGBA buffer │
│   cmd/front  (wasm)  blits that buffer into a browser <canvas>         │
│   internal/server    serves the wasm + proxies /api → Reddit           │
│   internal/webview   opens a WKWebView via purego (no cgo)             │
│                                                                        │
│   Transport (default): a WKURLSchemeHandler serves every request       │
│   in-process — no TCP, no unix socket, no listening port at all.       │
│                                                                        │
│        fetch  reader://app/api/feed ──► go-reddit/reddit ──► reddit.com │
└────────────────────────────────────────────────────────────────────────┘

The layout mirrors the Reddit web UI: a topbar with sort tabs (hot/new/top/rising) and the current feed, a sidebar of subreddits grouped into profiles (tabs) — e.g. keep your Pro and Perso feeds separate — and the scrollable feed of post cards. Clicking a sidebar feed or a sort tab reloads; clicking a post opens it; clicking a profile tab switches the feed set.

Preferences live in an in-canvas editor (click Settings in the sidebar) — also drawn with go-widgets, no separate HTML page: pick the theme, the default sort, and create/rename/delete profiles, adding or removing subreddits as chips. Everything persists to ~/Library/Application Support/go-reddit-reader/ settings.json (XDG/AppData off macOS).

Native look & feel per OS: the theme adapts to the host — WhiteSur (macOS), Adwaita (GNOME/Linux) or Fluent (Windows) — in light or dark following the system, or forced from Settings.

Three design choices worth calling out:

  1. go-widgets, not HTML. The cards, score badges, sidebar and topbar are painted by the go-widgets painter into an RGBA buffer, exactly as in a native window — the WebView is just a surface. Text is anti-aliased TrueType (the embedded Go fonts) rendered into that same buffer at device resolution, so it stays crisp at any zoom or on a Retina display.
  2. CGO=0 everywhere. The WKWebView, NSWindow and NSApplication are driven through the Objective-C runtime via purego. The shipped binary links only system libraries; AppKit/WebKit are dlopened at runtime.
  3. No socket. Instead of a loopback HTTP server, the default transport registers a private reader:// URL scheme and answers every request in-process from the same http.Handler. Nothing on the machine can reach the app's content, and no port is consumed. (A unix socket wouldn't help here — WKWebView can't dial one; the scheme handler is strictly better.) Pass -http to fall back to a 127.0.0.1 server (used off macOS and for automated testing).

Try it

# Real Reddit (front page; clicking a sidebar feed loads that subreddit):
task run                       # == go run .
go run . -sr golang -sort top  # start on a specific feed

# Build a double-clickable app bundle:
task app                       # produces dist/Reddit Reader.app
open "dist/Reddit Reader.app"

Reddit increasingly blocks anonymous .json access with a 403 (always from datacenter IPs, sometimes from residential). Log in with OAuth — either via the environment:

READER_OAUTH_CLIENT_ID=…  READER_OAUTH_CLIENT_SECRET=…  task run

…or, better, through the in-app login guarded by Touch ID: click Log in in the sidebar (or the menu-bar item), paste your Reddit app's client id + secret (from https://www.reddit.com/prefs/apps), and approve with Touch ID. The credentials are stored in the macOS Keychain; on later launches the menu-bar Log in with Touch ID unlocks them biometrically. The login form and sidebar entry are drawn with go-widgets like the rest of the UI — no separate window. A menu-bar (tray) item (R) offers Open / Log in / Log out / Quit.

Offline / no-credentials demo (built-in per-subreddit sample feeds — good for trying the UI and the sidebar switching without a network):

task demo                      # == go run . -demo
Flags & environment
Flag Env Meaning
-sr READER_SUBREDDIT subreddit (empty = front page)
-sort READER_SORT hot/new/top/rising/controversial/best
-demo serve a built-in sample feed, no network
-http use a loopback TCP server instead of the URL-scheme transport
-no-window open the default browser instead of a native window
-serve-only run headless over TCP and print the URL
READER_OAUTH_CLIENT_ID / _SECRET app-only OAuth
READER_OAUTH_USERNAME / _PASSWORD script-grant OAuth
Keyboard & window
  • Drag the window edge — the feed re-lays-out at the new size (cards widen/narrow, titles reflow), it does not stretch.
  • ⌘ + / ⌘ - — zoom the display in/out; ⌘ 0 resets. Zoom renders the go-widgets UI at a smaller/larger logical resolution (bigger text and cards, fewer at once), staying crisp rather than blurring.
  • Scroll — browse the feed; click a post — open it.

Build layout

  • internal/ui — the go-widgets scene: layout, hit-testing, rendering. Pure, native-testable (100% coverage), no build tag.
  • cmd/front — the GOOS=js GOARCH=wasm entry point (syscall/js glue).
  • internal/server — static bundle + /api proxy (100% coverage).
  • internal/webview — the purego WKWebView + WKURLSchemeHandler bridge.

The wasm bundle is a build artifact; scripts/build-wasm.sh (run by every task target) produces internal/server/assets/reader.wasm.

Testing notes

Everything that can run without a display is covered by native tests: the UI scene renders to a byte buffer checked pixel-for-non-blank (and dumped to PNG when READER_PNG is set), the server is driven through httptest, and the Objective-C bridge is exercised against the real runtime (NSString round trips, NSData, class registration, and the scheme-handler request/response path via a mock WKURLSchemeTask). The window creation and Cocoa run loop (webview.Run) are a native-integration boundary verified by launching the built app; they are the only substantial code the unit tests can't reach on a headless machine.

License

BSD-3-Clause — see LICENSE. Copyright the go-reddit/reader authors.

Documentation

Overview

Command reader is a native macOS app that browses Reddit with a go-widgets UI. It runs a local pure-Go HTTP server that (a) serves the WebAssembly front-end built from ./cmd/front and (b) proxies /api/* to Reddit through github.com/go-reddit/reddit, then opens a native WKWebView window (via purego, CGO=0) pointed at that server. Off macOS — or with -no-window — it prints the URL and opens the default browser instead.

reader -sr golang -sort top
READER_OAUTH_CLIENT_ID=… READER_OAUTH_CLIENT_SECRET=… reader

Directories

Path Synopsis
cmd
front command
mkicon command
Command mkicon renders the Reddit Reader app icon and writes it as a macOS .icns file (or a .png when the output path ends in .png).
Command mkicon renders the Reddit Reader app icon and writes it as a macOS .icns file (or a .png when the output path ends in .png).
internal
auth
Package auth handles Reddit OAuth login guarded by Touch ID.
Package auth handles Reddit OAuth login guarded by Touch ID.
browserhttp
Package browserhttp builds a portable, pure-Go (CGO=0) http.Client that presents a real Chrome TLS fingerprint via uTLS.
Package browserhttp builds a portable, pure-Go (CGO=0) http.Client that presents a real Chrome TLS fingerprint via uTLS.
server
Package server hosts the reader front-end: it serves the embedded wasm bundle and proxies the /api endpoints to Reddit through a go-reddit/reddit client.
Package server hosts the reader front-end: it serves the embedded wasm bundle and proxies the /api endpoints to Reddit through a go-reddit/reddit client.
settings
Package settings is the reader's persisted preferences: named profiles (tabs) that each group a subset of subreddits — so "Pro" and "Perso" feeds stay separate — plus the chosen sort and theme.
Package settings is the reader's persisted preferences: named profiles (tabs) that each group a subset of subreddits — so "Pro" and "Perso" feeds stay separate — plus the chosen sort and theme.
ui
Package ui renders the reader — a Reddit-style topbar + sidebar + feed — into an RGBA pixel buffer.
Package ui renders the reader — a Reddit-style topbar + sidebar + feed — into an RGBA pixel buffer.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL