rebooting project sans history
This commit is contained in:
commit
874b1632c7
8 changed files with 1285 additions and 0 deletions
1
.python-version
Normal file
1
.python-version
Normal file
|
@ -0,0 +1 @@
|
||||||
|
3.12
|
6
Dockerfile
Normal file
6
Dockerfile
Normal 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
32
README.md
Normal 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
44
docker-compose.yml
Normal 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
73
main.py
Normal 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
12
pyproject.toml
Normal 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
BIN
secrets.sh.age
Normal file
Binary file not shown.
Loading…
Add table
Reference in a new issue