Initial commit — Wormhole v3.0.0: advanced cross-server relay cog
Features: - Named wormhole networks with full per-network config - Webhook relay with custom avatar/name modes (user, server, both, custom) - Message edit, delete, reply, reaction, thread & sticker sync - Staff system (owner + staff) with granular permissions - Moderation: user ban/mute, server ban/mute, allowlist - Word & regex content filters with auto-delete - Token-bucket rate limiting per user per network - Per-network logging channel - Statistics dashboard - NSFW gating, freeze/pause, silent mode - Custom network icon, description, accent colour - Server nickname overrides - Ownership transfer - Thread support - Embed forwarding - Professional README, info.json, LICENSE
This commit is contained in:
commit
6ca37b9ba1
7 changed files with 1716 additions and 0 deletions
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2025 everestmcarthur
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
78
README.md
Normal file
78
README.md
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
# EveCogs
|
||||
|
||||
> A curated collection of advanced, professional-grade cogs for [Red-DiscordBot](https://github.com/Cog-Creators/Red-DiscordBot).
|
||||
|
||||
---
|
||||
|
||||
## 📦 Installation
|
||||
|
||||
```
|
||||
[p]repo add EveCogs https://github.com/everestmcarthur/EveCogs
|
||||
[p]cog install EveCogs <cog_name>
|
||||
[p]load <cog_name>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌀 Wormhole
|
||||
|
||||
**The most advanced cross-server relay system for Red-DiscordBot.**
|
||||
|
||||
Connect channels across unlimited servers into named networks. Every message, edit, delete, reaction, reply, sticker, embed, and file is relayed in real-time via webhooks — with full moderation, staff roles, filters, rate-limiting, and per-network customisation.
|
||||
|
||||
### Highlights
|
||||
|
||||
| Feature | Description |
|
||||
|---|---|
|
||||
| **Named Networks** | Create unlimited named networks — each with its own config, staff, and channels |
|
||||
| **Webhook Relay** | Messages appear under the sender's name and avatar (or server icon, or custom) |
|
||||
| **Edit & Delete Sync** | Edits and deletes propagate across every linked channel instantly |
|
||||
| **Reply Context** | Replies include a preview of the referenced message |
|
||||
| **Reaction Sync** | Reactions mirror across channels |
|
||||
| **Sticker & Embed Forwarding** | Stickers, rich embeds, and file attachments are all relayed |
|
||||
| **Staff System** | Network owner + unlimited staff with moderation access |
|
||||
| **User Ban / Mute** | Ban or mute individual users from the network |
|
||||
| **Server Ban / Mute** | Block or silence entire servers |
|
||||
| **Server Allowlist** | Restrict which servers may join a network |
|
||||
| **Word & Regex Filters** | Auto-delete messages that match filters before relay |
|
||||
| **Rate Limiting** | Token-bucket per-user per-network spam protection |
|
||||
| **Logging Channel** | Designate a channel to receive moderation logs |
|
||||
| **Custom Identity** | Name mode (user / server / both / custom template), image mode, custom icon |
|
||||
| **Server Nicknames** | Override how your server's name appears on the network |
|
||||
| **Freeze / Pause** | Temporarily halt all relay on a network |
|
||||
| **Silent Mode** | Suppress join/leave announcements |
|
||||
| **NSFW Gating** | Block relay from NSFW channels |
|
||||
| **Thread Support** | Optionally relay messages from threads |
|
||||
| **Ownership Transfer** | Hand a network to another user |
|
||||
| **Statistics** | Track total messages relayed, channels linked, and more |
|
||||
|
||||
### Quick Start
|
||||
|
||||
```
|
||||
[p]wh create my-network A cool global chat
|
||||
[p]wh open my-network (run in each channel you want linked)
|
||||
[p]wh set webhooks my-network true
|
||||
[p]wh set name-mode my-network both
|
||||
[p]wh info my-network
|
||||
[p]wh help
|
||||
```
|
||||
|
||||
### Command Overview
|
||||
|
||||
| Group | Commands |
|
||||
|---|---|
|
||||
| `[p]wh` | `create`, `delete`, `open`, `close`, `list`, `info`, `stats`, `transfer`, `help` |
|
||||
| `[p]wh set` | `webhooks`, `name-mode`, `image-mode`, `custom-icon`, `custom-name`, `description`, `colour`, `ratelimit`, `log-channel`, `nickname`, `freeze`, `silent`, `nsfw-gate`, `sync-edits`, `sync-deletes`, `sync-reactions`, `sync-replies`, `sync-stickers`, `sync-threads`, `forward-embeds` |
|
||||
| `[p]wh staff` | `add`, `remove`, `list` |
|
||||
| `[p]wh mod` | `ban`, `unban`, `mute`, `unmute`, `ban-server`, `unban-server`, `mute-server`, `unmute-server`, `allowlist-add`, `allowlist-remove` |
|
||||
| `[p]wh filter` | `add-word`, `remove-word`, `add-regex`, `remove-regex`, `list` |
|
||||
|
||||
---
|
||||
|
||||
## 📄 License
|
||||
|
||||
MIT — do whatever you want.
|
||||
|
||||
---
|
||||
|
||||
*Made with ❤️ by everestmcarthur*
|
||||
6
info.json
Normal file
6
info.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"author": ["everestmcarthur"],
|
||||
"description": "EveCogs — a curated collection of advanced, professional-grade cogs for Red-DiscordBot.",
|
||||
"install_msg": "Thank you for installing **EveCogs**! Browse available cogs with `[p]cog list` and install what you need.",
|
||||
"short": "Advanced cogs for Red-DiscordBot"
|
||||
}
|
||||
6
wormhole/__init__.py
Normal file
6
wormhole/__init__.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
from .wormhole import Wormhole
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
cog = Wormhole(bot)
|
||||
await bot.add_cog(cog)
|
||||
18
wormhole/info.json
Normal file
18
wormhole/info.json
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"author": ["everestmcarthur"],
|
||||
"description": "Wormhole — an advanced cross-server/cross-channel communication relay with named networks, moderation, staff roles, message sync (edits/deletes/replies/reactions), per-network customisation, logging, statistics, filters, rate-limiting, and much more.",
|
||||
"install_msg": "Thanks for installing **Wormhole**! Run `[p]wh help` to get started.",
|
||||
"short": "Advanced cross-server relay with networks, moderation & full sync",
|
||||
"end_user_data_statement": "This cog stores user IDs, guild IDs, channel IDs, and message-mapping data required for relay functionality. No message content is stored persistently.",
|
||||
"min_bot_version": "3.5.0",
|
||||
"min_python_version": [3, 9, 0],
|
||||
"tags": [
|
||||
"wormhole",
|
||||
"relay",
|
||||
"bridge",
|
||||
"cross-server",
|
||||
"network",
|
||||
"moderation",
|
||||
"webhook"
|
||||
]
|
||||
}
|
||||
113
wormhole/utils.py
Normal file
113
wormhole/utils.py
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
"""Utility helpers for Wormhole cog."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import time
|
||||
from collections import defaultdict
|
||||
from typing import Optional
|
||||
|
||||
import discord
|
||||
|
||||
# ── Colour palette ──────────────────────────────────────────────────────────
|
||||
|
||||
COLOUR_OK = discord.Colour.from_rgb(87, 242, 135) # green
|
||||
COLOUR_WARN = discord.Colour.from_rgb(254, 231, 92) # yellow
|
||||
COLOUR_ERR = discord.Colour.from_rgb(237, 66, 69) # red
|
||||
COLOUR_INFO = discord.Colour.from_rgb(88, 101, 242) # blurple
|
||||
COLOUR_NEUTRAL = discord.Colour.from_rgb(114, 137, 218) # light blurple
|
||||
|
||||
|
||||
# ── Cooldown bucket ────────────────────────────────────────────────────────
|
||||
|
||||
class CooldownBucket:
|
||||
"""Per-user per-network token-bucket rate limiter."""
|
||||
|
||||
def __init__(self, rate: int = 5, per: float = 10.0):
|
||||
self.rate = rate
|
||||
self.per = per
|
||||
self._buckets: dict[str, list[float]] = defaultdict(list)
|
||||
|
||||
def is_rate_limited(self, user_id: int, network: str) -> bool:
|
||||
key = f"{network}:{user_id}"
|
||||
now = time.monotonic()
|
||||
bucket = self._buckets[key]
|
||||
# Purge old timestamps
|
||||
self._buckets[key] = [t for t in bucket if now - t < self.per]
|
||||
if len(self._buckets[key]) >= self.rate:
|
||||
return True
|
||||
self._buckets[key].append(now)
|
||||
return False
|
||||
|
||||
def update(self, rate: int, per: float):
|
||||
self.rate = rate
|
||||
self.per = per
|
||||
|
||||
|
||||
# ── Filter helpers ──────────────────────────────────────────────────────────
|
||||
|
||||
def check_filters(content: str, word_filters: list[str], regex_filters: list[str]) -> Optional[str]:
|
||||
"""Return the first matched filter pattern, or None if clean."""
|
||||
lowered = content.lower()
|
||||
for word in word_filters:
|
||||
if word.lower() in lowered:
|
||||
return word
|
||||
for pattern in regex_filters:
|
||||
try:
|
||||
if re.search(pattern, content, re.IGNORECASE):
|
||||
return pattern
|
||||
except re.error:
|
||||
continue
|
||||
return None
|
||||
|
||||
|
||||
# ── Embed builders ──────────────────────────────────────────────────────────
|
||||
|
||||
def make_embed(
|
||||
title: str = "",
|
||||
description: str = "",
|
||||
colour: discord.Colour = COLOUR_INFO,
|
||||
**kwargs,
|
||||
) -> discord.Embed:
|
||||
em = discord.Embed(title=title, description=description, colour=colour, **kwargs)
|
||||
return em
|
||||
|
||||
|
||||
def ok_embed(description: str, title: str = "✅ Success") -> discord.Embed:
|
||||
return make_embed(title=title, description=description, colour=COLOUR_OK)
|
||||
|
||||
|
||||
def err_embed(description: str, title: str = "❌ Error") -> discord.Embed:
|
||||
return make_embed(title=title, description=description, colour=COLOUR_ERR)
|
||||
|
||||
|
||||
def warn_embed(description: str, title: str = "⚠️ Warning") -> discord.Embed:
|
||||
return make_embed(title=title, description=description, colour=COLOUR_WARN)
|
||||
|
||||
|
||||
def info_embed(description: str, title: str = "ℹ️ Info") -> discord.Embed:
|
||||
return make_embed(title=title, description=description, colour=COLOUR_INFO)
|
||||
|
||||
|
||||
# ── Formatting helpers ──────────────────────────────────────────────────────
|
||||
|
||||
def truncate(text: str, length: int = 2000) -> str:
|
||||
if len(text) <= length:
|
||||
return text
|
||||
return text[: length - 3] + "..."
|
||||
|
||||
|
||||
def human_timedelta(seconds: float) -> str:
|
||||
m, s = divmod(int(seconds), 60)
|
||||
h, m = divmod(m, 60)
|
||||
d, h = divmod(h, 24)
|
||||
parts = []
|
||||
if d:
|
||||
parts.append(f"{d}d")
|
||||
if h:
|
||||
parts.append(f"{h}h")
|
||||
if m:
|
||||
parts.append(f"{m}m")
|
||||
if s or not parts:
|
||||
parts.append(f"{s}s")
|
||||
return " ".join(parts)
|
||||
1474
wormhole/wormhole.py
Normal file
1474
wormhole/wormhole.py
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue