{"id":22472205,"url":"https://github.com/ckampfe/russ","last_synced_at":"2025-04-04T19:05:20.885Z","repository":{"id":40251112,"uuid":"266413195","full_name":"ckampfe/russ","owner":"ckampfe","description":"A TUI RSS reader with vim-like controls and a local-first, offline-first focus","archived":false,"fork":false,"pushed_at":"2025-01-14T20:32:09.000Z","size":3364,"stargazers_count":196,"open_issues_count":13,"forks_count":22,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-28T18:07:10.983Z","etag":null,"topics":["atom","atom-feed","rss","rss-feed","rss-reader","rust","tui"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ckampfe.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2020-05-23T20:21:36.000Z","updated_at":"2025-03-28T18:00:11.000Z","dependencies_parsed_at":"2024-02-25T19:27:41.553Z","dependency_job_id":"55edd2da-dff8-4fc2-be61-28be90124d4e","html_url":"https://github.com/ckampfe/russ","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ckampfe%2Fruss","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ckampfe%2Fruss/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ckampfe%2Fruss/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ckampfe%2Fruss/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ckampfe","download_url":"https://codeload.github.com/ckampfe/russ/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247234921,"owners_count":20905854,"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","atom-feed","rss","rss-feed","rss-reader","rust","tui"],"created_at":"2024-12-06T12:12:39.568Z","updated_at":"2025-04-04T19:05:20.859Z","avatar_url":"https://github.com/ckampfe.png","language":"Rust","readme":"# russ\n\nRuss is a TUI RSS/Atom reader with vim-like controls and a local-first, offline-first focus.\n\n[![Rust](https://github.com/ckampfe/russ/actions/workflows/rust.yml/badge.svg)](https://github.com/ckampfe/russ/actions/workflows/rust.yml)\n\n---\n\n![](entries.png)\n![](entry.png)\n\n## install\n\n```console\n$ cargo install russ --git https://github.com/ckampfe/russ\n\n  note that on linux, you will need these system dependencies as well, for example:\n$ sudo apt update \u0026\u0026 sudo apt install libxcb-shape0-dev libxcb-xfixes0-dev\n$ russ read\n```\n\n**Note** that on its first run with no arguments, `russ read` creates a SQLite database file called `feeds.db` to store RSS/Atom feeds in a location of its choosing. If you wish to override this, you can pass a path with the `-d` option, like `russ -d /your/database/location/my_feeds.db`. If you use a custom database location, you will need to pass the `-d` option every time you invoke `russ`. See the help with `russ -h` for more information about where `russ` will store the `feeds.db` database by default on your platform.\n\nI do not currently publish binary releases, but that may change if someone is interested in that.\n\n## use\n\nRuss is modal, like vim. If you are comfortable with vim, or know of vim, you are probably going to be immediately comfortable with Russ. If you don't know vim, don't be afraid! If you read the following controls section and tinker a bit, you'll have no trouble using Russ.\n\nThere are two modes: normal mode and insert mode.\n\nIn normal mode, you read your RSS entries, navigate between entries, navigate between feeds, refresh feeds, and a few other things. This is where you spend 99% of your time when using Russ.\n\nWhen you want to start following a new feed, you enter insert mode.\nIn insert mode, you enter the URL of a feed you wish to begin following, and Russ will download that feed for you.\n\nThat's basically it!\n\nRuss can also import feeds from an OPML file. See below for more details.\n\n### controls - normal mode\n\nSome normal mode controls vary based on whether you are currently selecting a feed or an entry.\n\n- `q`/`Esc` - quit Russ\n- `hjkl`/arrows - move up/down/left/right between feeds and entries, scroll up/down on an entry\n- `Enter` - read selected entry\n- `r` - refresh the selected feed\n- `r` - mark the selected entry as read\n- `x` - refresh all feeds\n- `i` - change to insert mode\n- `a` - toggle between read/unread entries\n- `c` - copy the selected link to the clipboard (feed or entry)\n- `o` - open the selected link in your browser (feed or entry)\n- `ctrl-u`/`ctrl-d` - scroll up/down a page at a time\n\n### controls - insert mode\n\n- `Esc` - go back to normal mode\n- `Enter` - subscribe to the feed you just typed in the input box\n- `Del` - delete the selected feed.\n\n## help/options/config\n\n```console\n$ russ -h\nA TUI RSS reader with vim-like controls and a local-first, offline-first focus\n\nUsage: russ \u003cCOMMAND\u003e\n\nCommands:\n  read    Read your feeds\n  import  Import feeds from an OPML document\n  help    Print this message or the help of the given subcommand(s)\n\nOptions:\n  -h, --help     Print help\n  -V, --version  Print version\n```\n\n## read mode\n\n```console\n$ russ read -h\nRead your feeds\n\nUsage: russ read [OPTIONS]\n\nOptions:\n  -d, --database-path \u003cDATABASE_PATH\u003e\n          Override where `russ` stores and reads feeds. By default, the feeds database on Linux this will be at `XDG_DATA_HOME/russ/feeds.db` or `$HOME/.local/share/russ/feeds.db`. On MacOS it will be at `$HOME/Library/Application Support/russ/feeds.db`. On Windows it will be at `{FOLDERID_LocalAppData}/russ/data/feeds.db`\n  -t, --tick-rate \u003cTICK_RATE\u003e\n          time in ms between two ticks [default: 250]\n  -f, --flash-display-duration-seconds \u003cFLASH_DISPLAY_DURATION_SECONDS\u003e\n          number of seconds to show the flash message before clearing it [default: 4]\n  -n, --network-timeout \u003cNETWORK_TIMEOUT\u003e\n          RSS/Atom network request timeout in seconds [default: 5]\n  -h, --help\n          Print help\n```\n\n## import OPML mode\n\n```console\n$ russ import -h\nImport feeds from an OPML document\n\nUsage: russ import [OPTIONS] --opml-path \u003cOPML_PATH\u003e\n\nOptions:\n  -d, --database-path \u003cDATABASE_PATH\u003e\n          Override where `russ` stores and reads feeds. By default, the feeds database on Linux this will be at `XDG_DATA_HOME/russ/feeds.db` or `$HOME/.local/share/russ/feeds.db`. On MacOS it will be at `$HOME/Library/Application Support/russ/feeds.db`. On Windows it will be at `{FOLDERID_LocalAppData}/russ/data/feeds.db`\n  -o, --opml-path \u003cOPML_PATH\u003e\n\n  -n, --network-timeout \u003cNETWORK_TIMEOUT\u003e\n          RSS/Atom network request timeout in seconds [default: 5]\n  -h, --help\n          Print help\n```\n\n## design\n\nRuss stores all application data in a SQLite database. Additionally, Russ is non-eager. It will not automatically refresh your feeds on a timer, it will not automatically mark entries as read. Russ will only do these things when you tell it to. This is intentional, as Russ has been designed to be 100% usable offline, with no internet connection. You should be able to load it up with new feeds and entries and fly to Australia, and not have Russ complain when the plane's Wifi fails. As long as you have a copy of Russ and a SQLite database of your RSS/Atom feeds, you will be able to read your RSS/Atom feeds.\n\nRuss is a [tui](https://crates.io/crates/tui) app that uses [crossterm](https://crates.io/crates/crossterm). I develop and use Russ primarily on a Mac, but I have run it successfully on Linux and WSL. It should be possible to use Russ on Windows, but I have not personally used Russ on Windows, so I cannot verify this. If you use Russ on Windows or have tried to use Russ on Windows, please open an issue and let me know!\n\n## stability\n\nThe application-level and database-level contracts encoded in Russ are stable. I can't remember the last time I broke one. That said, I still reserve the right to break application or database contracts to fix things, but I have no reason to believe this will happen. I use Russ every day, and it basically \"just works\". If you use Russ and this is not the case for you, please open an issue and let me know.\n\n## SQL\n\nDespite being a useful RSS reader for me and a few others, Russ cannot possibly provide all of\nthe functionality everyone might want from an RSS reader.\n\nHowever, Russ uses a regular SQLite database to store RSS feeds (more detail below),\nwhich means that if a feature you want isn't in Russ itself, you can probably accomplish\nwhat you want to do with regular SQL.\n\nThis is especially true for one-off tasks like running analysis of your RSS feeds,\nremoving duplicates when a feed changes its link scheme, etc.\n\nIf there's something you want to do with your RSS feeds and Russ doesn't do it,\nconsider opening a Github issue and asking if anyone knows how to make it happen with SQL.\n\n## features/todo\n\nThis is not a strict feature list, and it is not a roadmap. Unchecked items are ideas to explore rather than features that are going to be built. If you have an idea for a feature that you would enjoy, open an issue and we can talk about it.\n\n- [ ] visual indicator for which feeds have new/unacknowledged entries\n- [ ] profiling mode that shows speed of UI interaction\n- [ ] stabilize the database schema\n- [ ] automatically fetch entries that only provide a link field\n- [ ] debug view (show app state)\n- [x] import OPML feeds\n- [x] migration process for database changes\n- [x] rss support\n- [x] atom support\n- [x] vim-style hjkl navigation\n- [x] subscribe to a feed\n- [x] refresh a feed\n- [x] delete a feed\n- [x] mark entries as read\n- [x] mark entries as unread\n- [x] view only unread entries\n- [x] view only read entries\n- [x] entry reading/scrolling\n- [x] error handling/display\n- [x] display entry info\n- [x] display feed info\n- [x] configurable word wrapping line length\n- [x] parse and store proper `chrono::DateTime\u003cUtc\u003e` for `pub_date`\n- [x] sort entries by `pub_date` descending, fall back to `inserted_at` if no `pub_date`\n- [x] nonblocking IO (inspiration: https://keliris.dev/improving-spotify-tui/)\n- [x] refresh all feeds\n- [x] refresh all feeds in parallel (multithreaded IO)\n- [x] use a database connection pool when refreshing feeds\n- [x] show refresh time for single feed and all feeds\n- [x] fix N+1 queries on feed/entry creation\n- [x] set up CI\n- [x] copy feed and entry links to clipboard\n- [x] add a network timeout for fetching new rss/atom entries (default: 5 seconds)\n- [x] show scroll progress for an entry\n- [x] show/hide help with `?`\n- [x] page-down/page-up entry scrolling\n- [x] automatic line length for wrapping\n- [x] ability to open the current link in your default browser\n- [x] create a feeds database by default (overridable with `-d` CLI option)\n\n## Minimum Supported Rust Version (MSRV) policy\n\nRuss targets the latest stable version of the Rust compiler. Older Rust versions may work, but building Russ against non-latest stable versions is not a project goal and is not supported.\nLikewise, Russ may build with a nightly Rust compiler, but this is not a project goal.\n\n## SQLite version\n\n`russ` compiles and bundles its own embedded SQLite via the [Rusqlite](https://github.com/rusqlite/rusqlite) project, which is version 3.45.1.\n\nIf you prefer to use the version of SQLite on your system, edit `Cargo.toml` to\nremove the `\"bundled\"` feature from the `rusqlite` dependency and recompile `russ`.\n\n**Please note** that while `russ` may run just fine with whatever version of SQLite you happen to have on your system, I do not test `russ` with a system SQLite, **and running `russ` with a system SQLite is not officially supported.**\n\n## contributing\n\nI welcome contributions to Russ. If you have an idea for something you would like to contribute, open an issue and we can talk about it!\n\n## license\n\nSee the [license.](LICENSE)\nSPDX-License-Identifier: AGPL-3.0-or-later\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fckampfe%2Fruss","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fckampfe%2Fruss","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fckampfe%2Fruss/lists"}