news_crystal

Version, currently main branch1 version
  • main branchlatestJul 13, 2026

github.com/Laki0s/NewsCrystal

Tech news scraper and aggregator written in Crystal. Collects articles from several sources (Hacker News, Dev.to, Lobsters) into a single feed exposed through a REST API, a web interface and an RSS/Atom feed.

0 stars
0 dependents
License: MIT

Installation

# Add this to your shard.yml
dependencies:
  news_crystal:
    github: Laki0s/NewsCrystal
    branch: main

main is a branch, not a release, so this tracks it rather than pinning a version.

Then run:

shards install

shard.yml

Crystal
>= 1.10.0
License
MIT
Author
Laki0s
Target
  • news_crystal from src/news_crystal.cr

Dependencies

Runtime Dependencies

  • kemal~> 1.6github: kemalcr/kemal
  • lexbor~> 3.6github: kostya/lexbor
  • sqlite3~> 0.23github: crystal-lang/crystal-sqlite3

Development Dependencies

  • ameba~> 1.6github: crystal-ameba/amebadev

README

NewsCrystal

A fast tech-news scraper and aggregator, written in Crystal.

Follow Hacker News, Dev.to and Lobsters from a single feed โ€” browsable on the web, queryable through a REST API, and subscribable via RSS.

CI Valgrind Crystal


Why NewsCrystal?

Keeping up with tech means juggling half a dozen tabs. NewsCrystal scrapes those sources on a schedule, deduplicates the articles, and serves everything from one place โ€” a clean web page, a JSON API, or your favorite RSS reader.

It doubles as a hands-on tour of Crystal: static typing, fiber-based concurrency, and the shards ecosystem.

Features

  • ๐Ÿ“ฐ Multi-source aggregation โ€” Hacker News, Dev.to and Lobsters behind a single Source interface.
  • ๐Ÿงน Automatic deduplication โ€” a URL-derived hash keeps the feed clean across runs.
  • โฑ๏ธ Scheduled scraping โ€” a background fiber refreshes every source every 15 minutes, resilient to network failures.
  • ๐Ÿ”Œ REST API โ€” paginated, filterable access to the aggregated articles.
  • ๐Ÿ–ฅ๏ธ Web interface โ€” lightweight HTML/CSS/JS, sortable and searchable.
  • ๐Ÿ“ก RSS/Atom feed โ€” subscribe from any reader (/feed.xml).
  • ๐Ÿณ Container-ready โ€” ships with a Dockerfile for VPS deployment.

Tech stack

LayerChoice
LanguageCrystal (>= 1.10)
Web / APIKemal
HTML parsinglexbor
DatabaseSQLite via crystal-sqlite3
ConcurrencyCrystal fibers (periodic scraping)
LintingAmeba
CIGitHub Actions (self-hosted) โ€” format, lint, build, specs, Valgrind

Architecture

                +------------------+
   sources ---> |     Scraper      |  HTTP fetch + lexbor HTML parsing
  (HN, Dev.to,  |  (Source impls)  |
   Lobsters)    +--------+---------+
                         | Article
                         v
                +------------------+
                |     Storage      |  SQLite + URL-hash deduplication
                +--------+---------+
                         |
              +----------+-----------+
              v                      v
      +---------------+      +----------------+
      |   REST API    |      |   RSS/Atom     |   Kemal HTTP layer
      | /articles     |      |   /feed.xml    |
      +-------+-------+      +----------------+
              ^
              | fetch (JSON)
      +-------+-------+
      | Web interface |  HTML/CSS/vanilla JS
      +---------------+

  A scheduler fiber re-runs the scraper for every source every 15 minutes.

Requirements

  • Crystal >= 1.10 and Shards (install guide)
  • SQLite development headers โ€” libsqlite3-dev on Ubuntu/Debian
  • (optional) Docker, for the containerized deployment

Getting started

# 1. Clone
git clone git@github.com:Laki0s/NewsCrystal.git
cd NewsCrystal

# 2. Install dependencies
shards install

# 3. Run the test suite
crystal spec

# 4. Build and run
shards build
./bin/news_crystal

Configuration

Configuration is read from environment variables (a .env file is supported).

VariableDefaultDescription
PORT3000Port the HTTP server listens on
DATABASE_PATH./news_crystal.dbPath to the SQLite database file
SCRAPE_INTERVAL900Seconds between scraping runs (default 15 min)
HTTP_TIMEOUT10Per-request HTTP timeout in seconds

Configuration options land alongside their features (US5, US9). See the roadmap below for current status.

API

MethodRouteDescription
GET/articlesList articles โ€” paginated (?page, ?per_page), filterable (?source)
GET/articles/:idFetch a single article by id
GET/feed.xmlAggregated RSS 2.0 feed

Example:

curl "http://localhost:3000/articles?source=hackernews&per_page=10"

Development

crystal tool format          # auto-format the code
crystal tool format --check  # verify formatting (CI)
./bin/ameba                  # lint
crystal spec                 # run specs

Every push and pull request runs the self-hosted GitHub Actions pipeline: formatting, Ameba, release build, specs, and a Valgrind memory check.

Issue and PR templates live in .github/; contribution workflow and branch naming follow the User Stories (see below).

Project structure

src/
  news_crystal.cr        # Library entry point (wires the components together)
  news_crystal/
    version.cr           # VERSION constant
  scraper/               # HTTP fetching + HTML parsing of the sources
    scraper.cr
    source.cr            # Common Source interface
  storage/               # SQLite persistence + deduplication
    storage.cr
    article.cr           # Article domain model
  api/                   # REST API (Kemal) + RSS/Atom feed
    api.cr
  web/                   # Static assets for the web interface
spec/                    # Specs
.github/                 # Issue/PR templates and self-hosted CI workflows

Roadmap

Development follows the ten User Stories of the specification (cahier_des_charges_NewsCrystal.pdf), tracked in Issues.md.

  • [x] US1 โ€” Project & Crystal environment setup
  • [x] US2 โ€” Hacker News scraper
  • [x] US3 โ€” Storage & deduplication (SQLite)
  • [] US4 โ€” Additional sources (Dev.to, Lobsters)
  • [ ] US5 โ€” Automatic scraping scheduling
  • [ ] US6 โ€” REST API (Kemal)
  • [ ] US7 โ€” Web browsing interface
  • [ ] US8 โ€” RSS/Atom export
  • [ ] US9 โ€” Robustness & error handling
  • [ ] US10 โ€” Deployment & documentation

Status: early development โ€” the project structure is in place (US1). The features above are being implemented one User Story at a time.

Contributing

  1. Pick a User Story / issue and branch from main: feature/US<n>-<slug>.
  2. Keep the build green: crystal tool format, ./bin/ameba, crystal spec.
  3. Open a pull request using the template and link the issue (Closes #n).

License

Released under the MIT License.