Files

164 lines
7.5 KiB
Markdown
Executable File

# RepoRadar 🛰
A standalone Discord bot that **scrapes a git server for the newest projects**
and drops them into Discord — with descriptions, community voting, and
admin-curated highlights.
RepoRadar continually monitors a self-hosted or hosted git server (Gitea /
Forgejo, GitLab, or GitHub), and as soon as a *new* project appears it posts a
rich card linking the repo with its description, language, stars/forks, topics
and a live community vote tally. Existing repositories are **baselined silently**
the moment a watch is added, so you only ever see brand-new drops — in
chronological order, freshest last.
> RepoRadar is a **separate bot** from VulnForge/THREATLENS. It runs on its own
> token, with its own database and Docker stack.
---
## Features
- **Continual monitoring** of a git server — scoped to specific users/orgs *or*
server-wide.
- **Newest-only drops** — existing repos are baselined on first sight; only new
projects are announced afterwards.
- **Chronological order** — new projects post oldest → newest so the freshest
drop is always the most recent message.
- **Rich drop cards** — link, description, owner, language, stars, forks, topics
and a live vote tally.
- **Community voting, three ways**
- 👍 / 👎 buttons on each drop
- 💬 *Vote + Comment* modal
- `/radar_vote owner/repo up|down` slash command
- **Highlights** — projects matching configured keywords or a star threshold are
re-posted to a highlight channel with an optional role ping.
- **Admin modal editing** — admins (Manage Server) can edit a drop's description
and curator note in place, and configure everything via modals.
---
## Slash commands
| Command | Who | What it does |
| ----------------- | ----------- | ------------------------------------------------------- |
| `/radar_config` | Admin | Configure drop/highlight channels, role, keywords, stars (modal) |
| `/radar_watch` | Admin | Watch a git user/org or the whole server (modal) |
| `/radar_unwatch` | Admin | Remove a watch |
| `/radar_status` | Everyone | Show current monitor configuration and active watches |
| `/radar_latest` | Everyone | Show the newest projects on demand |
| `/radar_scan` | Admin | Force a scan cycle right now |
| `/radar_vote` | Everyone | Vote on a dropped project by `owner/repo` |
| `/radar_top` | Everyone | Community leaderboard of top-voted projects |
"Admin" = members with the **Manage Server** permission.
---
## Quick start
### 1. Create the Discord application
1. Go to <https://discord.com/developers/applications> → **New Application**.
2. **Bot** tab → **Add Bot** → copy the **token**.
3. **OAuth2 → URL Generator**: scopes `bot` + `applications.commands`;
bot permissions: *Send Messages*, *Embed Links*, *Read Message History*.
Invite the bot with the generated URL.
### 2. Configure
```bash
cp .env.example .env
# edit .env — set at minimum DISCORD_TOKEN, GIT_PROVIDER / GIT_BASE_URL, and
# (optionally) GUILD_ID for instant command sync.
```
### 3. Run with Docker (recommended)
```bash
docker compose up -d --build
docker compose logs -f reporadar
```
### 4. Run locally (without Docker)
```bash
python -m venv .venv
. .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
python main.py
```
### 5. Configure in Discord
1. `/radar_config` — set the drop channel (and optionally a highlight channel,
ping role, star threshold, and keywords).
2. `/radar_watch` — add a watch (`user`, `org`, or `server`). Existing repos are
baselined silently.
3. `/radar_scan` — force a scan to verify, or just wait for the poll loop.
---
## Configuration reference
All values can be set in `.env`; channels/roles/keywords are also settable in
Discord via `/radar_config` (per-guild settings take precedence).
| Env var | Default | Description |
| -------------------------- | ---------------- | ------------------------------------------------------- |
| `DISCORD_TOKEN` | — | Bot token (required) |
| `GUILD_ID` | — | Restrict command sync to one guild (instant updates) |
| `GIT_PROVIDER` | `auto` | `auto` \| `gitea` \| `gitlab` \| `github` |
| `GIT_BASE_URL` | — | Git server URL (blank for GitHub) |
| `GIT_TOKEN` | — | Read-only PAT (optional for public servers) |
| `GIT_DROP_CHANNEL_ID` | — | Default drop channel |
| `GIT_HIGHLIGHT_CHANNEL_ID` | — | Featured-drop channel |
| `GIT_HIGHLIGHT_ROLE_ID` | — | Role pinged on highlights |
| `GIT_POLL_INTERVAL` | `300` | Poll interval in seconds (min 60) |
| `GIT_MAX_DROPS_PER_CYCLE` | `10` | Burst guard — larger batches are baselined silently |
| `LOG_LEVEL` | `INFO` | `DEBUG` \| `INFO` \| `WARNING` \| `ERROR` |
---
## Supported git providers
| Provider | `GIT_PROVIDER` | Notes |
| ----------------- | -------------- | ------------------------------------------------------ |
| Gitea / Forgejo | `gitea` | Typical self-hosted git server (REST API v1) |
| GitLab | `gitlab` | self-hosted or gitlab.com (REST API v4) |
| GitHub | `github` | Leave `GIT_BASE_URL` blank (uses api.github.com) |
| Auto-detect | `auto` | Probes `/api/v1/version` then `/api/v4/version` |
---
## Under the hood
1. **`utils/git_api.py`** — a provider-agnostic async client (single shared
`aiohttp` session, retry/backoff) that normalises every provider's payload
into a simple `Repo` dataclass. `created_at` drives the "newest-only" logic.
2. **`utils/helpers.py`** — an async SQLite `Store` (config, watches, seen-repo
de-dup, drop anchors, community votes) + small formatting helpers.
3. **`utils/embeds.py`** — all the cyberpunk-styled embed builders.
4. **`cogs/gitscan.py`** — the monitor loop, drop logic, voting UI and slash
commands.
5. **`main.py`** — Nextcord 2.6 boot (bot built inside the loop, manual
extension load + command rollout, graceful shutdown).
State persists in `data/reporadar.db` (mounted as a Docker volume), so seen
repos and votes survive restarts.
---
## Project structure
```
reporadar/
├── main.py # entrypoint / bot bootstrap
├── config.py # env-driven settings + colour palette
├── requirements.txt
├── Dockerfile
├── docker-compose.yml
├── .env.example
├── .dockerignore
├── cogs/
│ └── gitscan.py # monitor + voting + slash commands
└── utils/
├── git_api.py # provider-agnostic git client
├── helpers.py # async SQLite store + formatting
└── embeds.py # embed builders
```