5.0 KiB
# CLAUDE.md - Project Pravda
## Overview
**Pravda** is a Python-based Dockerized service that monitors Donald Trump's Truth Social feed using the truthbrush library. It relays posts to Discord via Webhooks with intelligent media handling (transcoding/splitting) and supports interactive message components.
## Tech Stack
* **Language:** Python 3.12+
* **Core Libs:** truthbrush, requests, fastapi, uvicorn, ffmpeg-python
* **System Tools:** ffmpeg (installed in container)
* **Deployment:** Docker, Gitea Actions
## Architecture
The application runs two concurrent processes:
1. **The Poller:** Loops infinitely, checking truthbrush for new posts. Processed posts are cached (SQLite/File) to prevent duplicates.
2. **The Server:** A FastAPI instance listening on port **8080** to handle Discord Interaction Webhooks (button clicks).
## Commands
### Local Development
\# Install dependencies
pip install -r requirements.txt
\# Run locally (requires ENV vars set)
python main.py
\# Run unit tests
pytest
### Docker Operations
\# Build image
docker build -t pravda .
\# Run in background (Poller + Server)
docker run -d \\
-e DISCORD\_WEBHOOK="your\_webhook\_url" \\
-e DISCORD\_PUBLIC\_KEY="your\_app\_public\_key" \\
-v $(pwd)/data:/data \\
-p 8080:8080 \\
pravda
\# Manual Invocation (One-off relay of specific post)
\# Overrides normal execution loop
docker run --rm \\
-e DISCORD\_WEBHOOK="your\_webhook\_url" \\
pravda https://truthsocial.com/@realDonaldTrump/posts/123456789
## Environment Variables
| Variable | Description | Required |
| --- | --- | --- |
| DISCORD\_WEBHOOK | The Discord Webhook URL for posting messages. | Yes |
| DISCORD\_APPLICATION\_ID | App ID (for component construction). | Yes |
| DISCORD\_PUBLIC\_KEY | Public Key for verifying interaction signatures. | Yes (if Server enabled) |
| POLL\_INTERVAL | Seconds between checks (default: 300). | No |
| TRUTH\_USER | Target username (default: realDonaldTrump). | No |
| DB\_PATH | Path to SQLite DB for tracking seen IDs (default: /data/seen.db). | No |
## Application Logic Requirements
### 1. Media Handling (The "Smart" Relay)
* **Images:** Download and attach directly.
* **Videos:**
* **Must** use ffmpeg to re-encode to H.264/AAC (MP4 container) for maximum Discord compatibility.
* **Constraint:** Output file must be < 50MB (Discord Nitro limit safeguard).
* **Logic:** If > 50MB, attempt to downscale resolution or lower bitrate.
* **Limits:**
* Discord allows max 10 attachments per message.
* Discord allows max 2000 chars per message.
* **Splitting:** If a post exceeds these limits, split the content into a thread or sequential messages. "Part 1/X" style.
### 2. Interaction Handler (FastAPI)
* Expose POST /interactions.
* Verify Ed25519 signature using DISCORD\_PUBLIC\_KEY.
* **Component 1 (Delete):** Check if user has MANAGE\_MESSAGES permission (or allow-list). Delete the webhook message.
* **Component 2 (Raw):** Reply with flags: 64 (Ephemeral) containing the raw JSON snippet of the post.
### 3. Gitea Action Workflow
Create .gitea/workflows/build-push.yaml:
* **Trigger:** On push to any branch.
* **Steps:**
1. Checkout code.
2. Login to Gitea Registry using ${{ secrets.REGISTRY\_USERNAME }} and ${{ secrets.REGISTRY\_PASSWORD }}.
3. Build Docker image.
4. Tag: gitea.stevedudenhoeffer.com/steve/pravda:${{ gitea.ref\_name }}.
5. If branch is main, also tag :latest.
6. Push all tags.
## Dockerfile Specification
* **Base:** python:3.12-slim
* **System Deps:** ffmpeg, git (needed for truthbrush?)
* **Entrypoint:** A script entrypoint.sh that detects arguments.
* If args provided (URL), run "One-off Mode".
* If no args, run "Daemon Mode" (Poller + Uvicorn).
## Code Style
* **Formatter:** black
* **Linter:** ruff
* **Typing:** Strong typing enforced (mypy).
* **Error Handling:** Never crash the poller loop on a network error. Log to stderr and retry.
## Example Interaction Payload (JSON)
When sending the webhook, include components:
{
"content": "Post text here...",
"components": \[
{
"type": 1,
"components": \[
{
"type": 2,
"style": 4,
"label": "Delete",
"custom\_id": "delete\_msg"
},
{
"type": 2,
"style": 2,
"label": "View Raw",
"custom\_id": "view\_raw"
},
{
"type": 2,
"style": 5,
"label": "Original Post",
"url": "https://truthsocial.com/..."
}
]
}
]
}