Files
pravda/CLAUDE.md
2026-01-23 00:53:46 -05:00

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:


{

&nbsp; "content": "Post text here...",

&nbsp; "components": \[

&nbsp;   {

&nbsp;     "type": 1,

&nbsp;     "components": \[

&nbsp;       {

&nbsp;         "type": 2,

&nbsp;         "style": 4, 

&nbsp;         "label": "Delete",

&nbsp;         "custom\_id": "delete\_msg"

&nbsp;       },

&nbsp;       {

&nbsp;         "type": 2,

&nbsp;         "style": 2,

&nbsp;         "label": "View Raw",

&nbsp;         "custom\_id": "view\_raw"

&nbsp;       },

&nbsp;       {

&nbsp;         "type": 2,

&nbsp;         "style": 5,

&nbsp;         "label": "Original Post",

&nbsp;         "url": "https://truthsocial.com/..."

&nbsp;       }

&nbsp;     ]

&nbsp;   }

&nbsp; ]

}