Files

203 lines
9.7 KiB
Markdown
Raw Permalink Normal View History

2026-10-16 14:53:37 +02:00
# Tagesbyte
Your daily tech news in bytes. A Flutter app that collects the day's tech news
from German and English RSS/Atom feeds and uses AI to summarize single articles
or write a daily briefing. It's meant to replace the n8n → Discord workflow.
## Features (prototype)
- **Today**: all articles from the enabled sources in the last 12/24/48 h, newest
first. Filter by language or source, pull to refresh.
- **Reading in the app**: tapping an article opens a clean **reader view** (text,
headings, lists, quotes, images) without ads or cookie banners. The globe icon
switches to the **original page** in an in-app WebView, for paywalls or sites
that block reader view. **Summarize with AI** uses the same downloaded text, so
the summary is based on the full article, not just the RSS teaser. Links in the
briefing open the same way.
- **Briefing**: AI picks the 6–10 most important stories of the day, merges
coverage from different outlets, and links every topic to its sources. Every
briefing is saved on the device (`briefings.json` in the app's private
storage); the history button lists them by month, tap to read, swipe to delete
(with undo).
- **Paid articles and ads hidden**: heise+ and Golem `(g+)` are recognized by
their title; SPIEGEL+ and t3n Pro by a marker in the article page, which the app
checks once per new article in the background (it reads only until the marker,
and remembers results for 14 days). Sponsored posts (`Anzeige:`) are hidden too.
The feed header shows how many were hidden; both filters can be turned off.
- **Ad and cookie-banner blocking** in the original-page view: requests to ~80
ad/tracker hosts and the common consent managers (Sourcepoint, OneTrust,
consentmanager, Usercentrics, Didomi, Cookiebot, …) are blocked, and a
stylesheet hides leftover ad slots and banners. Nothing is accepted, so sites
treat it like a rejection. Golem redirects to a separate consent page instead
of showing a banner; with "Accept cookie walls" on (default), the app makes the
same request as Golem's own "Zustimmen" button (`/abo/setconsentcookie.php`,
valid for a day) and reuses the cookie for reader view and the in-app page.
With it off, the app shows the teaser and an "Open website anyway" option.
- **Sources**: 23 curated feeds (13 German, 10 English), toggle each one, or add any
2026-10-16 14:53:37 +02:00
RSS/Atom feed (it's validated before being added).
- **Dark mode**: System / Light / Dark in Settings (applies instantly). The
original-page view follows it too: when the phone is dark, sites use their own
dark design or Android darkens them; when only the app is dark, the app inverts
the page colours and keeps photos and videos as they are.
- **Settings**: AI provider (off / Claude API / n8n webhook), model, summary
language (German/English, whatever the source language), time window, paid/ad
filters, ad and cookie-banner blocking.
## Running
```bash
flutter pub get
flutter run # pick an Android emulator/device
flutter test # unit tests (parser, Claude request/response handling)
LIVE_FEEDS=1 flutter test test/live_feeds_test.dart # checks every real feed
```
Platform notes:
- **Android / iOS**: work as-is (Android 6.0+).
- **Windows desktop**: requires Visual Studio with the "Desktop development with
C++" workload. Reader view works; "original page" opens the browser because
the WebView plugin has no Windows support.
- **Web**: browsers block cross-origin feed requests (CORS). Set a CORS proxy
prefix in Settings (only shown on web), or use the app on mobile/desktop.
## AI setup
### Option A: Claude API (direct)
1. Create a key at <https://console.anthropic.com/settings/keys>.
2. Settings → AI summaries → **Claude API** → paste the key → Save.
The key is stored in the platform keystore (`flutter_secure_storage`) and only
sent to `api.anthropic.com`. Model choices:
| Model | Use it for |
|---|---|
| `claude-opus-5-5` (default) | Best briefing quality |
| `claude-sonnet-5-5` | Balanced cost and quality |
| `claude-haiku-5-5` | Cheapest; good enough for single-article summaries |
Requests use low effort (summarizing is routine work) and, for the briefing,
structured JSON output so the result maps reliably to topics and links. On Opus
and Sonnet the app also enables Anthropic's server-side refusal fallback
(`fallbacks: "default"`): if a safety classifier declines a request, the API
retries it on a fallback model.
> Shipping the app to other people with your key inside isn't safe. For
> personal use a key you entered yourself is fine; for distribution, route
> requests through your own backend (e.g. the n8n option below).
### Option B: Your n8n workflow
Settings → AI summaries → **n8n webhook** → enter the production URL of a
*Webhook* trigger node (method POST, "Respond: Using 'Respond to Webhook' node").
The app sends JSON and expects JSON back.
**Daily briefing**
```jsonc
// Request
{
"action": "daily_briefing",
"language": "de", // "de" | "en"
"articles": [
{
"id": "a1",
"title": "…",
"url": "https://…",
"source": "heise online",
"language": "de",
"published": "2026-10-11T07:30:00.000Z",
"excerpt": "…"
}
]
}
// Response, option 1 (structured; topics link back to the articles)
{
"intro": "One or two sentences on the day.",
"topics": [
{ "title": "…", "summary": "…", "article_ids": ["a1", "a7"] }
]
}
// Response, option 2 (plain text, e.g. your existing Discord message)
{ "text": "…" }
```
**Single article**
```jsonc
// Request
{
"action": "summarize_article",
"language": "de",
"article": { "title": "…", "url": "…", "source": "…", "published": "…", "text": "extracted article body" }
}
// Response
{ "summary": "…" } // a plain-text body also works
```
Use a *Switch* node on `{{$json.body.action}}` to route the two cases to your
existing AI nodes.
## News sources
Every feed URL below was checked to load and parse. The ★ sources are enabled by
default: a small set of high-signal News sources. The others stay in the catalog
to switch on in the Sources tab.
2026-10-16 14:53:37 +02:00
| | Source | Feed | Focus |
|---|---|---|---|
| 🇩🇪 ★ | heise online | `heise.de/rss/heise-atom.xml` | Broad IT news, high volume (~150/day) |
| 🇩🇪 ★ | Golem.de | `rss.golem.de/rss.php?feed=ATOM1.0` | IT news for professionals |
| 🇩🇪 ★ | The Decoder | `the-decoder.de/feed/` | AI news: models, research, industry |
| 🇩🇪 | t3n | `t3n.de/rss.xml` | Digital business, startups, AI |
| 🇩🇪 | ComputerBase | `computerbase.de/rss/news.xml` | Hardware, software, gaming |
2026-10-16 14:53:37 +02:00
| 🇩🇪 | SPIEGEL Netzwelt | `spiegel.de/netzwelt/index.rss` | Mainstream news magazine view |
| 🇩🇪 | ZEIT Digital | `newsfeed.zeit.de/digital/index` | Digital policy and society |
| 🇩🇪 | netzpolitik.org | `netzpolitik.org/feed/` | Digital rights, privacy |
| 🇩🇪 | heise Security | `heise.de/security/rss/news-atom.xml` | Security section of heise online (turn heise online off to use it) |
| 🇩🇪 | heise Developer | `heise.de/developer/rss/news-atom.xml` | Developer section of heise online (turn heise online off to use it) |
2026-10-16 14:53:37 +02:00
| 🇩🇪 | Caschys Blog | `stadt-bremerhaven.de/feed/` | Consumer tech, smartphones |
| 🇩🇪 | derStandard Web | `derstandard.at/rss/web` | Austrian daily's tech section |
| 🇩🇪 | Borns IT- und Windows-Blog | `borncity.com/blog/feed/` | Windows, patches, admin topics |
| 🇬🇧 | The Verge | `theverge.com/rss/index.xml` | Consumer tech, policy |
2026-10-16 14:53:37 +02:00
| 🇬🇧 ★ | Ars Technica | `feeds.arstechnica.com/arstechnica/index` | In-depth tech and science |
| 🇬🇧 | TechCrunch | `techcrunch.com/feed/` | Startups, funding |
| 🇬🇧 ★ | Hacker News | `hnrss.org/frontpage?points=150` | Front page stories with 150+ points |
| 🇬🇧 ★ | Techmeme | `techmeme.com/feed.xml` | The day's top tech stories, picked by editors |
| 🇬🇧 ★ | Lobsters | `lobste.rs/rss` | Computing links, voted by a programmer community |
| 🇬🇧 ★ | Simon Willison | `simonwillison.net/atom/entries/` | LLMs and AI tools, tried out hands-on |
2026-10-16 14:53:37 +02:00
| 🇬🇧 | MIT Technology Review | `technologyreview.com/feed/` | AI, biotech, climate |
| 🇬🇧 | The Register | `theregister.com/headlines.atom` | Enterprise IT |
| 🇬🇧 | BleepingComputer | `bleepingcomputer.com/feed/` | Security, malware |
Reader view works for the publishers' own articles except ZEIT Digital, which
blocks non-browser requests, so the app shows the teaser and offers the original
page. Hacker News and Lobsters link to articles all over the web, so reader view
depends on the linked site. Techmeme links to its own summary page, which only
has the teaser; the original page links on to the full story.
2026-10-16 14:53:37 +02:00
## Project layout
```
lib/
main.dart App entry, theme
data/default_sources.dart Curated feed list
models/ Article, NewsSource, DailyBriefing, AppSettings
services/
feed_parser.dart RSS 2.0 / RSS 1.0 / Atom parser, date parsing
feed_service.dart Parallel fetching, dedupe, time window
article_extractor.dart Article page → reader blocks + text for the AI
summarizer.dart Summarizer interface and shared prompt input
claude_summarizer.dart Claude Messages API over HTTP
n8n_summarizer.dart n8n webhook bridge
storage.dart Settings, sources, briefing persistence
paywall_service.dart Paid/sponsored detection (titles + page marker)
content_blocking.dart Ad/tracker/consent blocklists for the WebView
consent_service.dart Accepts consent walls (Golem) and keeps the cookies
state/app_state.dart ChangeNotifier holding app state
ui/ Screens (Today, Article, Briefing, Sources, Settings)
```