{"id":20653785,"url":"https://github.com/lukehsiao/openring-rs","last_synced_at":"2026-02-27T10:46:23.221Z","repository":{"id":59552174,"uuid":"521482157","full_name":"lukehsiao/openring-rs","owner":"lukehsiao","description":":chains: a webring for static site generators written in Rust","archived":false,"fork":false,"pushed_at":"2025-07-21T00:06:28.000Z","size":352,"stargazers_count":20,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-21T00:25:37.707Z","etag":null,"topics":["atom","openring","rss","rust","static-site","webring"],"latest_commit_sha":null,"homepage":"https://luke.hsiao.dev/blog/openring-rs/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lukehsiao.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-08-05T02:50:25.000Z","updated_at":"2025-07-21T00:06:31.000Z","dependencies_parsed_at":"2023-12-02T00:31:37.568Z","dependency_job_id":"6119bffe-f5de-4a38-80d6-615e3a79d3f3","html_url":"https://github.com/lukehsiao/openring-rs","commit_stats":{"total_commits":45,"total_committers":1,"mean_commits":45.0,"dds":0.0,"last_synced_commit":"2ca889f3a40905b4830d0e5e1e9c7b036e80eea6"},"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"purl":"pkg:github/lukehsiao/openring-rs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukehsiao%2Fopenring-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukehsiao%2Fopenring-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukehsiao%2Fopenring-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukehsiao%2Fopenring-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lukehsiao","download_url":"https://codeload.github.com/lukehsiao/openring-rs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukehsiao%2Fopenring-rs/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266253796,"owners_count":23900056,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["atom","openring","rss","rust","static-site","webring"],"created_at":"2024-11-16T17:48:17.468Z","updated_at":"2026-02-27T10:46:23.208Z","avatar_url":"https://github.com/lukehsiao.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\n    ⛓\u003cbr\u003e\n    openring-rs\n\u003c/h1\u003e\n\u003cdiv align=\"center\"\u003e\n    \u003cstrong\u003eA tool for generating a webring from Atom/RSS feeds.\u003c/strong\u003e\n\u003c/div\u003e\n\u003cbr\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://github.com/lukehsiao/openring-rs/actions/workflows/general.yml\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/actions/workflow/status/lukehsiao/openring-rs/general.yml\" alt=\"Build Status\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://crates.io/crates/openring\"\u003e\n    \u003cimg src=\"https://img.shields.io/crates/v/openring\" alt=\"Version\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/lukehsiao/openring-rs/blob/main/LICENSE.md\"\u003e\n    \u003cimg src=\"https://img.shields.io/crates/l/openring\" alt=\"License\"\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\u003cbr\u003e\n\n`openring-rs` is a tool for generating a webring from Atom/RSS feeds, so you can populate a template with articles from those feeds and embed them in your own blog. An example template is provided in `in.html`.\n\nThis is a Rust-port of Drew DeVault's [openring](https://git.sr.ht/~sircmpwn/openring), with the primary differences being:\n- we respect throttling and send conditional requests by default via caching (disable with `--no-cache`)\n- the template is written using [Tera](https://keats.github.io/tera/) and is provided as an argument, not read from stdin\n- we show a little progress bar\n- we fetch all feeds concurrently\n- we provide better error messages (via [miette](https://github.com/zkat/miette))\n- we allow filtering feeds with `--before`\n\n## Demo\n\nTo see this in action, you can look at the footer of this blog post.\n\n\u003chttps://luke.hsiao.dev/blog/openring-rs/\u003e\n\n## Install\n\n```\ncargo install --locked openring\n```\n\n## Usage\n\n```\nA webring for static site generators written in Rust\n\nUsage: openring [OPTIONS] --template-file \u003cFILE\u003e\n\nOptions:\n  -n, --num-articles \u003cNUM_ARTICLES\u003e    Total number of articles to fetch [default: 3]\n  -p, --per-source \u003cPER_SOURCE\u003e        Number of most recent articles to get from each feed [default: 1]\n  -S, --url-file \u003cFILE\u003e                File with URLs of Atom/RSS feeds to read (one URL per line, lines starting with '#' or \"//\" are ignored)\n  -t, --template-file \u003cFILE\u003e           Tera template file\n  -s, --url \u003cURL\u003e                      A single URL to consider (can be repeated to specify multiple)\n  -b, --before \u003cBEFORE\u003e                Only include articles before this date (in YYYY-MM-DD format)\n      --no-cache                       Do NOT use request cache stored on disk\n      --max-cache-age \u003cMAX_CACHE_AGE\u003e  Discard all cached requests older than this duration [default: 30d]\n  -v, --verbose...                     Increase logging verbosity\n  -q, --quiet...                       Decrease logging verbosity\n  -h, --help                           Print help (see more with '--help')\n  -V, --version                        Print version\n```\n\n## Using Tera templates\n\nThe templates supported by `openring-rs` are written using [Tera](https://keats.github.io/tera/).\nPlease refer to the Tera documentation for details.\n\n## Caching\n\nWe use OS-standard locations for caching.\n\n- **Linux**: `$XDG_CACHE_HOME/openring/cache.json` or `$HOME/.cache/openring/cache.json`\n- **macOS**: `$HOME/Library/Caches/dev.hsiao.openring/cache.json`\n- **Windows**: `{FOLDERID_LocalAppData}\\hsiao\\openring\\cache\\cache.json`\n\nThe cache file is simple JSON.\n\nThe cache only prevents refetching a feed if the feed source responds with a 429.\nIn this case, we respect `Retry-After`, or default to 4 hours.\nOtherwise, we use the cache to send conditional requests by respecting the `ETag` and `Last-Modified` headers.\n\n## Why a Rust port?\n\nJust for fun.\n\n## TODO\n\n### Test suite\nI've only recently added some property-based testing to this repository for some happy-path behavior.\nI'd love to make this test suite more rigorous.\nThe most significant hole right now is all the log in `src/lib.rs` which handles variables nuances of a feed body.\nThe test suite only contains a single valid RSS 2.0 feed.\nIt would be great to generate test strategies that provide far more coverage of both RSS and Atom feeds.\n\nAnother thing that is interesting is the potential holes revealed by `cargo-mutant`.\nWe've added a GitHub workflow for it to show the holes.\n\nFinally, `proptest` tests for `src/feedfetcher.rs` are excessively slow.\nWe should be able to speed those up.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flukehsiao%2Fopenring-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flukehsiao%2Fopenring-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flukehsiao%2Fopenring-rs/lists"}