grokfeed 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. grokfeed-0.2.0/.github/release.yml +14 -0
  2. grokfeed-0.2.0/.github/workflows/ci.yml +47 -0
  3. grokfeed-0.2.0/.github/workflows/codeql.yml +32 -0
  4. grokfeed-0.2.0/.github/workflows/release.yml +42 -0
  5. grokfeed-0.2.0/.gitignore +8 -0
  6. grokfeed-0.2.0/.pre-commit-config.yaml +14 -0
  7. grokfeed-0.2.0/LICENSE +21 -0
  8. grokfeed-0.2.0/PKG-INFO +168 -0
  9. grokfeed-0.2.0/README.md +121 -0
  10. grokfeed-0.2.0/config.example.toml +17 -0
  11. grokfeed-0.2.0/docs/screenshots/comments.png +0 -0
  12. grokfeed-0.2.0/docs/screenshots/feed.png +0 -0
  13. grokfeed-0.2.0/docs/screenshots/post.png +0 -0
  14. grokfeed-0.2.0/grokfeed/__init__.py +1 -0
  15. grokfeed-0.2.0/grokfeed/app.py +290 -0
  16. grokfeed-0.2.0/grokfeed/config.py +72 -0
  17. grokfeed-0.2.0/grokfeed/main.py +19 -0
  18. grokfeed-0.2.0/grokfeed/sources/__init__.py +5 -0
  19. grokfeed-0.2.0/grokfeed/sources/comments.py +154 -0
  20. grokfeed-0.2.0/grokfeed/sources/hn.py +89 -0
  21. grokfeed-0.2.0/grokfeed/sources/lobsters.py +61 -0
  22. grokfeed-0.2.0/grokfeed/sources/reddit.py +92 -0
  23. grokfeed-0.2.0/grokfeed/widgets/__init__.py +6 -0
  24. grokfeed-0.2.0/grokfeed/widgets/comments_modal.py +124 -0
  25. grokfeed-0.2.0/grokfeed/widgets/content_modal.py +82 -0
  26. grokfeed-0.2.0/grokfeed/widgets/feed.py +75 -0
  27. grokfeed-0.2.0/grokfeed/widgets/post_split_modal.py +179 -0
  28. grokfeed-0.2.0/grokfeed/widgets/story.py +73 -0
  29. grokfeed-0.2.0/pyproject.toml +74 -0
  30. grokfeed-0.2.0/tests/__init__.py +0 -0
  31. grokfeed-0.2.0/tests/test_config.py +88 -0
  32. grokfeed-0.2.0/tests/test_interleave.py +49 -0
  33. grokfeed-0.2.0/tests/test_sources_hn.py +114 -0
  34. grokfeed-0.2.0/tests/test_sources_lobsters.py +73 -0
  35. grokfeed-0.2.0/tests/test_sources_reddit.py +107 -0
  36. grokfeed-0.2.0/uv.lock +693 -0
