rebooting project sans history

This commit is contained in:
Matthew Ryan Dillon 2025-04-20 07:37:23 -04:00
commit 874b1632c7
8 changed files with 1285 additions and 0 deletions

1
.python-version Normal file
View file

@ -0,0 +1 @@
3.12

6
Dockerfile Normal file
View file

@ -0,0 +1,6 @@
FROM python:3.12-slim-bookworm
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
ADD . /app
WORKDIR /app
RUN uv sync --frozen --no-cache
CMD ["/app/.venv/bin/fastapi", "run", "main.py", "--port", "8887"]

32
README.md Normal file
View file

@ -0,0 +1,32 @@
# rss
collection of rss-related tools
```bash
docker compose -f docker-compose.yml up -d
```
example secrets file:
```bash
# secrets.sh
export RSS_HOST="http://localhost:8888"
export REDDIT_CLIENT_ID="blah"
export REDDIT_CLIENT_SECRET="blah"
export REDDIT_USERNAME="blah"
export REDDIT_PASSWORD="bla"
```
editing secrets:
```bash
age --decrypt -i path/to/key -o secrets.sh secrets.sh.age
age -r $RECIPIENT -o secrets.sh.age secrets.sh
```
example envrc:
```bash
# .envrc
age --decrypt -i path/to/key -o secrets.sh secrets.sh.age && source secrets.sh && rm secrets.sh
```

44
docker-compose.yml Normal file
View file

@ -0,0 +1,44 @@
services:
miniflux:
image: miniflux/miniflux:latest
ports:
- "8888:8080"
depends_on:
db:
condition: service_healthy
environment:
- DATABASE_URL=postgres://miniflux:secret@db/miniflux?sslmode=disable
- RUN_MIGRATIONS=1
- CREATE_ADMIN=1
- ADMIN_USERNAME=admin
- ADMIN_PASSWORD=test123
- HTTP_CLIENT_TIMEOUT=300
db:
image: postgres:17-alpine
environment:
- POSTGRES_USER=miniflux
- POSTGRES_PASSWORD=secret
- POSTGRES_DB=miniflux
volumes:
- miniflux-db:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "miniflux"]
interval: 10s
start_period: 30s
reddit_rss:
build:
context: ./
dockerfile: Dockerfile
ports:
- "8887:8887"
environment:
- REDDIT_CLIENT_ID
- REDDIT_CLIENT_SECRET
- REDDIT_PASSWORD
- REDDIT_USERNAME
- RSS_HOST
volumes:
miniflux-db:

73
main.py Normal file
View file

@ -0,0 +1,73 @@
from contextlib import asynccontextmanager
from datetime import datetime, timezone
from os import environ
import asyncpraw
from async_lru import alru_cache
from fastapi import FastAPI, Response, HTTPException
from feedgen.feed import FeedGenerator
REDDIT_CLIENT_ID = environ["REDDIT_CLIENT_ID"]
REDDIT_CLIENT_SECRET = environ["REDDIT_CLIENT_SECRET"]
REDDIT_PASSWORD = environ["REDDIT_PASSWORD"]
REDDIT_USERNAME = environ["REDDIT_USERNAME"]
RSS_HOST = environ["RSS_HOST"]
@alru_cache(ttl=15 * 60)
async def fetch(feed, comments):
fg = FeedGenerator()
fg.id(f'{RSS_HOST}/{feed}')
fg.title(f'r/{feed}')
fg.link(href=f'{RSS_HOST}/{feed}')
fg.description(f'r/{feed}')
client = asyncpraw.Reddit(
user_agent="stuff",
client_id=REDDIT_CLIENT_ID,
client_secret=REDDIT_CLIENT_SECRET,
username=REDDIT_USERNAME,
password=REDDIT_PASSWORD,
)
async with client as reddit:
subreddit = await reddit.subreddit(feed)
async for submission in subreddit.top(limit=30, time_filter="week"):
if submission.selftext == "":
continue
fe = fg.add_entry()
fe.id(submission.id)
fe.title(submission.title)
fe.link(href=submission.url)
fe.pubDate(datetime.fromtimestamp(submission.created_utc, timezone.utc))
author = 'none' if submission.author is None else submission.author.name
content = f"<p>{author} ({submission.score})</p>"
content += f"<p>{submission.selftext_html}</p>"
if comments:
comments = ""
for comment in await submission.comments():
if isinstance(comment, asyncpraw.models.MoreComments):
continue
if comment.author is None:
continue
author = comment.author.name
if author.lower() == 'automoderator':
continue
comments += f"<li>{author} ({comment.score}) {comment.body_html}"
content += f"<ul>{comments}</ul>"
fe.content(content)
rss = fg.rss_str(pretty=True)
return rss
app = FastAPI()
@app.get("/{feed}")
async def root(feed: str, comments: bool = False):
rss = await fetch(feed, comments)
return Response(content=rss, media_type="application/xml")

12
pyproject.toml Normal file
View file

@ -0,0 +1,12 @@
[project]
name = "rss"
version = "0.1.0"
description = "reformats reddit for rss consumption"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"async-lru>=2.0.5",
"asyncpraw>=7.8.1",
"fastapi[standard]>=0.115.12",
"feedgen>=1.0.0",
]

BIN
secrets.sh.age Normal file

Binary file not shown.

1117
uv.lock generated Normal file

File diff suppressed because it is too large Load diff