DEV Community

Cover image for How I built a news reader that wants nothing from you: five topics, one window
fralsare
fralsare

Posted on

How I built a news reader that wants nothing from you: five topics, one window

I built a news reader that wants nothing from you : five topics, one window

Every news app I tried in the last few years asks for the same three
things before you see a single headline: an account, an API key, and
eventually a subscription. I got tired of negotiating with software
about reading the news, so I built fralsare-daily Github Link - a
small, open-source desktop app that reads public RSS feeds and stops
asking.

What it is

fralsare-daily is a Tauri 2 desktop app (Windows + Linux) that aggregates
public RSS feeds into five fixed topics:

  • Geopolitics & Conflict
  • Politics & Governance
  • Sports
  • Technology & Business
  • Viral & Social Issues

Five, not fifty. That's the point: a fixed, small set of shelves you can
clear in ten minutes, instead of a personalized infinite scroll.

Clicking a story opens it in a built-in reader. The whole experience
stays in one window — article body, images, internal links with a back
button — with an "Open in browser" escape hatch one click away. There's
also an images / text-only toggle for slow connections.

Screenshot

Why Tauri 2?

The constraint that shaped the architecture: this is a news reader, not a
browser. It needs to fetch feeds and article HTML from arbitrary domains —
which a plain web frontend can't do (CORS) — but it should weigh what a
desktop utility weighs, not 100+ MB of Chromium.

So the split is:

  • Rust backend owns all network I/O: it fetches feeds, parses RSS 2.0 and Atom with a streaming parser (no full DOM build), fetches article pages, and does the first sanitization pass.
  • Vanilla TypeScript + Vite frontend renders the UI. No framework — the app is one sidebar, one list, one reader view, and a state machine of about 200 lines.

Result: a ~15–20 MB release binary with CI-built packages for both
platforms.

The part that took the most iteration: sanitization

Rendering third-party HTML inside your app is the security-critical part.
I ended up with defense in depth:

  1. Extraction — before anything else, the backend picks the actual article body (largest <article> block, then <main>, else the document) so site chrome, nav bars, and "related stories" never enter the reader.
  2. Rust regex pass — strips script/style/iframe/form and other executable tags, removes on* attributes and inline styles, and neutralizes javascript: URLs.
  3. Frontend DOM pass — a second sanitizer walks the parsed DOM and removes the same tag/attribute classes, because regex alone is not a parser and I don't trust one layer.
  4. Navigation guard — the Tauri webview blocks any navigation away from the app shell; a link inside an article either pushes the in-app history stack or, if it can't be rendered safely, falls back to the system browser.

Images only render after the backend checks the response's magic bytes
(actual JPEG/PNG/GIF/WEBP), which avoids the classic "HTML file with an
image content type" trap.

What I'd do differently

  • A real HTML parser (html5ever) in the backend would replace the regex layer — I traded robustness for a lighter dependency tree, but that's a defensible trade I might revisit.
  • Feed selection is currently fixed per topic. Custom feeds are the obvious next feature.

Try it

It's MIT-licensed and the source is small enough to read in an afternoon : Repo URL
Prebuilt Windows and Linux binaries are on the releases page,
or cargo tauri dev if you'd rather build it.

If you've been looking for a reason to move off the infinite scroll, this
is my attempt at the reason: fewer topics, no account, no keys, no
tracking, one window.

Top comments (1)

Collapse
 
fralsare profile image
fralsare •

fralsare-daily v0.1.0 - released - Linux appimage and windows setup available now - github.com/fralsare/fralsare-daily...