尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证Daily newspaper for e-readers, built and delivered while you sleep. Zero maintenance, runs entirely through GitHub Actions. Full stack: Next.js web app, Python content extraction + sanitization pipeline, Supabase auth + storage, timezone aware scheduling, multi-device delivery (Kobo, Kindle, reMarkable), 850+ tests.
翻译准备中
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
Your personalized newspaper, compiled from 50+ news sources and delivered to your Kobo, Kindle, or reMarkable before you wake up.
I was following the news mostly through social media and wanted to switch to reading actual articles. I already loved my Kobo for books, so when my dad shared his FT subscription, it sparked an idea: could I get the news on my e-reader every morning?
Paper Boy started as a Python CLI, grew into a Streamlit prototype, and evolved into a full-stack Next.js + GitHub Actions pipeline. Each iteration solved real pain points I hit as a daily user.查看完整 README ↗Your personalized newspaper, compiled from 50+ news sources and delivered to your Kobo, Kindle, or reMarkable before you wake up.
Live Demo · Report Bug · Request Feature
I was following the news mostly through social media and wanted to switch to reading actual articles. I already loved my Kobo for books, so when my dad shared his FT subscription, it sparked an idea: could I get the news on my e-reader every morning?
Paper Boy started as a Python CLI, grew into a Streamlit prototype, and evolved into a full-stack Next.js + GitHub Actions pipeline. Each iteration solved real pain points I hit as a daily user.
graph LR
subgraph Frontend["Web app"]
A[Next.js + React 19<br/>Vercel]
end
subgraph Triggers["Reliable cron"]
B[Cloudflare Worker<br/>± 1 s drift]
end
subgraph Builds["Build pipeline"]
C[GitHub Actions<br/>repository_dispatch]
end
subgraph Core["Extraction + EPUB"]
D[Python library<br/>feedparser · trafilatura · ebooklib]
end
subgraph Data["Stateful services"]
E[(Supabase<br/>Postgres · Auth · Storage)]
end
subgraph Delivery["Delivery"]
F[Email · Wireless sync<br/>Direct download · Drive]
end
A -->|Server Actions| E
A -->|repository_dispatch<br/>on demand| C
B -->|repository_dispatch<br/>scheduled| C
C --> D
C -->|read/write| E
D -->|EPUB| F
style A fill:#0a0a0a,stroke:#333,color:#fff
style B fill:#1a1a2e,stroke:#333,color:#fff
style C fill:#2d2d2d,stroke:#333,color:#fff
style D fill:#2d2d2d,stroke:#333,color:#fff
style E fill:#1e3a5f,stroke:#333,color:#fff
style F fill:#2d2d2d,stroke:#333,color:#fff
Next.js handles auth, onboarding, and the dashboard via Supabase. When you hit "Get it now," it fires a repository_dispatch event to GitHub Actions, which runs the Python core library to extract full article text, generate an e-ink optimized EPUB, and push it to your device.
Scheduled runs are triggered by a tiny Cloudflare Worker instead of GitHub Actions' built-in cron — the worker fires build and deliver dispatches on time within ~1 second, while GitHub's schedule: trigger routinely drifts by 20+ minutes or skips slots entirely. Six build windows every 4 hours plus delivery checks every 30 minutes cover all timezones, so editions land at each user's local delivery time.
Schema migrations are deployed automatically by a separate workflow (.github/workflows/supabase-migrate.yml) that lints, runs a safety checker, and applies pending migrations to production after merge to main.
| Layer | Stack |
|---|---|
| Web app | Next.js 16, React 19, TypeScript (strict), Tailwind CSS v4, shadcn/ui |
| Auth & DB | Supabase (PostgreSQL + Auth + Storage), Drizzle ORM |
| Build pipeline | GitHub Actions (repository_dispatch), Python scripts |
| Cron triggers | Cloudflare Worker (free plan, 2 cron triggers) |
| Schema deploy | GitHub Actions + Supabase CLI (supabase db push) |
| Core library | Python 3.9+, feedparser, trafilatura, ebooklib, Pillow, Playwright (optional, for FT) |
| Email delivery | Resend |
| Testing | Vitest (220 tests) + pytest (743 tests) |
| CI/CD | GitHub Actions, Vercel (web) |
Web App
Core Library
delivery_history, dedupe via Idempotency-Key headerCLI
paper-boy build generates an EPUB from your configpaper-boy deliver builds and pushes to Google Drive or emailAutomation
schedule: triggers are kept as a safety netsupabase/migrations/** get a safety report; merging to main runs supabase db push --linked against productionwww.paper-boy-news.com — sign up and build your first edition in minutes.
# Prerequisites: Docker Desktop, Node.js 20+, pnpm, Supabase CLI
git clone https://github.com/luclacombe/paper-boy-news.git
cd paper-boy-news
# Start local Supabase (Postgres + Auth + Studio)
supabase start
# Start the web app
cd web
cp .env.local.example .env.local
pnpm install
pnpm dev # http://localhost:3000
Test accounts (password: password123): [email protected] / [email protected]
pip install -e .
cp config.example.yaml config.yaml # customize feeds + delivery
paper-boy build # build EPUB locally
paper-boy deliver # build + deliver
Email delivery uses Resend — set RESEND_API_KEY in your shell. Google Drive needs credentials.json (service account) in the project root for CLI use.
.github/workflows/build-newspaper.yml for the full listcron-worker/ to replace GitHub's unreliable cron — see cron-worker/README.mdSUPABASE_ACCESS_TOKEN and SUPABASE_DB_PASSWORD so migrations auto-deploy on merge — see the Release Process section in CLAUDE.mdsrc/paper_boy/ Core Python library + CLI
scripts/ Build runner + utility scripts
build_for_users.py Build runner used by GitHub Actions
check_migrations.py Pre-merge safety check for SQL migrations
seed_feed_stats.py Populate the feed_stats table
web/ Next.js web app (Vercel)
src/
actions/ Server Actions (data mutations)
app/ App Router pages + API routes
components/ React components (dashboard, settings, onboarding)
db/ Drizzle schema + queries
lib/ Supabase clients, edition logic, utilities
cron-worker/ Cloudflare Worker that fires scheduled dispatches
supabase/migrations/ Versioned SQL migrations (auto-deployed on merge)
tests/ Python tests
.github/workflows/ CI, build pipeline, schema deploy
legacy/ Archived prototypes (Streamlit, FastAPI)
newspaper:
title: "Morning Digest"
language: "en"
total_article_budget: 7 # ignored if reading_time_minutes is set
reading_time_minutes: 20 # word count / 238 WPM, scarcity-aware
include_images: true
feeds:
- name: "World News"
url: "https://www.theguardian.com/world/rss"
- name: "Technology"
url: "https://feeds.arstechnica.com/arstechnica/index"
delivery:
method: "google_drive" # "google_drive", "email", or "local"
device: "kobo" # "kobo", "kindle", "remarkable", or "other"
google_drive:
folder_name: "Rakuten Kobo"
credentials_file: "credentials.json"
email:
recipient: "[email protected]"
keep_days: 30
Email delivery requires RESEND_API_KEY in the environment. The web app uses the same recipient field plus its own Resend key set as a GitHub Secret.
GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET as GitHub Secretscredentials.json in the project rootconfig.yaml under delivery.email.recipient# Python core library
pip install -e ".[dev]"
pytest # 743 tests
# Next.js web app
cd web
pnpm dev # dev server
pnpm test # 220 tests (Vitest)
pnpm build # production build
pnpm lint # ESLint
# Cloudflare Worker (cron triggers)
cd cron-worker
pnpm install
pnpm test # Vitest under workerd via @cloudflare/vitest-pool-workers
pnpm deploy:dry # validate wrangler config without deploying
Detailed docs:
CLAUDE.md — root overview, build pipeline, edition model, release processsrc/paper_boy/CLAUDE.md — core library design decisionsweb/CLAUDE.md — web app architecturetests/CLAUDE.md — test organizationcron-worker/README.md — worker deploy + secret rotationPolyForm Noncommercial 1.0.0. Free to use, modify, and distribute for noncommercial purposes.