@@ -0,0 +1,14 @@
1
+ changelog:
2
+ categories:
3
+ - title: "What's New"
4
+ labels:
5
+ - enhancement
6
+ - title: Bug Fixes
7
+ labels:
8
+ - bug
9
+ - title: Performance
10
+ labels:
11
+ - performance
12
+ - title: Maintenance
13
+ labels:
14
+ - chore
@@ -0,0 +1,47 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ lint:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ - uses: astral-sh/setup-uv@v5
14
+ with:
15
+ python-version: "3.12"
16
+ - run: uv sync
17
+ - run: uv run ruff check .
18
+ - run: uv run ruff format --check .
19
+ - run: uv run mypy grokfeed
20
+
21
+ test:
22
+ runs-on: ${{ matrix.os }}
23
+ strategy:
24
+ fail-fast: false
25
+ matrix:
26
+ os: [ubuntu-latest, macos-latest]
27
+ python: ["3.11", "3.12"]
28
+ steps:
29
+ - uses: actions/checkout@v4
30
+ - uses: astral-sh/setup-uv@v5
31
+ with:
32
+ python-version: ${{ matrix.python }}
33
+ - run: uv sync
34
+ - run: uv run pytest --cov=grokfeed --cov-report=xml
35
+ - name: Upload coverage
36
+ if: matrix.os == 'ubuntu-latest' && matrix.python == '3.12'
37
+ uses: codecov/codecov-action@v4
38
+ with:
39
+ token: ${{ secrets.CODECOV_TOKEN }}
40
+
41
+ build-check:
42
+ runs-on: ubuntu-latest
43
+ steps:
44
+ - uses: actions/checkout@v4
45
+ - uses: astral-sh/setup-uv@v5
46
+ - run: uv build
47
+ - run: uv run --with twine twine check dist/*
@@ -0,0 +1,32 @@
1
+ name: CodeQL
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ schedule:
8
+ - cron: "17 11 * * 2" # weekly on Tuesday
9
+
10
+ jobs:
11
+ analyze:
12
+ runs-on: ubuntu-latest
13
+ permissions:
14
+ security-events: write
15
+ actions: read
16
+ contents: read
17
+ strategy:
18
+ fail-fast: false
19
+ matrix:
20
+ language: [python]
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+
24
+ - uses: github/codeql-action/init@v3
25
+ with:
26
+ languages: ${{ matrix.language }}
27
+
28
+ - uses: github/codeql-action/autobuild@v3
29
+
30
+ - uses: github/codeql-action/analyze@v3
31
+ with:
32
+ category: "/language:${{ matrix.language }}"
@@ -0,0 +1,42 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ permissions:
8
+ contents: write
9
+ id-token: write # required for PyPI trusted publishing
10
+
11
+ jobs:
12
+ release:
13
+ runs-on: ubuntu-latest
14
+ environment: pypi
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ with:
18
+ fetch-depth: 0 # full history for release notes
19
+
20
+ - uses: astral-sh/setup-uv@v5
21
+
22
+ - run: uv build
23
+
24
+ - name: Publish to PyPI
25
+ uses: pypa/gh-action-pypi-publish@release/v1
26
+
27
+ - name: Create GitHub Release
28
+ uses: softprops/action-gh-release@v2
29
+ with:
30
+ generate_release_notes: true
31
+ files: dist/*
32
+
33
+ - name: Update Homebrew formula
34
+ uses: mislav/bump-homebrew-formula-action@v3
35
+ with:
36
+ formula-name: grokfeed
37
+ homebrew-tap: emarkou/homebrew-grokfeed
38
+ base-branch: main
39
+ download-url: https://github.com/emarkou/grokfeed/archive/refs/tags/${{ github.ref_name }}.tar.gz
40
+ commit-message: "grokfeed {{version}}"
41
+ env:
42
+ COMMITTER_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }}
@@ -0,0 +1,8 @@
1
+ __pycache__/
2
+ *.pyc
3
+ *.pyo
4
+ .venv/
5
+ *.egg-info/
6
+ dist/
7
+ build/
8
+ .claude/
@@ -0,0 +1,14 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.4.0
4
+ hooks:
5
+ - id: ruff
6
+ args: [--fix]
7
+ - id: ruff-format
8
+
9
+ - repo: https://github.com/pre-commit/mirrors-mypy
10
+ rev: v1.10.0
11
+ hooks:
12
+ - id: mypy
13
+ args: [--ignore-missing-imports]
14
+ additional_dependencies: [types-tomli]
grokfeed-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Eleni Markou
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,168 @@
1
+ Metadata-Version: 2.4
2
+ Name: grokfeed
3
+ Version: 0.2.0
4
+ Summary: Hacker News + Reddit + lobste.rs terminal feed viewer
5
+ Project-URL: Homepage, https://github.com/emarkou/grokfeed
6
+ Project-URL: Repository, https://github.com/emarkou/grokfeed
7
+ Project-URL: Issues, https://github.com/emarkou/grokfeed/issues
8
+ Author-email: Eleni Markou <eamarkou@gmail.com>
9
+ License: MIT License
10
+
11
+ Copyright (c) 2026 Eleni Markou
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
30
+ License-File: LICENSE
31
+ Keywords: feed,hacker-news,lobsters,reddit,terminal,tui
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Environment :: Console
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: License :: OSI Approved :: MIT License
36
+ Classifier: Programming Language :: Python :: 3
37
+ Classifier: Programming Language :: Python :: 3.11
38
+ Classifier: Programming Language :: Python :: 3.12
39
+ Classifier: Topic :: Internet :: WWW/HTTP
40
+ Classifier: Topic :: Terminals
41
+ Requires-Python: >=3.11
42
+ Requires-Dist: click>=8.0.0
43
+ Requires-Dist: httpx[http2]>=0.27.0
44
+ Requires-Dist: textual>=0.47.0
45
+ Requires-Dist: tomli>=2.0.0; python_version < '3.11'
46
+ Description-Content-Type: text/markdown
47
+
48
+ # grokfeed
49
+
50
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
51
+
52
+ Terminal feed reader for Hacker News, Reddit, and lobste.rs.
53
+
54
+
55
+ ## Features
56
+
57
+ - Unified scrollable feed from HN, Reddit subreddits, and lobste.rs
58
+ - Color-coded by source: HN orange, lobste.rs red, subreddits in a cycling palette
59
+ - Read text posts and Ask HN inline — no browser needed
60
+ - Comments viewer with nested replies (up to 2 levels)
61
+ - Filter feed by source, refresh on demand
62
+ - Config file at `~/.grokfeed/config.toml` — created automatically on first run
63
+
64
+ ## Install
65
+
66
+ ### Homebrew (recommended)
67
+
68
+ ```bash
69
+ brew tap emarkou/grokfeed
70
+ brew install grokfeed
71
+ ```
72
+
73
+ On first run, a config file is created at `~/.grokfeed/config.toml`. Edit it to change subreddits:
74
+
75
+ ```bash
76
+ nano ~/.grokfeed/config.toml
77
+ ```
78
+
79
+ ```toml
80
+ subreddits = ["programming", "ClaudeAI", "machinelearning"]
81
+ hn_story_count = 30
82
+ reddit_post_count = 15
83
+ lobsters_post_count = 25
84
+ ```
85
+
86
+ Changes take effect on next launch or press `r` to refresh.
87
+
88
+ ### From source
89
+
90
+ Requires Python 3.11+. Recommended: use [uv](https://github.com/astral-sh/uv).
91
+
92
+ ```bash
93
+ # with uv
94
+ uv venv --python 3.13 .venv
95
+ source .venv/bin/activate
96
+ uv pip install -e .
97
+
98
+ # or plain pip (Python 3.11+)
99
+ pip install -e .
100
+ ```
101
+
102
+ ## Run
103
+
104
+ ```bash
105
+ grokfeed
106
+ ```
107
+
108
+ ## Screenshots
109
+
110
+ ![Feed](docs/screenshots/feed.png)
111
+
112
+ ![Post body](docs/screenshots/post.png)
113
+
114
+ ![Comments](docs/screenshots/comments.png)
115
+
116
+ ## Key bindings
117
+
118
+ ### Main feed
119
+
120
+ | Key | Action |
121
+ |-----|--------|
122
+ | `j` / `↓` | Move down |
123
+ | `k` / `↑` | Move up |
124
+ | `Enter` | Open post body (text posts) or URL in browser (link posts) |
125
+ | `c` | Open comments |
126
+ | `f` | Cycle source filter (All → HN → r/sub → lobste.rs → …) |
127
+ | `r` | Refresh all sources |
128
+ | `q` | Quit |
129
+
130
+ ### Post body modal
131
+
132
+ | Key | Action |
133
+ |-----|--------|
134
+ | `j` / `↓` | Scroll down |
135
+ | `k` / `↑` | Scroll up |
136
+ | `c` | Open comments for this post |
137
+ | `o` | Open URL in browser |
138
+ | `q` / `Esc` | Close |
139
+
140
+ ### Comments modal
141
+
142
+ | Key | Action |
143
+ |-----|--------|
144
+ | `j` / `↓` | Scroll down |
145
+ | `k` / `↑` | Scroll up |
146
+ | `q` / `Esc` | Close |
147
+
148
+ ## Config
149
+
150
+ `~/.grokfeed/config.toml` — created on first run with defaults.
151
+
152
+ ```toml
153
+ subreddits = ["programming", "python", "machinelearning"]
154
+ hn_story_count = 30
155
+ reddit_post_count = 15
156
+ lobsters_post_count = 25
157
+ ```
158
+
159
+ Edit to add or remove subreddits. Changes take effect on next launch or `r` refresh.
160
+
161
+ ## Tech stack
162
+
163
+ | Library | Role |
164
+ |---------|------|
165
+ | [Textual](https://github.com/Textualize/textual) | TUI framework |
166
+ | [httpx](https://www.python-httpx.org/) | Async HTTP client |
167
+ | [Typer](https://typer.tiangolo.com/) | CLI entry point |
168
+ | [Rich](https://github.com/Textualize/rich) | Text rendering |
@@ -0,0 +1,121 @@
1
+ # grokfeed
2
+
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
+
5
+ Terminal feed reader for Hacker News, Reddit, and lobste.rs.
6
+
7
+
8
+ ## Features
9
+
10
+ - Unified scrollable feed from HN, Reddit subreddits, and lobste.rs
11
+ - Color-coded by source: HN orange, lobste.rs red, subreddits in a cycling palette
12
+ - Read text posts and Ask HN inline — no browser needed
13
+ - Comments viewer with nested replies (up to 2 levels)
14
+ - Filter feed by source, refresh on demand
15
+ - Config file at `~/.grokfeed/config.toml` — created automatically on first run
16
+
17
+ ## Install
18
+
19
+ ### Homebrew (recommended)
20
+
21
+ ```bash
22
+ brew tap emarkou/grokfeed
23
+ brew install grokfeed
24
+ ```
25
+
26
+ On first run, a config file is created at `~/.grokfeed/config.toml`. Edit it to change subreddits:
27
+
28
+ ```bash
29
+ nano ~/.grokfeed/config.toml
30
+ ```
31
+
32
+ ```toml
33
+ subreddits = ["programming", "ClaudeAI", "machinelearning"]
34
+ hn_story_count = 30
35
+ reddit_post_count = 15
36
+ lobsters_post_count = 25
37
+ ```
38
+
39
+ Changes take effect on next launch or press `r` to refresh.
40
+
41
+ ### From source
42
+
43
+ Requires Python 3.11+. Recommended: use [uv](https://github.com/astral-sh/uv).
44
+
45
+ ```bash
46
+ # with uv
47
+ uv venv --python 3.13 .venv
48
+ source .venv/bin/activate
49
+ uv pip install -e .
50
+
51
+ # or plain pip (Python 3.11+)
52
+ pip install -e .
53
+ ```
54
+
55
+ ## Run
56
+
57
+ ```bash
58
+ grokfeed
59
+ ```
60
+
61
+ ## Screenshots
62
+
63
+ ![Feed](docs/screenshots/feed.png)
64
+
65
+ ![Post body](docs/screenshots/post.png)
66
+
67
+ ![Comments](docs/screenshots/comments.png)
68
+
69
+ ## Key bindings
70
+
71
+ ### Main feed
72
+
73
+ | Key | Action |
74
+ |-----|--------|
75
+ | `j` / `↓` | Move down |
76
+ | `k` / `↑` | Move up |
77
+ | `Enter` | Open post body (text posts) or URL in browser (link posts) |
78
+ | `c` | Open comments |
79
+ | `f` | Cycle source filter (All → HN → r/sub → lobste.rs → …) |
80
+ | `r` | Refresh all sources |
81
+ | `q` | Quit |
82
+
83
+ ### Post body modal
84
+
85
+ | Key | Action |
86
+ |-----|--------|
87
+ | `j` / `↓` | Scroll down |
88
+ | `k` / `↑` | Scroll up |
89
+ | `c` | Open comments for this post |
90
+ | `o` | Open URL in browser |
91
+ | `q` / `Esc` | Close |
92
+
93
+ ### Comments modal
94
+
95
+ | Key | Action |
96
+ |-----|--------|
97
+ | `j` / `↓` | Scroll down |
98
+ | `k` / `↑` | Scroll up |
99
+ | `q` / `Esc` | Close |
100
+
101
+ ## Config
102
+
103
+ `~/.grokfeed/config.toml` — created on first run with defaults.
104
+
105
+ ```toml
106
+ subreddits = ["programming", "python", "machinelearning"]
107
+ hn_story_count = 30
108
+ reddit_post_count = 15
109
+ lobsters_post_count = 25
110
+ ```
111
+
112
+ Edit to add or remove subreddits. Changes take effect on next launch or `r` refresh.
113
+
114
+ ## Tech stack
115
+
116
+ | Library | Role |
117
+ |---------|------|
118
+ | [Textual](https://github.com/Textualize/textual) | TUI framework |
119
+ | [httpx](https://www.python-httpx.org/) | Async HTTP client |
120
+ | [Typer](https://typer.tiangolo.com/) | CLI entry point |
121
+ | [Rich](https://github.com/Textualize/rich) | Text rendering |
@@ -0,0 +1,17 @@
1
+ # grokfeed configuration
2
+ # Copy to ~/.grokfeed/config.toml and edit to taste.
3
+
4
+ # Subreddits to include in the feed (without the r/ prefix).
5
+ subreddits = ["programming", "python", "machinelearning", "rust", "devops"]
6
+
7
+ # Number of HN top stories to load per fetch.
8
+ hn_story_count = 30
9
+
10
+ # Number of posts to fetch per subreddit per fetch.
11
+ reddit_post_count = 15
12
+
13
+ # Number of lobste.rs posts to fetch.
14
+ lobsters_post_count = 25
15
+
16
+ # How many minutes to serve cached results before hitting the network again.
17
+ cache_ttl_minutes = 10
Binary file
Binary file
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"