Compare commits
23 Commits
cd68e42de2
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f57cccea5 | ||
|
|
36b32de34c | ||
|
|
d24b810164 | ||
|
|
a52d84467d | ||
|
|
1da2085087 | ||
|
|
20193404e8 | ||
|
|
299351463c | ||
|
|
6b0091f7d5 | ||
|
|
fc77f0a3c2 | ||
|
|
f15c869993 | ||
|
|
60390009d1 | ||
|
|
18ef29f777 | ||
|
|
9006b06c09 | ||
|
|
8294c1b4f7 | ||
|
|
831a3ac8ea | ||
|
|
698d61ec6d | ||
|
|
daf3338382 | ||
|
|
03c8f2ec2c | ||
|
|
7dca4fb77a | ||
|
|
9bcde844da | ||
|
|
41d5841d82 | ||
|
|
b4110c3d66 | ||
| 5f34db4f3b |
50
.env.docker.example
Normal file
50
.env.docker.example
Normal file
@@ -0,0 +1,50 @@
|
||||
# ── Docker Compose (.env) — copy to .env in the repo root ─────────────────────
|
||||
# cp .env.docker.example .env
|
||||
|
||||
# Discord Bot
|
||||
TOKEN=TOKEN_HERE
|
||||
brand_name=Axiom
|
||||
OWNER_IDS=YOUR_DISCORD_USER_ID_HERE
|
||||
DASHBOARD_ADMIN_IDS=YOUR_DISCORD_USER_ID_HERE
|
||||
|
||||
# Sharding — leave unset for auto (recommended). Multi-process: same TOKEN, shared bot-db volume.
|
||||
# SHARD_COUNT=
|
||||
# SHARD_IDS=0,1
|
||||
# SHARD_PRIMARY=
|
||||
# Enable API only on the primary shard process.
|
||||
|
||||
# Shared secret — must match between bot API and dashboard
|
||||
DASHBOARD_API_KEY=generate_a_long_random_secret_here
|
||||
|
||||
# Lavalink (optional music)
|
||||
LAVALINK_HOST=lavalink.jirayu.net
|
||||
LAVALINK_PASSWORD=youshallnotpass
|
||||
LAVALINK_SECURE=false
|
||||
LAVALINK_PORT=13592
|
||||
|
||||
EMOJI_SYNC=false
|
||||
JISHAKU_ENABLED=false
|
||||
|
||||
# Slash (/) command sync — use ONE mode to avoid duplicate commands in Discord
|
||||
SLASH_SYNC_MODE=global
|
||||
SLASH_CLEAR_GUILD_COMMANDS=true
|
||||
# SLASH_GUILD_IDS=
|
||||
|
||||
# Traefik (optional override — default in compose: letsencrypt)
|
||||
# TRAEFIK_CERT_RESOLVER=letsencrypt
|
||||
|
||||
# ── Dashboard / NextAuth ──────────────────────────────────────────────────────
|
||||
NEXTAUTH_SECRET=generate_a_long_random_secret_here
|
||||
DISCORD_CLIENT_ID=
|
||||
DISCORD_CLIENT_SECRET=
|
||||
# Optional: Discord permission bitfield for /api/invite (default: 8 = Administrator)
|
||||
# DISCORD_BOT_PERMISSIONS=8
|
||||
|
||||
# Same Discord user IDs as owners/admins (comma-separated)
|
||||
ADMIN_IDS=YOUR_DISCORD_USER_ID_HERE
|
||||
NEXT_PUBLIC_ADMIN_IDS=YOUR_DISCORD_USER_ID_HERE
|
||||
NEXT_PUBLIC_BRAND_NAME=Axiom
|
||||
NEXT_PUBLIC_BRAND_NAME_WORD=AX
|
||||
|
||||
# Discord OAuth Redirect URL in the Discord Developer Portal:
|
||||
# https://bot.hexahost.de/api/auth/callback/discord
|
||||
76
.github/workflows/ci.yml
vendored
Normal file
76
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, master]
|
||||
pull_request:
|
||||
branches: [main, master]
|
||||
|
||||
jobs:
|
||||
bot:
|
||||
name: Bot (Python)
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: bot
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
cache: pip
|
||||
cache-dependency-path: bot/requirements.txt
|
||||
|
||||
- name: Install dependencies
|
||||
run: pip install -r requirements.txt
|
||||
|
||||
- name: Syntax check
|
||||
run: python -m compileall -q -x 'leveling_original' .
|
||||
|
||||
- name: Import smoke test
|
||||
env:
|
||||
TOKEN: test
|
||||
OWNER_IDS: "123456789012345678"
|
||||
API_ENABLED: "false"
|
||||
TUNNEL_ENABLED: "false"
|
||||
run: |
|
||||
python - <<'PY'
|
||||
from core.axiom import Axiom
|
||||
from api.server import create_app
|
||||
bot = Axiom()
|
||||
create_app()
|
||||
import cogs
|
||||
print("imports ok")
|
||||
PY
|
||||
|
||||
dashboard:
|
||||
name: Dashboard (Next.js)
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: dashboard
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
cache: npm
|
||||
cache-dependency-path: dashboard/package-lock.json
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Lint
|
||||
run: npm run lint
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
DASHBOARD_API_URL: http://127.0.0.1:8000/api/v1
|
||||
DASHBOARD_API_KEY: ci-test-key
|
||||
NEXTAUTH_URL: http://localhost:3000
|
||||
NEXTAUTH_SECRET: ci-test-secret-min-32-chars-long!!
|
||||
DISCORD_CLIENT_ID: "0"
|
||||
DISCORD_CLIENT_SECRET: ci-secret
|
||||
run: npm run build
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -46,9 +46,15 @@ build/
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
!.env.docker.example
|
||||
!.env.example
|
||||
|
||||
# Ignore SQLite runtime files
|
||||
bot/db/**/*.db-journal
|
||||
|
||||
# Ignore node_modules
|
||||
node_modules/
|
||||
|
||||
package-lock.json
|
||||
|
||||
# Ignore Next.js build output
|
||||
|
||||
201
DOCKER.md
Normal file
201
DOCKER.md
Normal file
@@ -0,0 +1,201 @@
|
||||
# Axiom — Docker-Setup (Hersteller: HexaHost, Traefik)
|
||||
|
||||
Dashboard: **https://bot.hexahost.de**
|
||||
Bot-API: nur intern (`http://bot:8000`) — nicht öffentlich.
|
||||
|
||||
---
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
1. **Docker** + **Docker Compose** auf dem Server
|
||||
2. **Traefik** läuft bereits und ist am Netzwerk `traefik-network` angeschlossen
|
||||
3. DNS: `bot.hexahost.de` zeigt auf die IP deines Traefik-Servers (A/AAAA)
|
||||
4. Discord-Anwendung (Bot + OAuth) im [Discord Developer Portal](https://discord.com/developers/applications)
|
||||
|
||||
Traefik erwartet typischerweise:
|
||||
|
||||
| Einstellung | Wert (Standard hier) |
|
||||
|-------------|----------------------|
|
||||
| Externes Netzwerk | `traefik-network` |
|
||||
| HTTP-Entrypoint | `web` (Port 80) |
|
||||
| HTTPS-Entrypoint | `websecure` (Port 443) |
|
||||
| Cert-Resolver | `letsencrypt` |
|
||||
|
||||
Falls dein Cert-Resolver anders heißt → später `TRAEFIK_CERT_RESOLVER` in `.env` setzen.
|
||||
|
||||
---
|
||||
|
||||
## 1. Projekt auf den Server holen
|
||||
|
||||
```bash
|
||||
git clone <dein-repo-url> Axiom
|
||||
cd Axiom
|
||||
```
|
||||
|
||||
Oder Dateien per SCP/SFTP hochladen und in den Projektordner wechseln.
|
||||
|
||||
---
|
||||
|
||||
## 2. Traefik-Netzwerk prüfen
|
||||
|
||||
```bash
|
||||
docker network ls | grep traefik-network
|
||||
```
|
||||
|
||||
Falls es fehlt (nur wenn Traefik es nicht schon angelegt hat):
|
||||
|
||||
```bash
|
||||
docker network create traefik-network
|
||||
```
|
||||
|
||||
**Wichtig:** Traefik selbst muss an `traefik-network` hängen. Sonst erreicht Traefik das Dashboard nicht.
|
||||
|
||||
---
|
||||
|
||||
## 3. Secrets / `.env` anlegen
|
||||
|
||||
```bash
|
||||
cp .env.docker.example .env
|
||||
nano .env # oder vim / code
|
||||
```
|
||||
|
||||
### Pflichtfelder ausfüllen
|
||||
|
||||
| Variable | Bedeutung |
|
||||
|----------|-----------|
|
||||
| `TOKEN` | Bot-Token (Discord → Bot → Reset Token) |
|
||||
| `OWNER_IDS` | Deine Discord-User-ID (Komma bei mehreren) |
|
||||
| `DASHBOARD_ADMIN_IDS` | IDs für Bot-Admin-API (meist = Owner) |
|
||||
| `DASHBOARD_API_KEY` | Langes zufälliges Geheimnis (Bot ↔ Dashboard) |
|
||||
| `NEXTAUTH_SECRET` | Anderes langes zufälliges Geheimnis |
|
||||
| `DISCORD_CLIENT_ID` | Application ID der Discord-App |
|
||||
| `DISCORD_CLIENT_SECRET` | OAuth2 → Client Secret |
|
||||
| `ADMIN_IDS` | Dashboard-Admins (Discord-User-IDs) |
|
||||
| `NEXT_PUBLIC_ADMIN_IDS` | Gleich wie `ADMIN_IDS` |
|
||||
|
||||
Secrets erzeugen (Beispiel):
|
||||
|
||||
```bash
|
||||
openssl rand -hex 32 # für DASHBOARD_API_KEY
|
||||
openssl rand -hex 32 # für NEXTAUTH_SECRET
|
||||
```
|
||||
|
||||
Discord-User-ID: Discord → Einstellungen → Erweitert → Entwicklermodus → Rechtsklick auf dich → „ID kopieren“.
|
||||
|
||||
---
|
||||
|
||||
## 4. Discord Developer Portal
|
||||
|
||||
### Bot
|
||||
|
||||
1. Application öffnen → **Bot** → Token kopieren → in `.env` als `TOKEN`
|
||||
2. Privileged Gateway Intents aktivieren, die der Bot braucht (z. B. Server Members, Message Content — je nach Features)
|
||||
3. Bot auf den Server einladen (OAuth2 → URL Generator → `bot` + benötigte Permissions)
|
||||
|
||||
### OAuth fürs Dashboard
|
||||
|
||||
1. **OAuth2 → General**
|
||||
2. Redirects hinzufügen:
|
||||
|
||||
```text
|
||||
https://bot.hexahost.de/api/auth/callback/discord
|
||||
```
|
||||
|
||||
3. **Client ID** und **Client Secret** in `.env` eintragen (`DISCORD_CLIENT_ID` / `DISCORD_CLIENT_SECRET`)
|
||||
|
||||
---
|
||||
|
||||
## 5. Container starten
|
||||
|
||||
Im Projektroot (dort wo `docker-compose.yml` liegt):
|
||||
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
Erster Build kann einige Minuten dauern (Python-Deps + Next.js-Build).
|
||||
|
||||
Status prüfen:
|
||||
|
||||
```bash
|
||||
docker compose ps
|
||||
docker compose logs -f bot
|
||||
docker compose logs -f dashboard
|
||||
```
|
||||
|
||||
Erwartung:
|
||||
|
||||
- `axiom-bot` — online, Discord-Login, API auf Port 8000
|
||||
- `axiom-dashboard` — läuft, Traefik routet `bot.hexahost.de`
|
||||
|
||||
---
|
||||
|
||||
## 6. Testen
|
||||
|
||||
1. Browser: **https://bot.hexahost.de**
|
||||
2. Mit Discord anmelden
|
||||
3. Guilds sollten erscheinen (Bot muss auf dem Server sein + du brauchst Manage Server / Admin)
|
||||
|
||||
---
|
||||
|
||||
## Alltag: Updates & Wartung
|
||||
|
||||
```bash
|
||||
# Neueste Version holen und neu bauen
|
||||
git pull
|
||||
docker compose up -d --build
|
||||
|
||||
# Nur Neustart
|
||||
docker compose restart
|
||||
|
||||
# Stoppen
|
||||
docker compose down
|
||||
|
||||
# Logs
|
||||
docker compose logs -f --tail=100
|
||||
```
|
||||
|
||||
Daten liegen in Docker-Volumes (`bot-db`, `bot-jsondb`, `bot-logs`) und bleiben bei `docker compose down` erhalten.
|
||||
Volumes **löschen** (Daten weg): `docker compose down -v` — nur bewusst nutzen.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Problem | Check |
|
||||
|---------|--------|
|
||||
| 502 / Gateway Timeout | `docker compose ps` — läuft `axiom-dashboard`? Traefik am richtigen Netzwerk? |
|
||||
| Kein HTTPS-Zertifikat | DNS auf Server? Cert-Resolver-Name (`TRAEFIK_CERT_RESOLVER`)? Entrypoints `web`/`websecure`? |
|
||||
| Login schlägt fehl | Redirect-URL exakt wie oben? `NEXTAUTH_URL` = `https://bot.hexahost.de/`? |
|
||||
| Dashboard leer / API-Fehler | Gleiches `DASHBOARD_API_KEY`? Bot-Logs: `API_ENABLED` / Startfehler? |
|
||||
| Bot offline | `TOKEN` gültig? Intents? `docker compose logs bot` |
|
||||
| Traefik sieht Container nicht | Beide an `traefik-network`? Label `traefik.enable=true`? |
|
||||
|
||||
Netzwerk-Check:
|
||||
|
||||
```bash
|
||||
docker network inspect traefik-network
|
||||
```
|
||||
|
||||
Dort sollten u. a. Traefik, `axiom-bot` und `axiom-dashboard` erscheinen.
|
||||
|
||||
---
|
||||
|
||||
## Architektur (kurz)
|
||||
|
||||
```text
|
||||
Internet
|
||||
│
|
||||
▼
|
||||
Traefik (traefik-network)
|
||||
│ Host: bot.hexahost.de
|
||||
▼
|
||||
axiom-dashboard :3000
|
||||
│ DASHBOARD_API_URL=http://bot:8000/api/v1
|
||||
▼
|
||||
axiom-bot :8000 (nur Docker-intern)
|
||||
│
|
||||
└── Discord Gateway (ausgehend)
|
||||
```
|
||||
|
||||
Die Bot-API wird **nicht** über Traefik veröffentlicht; das Dashboard spricht sie nur im internen Netzwerk an.
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 CodeX Devs
|
||||
Copyright (c) 2026 HexaHost
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **Report ID** | ZYROX-SEC-2026-001 |
|
||||
| **Target** | ZyroX CV2 AIO Discord Bot with Dashboard |
|
||||
| **Repository** | `ZyroX-CV2-AIO-With-Dashboard-main` |
|
||||
| **Target** | Axiom CV2 AIO Discord Bot with Dashboard |
|
||||
| **Repository** | `Axiom-CV2-AIO-With-Dashboard-main` |
|
||||
| **Assessment Date** | 2026-07-21 |
|
||||
| **Report Version** | 1.0 |
|
||||
| **Classification** | Internal — Distribution Restricted |
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
## 1. Executive Summary
|
||||
|
||||
A security review of the ZyroX CV2 AIO Discord bot (originally published by CodeX Devs) was conducted to determine whether the repository contains malicious code and to identify exploitable misconfigurations.
|
||||
A security review of the Axiom CV2 AIO Discord bot (originally published by HexaHost) was conducted to determine whether the repository contains malicious code and to identify exploitable misconfigurations.
|
||||
|
||||
### 1.1 Malware Classification
|
||||
|
||||
@@ -69,7 +69,7 @@ A security review of the ZyroX CV2 AIO Discord bot (originally published by Code
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ Trust Boundary │
|
||||
Discord Users ───►│ discord.py Gateway (bot/CodeX.py) │
|
||||
Discord Users ───►│ discord.py Gateway (bot/Axiom.py) │
|
||||
│ │ │ │
|
||||
│ ▼ ▼ │
|
||||
│ SQLite (bot/db/) FastAPI :8000 │
|
||||
@@ -153,7 +153,7 @@ OWNER_IDS: list[int] = _parse_ids("OWNER_IDS", [870179991462236170])
|
||||
| **CVSS 3.1 (est.)** | 9.8 (AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H) |
|
||||
| **Status at review** | Open → Remediated (#2) |
|
||||
|
||||
**Affected component:** `bot/CodeX.py` (~L345)
|
||||
**Affected component:** `bot/Axiom.py` (~L345)
|
||||
|
||||
```python
|
||||
await client.load_extension("jishaku")
|
||||
@@ -176,7 +176,7 @@ await client.load_extension("jishaku")
|
||||
| **CVSS 3.1 (est.)** | 7.5 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N) |
|
||||
| **Status at review** | Open → Remediated (#3) |
|
||||
|
||||
**Affected component:** `bot/CodeX.py` → `on_command_completion`
|
||||
**Affected component:** `bot/Axiom.py` → `on_command_completion`
|
||||
|
||||
**Description:** Non-owner command invocations are POSTed to `CMD_WEBHOOK_URL` with command text, user ID, guild name/ID, and channel ID. Owner commands are explicitly excluded from logging.
|
||||
|
||||
@@ -198,9 +198,9 @@ await client.load_extension("jishaku")
|
||||
|
||||
| File | Channel ID | Function |
|
||||
|------|------------|----------|
|
||||
| `bot/CodeX.py` | `1396794297386532978` | Guild join notifications |
|
||||
| `bot/CodeX.py` | `1419729255977189467` | Server count display |
|
||||
| `bot/CodeX.py` | `1419729283861184632` | Member count display |
|
||||
| `bot/Axiom.py` | `1396794297386532978` | Guild join notifications |
|
||||
| `bot/Axiom.py` | `1419729255977189467` | Server count display |
|
||||
| `bot/Axiom.py` | `1419729283861184632` | Member count display |
|
||||
| `bot/cogs/events/on_guild.py` | `1396794297386532978` | Join/leave detail logs |
|
||||
| `bot/cogs/commands/np.py` | `1396794297386532978` | No-prefix command audit |
|
||||
|
||||
@@ -218,7 +218,7 @@ await client.load_extension("jishaku")
|
||||
| **CWE** | [CWE-284](https://cwe.mitre.org/data/definitions/284.html) — Improper Access Control |
|
||||
| **Status at review** | Open → Partially remediated (#5, #10) |
|
||||
|
||||
**Affected components:** `bot/api/server.py`, `bot/utils/tunnel.py`, `bot/CodeX.py`
|
||||
**Affected components:** `bot/api/server.py`, `bot/utils/tunnel.py`, `bot/Axiom.py`
|
||||
|
||||
**Description:** API listens on `0.0.0.0:8000` by default. Cloudflare tunnel can expose localhost to the public internet. Authentication is a single shared bearer token without per-guild Discord authorization (pre-fix).
|
||||
|
||||
@@ -324,7 +324,7 @@ const API_KEY = process.env.NEXT_PUBLIC_DASHBOARD_API_KEY;
|
||||
| **Severity** | Low / Informational |
|
||||
| **Status at review** | Acknowledged — no code change required |
|
||||
|
||||
**Description:** >100 files contain CodeX branding headers (`discord.gg/codexdev`). Commented `autoblacklist` cog references external support channel. Help footers link to developer Discord.
|
||||
**Description:** >100 files contain legacy branding headers (`discord.gg/hexahost`). Commented `autoblacklist` cog references external support channel. Help footers link to developer Discord.
|
||||
|
||||
**Impact:** No direct exploitation path; increases fingerprinting and social-trust surface.
|
||||
|
||||
@@ -388,8 +388,8 @@ const API_KEY = process.env.NEXT_PUBLIC_DASHBOARD_API_KEY;
|
||||
|
||||
| Component | Role |
|
||||
|-----------|------|
|
||||
| `CodeX.py` | Process entry: bot, API thread, optional tunnel |
|
||||
| `core/zyrox.py` | `AutoShardedBot` subclass, prefix resolution |
|
||||
| `Axiom.py` | Process entry: bot, API thread, optional tunnel |
|
||||
| `core/axiom.py` | `AutoShardedBot` subclass, prefix resolution |
|
||||
| `utils/config.py` | Centralized environment configuration |
|
||||
| `api/` | FastAPI REST layer for dashboard |
|
||||
| `cogs/` | Feature modules (~80+ extensions) |
|
||||
@@ -454,7 +454,7 @@ All databases are local SQLite files under `bot/db/`. No encryption at rest obse
|
||||
## Appendix D — Startup Sequence
|
||||
|
||||
```
|
||||
python bot/CodeX.py
|
||||
python bot/Axiom.py
|
||||
├─ load_dotenv()
|
||||
├─ FastAPI thread (if API_ENABLED)
|
||||
├─ Cloudflare tunnel (if TUNNEL_ENABLED)
|
||||
@@ -473,7 +473,7 @@ npm run dev (dashboard/)
|
||||
|
||||
## 6. Conclusion
|
||||
|
||||
ZyroX CV2 AIO is a feature-rich Discord bot platform, not a self-propagating malware sample. The primary security concern is **deployment-time trust delegation**: unchanged defaults effectively assign operational control and observability to the original publisher.
|
||||
Axiom CV2 AIO is a feature-rich Discord bot platform, not a self-propagating malware sample. The primary security concern is **deployment-time trust delegation**: unchanged defaults effectively assign operational control and observability to the original publisher.
|
||||
|
||||
Operators treating this as production software must treat initial configuration as a **security-critical step**, equivalent to key ceremony for any SaaS deployment.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Summary
|
||||
|
||||
Security audit and hardening of the ZyroX CV2 AIO Discord bot with dashboard. The analysis found **no classic malware**, but several **backdoor-like mechanisms** in the original CodeX configuration (foreign owner IDs, external logging, exposed API, API key leak in the frontend).
|
||||
Security audit and hardening of the Axiom CV2 AIO Discord bot with dashboard. The analysis found **no classic malware**, but several **backdoor-like mechanisms** in the original legacy configuration (foreign owner IDs, external logging, exposed API, API key leak in the frontend).
|
||||
|
||||
This PR addresses **10 security issues** and introduces **secure defaults**: without a proper `.env` configuration, no foreign user retains owner rights, no external logging occurs, and the API is not publicly exposed.
|
||||
|
||||
|
||||
50
README.md
50
README.md
@@ -1,18 +1,14 @@
|
||||
<div align="center">
|
||||
|
||||
```
|
||||
███████╗██╗ ██╗██████╗ ██████╗ ██╗ ██╗
|
||||
╚══███╔╝╚██╗ ██╔╝██╔══██╗██╔═══██╗╚██╗██╔╝
|
||||
███╔╝ ╚████╔╝ ██████╔╝██║ ██║ ╚███╔╝
|
||||
███╔╝ ╚██╔╝ ██╔══██╗██║ ██║ ██╔██╗
|
||||
███████╗ ██║ ██║ ██║╚██████╔╝██╔╝ ██╗
|
||||
╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝
|
||||
+-+-+-+-+-+
|
||||
|A|x|i|o|m|
|
||||
+-+-+-+-+-+
|
||||
by HexaHost
|
||||
```
|
||||
|
||||
<h3>A feature-rich Discord bot paired with a sleek Next.js dashboard</h3>
|
||||
|
||||
<a href="https://nexiohost.in"><img src="https://img.shields.io/badge/⭐%20PREMIUM%20HOSTING-NexioHost-FFD700?style=for-the-badge&labelColor=1a1a2e&color=FFD700&logoColor=FFD700"/></a>
|
||||
|
||||
<p>
|
||||
<a href="https://python.org"><img src="https://img.shields.io/badge/Python-3.10+-3776AB?style=for-the-badge&logo=python&logoColor=white"/></a>
|
||||
<a href="https://nextjs.org"><img src="https://img.shields.io/badge/Next.js-14+-000000?style=for-the-badge&logo=nextdotjs&logoColor=white"/></a>
|
||||
@@ -21,9 +17,8 @@
|
||||
</p>
|
||||
<p>
|
||||
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-red?style=for-the-badge"/></a>
|
||||
<a href="https://discord.gg/codexdev"><img src="https://img.shields.io/badge/Discord-Join_Server-5865F2?style=for-the-badge&logo=discord&logoColor=white"/></a>
|
||||
<a href="https://youtube.com/@CodeXDevs"><img src="https://img.shields.io/badge/YouTube-CodeXDevs-FF0000?style=for-the-badge&logo=youtube&logoColor=white"/></a>
|
||||
<a href="https://github.com/RayExo"><img src="https://img.shields.io/badge/GitHub-RayExo-181717?style=for-the-badge&logo=github&logoColor=white"/></a>
|
||||
<a href="https://discord.gg/hexahost"><img src="https://img.shields.io/badge/Discord-Join_Server-5865F2?style=for-the-badge&logo=discord&logoColor=white"/></a>
|
||||
<a href="https://github.com/theoneandonlymace"><img src="https://img.shields.io/badge/GitHub-theoneandonlymace-181717?style=for-the-badge&logo=github&logoColor=white"/></a>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
@@ -32,10 +27,10 @@
|
||||
|
||||
## ✦ Overview
|
||||
|
||||
ZyroX is a fully-featured Discord bot with a modern web dashboard for managing everything from antinuke to music. Built on `discord.py v2`, `FastAPI`, and `Next.js 14` with Tailwind CSS.
|
||||
Axiom is a fully-featured Discord bot by HexaHost with a modern web dashboard for managing everything from antinuke to music. Built on `discord.py v2`, `FastAPI`, and `Next.js 14` with Tailwind CSS.
|
||||
|
||||
```
|
||||
ZyroX-CV2-With-Dashboard/
|
||||
Axiom-CV2-With-Dashboard/
|
||||
├── 🤖 bot/ Python Discord bot + FastAPI backend
|
||||
│ ├── api/ Dashboard REST API (FastAPI)
|
||||
│ ├── cogs/ All bot features (commands, events, antinuke, automod…)
|
||||
@@ -43,7 +38,7 @@ ZyroX-CV2-With-Dashboard/
|
||||
│ ├── utils/ Shared utilities (emoji, tools, sync, cloudflare tunnel…)
|
||||
│ ├── games/ Standalone game modules
|
||||
│ ├── assets/ Fonts, backgrounds, GIFs
|
||||
│ └── CodeX.py Entry point
|
||||
│ └── Axiom.py Entry point
|
||||
│
|
||||
└── 🌐 dashboard/ Next.js frontend
|
||||
├── app/ App Router pages & API routes
|
||||
@@ -122,7 +117,7 @@ ZyroX-CV2-With-Dashboard/
|
||||
- Slash + prefix commands
|
||||
- FastAPI backend with API key auth + rate limiting
|
||||
- Cloudflare Tunnel — unlimited bandwidth, permanent URL, zero system installs
|
||||
- CodeX Devs watermark on every source file
|
||||
- HexaHost manufacturer watermark on every source file
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
@@ -148,8 +143,8 @@ ZyroX-CV2-With-Dashboard/
|
||||
**1 — Clone the repo**
|
||||
|
||||
```bash
|
||||
git clone https://github.com/RayExo/ZyroX-CV2-With-Dashboard
|
||||
cd ZyroX-CV2-With-Dashboard/bot
|
||||
git clone https://github.com/theoneandonlymace/Axiom-CV2-With-Dashboard
|
||||
cd Axiom-CV2-With-Dashboard/bot
|
||||
```
|
||||
|
||||
**2 — Install dependencies**
|
||||
@@ -173,7 +168,7 @@ Copy `.env.example` to `.env` and fill in the values:
|
||||
```env
|
||||
# ── Core ──────────────────────────────────────────────────────────
|
||||
TOKEN = your_discord_bot_token
|
||||
brand_name = 'ZyroX'
|
||||
brand_name = 'Axiom'
|
||||
|
||||
# ── Owner IDs (REQUIRED — your Discord user ID) ───────────────────
|
||||
OWNER_IDS = YOUR_DISCORD_USER_ID_HERE
|
||||
@@ -207,7 +202,7 @@ CF_TUNNEL_URL = "https://api.yourdomain.com"
|
||||
**4 — Run the bot**
|
||||
|
||||
```bash
|
||||
python CodeX.py
|
||||
python Axiom.py
|
||||
```
|
||||
|
||||
---
|
||||
@@ -237,7 +232,7 @@ DISCORD_CLIENT_SECRET = your_discord_oauth_client_secret
|
||||
|
||||
ADMIN_IDS = your_discord_user_id
|
||||
NEXT_PUBLIC_ADMIN_IDS = your_discord_user_id
|
||||
NEXT_PUBLIC_BRAND_NAME = "ZyroX"
|
||||
NEXT_PUBLIC_BRAND_NAME = "Axiom"
|
||||
NEXT_PUBLIC_BRAND_NAME_WORD = "ZX"
|
||||
```
|
||||
|
||||
@@ -309,7 +304,7 @@ The bot uses **pycloudflared** — a Python package that downloads the `cloudfla
|
||||
**Setup (browser only, no CLI needed):**
|
||||
|
||||
1. Go to [one.dash.cloudflare.com](https://one.dash.cloudflare.com) → **Networks → Tunnels → Create a tunnel**
|
||||
2. Choose **Cloudflared**, give it a name (e.g. `zyrox-api`), save
|
||||
2. Choose **Cloudflared**, give it a name (e.g. `axiom-api`), save
|
||||
3. On the **Install connector** step, copy the token from the command shown:
|
||||
```
|
||||
cloudflared tunnel run --token <COPY_THIS>
|
||||
@@ -336,7 +331,7 @@ On every startup the console prints:
|
||||
### 🤖 Bot — any Python host
|
||||
|
||||
1. Upload the entire `bot/` folder to your host (Pterodactyl, Render, Railway, Fly.io, VPS…)
|
||||
2. Set the start command to `python CodeX.py`
|
||||
2. Set the start command to `python Axiom.py`
|
||||
3. Add all environment variables
|
||||
4. `pycloudflared` downloads the binary automatically on first run — no extra steps
|
||||
|
||||
@@ -407,19 +402,18 @@ Runs automatically on startup when `EMOJI_SYNC=true`:
|
||||
|
||||
<div align="center">
|
||||
|
||||
## ✦ CodeX Devs
|
||||
## ✦ HexaHost
|
||||
|
||||
*Built for protection. Designed for style.*
|
||||
|
||||
<a href="https://discord.gg/codexdev"><img src="https://discord.com/api/guilds/1301573144817045524/widget.png?style=banner2" alt="CodeX Development Discord Server" width="480"/></a>
|
||||
<a href="https://discord.gg/hexahost"><img src="https://discord.com/api/guilds/1301573144817045524/widget.png?style=banner2" alt="HexaHost Discord Server" width="480"/></a>
|
||||
|
||||
<p>
|
||||
<a href="https://discord.gg/codexdev"><img src="https://img.shields.io/badge/Discord-Join_Server-5865F2?style=for-the-badge&logo=discord&logoColor=white"/></a>
|
||||
<a href="https://youtube.com/@CodeXDevs"><img src="https://img.shields.io/badge/YouTube-CodeXDevs-FF0000?style=for-the-badge&logo=youtube&logoColor=white"/></a>
|
||||
<a href="https://github.com/RayExo"><img src="https://img.shields.io/badge/GitHub-RayExo-181717?style=for-the-badge&logo=github&logoColor=white"/></a>
|
||||
<a href="https://discord.gg/hexahost"><img src="https://img.shields.io/badge/Discord-Join_Server-5865F2?style=for-the-badge&logo=discord&logoColor=white"/></a>
|
||||
<a href="https://github.com/theoneandonlymace"><img src="https://img.shields.io/badge/GitHub-theoneandonlymace-181717?style=for-the-badge&logo=github&logoColor=white"/></a>
|
||||
<a href="https://nexiohost.in"><img src="https://img.shields.io/badge/⭐%20PREMIUM%20HOSTING-NexioHost-FFD700?style=for-the-badge&labelColor=1a1a2e&color=FFD700&logoColor=FFD700"/></a>
|
||||
</p>
|
||||
|
||||
© 2026 CodeX Devs — MIT License
|
||||
© 2026 HexaHost — MIT License
|
||||
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
| **Publication Date** | 2026-07-21 |
|
||||
| **Status** | Patches applied — operator action required |
|
||||
| **Classification** | Internal — Distribution Restricted |
|
||||
| **Affected Product** | ZyroX CV2 AIO Discord Bot with Dashboard |
|
||||
| **Affected Product** | Axiom CV2 AIO Discord Bot with Dashboard |
|
||||
|
||||
---
|
||||
|
||||
@@ -46,7 +46,7 @@ This document tracks remediation of findings identified during static security a
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `bot/utils/config.py` | `_parse_ids()` returns empty list on missing env var |
|
||||
| `bot/CodeX.py` | Startup warning when `OWNER_IDS` is empty |
|
||||
| `bot/Axiom.py` | Startup warning when `OWNER_IDS` is empty |
|
||||
| `bot/.env.example` | Placeholder `YOUR_DISCORD_USER_ID_HERE`; foreign IDs removed |
|
||||
| `dashboard/.env.example` | `ADMIN_IDS` placeholder replaces foreign ID |
|
||||
|
||||
@@ -67,7 +67,7 @@ OWNER_IDS=<your_discord_snowflake>
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `bot/utils/config.py` | `JISHAKU_ENABLED` flag (default: `false`) |
|
||||
| `bot/CodeX.py` | Conditional extension load |
|
||||
| `bot/Axiom.py` | Conditional extension load |
|
||||
| `bot/.env.example` | Documented opt-in flag |
|
||||
|
||||
**Post-patch behavior:** Jishaku inactive unless `JISHAKU_ENABLED=true`. Recommended for local debugging only.
|
||||
@@ -82,7 +82,7 @@ OWNER_IDS=<your_discord_snowflake>
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `bot/utils/config.py` | `_valid_webhook_url()` rejects empty/placeholder values |
|
||||
| `bot/CodeX.py` | `on_command_completion` early-return when URL invalid |
|
||||
| `bot/Axiom.py` | `on_command_completion` early-return when URL invalid |
|
||||
|
||||
**Post-patch behavior:** No outbound command telemetry without fully qualified, operator-configured webhook URL.
|
||||
|
||||
@@ -96,7 +96,7 @@ OWNER_IDS=<your_discord_snowflake>
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `bot/utils/config.py` | `LOG_CHANNEL_ID`, `SERVER_COUNT_CHANNEL_ID`, `USER_COUNT_CHANNEL_ID` |
|
||||
| `bot/CodeX.py` | Config-driven channel references; stats task gated on config |
|
||||
| `bot/Axiom.py` | Config-driven channel references; stats task gated on config |
|
||||
| `bot/cogs/events/on_guild.py` | Join/leave logging conditional on `LOG_CHANNEL_ID` |
|
||||
| `bot/cogs/commands/np.py` | Audit logs use `LOG_CHANNEL_ID` |
|
||||
| `bot/.env.example` | Optional IDs documented (commented) |
|
||||
@@ -120,7 +120,7 @@ USER_COUNT_CHANNEL_ID=<channel_snowflake>
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `bot/utils/config.py` | `API_ENABLED=false`, `API_HOST=127.0.0.1`, `TUNNEL_ENABLED=false` |
|
||||
| `bot/CodeX.py` | Bind to `API_HOST`; warn on `0.0.0.0` |
|
||||
| `bot/Axiom.py` | Bind to `API_HOST`; warn on `0.0.0.0` |
|
||||
| `bot/.env.example` | Secure defaults documented |
|
||||
|
||||
**Post-patch behavior:** API and tunnel disabled until explicitly enabled. Localhost binding by default.
|
||||
@@ -200,7 +200,7 @@ Remove `NEXT_PUBLIC_DASHBOARD_API_KEY` from any existing `.env`.
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `bot/cogs/commands/general.py` | Removed `hack`, `token`, `wizz`; dead code cleanup |
|
||||
| `bot/cogs/zyrox/general.py` | Help index updated |
|
||||
| `bot/cogs/axiom/general.py` | Help index updated |
|
||||
|
||||
**Post-patch behavior:** Commands no longer registered. No regression in remaining general commands.
|
||||
|
||||
@@ -234,8 +234,8 @@ Secondary pass on remediation code identified gaps in the initial proxy implemen
|
||||
| API proxy accessible without session | Critical | Session gate + guild/admin validation in proxy route |
|
||||
| Guild dashboard pages lacking authZ check | High | `guild/[guildId]/layout.tsx` enforces Discord permissions |
|
||||
| `GET /guilds` returned all bot guilds | High | Proxy filters to user-manageable intersection |
|
||||
| `on_command_completion` NullPointer on `command is None` | Medium | Guard clause in `CodeX.py` |
|
||||
| Orphaned `jishaku` import in `bot/core/zyrox.py` | Low | Import removed |
|
||||
| `on_command_completion` NullPointer on `command is None` | Medium | Guard clause in `Axiom.py` |
|
||||
| Orphaned `jishaku` import in `bot/core/axiom.py` | Low | Import removed |
|
||||
| Admin check relied solely on `NEXT_PUBLIC_ADMIN_IDS` | Medium | Server-side `ADMIN_IDS` supported |
|
||||
|
||||
---
|
||||
@@ -274,8 +274,8 @@ Execute after pulling patched codebase:
|
||||
| Item | Rationale | Risk Level |
|
||||
|------|-----------|------------|
|
||||
| Developer credits in `mention.py`, `stats.py` | Cosmetic attribution | Informational |
|
||||
| CodeX file headers | Branding | Informational |
|
||||
| `discord.gg/codexdev` in welcome templates | Operator-configurable content | Informational |
|
||||
| Legacy file headers | Branding | Informational |
|
||||
| `discord.gg/hexahost` in welcome templates | Operator-configurable content | Informational |
|
||||
|
||||
These items do not constitute exploitable vulnerabilities under the assessed threat model.
|
||||
|
||||
|
||||
19
bot/.dockerignore
Normal file
19
bot/.dockerignore
Normal file
@@ -0,0 +1,19 @@
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
__pycache__
|
||||
*.py[cod]
|
||||
*.db
|
||||
*.db-journal
|
||||
.venv
|
||||
venv
|
||||
myenv
|
||||
.git
|
||||
.gitignore
|
||||
*.md
|
||||
LICENSE
|
||||
logs
|
||||
*.log
|
||||
.pytest_cache
|
||||
.mypy_cache
|
||||
CodeX.py
|
||||
@@ -1,6 +1,23 @@
|
||||
TOKEN=TOKEN_HERE
|
||||
brand_name='ZyroX'
|
||||
NEXT_PUBLIC_BRAND_NAME='ZyroX'
|
||||
brand_name='Axiom'
|
||||
NEXT_PUBLIC_BRAND_NAME='Axiom'
|
||||
|
||||
# ── Multiple instances (optional) ─────────────────────────────────────────────
|
||||
# Run several bot processes on one host — each needs its own .env / TOKEN / API_PORT.
|
||||
# BOT_INSTANCE_ID isolates all SQLite + jsondb files under bot/db/<id>/ (and jsondb subfolder).
|
||||
# Leave unset for normal single-bot operation (paths stay bot/db/*.db and bot/jsondb/*.json).
|
||||
# BOT_INSTANCE_ID=prod-a
|
||||
# API_PORT=8001
|
||||
|
||||
# ── Discord sharding (optional) ───────────────────────────────────────────────
|
||||
# Default (all unset): AutoShardedBot asks Discord for recommended shard count (one process).
|
||||
# Multi-process cluster: same TOKEN + shared DB volume; set SHARD_COUNT + SHARD_IDS per process.
|
||||
# API / slash sync / emoji sync only on the primary (shard 0 in SHARD_IDS, or SHARD_PRIMARY=true).
|
||||
# SHARD_COUNT=
|
||||
# SHARD_IDS=0,1
|
||||
# SHARD_PRIMARY=
|
||||
# Only enable API on the primary process:
|
||||
# API_ENABLED=true
|
||||
|
||||
# ── Owner / Staff IDs (REQUIRED — comma-separated Discord user IDs) ───────────
|
||||
# Set your own Discord user ID(s). No foreign IDs are used as fallback.
|
||||
@@ -20,8 +37,12 @@ LAVALINK_PASSWORD="youshallnotpass"
|
||||
LAVALINK_SECURE="false"
|
||||
LAVALINK_PORT="13592"
|
||||
|
||||
# ── Emoji Sync ────────────────────────────────────────────────────────────────
|
||||
EMOJI_SYNC="false"
|
||||
SLASH_SYNC_MODE=global
|
||||
# global = one set worldwide (default, no duplicates)
|
||||
# guild = instant only in connected servers (set SLASH_GUILD_IDS or rely on all guilds)
|
||||
# SLASH_GUILD_IDS=
|
||||
# Clears old per-server copies that caused duplicate /commands in Discord
|
||||
SLASH_CLEAR_GUILD_COMMANDS=true
|
||||
|
||||
# ── API / Dashboard Backend ───────────────────────────────────────────────────
|
||||
API_ENABLED="false"
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -29,11 +28,12 @@ from discord.ext import commands, tasks
|
||||
|
||||
from core import Context
|
||||
from core.Cog import Cog
|
||||
from core.zyrox import zyrox
|
||||
from core.axiom import Axiom
|
||||
from utils.Tools import *
|
||||
from utils.config import *
|
||||
from utils.emoji import SUCCESS, ERROR, TICK, CROSS, REACTION_TEST_EMOJIS
|
||||
from utils.sync_emojis import run_sync
|
||||
from utils.slash_sync import sync_slash_commands
|
||||
|
||||
import cogs
|
||||
|
||||
@@ -51,7 +51,7 @@ if not OWNER_IDS:
|
||||
print("\033[33m⚠ OWNER_IDS is not set in .env — no bot owners configured.\033[0m")
|
||||
print("\033[33m Set OWNER_IDS=YOUR_DISCORD_USER_ID before running in production.\033[0m")
|
||||
|
||||
client = zyrox()
|
||||
client = Axiom()
|
||||
tree = client.tree
|
||||
|
||||
# --- Background Task for Stats ---
|
||||
@@ -87,37 +87,75 @@ async def on_ready():
|
||||
|
||||
print("""
|
||||
\033[1;31m
|
||||
██████╗ ██████╗ ██████╗ ███████╗██╗ ██╗
|
||||
██╔════╝██╔═══██╗██╔══██╗██╔════╝╚██╗██╔╝
|
||||
██║ ██║ ██║██║ ██║█████╗ ╚███╔╝
|
||||
██║ ██║ ██║██║ ██║██╔══╝ ██╔██╗
|
||||
╚██████╗╚██████╔╝██████╔╝███████╗██╔╝ ██╗
|
||||
╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝
|
||||
+-+-+-+-+-+-+-+-+-+
|
||||
|H|e|x|a|H|o|s|t|
|
||||
+-+-+-+-+-+-+-+-+-+
|
||||
\033[0m
|
||||
""")
|
||||
print("Loaded & Online!")
|
||||
print(f"Logged in as: {client.user}")
|
||||
print(f"Connected to: {len(client.guilds)} guilds")
|
||||
print(f"Connected to: {len(client.users)} users")
|
||||
shard_count = client.shard_count or 1
|
||||
shard_ids = list(client.shards.keys()) if client.shards else [0]
|
||||
print(f"Shards: {shard_count} (this process: {shard_ids})")
|
||||
print(f"Shard primary: {IS_SHARD_PRIMARY}")
|
||||
if client.latencies:
|
||||
for sid, lat in client.latencies:
|
||||
print(f" Shard {sid}: {round(lat * 1000)}ms")
|
||||
|
||||
if not IS_SHARD_PRIMARY:
|
||||
print("\033[33m◈ Non-primary shard process — skipping API-side sync tasks\033[0m")
|
||||
return
|
||||
|
||||
# Sync application emojis on startup
|
||||
await run_sync(TOKEN)
|
||||
|
||||
async def sync_commands():
|
||||
# Register / slash commands (guild sync = instant; global can take up to ~1h)
|
||||
if not getattr(client, "_slash_synced", False):
|
||||
client._slash_synced = True
|
||||
try:
|
||||
synced = await client.tree.sync()
|
||||
all_commands = list(client.commands)
|
||||
print(f"Synced Total {len(all_commands)} Client Commands and {len(synced)} Slash Commands")
|
||||
await sync_slash_commands(client)
|
||||
except Exception as e:
|
||||
print(f"Error syncing command tree: {e}")
|
||||
print(f"\033[31mError syncing command tree: {e}\033[0m")
|
||||
|
||||
client.loop.create_task(sync_commands())
|
||||
if SERVER_COUNT_CHANNEL_ID or USER_COUNT_CHANNEL_ID:
|
||||
client.loop.create_task(update_stats())
|
||||
|
||||
|
||||
@client.event
|
||||
async def on_shard_connect(shard_id: int):
|
||||
print(f"\033[32m◈ Shard {shard_id}: connected\033[0m")
|
||||
|
||||
|
||||
@client.event
|
||||
async def on_shard_ready(shard_id: int):
|
||||
print(f"\033[32m◈ Shard {shard_id}: ready\033[0m")
|
||||
|
||||
|
||||
@client.event
|
||||
async def on_shard_disconnect(shard_id: int):
|
||||
print(f"\033[33m◈ Shard {shard_id}: disconnected\033[0m")
|
||||
|
||||
|
||||
@client.event
|
||||
async def on_shard_resumed(shard_id: int):
|
||||
print(f"\033[32m◈ Shard {shard_id}: resumed\033[0m")
|
||||
|
||||
|
||||
@client.event
|
||||
async def on_guild_join(guild: discord.Guild):
|
||||
# Only guild-mode needs per-server registration; global mode must not
|
||||
# copy commands into the guild or Discord shows duplicates (/afk twice).
|
||||
if IS_SHARD_PRIMARY:
|
||||
try:
|
||||
from utils.slash_sync import _sync_mode, sync_guild
|
||||
if _sync_mode() == "guild":
|
||||
synced = await sync_guild(client, guild, copy_global=True)
|
||||
print(f"◈ Slash sync for new guild {guild.id}: {len(synced)} command(s)")
|
||||
except Exception as e:
|
||||
print(f"Slash sync on guild join failed: {e}")
|
||||
|
||||
if not LOG_CHANNEL_ID:
|
||||
return
|
||||
log_channel = client.get_channel(LOG_CHANNEL_ID)
|
||||
@@ -322,6 +360,9 @@ def run_api():
|
||||
uvicorn.run(fastapi_app, host=API_HOST, port=API_PORT, log_level="warning")
|
||||
|
||||
def keep_alive():
|
||||
if not IS_SHARD_PRIMARY:
|
||||
print(f"\033[33m◈ API Server: Skipped (non-primary shard process)\033[0m")
|
||||
return
|
||||
if not API_ENABLED:
|
||||
print(f"\033[33m◈ API Server: Disabled via API_ENABLED=false\033[0m")
|
||||
return
|
||||
@@ -335,7 +376,10 @@ keep_alive()
|
||||
|
||||
# --- Cloudflare Tunnel (HTTPS for API) — only when explicitly enabled ---
|
||||
from utils.tunnel import start_tunnel
|
||||
start_tunnel()
|
||||
if IS_SHARD_PRIMARY:
|
||||
start_tunnel()
|
||||
else:
|
||||
print("\033[33m◈ Cloudflare Tunnel: Skipped (non-primary shard process)\033[0m")
|
||||
|
||||
# --- Main Bot Execution ---
|
||||
async def main():
|
||||
29
bot/Dockerfile
Normal file
29
bot/Dockerfile
Normal file
@@ -0,0 +1,29 @@
|
||||
# Axiom Discord Bot + FastAPI dashboard backend (by HexaHost)
|
||||
FROM python:3.12-slim-bookworm
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PIP_NO_CACHE_DIR=1 \
|
||||
PIP_DISABLE_PIP_VERSION_CHECK=1
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
libffi-dev \
|
||||
libjpeg62-turbo-dev \
|
||||
zlib1g-dev \
|
||||
libsodium-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY requirements.txt .
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
# Persist SQLite / JSON data outside the image
|
||||
RUN mkdir -p /app/db /app/jsondb /app/logs
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
CMD ["python", "Axiom.py"]
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 CodeX Devs
|
||||
Copyright (c) 2026 HexaHost
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
<div align="center">
|
||||
|
||||
```
|
||||
███████╗██╗ ██╗██████╗ ██████╗ ██╗ ██╗
|
||||
╚══███╔╝╚██╗ ██╔╝██╔══██╗██╔═══██╗╚██╗██╔╝
|
||||
███╔╝ ╚████╔╝ ██████╔╝██║ ██║ ╚███╔╝
|
||||
███╔╝ ╚██╔╝ ██╔══██╗██║ ██║ ██╔██╗
|
||||
███████╗ ██║ ██║ ██║╚██████╔╝██╔╝ ██╗
|
||||
╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝
|
||||
+-+-+-+-+-+
|
||||
|A|x|i|o|m|
|
||||
+-+-+-+-+-+
|
||||
by HexaHost
|
||||
```
|
||||
|
||||
<h3>ZyroX Bot — Python Discord Bot + FastAPI Backend</h3>
|
||||
<h3>Axiom Bot — Python Discord Bot + FastAPI Backend</h3>
|
||||
|
||||
<a href="https://nexiohost.in"><img src="https://img.shields.io/badge/⭐%20PREMIUM%20HOSTING-NexioHost-FFD700?style=for-the-badge&labelColor=1a1a2e&color=FFD700&logoColor=FFD700"/></a>
|
||||
|
||||
@@ -20,9 +18,8 @@
|
||||
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-red?style=for-the-badge"/></a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://discord.gg/codexdev"><img src="https://img.shields.io/badge/Discord-Join_Server-5865F2?style=for-the-badge&logo=discord&logoColor=white"/></a>
|
||||
<a href="https://youtube.com/@CodeXDevs"><img src="https://img.shields.io/badge/YouTube-CodeXDevs-FF0000?style=for-the-badge&logo=youtube&logoColor=white"/></a>
|
||||
<a href="https://github.com/RayExo"><img src="https://img.shields.io/badge/GitHub-RayExo-181717?style=for-the-badge&logo=github&logoColor=white"/></a>
|
||||
<a href="https://discord.gg/hexahost"><img src="https://img.shields.io/badge/Discord-Join_Server-5865F2?style=for-the-badge&logo=discord&logoColor=white"/></a>
|
||||
<a href="https://github.com/theoneandonlymace"><img src="https://img.shields.io/badge/GitHub-theoneandonlymace-181717?style=for-the-badge&logo=github&logoColor=white"/></a>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
@@ -31,7 +28,7 @@
|
||||
|
||||
## ✦ Overview
|
||||
|
||||
This folder contains the ZyroX Discord bot built on `discord.py v2` alongside a `FastAPI` backend that powers the web dashboard. Everything runs from a single `python CodeX.py` command.
|
||||
This folder contains the Axiom Discord bot built on `discord.py v2` alongside a `FastAPI` backend that powers the web dashboard. Everything runs from a single `python Axiom.py` command.
|
||||
|
||||
```
|
||||
bot/
|
||||
@@ -43,12 +40,12 @@ bot/
|
||||
│ ├── commands/ All slash & prefix command modules
|
||||
│ ├── events/ General Discord event listeners
|
||||
│ ├── moderation/ Moderation action modules
|
||||
│ └── zyrox/ Core ZyroX feature cogs
|
||||
│ └── axiom/ Help / feature index cogs
|
||||
├── core/ Bot client, context, cog base classes
|
||||
├── games/ Standalone game logic + button views
|
||||
├── utils/ Emoji, tools, sync, Cloudflare tunnel
|
||||
├── assets/ Fonts, backgrounds, GIFs
|
||||
└── CodeX.py Entry point
|
||||
└── Axiom.py Entry point
|
||||
```
|
||||
|
||||
---
|
||||
@@ -136,7 +133,7 @@ bot/
|
||||
- Slash + prefix commands
|
||||
- Cloudflare Tunnel via pycloudflared — zero system installs, unlimited traffic
|
||||
- Single `OWNER_IDS` env var controls all permission checks
|
||||
- CodeX Devs watermark on every source file
|
||||
- HexaHost manufacturer watermark on every source file
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
@@ -178,7 +175,7 @@ Create a `.env` file (copy from `.env.example`):
|
||||
```env
|
||||
# ── Core ──────────────────────────────────────────────────────────
|
||||
TOKEN = your_discord_bot_token
|
||||
brand_name = 'ZyroX'
|
||||
brand_name = 'Axiom'
|
||||
|
||||
# ── Owner IDs (REQUIRED — your Discord user ID) ───────────────────
|
||||
OWNER_IDS = YOUR_DISCORD_USER_ID_HERE
|
||||
@@ -212,7 +209,7 @@ CF_TUNNEL_URL = "https://api.yourdomain.com"
|
||||
### 3 — Run
|
||||
|
||||
```bash
|
||||
python CodeX.py
|
||||
python Axiom.py
|
||||
```
|
||||
|
||||
---
|
||||
@@ -262,7 +259,7 @@ Uses **pycloudflared** — downloads the `cloudflared` binary automatically on f
|
||||
**Setup (browser only — no CLI needed):**
|
||||
|
||||
1. Go to [one.dash.cloudflare.com](https://one.dash.cloudflare.com) → **Networks → Tunnels → Create a tunnel**
|
||||
2. Choose **Cloudflared**, name it (e.g. `zyrox-api`), save
|
||||
2. Choose **Cloudflared**, name it (e.g. `axiom-api`), save
|
||||
3. On **Install connector**, copy the token from the command shown:
|
||||
```
|
||||
cloudflared tunnel run --token <COPY_THIS_TOKEN>
|
||||
@@ -304,7 +301,7 @@ When `EMOJI_SYNC=true`, the bot syncs application emojis on every startup:
|
||||
Upload the entire `bot/` folder to your host and set the start command to:
|
||||
|
||||
```bash
|
||||
python CodeX.py
|
||||
python Axiom.py
|
||||
```
|
||||
|
||||
`pycloudflared` downloads the binary on first run — no extra steps on any host.
|
||||
@@ -331,19 +328,18 @@ python CodeX.py
|
||||
|
||||
<div align="center">
|
||||
|
||||
## ✦ CodeX Devs
|
||||
## ✦ HexaHost
|
||||
|
||||
*Built for protection. Designed for style.*
|
||||
|
||||
<a href="https://discord.gg/codexdev"><img src="https://discord.com/api/guilds/1301573144817045524/widget.png?style=banner2" alt="CodeX Development Discord Server" width="480"/></a>
|
||||
<a href="https://discord.gg/hexahost"><img src="https://discord.com/api/guilds/1301573144817045524/widget.png?style=banner2" alt="HexaHost Discord Server" width="480"/></a>
|
||||
|
||||
<p>
|
||||
<a href="https://discord.gg/codexdev"><img src="https://img.shields.io/badge/Discord-Join_Server-5865F2?style=for-the-badge&logo=discord&logoColor=white"/></a>
|
||||
<a href="https://youtube.com/@CodeXDevs"><img src="https://img.shields.io/badge/YouTube-CodeXDevs-FF0000?style=for-the-badge&logo=youtube&logoColor=white"/></a>
|
||||
<a href="https://github.com/RayExo"><img src="https://img.shields.io/badge/GitHub-RayExo-181717?style=for-the-badge&logo=github&logoColor=white"/></a>
|
||||
<a href="https://discord.gg/hexahost"><img src="https://img.shields.io/badge/Discord-Join_Server-5865F2?style=for-the-badge&logo=discord&logoColor=white"/></a>
|
||||
<a href="https://github.com/theoneandonlymace"><img src="https://img.shields.io/badge/GitHub-theoneandonlymace-181717?style=for-the-badge&logo=github&logoColor=white"/></a>
|
||||
<a href="https://nexiohost.in"><img src="https://img.shields.io/badge/⭐%20PREMIUM%20HOSTING-NexioHost-FFD700?style=for-the-badge&labelColor=1a1a2e&color=FFD700&logoColor=FFD700"/></a>
|
||||
</p>
|
||||
|
||||
© 2026 CodeX Devs — MIT License
|
||||
© 2026 HexaHost — MIT License
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -16,6 +15,8 @@ import aiosqlite
|
||||
import asyncio
|
||||
from typing import Dict
|
||||
|
||||
from utils.db_paths import resolve_db_path
|
||||
|
||||
class DatabaseManager:
|
||||
"""
|
||||
A simple manager for persistent SQLite connections to avoid
|
||||
@@ -29,6 +30,7 @@ class DatabaseManager:
|
||||
"""
|
||||
Retrieves an existing connection or creates a new one for the given path.
|
||||
"""
|
||||
db_path = resolve_db_path(db_path)
|
||||
async with self._lock:
|
||||
if db_path not in self._connections:
|
||||
# We use check_same_thread=False because aiosqlite handles
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -21,13 +20,13 @@ from slowapi import Limiter
|
||||
from slowapi.util import get_remote_address
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.zyrox import zyrox
|
||||
from core.axiom import Axiom
|
||||
|
||||
# Initialize rate limiter
|
||||
limiter = Limiter(key_func=get_remote_address, default_limits=["1000 per minute"])
|
||||
|
||||
# Global reference to the bot instance
|
||||
_bot_instance: Optional["zyrox"] = None
|
||||
_bot_instance: Optional["Axiom"] = None
|
||||
|
||||
# Security scheme
|
||||
security = HTTPBearer()
|
||||
@@ -54,18 +53,18 @@ def verify_api_key(credentials: HTTPAuthorizationCredentials = Security(security
|
||||
)
|
||||
return credentials.credentials
|
||||
|
||||
def set_bot(bot_instance: "zyrox"):
|
||||
def set_bot(bot_instance: "Axiom"):
|
||||
"""
|
||||
Sets the global bot instance.
|
||||
This should be called in CodeX.py during startup.
|
||||
This should be called in Axiom.py during startup.
|
||||
"""
|
||||
global _bot_instance
|
||||
_bot_instance = bot_instance
|
||||
|
||||
def get_bot() -> "zyrox":
|
||||
def get_bot() -> "Axiom":
|
||||
"""
|
||||
FastAPI dependency to retrieve the Discord bot instance.
|
||||
Usage: bot: zyrox = Depends(get_bot)
|
||||
Usage: bot: Axiom = Depends(get_bot)
|
||||
"""
|
||||
if _bot_instance is None:
|
||||
raise HTTPException(
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ Discord OAuth permission checks for dashboard API requests ║
|
||||
# ║ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import re
|
||||
import time
|
||||
from typing import Any
|
||||
|
||||
import aiohttp
|
||||
@@ -17,6 +28,17 @@ ADMINISTRATOR = 0x8
|
||||
|
||||
GUILD_PATH_RE = re.compile(r"^/api/v1/guilds/(\d+)(?:/|$)")
|
||||
|
||||
# Short-lived process caches — cut Discord 429s from dashboard reloads
|
||||
_USER_CACHE_TTL = 60.0
|
||||
_GUILDS_CACHE_TTL = 60.0
|
||||
_user_cache: dict[str, tuple[float, dict[str, Any]]] = {}
|
||||
_guilds_cache: dict[str, tuple[float, list[dict[str, Any]]]] = {}
|
||||
_guilds_inflight: dict[str, asyncio.Future[list[dict[str, Any]]]] = {}
|
||||
|
||||
|
||||
def _token_key(access_token: str) -> str:
|
||||
return f"{access_token[:12]}:{len(access_token)}:{access_token[-8:]}"
|
||||
|
||||
|
||||
def _parse_admin_ids() -> list[str]:
|
||||
import os
|
||||
@@ -37,33 +59,92 @@ def can_manage_guild(guild: dict[str, Any]) -> bool:
|
||||
return bool(perms & ADMINISTRATOR) or bool(perms & MANAGE_GUILD)
|
||||
|
||||
|
||||
def _discord_auth_error(status: int) -> HTTPException:
|
||||
if status == 429:
|
||||
return HTTPException(
|
||||
status_code=429,
|
||||
detail="Discord rate limit — please wait a few seconds and retry.",
|
||||
)
|
||||
if status in (401, 403):
|
||||
return HTTPException(
|
||||
status_code=401,
|
||||
detail="Invalid or expired Discord access token. Please sign out and sign in again.",
|
||||
)
|
||||
return HTTPException(
|
||||
status_code=403,
|
||||
detail=f"Discord API error ({status}).",
|
||||
)
|
||||
|
||||
|
||||
async def fetch_user_guilds(access_token: str) -> list[dict[str, Any]]:
|
||||
key = _token_key(access_token)
|
||||
cached = _guilds_cache.get(key)
|
||||
if cached and cached[0] > time.monotonic():
|
||||
return cached[1]
|
||||
|
||||
existing = _guilds_inflight.get(key)
|
||||
if existing is not None:
|
||||
return await existing
|
||||
|
||||
loop = asyncio.get_running_loop()
|
||||
fut: asyncio.Future[list[dict[str, Any]]] = loop.create_future()
|
||||
_guilds_inflight[key] = fut
|
||||
|
||||
try:
|
||||
guilds = await _fetch_user_guilds_uncached(access_token)
|
||||
_guilds_cache[key] = (time.monotonic() + _GUILDS_CACHE_TTL, guilds)
|
||||
fut.set_result(guilds)
|
||||
return guilds
|
||||
except Exception as exc:
|
||||
fut.set_exception(exc)
|
||||
raise
|
||||
finally:
|
||||
_guilds_inflight.pop(key, None)
|
||||
|
||||
|
||||
async def _fetch_user_guilds_uncached(access_token: str) -> list[dict[str, Any]]:
|
||||
max_attempts = 3
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(
|
||||
"https://discord.com/api/users/@me/guilds",
|
||||
headers={"Authorization": f"Bearer {access_token}"},
|
||||
) as resp:
|
||||
if resp.status != 200:
|
||||
raise HTTPException(
|
||||
status_code=403,
|
||||
detail="Invalid or expired Discord access token.",
|
||||
)
|
||||
data = await resp.json()
|
||||
return data if isinstance(data, list) else []
|
||||
for attempt in range(1, max_attempts + 1):
|
||||
async with session.get(
|
||||
"https://discord.com/api/users/@me/guilds",
|
||||
headers={"Authorization": f"Bearer {access_token}"},
|
||||
) as resp:
|
||||
if resp.status == 200:
|
||||
data = await resp.json()
|
||||
return data if isinstance(data, list) else []
|
||||
|
||||
if resp.status == 429 and attempt < max_attempts:
|
||||
retry_after = 1.0
|
||||
try:
|
||||
body = await resp.json()
|
||||
retry_after = float(body.get("retry_after", 1))
|
||||
except Exception:
|
||||
retry_after = float(resp.headers.get("Retry-After", "1") or 1)
|
||||
await asyncio.sleep(min(max(retry_after, 0.3), 5.0))
|
||||
continue
|
||||
|
||||
raise _discord_auth_error(resp.status)
|
||||
|
||||
raise _discord_auth_error(429)
|
||||
|
||||
|
||||
async def verify_discord_token(access_token: str) -> dict[str, Any]:
|
||||
key = _token_key(access_token)
|
||||
cached = _user_cache.get(key)
|
||||
if cached and cached[0] > time.monotonic():
|
||||
return cached[1]
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(
|
||||
"https://discord.com/api/users/@me",
|
||||
headers={"Authorization": f"Bearer {access_token}"},
|
||||
) as resp:
|
||||
if resp.status != 200:
|
||||
raise HTTPException(
|
||||
status_code=403,
|
||||
detail="Invalid or expired Discord access token.",
|
||||
)
|
||||
return await resp.json()
|
||||
raise _discord_auth_error(resp.status)
|
||||
user = await resp.json()
|
||||
_user_cache[key] = (time.monotonic() + _USER_CACHE_TTL, user)
|
||||
return user
|
||||
|
||||
|
||||
async def user_can_manage_guild(access_token: str, guild_id: int) -> bool:
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from api.dependencies import get_bot
|
||||
@@ -20,11 +20,11 @@ import os
|
||||
import aiosqlite
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.zyrox import zyrox
|
||||
from core.axiom import Axiom
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
CONFIG_DB = "db/admin_config.db"
|
||||
CONFIG_DB = db_path("admin_config.db")
|
||||
|
||||
async def init_db():
|
||||
async with aiosqlite.connect(CONFIG_DB) as db:
|
||||
@@ -38,7 +38,7 @@ import psutil
|
||||
import time
|
||||
|
||||
@router.get("/stats", response_model=AdminStats)
|
||||
async def get_admin_stats(bot: "zyrox" = Depends(get_bot)):
|
||||
async def get_admin_stats(bot: "Axiom" = Depends(get_bot)):
|
||||
# Calculate DB size and shard info
|
||||
total_size: float = 0.0
|
||||
db_count = 0
|
||||
@@ -87,7 +87,16 @@ async def get_admin_stats(bot: "zyrox" = Depends(get_bot)):
|
||||
AdminNodeStatus(
|
||||
name="Auth Sockets",
|
||||
status="Healthy",
|
||||
load=f"Shard: {bot.shard_count} | Latency: {round(bot.latency * 1000)}ms",
|
||||
load=(
|
||||
f"Shards: {bot.shard_count or 1} | "
|
||||
f"Latency: {round(bot.latency * 1000)}ms"
|
||||
+ (
|
||||
" | "
|
||||
+ ", ".join(f"s{sid}:{round(lat * 1000)}ms" for sid, lat in bot.latencies)
|
||||
if bot.latencies and len(bot.latencies) > 1
|
||||
else ""
|
||||
)
|
||||
),
|
||||
icon="Lock"
|
||||
)
|
||||
]
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -20,26 +19,33 @@ from utils.config import *
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.zyrox import zyrox
|
||||
from core.axiom import Axiom
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.get("/status", response_model=BotStatus, summary="Get bot status", description="Returns real-time health metrics, latency, and scale information.")
|
||||
async def get_status(bot: "zyrox" = Depends(get_bot)):
|
||||
async def get_status(bot: "Axiom" = Depends(get_bot)):
|
||||
"""
|
||||
Returns the live status of the bot.
|
||||
"""
|
||||
shard_ids = list(bot.shards.keys()) if bot.shards else ([0] if bot.shard_count else [])
|
||||
shard_latencies = [
|
||||
{"id": sid, "latency_ms": round(lat * 1000, 2)}
|
||||
for sid, lat in (bot.latencies or [])
|
||||
]
|
||||
return BotStatus(
|
||||
user=str(bot.user),
|
||||
id=str(bot.user.id) if bot.user else None,
|
||||
latency=bot.latency * 1000,
|
||||
guild_count=len(bot.guilds),
|
||||
user_count=sum(g.member_count or 0 for g in bot.guilds),
|
||||
shards=bot.shard_count
|
||||
shards=bot.shard_count,
|
||||
shard_ids=shard_ids,
|
||||
shard_latencies=shard_latencies,
|
||||
)
|
||||
|
||||
@router.get("/info", response_model=BotInfo, summary="Get bot info", description="Returns general information about the bot including command count and user reach.")
|
||||
async def get_bot_info(bot: "zyrox" = Depends(get_bot)):
|
||||
async def get_bot_info(bot: "Axiom" = Depends(get_bot)):
|
||||
"""
|
||||
Get general information about the Discord bot.
|
||||
"""
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path, jsondb_path
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request
|
||||
from api.dependencies import get_bot, limiter
|
||||
from api.discord_auth import require_discord_session, get_manageable_guild_ids
|
||||
from api.discord_auth import get_manageable_guild_ids, get_discord_headers
|
||||
from api.db_manager import db_manager
|
||||
from api.schemas import (
|
||||
GuildSummary, GuildDetails, PrefixConfig, AutomodConfig,
|
||||
GuildSummary, GuildDetails, PrefixConfig, AutomodConfig, AutomodEventConfig,
|
||||
TicketConfig, LevelingConfig, LoggingConfig, TicketEmbed,
|
||||
TicketCategory, LevelingEmbedStyle, PrefixUpdate,
|
||||
AutomodUpdate, LevelingUpdate, LoggingUpdate, TicketUpdate,
|
||||
@@ -30,24 +30,39 @@ from api.schemas import (
|
||||
RRConfig, RRUpdate, ReactionRoleEntry,
|
||||
InviteStat, InvitesLeaderboard
|
||||
)
|
||||
from utils.automod_settings import (
|
||||
EVENT_ID_TO_DB,
|
||||
THRESHOLD_META,
|
||||
MAX_IGNORED,
|
||||
NSFW_KEYWORDS,
|
||||
normalize_event_id,
|
||||
normalize_punishment,
|
||||
ensure_thresholds_table,
|
||||
get_all_thresholds,
|
||||
set_thresholds,
|
||||
)
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
import math
|
||||
import aiosqlite
|
||||
import json
|
||||
import os
|
||||
import discord
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.zyrox import zyrox
|
||||
from core.axiom import Axiom
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/", response_model=List[GuildSummary], summary="List all guilds", description="Returns guilds the authenticated user can manage that the bot is in.")
|
||||
async def list_guilds(request: Request, bot: "zyrox" = Depends(get_bot)):
|
||||
async def list_guilds(request: Request, bot: "Axiom" = Depends(get_bot)):
|
||||
"""
|
||||
Lists guilds the bot is in, filtered to those the caller can manage on Discord.
|
||||
Session is already verified by middleware — only fetch manageable guild IDs here.
|
||||
"""
|
||||
token, _ = await require_discord_session(request)
|
||||
token, _ = get_discord_headers(request)
|
||||
if not token:
|
||||
raise HTTPException(status_code=403, detail="X-Discord-Access-Token header is required.")
|
||||
manageable_ids = await get_manageable_guild_ids(token)
|
||||
|
||||
guilds_list = []
|
||||
@@ -64,7 +79,7 @@ async def list_guilds(request: Request, bot: "zyrox" = Depends(get_bot)):
|
||||
return guilds_list
|
||||
|
||||
@router.get("/{guild_id}", response_model=GuildDetails, summary="Get guild details", description="Returns detailed metrics and metadata for a specific Discord guild.")
|
||||
async def get_guild_details(guild_id: int, bot: "zyrox" = Depends(get_bot)):
|
||||
async def get_guild_details(guild_id: int, bot: "Axiom" = Depends(get_bot)):
|
||||
"""
|
||||
Returns detailed info for a specific guild by its ID.
|
||||
"""
|
||||
@@ -87,7 +102,7 @@ async def get_guild_prefix(guild_id: int):
|
||||
"""
|
||||
Retrieves the custom prefix for a specific guild.
|
||||
"""
|
||||
db = await db_manager.get_connection('db/prefix.db')
|
||||
db = await db_manager.get_connection(db_path('prefix.db'))
|
||||
cursor = await db.execute("SELECT prefix FROM prefixes WHERE guild_id = ?", (guild_id,))
|
||||
row = await cursor.fetchone()
|
||||
prefix = row[0] if row else ">"
|
||||
@@ -101,7 +116,7 @@ async def update_guild_prefix(guild_id: int, data: PrefixUpdate):
|
||||
if not data.prefix or len(data.prefix) > 10:
|
||||
raise HTTPException(status_code=400, detail="Invalid prefix. Must be 1-10 characters.")
|
||||
|
||||
db = await db_manager.get_connection('db/prefix.db')
|
||||
db = await db_manager.get_connection(db_path('prefix.db'))
|
||||
await db.execute(
|
||||
"INSERT OR REPLACE INTO prefixes (guild_id, prefix) VALUES (?, ?)",
|
||||
(guild_id, data.prefix)
|
||||
@@ -117,79 +132,265 @@ async def get_guild_automod(guild_id: int):
|
||||
"""
|
||||
Retrieves the AutoMod configuration for a specific guild.
|
||||
"""
|
||||
db = await db_manager.get_connection('db/automod.db')
|
||||
# Check enabled status
|
||||
db = await db_manager.get_connection(db_path('automod.db'))
|
||||
await ensure_thresholds_table(db)
|
||||
|
||||
cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,))
|
||||
enabled_row = await cursor.fetchone()
|
||||
enabled = bool(enabled_row[0]) if enabled_row else False
|
||||
|
||||
# Get punishments
|
||||
cursor = await db.execute("SELECT event, punishment FROM automod_punishments WHERE guild_id = ?", (guild_id,))
|
||||
punishments = {row[0]: row[1] for row in await cursor.fetchall()}
|
||||
cursor = await db.execute(
|
||||
"SELECT event, punishment FROM automod_punishments WHERE guild_id = ?",
|
||||
(guild_id,),
|
||||
)
|
||||
raw_punishments = {row[0]: row[1] for row in await cursor.fetchall()}
|
||||
|
||||
# Get ignored items
|
||||
cursor = await db.execute("SELECT type, id FROM automod_ignored WHERE guild_id = ?", (guild_id,))
|
||||
events: dict[str, AutomodEventConfig] = {}
|
||||
punishments_out: dict[str, str] = {}
|
||||
for event_id, db_name in EVENT_ID_TO_DB.items():
|
||||
present = db_name in raw_punishments
|
||||
pun = raw_punishments.get(db_name)
|
||||
if event_id == "anti_nsfw_link":
|
||||
events[event_id] = AutomodEventConfig(
|
||||
enabled=present,
|
||||
punishment="block_message",
|
||||
readonly_punishment=True,
|
||||
)
|
||||
if present:
|
||||
punishments_out[event_id] = "block_message"
|
||||
else:
|
||||
norm = normalize_punishment(pun) if present else None
|
||||
events[event_id] = AutomodEventConfig(
|
||||
enabled=present,
|
||||
punishment=norm or ("Mute" if present else None),
|
||||
readonly_punishment=False,
|
||||
)
|
||||
if present and norm:
|
||||
punishments_out[event_id] = norm
|
||||
|
||||
cursor = await db.execute(
|
||||
"SELECT type, id FROM automod_ignored WHERE guild_id = ?", (guild_id,)
|
||||
)
|
||||
ignored_items = await cursor.fetchall()
|
||||
ignored_roles = [row[1] for row in ignored_items if row[0] == 'role']
|
||||
ignored_channels = [row[1] for row in ignored_items if row[0] == 'channel']
|
||||
ignored_roles = [row[1] for row in ignored_items if row[0] == "role"]
|
||||
ignored_channels = [row[1] for row in ignored_items if row[0] == "channel"]
|
||||
|
||||
# Get logging channel
|
||||
cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild_id,))
|
||||
cursor = await db.execute(
|
||||
"SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild_id,)
|
||||
)
|
||||
logging_row = await cursor.fetchone()
|
||||
logging_channel = logging_row[0] if logging_row else None
|
||||
|
||||
thresholds = await get_all_thresholds(guild_id)
|
||||
|
||||
return AutomodConfig(
|
||||
guild_id=guild_id,
|
||||
enabled=enabled,
|
||||
punishments=punishments,
|
||||
punishments=punishments_out,
|
||||
events=events,
|
||||
thresholds=thresholds,
|
||||
threshold_meta=THRESHOLD_META,
|
||||
ignored_roles=ignored_roles,
|
||||
ignored_channels=ignored_channels,
|
||||
logging_channel=logging_channel
|
||||
logging_channel=logging_channel,
|
||||
limits={"max_ignored_roles": MAX_IGNORED, "max_ignored_channels": MAX_IGNORED},
|
||||
)
|
||||
|
||||
|
||||
async def _sync_nsfw_rule(
|
||||
bot: "Axiom",
|
||||
guild_id: int,
|
||||
*,
|
||||
enabled: bool,
|
||||
ignored_roles: list[int],
|
||||
ignored_channels: list[int],
|
||||
) -> None:
|
||||
guild = bot.get_guild(guild_id)
|
||||
if not guild:
|
||||
return
|
||||
|
||||
existing = None
|
||||
try:
|
||||
rules = await guild.fetch_automod_rules()
|
||||
existing = next((r for r in rules if r.name == "Anti NSFW Links"), None)
|
||||
except (discord.Forbidden, discord.HTTPException):
|
||||
return
|
||||
|
||||
if not enabled:
|
||||
if existing:
|
||||
try:
|
||||
await existing.delete(reason="Automod NSFW disabled via dashboard")
|
||||
except (discord.Forbidden, discord.HTTPException):
|
||||
pass
|
||||
return
|
||||
|
||||
exempt_roles = [discord.Object(i) for i in ignored_roles[:MAX_IGNORED]]
|
||||
exempt_channels = [discord.Object(i) for i in ignored_channels[:MAX_IGNORED]]
|
||||
try:
|
||||
if existing:
|
||||
await existing.edit(
|
||||
exempt_roles=exempt_roles,
|
||||
exempt_channels=exempt_channels,
|
||||
enabled=True,
|
||||
reason="Automod NSFW updated via dashboard",
|
||||
)
|
||||
else:
|
||||
await guild.create_automod_rule(
|
||||
name="Anti NSFW Links",
|
||||
event_type=discord.AutoModRuleEventType.message_send,
|
||||
trigger=discord.AutoModTrigger(
|
||||
type=discord.AutoModRuleTriggerType.keyword,
|
||||
keyword_filter=NSFW_KEYWORDS,
|
||||
),
|
||||
actions=[
|
||||
discord.AutoModRuleAction(type=discord.AutoModRuleActionType.block_message),
|
||||
],
|
||||
enabled=True,
|
||||
exempt_roles=exempt_roles,
|
||||
exempt_channels=exempt_channels,
|
||||
reason="Automod NSFW enabled via dashboard",
|
||||
)
|
||||
except (discord.Forbidden, discord.HTTPException) as e:
|
||||
print(f"Automod NSFW sync error for guild {guild_id}: {e}")
|
||||
|
||||
|
||||
@router.patch("/{guild_id}/automod", summary="Update AutoMod config", description="Partially updates the AutoMod configuration components.")
|
||||
async def patch_guild_automod(guild_id: int, data: AutomodUpdate):
|
||||
async def patch_guild_automod(
|
||||
guild_id: int,
|
||||
data: AutomodUpdate,
|
||||
bot: "Axiom" = Depends(get_bot),
|
||||
):
|
||||
"""
|
||||
Updates parts of the AutoMod configuration for a specific guild.
|
||||
"""
|
||||
db = await db_manager.get_connection('db/automod.db')
|
||||
db = await db_manager.get_connection(db_path('automod.db'))
|
||||
await ensure_thresholds_table(db)
|
||||
|
||||
if data.enabled is not None:
|
||||
await db.execute(
|
||||
"INSERT OR REPLACE INTO automod (guild_id, enabled) VALUES (?, ?)",
|
||||
(guild_id, 1 if data.enabled else 0)
|
||||
(guild_id, 1 if data.enabled else 0),
|
||||
)
|
||||
|
||||
if data.punishments is not None:
|
||||
for event, punishment in data.punishments.items():
|
||||
await db.execute(
|
||||
"INSERT OR REPLACE INTO automod_punishments (guild_id, event, punishment) VALUES (?, ?, ?)",
|
||||
(guild_id, event, punishment)
|
||||
)
|
||||
# Build canonical enabled events from events{} and/or legacy punishments{}
|
||||
events_payload = data.events
|
||||
if events_payload is None and data.punishments is not None:
|
||||
events_payload = {}
|
||||
for raw_key, raw_pun in data.punishments.items():
|
||||
eid = normalize_event_id(raw_key)
|
||||
if not eid:
|
||||
continue
|
||||
if eid == "anti_nsfw_link":
|
||||
events_payload[eid] = AutomodEventConfig(
|
||||
enabled=True, punishment="block_message", readonly_punishment=True
|
||||
)
|
||||
else:
|
||||
pun = normalize_punishment(raw_pun) or "Mute"
|
||||
events_payload[eid] = AutomodEventConfig(enabled=True, punishment=pun)
|
||||
|
||||
if data.ignored_roles is not None:
|
||||
await db.execute("DELETE FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,))
|
||||
for role_id in data.ignored_roles:
|
||||
nsfw_enabled: bool | None = None
|
||||
if events_payload is not None:
|
||||
await db.execute(
|
||||
"DELETE FROM automod_punishments WHERE guild_id = ?", (guild_id,)
|
||||
)
|
||||
for raw_id, cfg in events_payload.items():
|
||||
eid = normalize_event_id(raw_id)
|
||||
if not eid or not cfg.enabled:
|
||||
if eid == "anti_nsfw_link":
|
||||
nsfw_enabled = False
|
||||
continue
|
||||
db_name = EVENT_ID_TO_DB[eid]
|
||||
if eid == "anti_nsfw_link":
|
||||
await db.execute(
|
||||
"INSERT INTO automod_punishments (guild_id, event, punishment) VALUES (?, ?, ?)",
|
||||
(guild_id, db_name, "Block message"),
|
||||
)
|
||||
nsfw_enabled = True
|
||||
else:
|
||||
pun = normalize_punishment(cfg.punishment) or "Mute"
|
||||
await db.execute(
|
||||
"INSERT INTO automod_punishments (guild_id, event, punishment) VALUES (?, ?, ?)",
|
||||
(guild_id, db_name, pun),
|
||||
)
|
||||
# Full-replace: omitted/disabled NSFW must drop the Discord rule
|
||||
if nsfw_enabled is None:
|
||||
nsfw_enabled = False
|
||||
|
||||
if data.thresholds is not None:
|
||||
await set_thresholds(db, guild_id, data.thresholds)
|
||||
|
||||
ignored_roles = data.ignored_roles
|
||||
ignored_channels = data.ignored_channels
|
||||
|
||||
if ignored_roles is not None:
|
||||
ignored_roles = list(dict.fromkeys(ignored_roles))[:MAX_IGNORED]
|
||||
await db.execute(
|
||||
"DELETE FROM automod_ignored WHERE guild_id = ? AND type = 'role'",
|
||||
(guild_id,),
|
||||
)
|
||||
for role_id in ignored_roles:
|
||||
await db.execute(
|
||||
"INSERT OR REPLACE INTO automod_ignored (guild_id, type, id) VALUES (?, 'role', ?)",
|
||||
(guild_id, role_id)
|
||||
(guild_id, role_id),
|
||||
)
|
||||
|
||||
if data.ignored_channels is not None:
|
||||
await db.execute("DELETE FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,))
|
||||
for channel_id in data.ignored_channels:
|
||||
if ignored_channels is not None:
|
||||
ignored_channels = list(dict.fromkeys(ignored_channels))[:MAX_IGNORED]
|
||||
await db.execute(
|
||||
"DELETE FROM automod_ignored WHERE guild_id = ? AND type = 'channel'",
|
||||
(guild_id,),
|
||||
)
|
||||
for channel_id in ignored_channels:
|
||||
await db.execute(
|
||||
"INSERT OR REPLACE INTO automod_ignored (guild_id, type, id) VALUES (?, 'channel', ?)",
|
||||
(guild_id, channel_id)
|
||||
(guild_id, channel_id),
|
||||
)
|
||||
|
||||
if data.logging_channel is not None:
|
||||
if data.clear_logging:
|
||||
await db.execute(
|
||||
"INSERT OR REPLACE INTO automod_logging (guild_id, log_channel) VALUES (?, ?)",
|
||||
(guild_id, data.logging_channel)
|
||||
"DELETE FROM automod_logging WHERE guild_id = ?", (guild_id,)
|
||||
)
|
||||
elif data.logging_channel is not None:
|
||||
if data.logging_channel == 0:
|
||||
await db.execute(
|
||||
"DELETE FROM automod_logging WHERE guild_id = ?", (guild_id,)
|
||||
)
|
||||
else:
|
||||
await db.execute(
|
||||
"INSERT OR REPLACE INTO automod_logging (guild_id, log_channel) VALUES (?, ?)",
|
||||
(guild_id, data.logging_channel),
|
||||
)
|
||||
|
||||
await db.commit()
|
||||
|
||||
|
||||
# Resolve current ignore lists for NSFW sync if not in this payload
|
||||
if ignored_roles is None or ignored_channels is None:
|
||||
cursor = await db.execute(
|
||||
"SELECT type, id FROM automod_ignored WHERE guild_id = ?", (guild_id,)
|
||||
)
|
||||
items = await cursor.fetchall()
|
||||
if ignored_roles is None:
|
||||
ignored_roles = [r[1] for r in items if r[0] == "role"]
|
||||
if ignored_channels is None:
|
||||
ignored_channels = [r[1] for r in items if r[0] == "channel"]
|
||||
|
||||
if nsfw_enabled is None and (data.ignored_roles is not None or data.ignored_channels is not None):
|
||||
# Keep Discord rule exempts in sync when ignores change
|
||||
cursor = await db.execute(
|
||||
"SELECT 1 FROM automod_punishments WHERE guild_id = ? AND event = ?",
|
||||
(guild_id, EVENT_ID_TO_DB["anti_nsfw_link"]),
|
||||
)
|
||||
nsfw_enabled = bool(await cursor.fetchone())
|
||||
|
||||
if nsfw_enabled is not None:
|
||||
await _sync_nsfw_rule(
|
||||
bot,
|
||||
guild_id,
|
||||
enabled=nsfw_enabled,
|
||||
ignored_roles=ignored_roles or [],
|
||||
ignored_channels=ignored_channels or [],
|
||||
)
|
||||
|
||||
return {"status": "success", "guild_id": guild_id}
|
||||
|
||||
@router.get("/{guild_id}/tickets", response_model=TicketConfig, summary="Get Ticket config", description="Retrieves the support ticket system setup, categories, and staff roles.")
|
||||
@@ -197,7 +398,7 @@ async def get_guild_tickets(guild_id: int):
|
||||
"""
|
||||
Retrieves the ticket system configuration for a specific guild.
|
||||
"""
|
||||
db = await db_manager.get_connection('db/ticket.db')
|
||||
db = await db_manager.get_connection(db_path('ticket.db'))
|
||||
|
||||
# Get basic config
|
||||
cursor = await db.execute(
|
||||
@@ -263,7 +464,7 @@ async def patch_guild_tickets(guild_id: int, data: TicketUpdate):
|
||||
"""
|
||||
Updates the ticket system configuration for a specific guild.
|
||||
"""
|
||||
db = await db_manager.get_connection('db/ticket.db')
|
||||
db = await db_manager.get_connection(db_path('ticket.db'))
|
||||
|
||||
# Initialize config row if not exists
|
||||
cursor = await db.execute("SELECT guild_id FROM guild_configs WHERE guild_id = ?", (guild_id,))
|
||||
@@ -322,7 +523,7 @@ async def get_guild_leveling(guild_id: int):
|
||||
"""
|
||||
Retrieves the leveling system configuration for a specific guild.
|
||||
"""
|
||||
db = await db_manager.get_connection('db/leveling.db')
|
||||
db = await db_manager.get_connection(db_path('leveling.db'))
|
||||
cursor = await db.execute("SELECT * FROM leveling_settings WHERE guild_id = ?", (guild_id,))
|
||||
row = await cursor.fetchone()
|
||||
|
||||
@@ -357,7 +558,7 @@ async def patch_guild_leveling(guild_id: int, data: LevelingUpdate):
|
||||
"""
|
||||
Updates parts of the leveling configuration for a specific guild.
|
||||
"""
|
||||
db = await db_manager.get_connection('db/leveling.db')
|
||||
db = await db_manager.get_connection(db_path('leveling.db'))
|
||||
# We use a series of updates or a single dynamic update.
|
||||
# For simplicity and robustness with INSERT OR REPLACE:
|
||||
|
||||
@@ -400,7 +601,7 @@ async def get_guild_welcome(guild_id: int):
|
||||
import aiosqlite
|
||||
import json
|
||||
|
||||
async with aiosqlite.connect("db/welcome.db") as db:
|
||||
async with aiosqlite.connect(db_path("welcome.db")) as db:
|
||||
async with db.execute("SELECT welcome_type, welcome_message, channel_id, embed_data, auto_delete_duration FROM welcome WHERE guild_id = ?", (guild_id,)) as cursor:
|
||||
row = await cursor.fetchone()
|
||||
|
||||
@@ -432,7 +633,7 @@ async def patch_guild_welcome(guild_id: int, data: WelcomeUpdate):
|
||||
import aiosqlite
|
||||
import json
|
||||
|
||||
async with aiosqlite.connect("db/welcome.db") as db:
|
||||
async with aiosqlite.connect(db_path("welcome.db")) as db:
|
||||
# Get existing or create
|
||||
async with db.execute("SELECT welcome_type, welcome_message, channel_id, embed_data, auto_delete_duration FROM welcome WHERE guild_id = ?", (guild_id,)) as cursor:
|
||||
row = await cursor.fetchone()
|
||||
@@ -468,7 +669,7 @@ async def patch_guild_welcome(guild_id: int, data: WelcomeUpdate):
|
||||
async def get_guild_antinuke(guild_id: int):
|
||||
import aiosqlite
|
||||
|
||||
async with aiosqlite.connect("db/anti.db") as db:
|
||||
async with aiosqlite.connect(db_path("anti.db")) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild_id,)) as cursor:
|
||||
row = await cursor.fetchone()
|
||||
|
||||
@@ -490,7 +691,7 @@ async def get_guild_antinuke(guild_id: int):
|
||||
async def patch_guild_antinuke(guild_id: int, data: AntiNukeUpdate):
|
||||
import aiosqlite
|
||||
|
||||
async with aiosqlite.connect("db/anti.db") as db:
|
||||
async with aiosqlite.connect(db_path("anti.db")) as db:
|
||||
if data.status is not None:
|
||||
# Get existing or create
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild_id,)) as cursor:
|
||||
@@ -538,7 +739,7 @@ async def patch_guild_antinuke(guild_id: int, data: AntiNukeUpdate):
|
||||
async def get_guild_verification(guild_id: int):
|
||||
import aiosqlite
|
||||
|
||||
async with aiosqlite.connect("db/verification.db") as db:
|
||||
async with aiosqlite.connect(db_path("verification.db")) as db:
|
||||
async with db.execute("SELECT verification_channel_id, verified_role_id, log_channel_id, verification_method, enabled FROM verification_config WHERE guild_id = ?", (guild_id,)) as cursor:
|
||||
row = await cursor.fetchone()
|
||||
|
||||
@@ -564,7 +765,7 @@ async def get_guild_verification(guild_id: int):
|
||||
async def patch_guild_verification(guild_id: int, data: VerificationUpdate):
|
||||
import aiosqlite
|
||||
|
||||
async with aiosqlite.connect("db/verification.db") as db:
|
||||
async with aiosqlite.connect(db_path("verification.db")) as db:
|
||||
async with db.execute("SELECT * FROM verification_config WHERE guild_id = ?", (guild_id,)) as cursor:
|
||||
row = await cursor.fetchone()
|
||||
|
||||
@@ -589,7 +790,7 @@ async def get_guild_vanityroles(guild_id: int):
|
||||
import aiosqlite
|
||||
|
||||
setups = []
|
||||
async with aiosqlite.connect("db/vanity.db") as db:
|
||||
async with aiosqlite.connect(db_path("vanity.db")) as db:
|
||||
async with db.execute("SELECT vanity, role_id, log_channel_id FROM vanity_roles WHERE guild_id = ?", (guild_id,)) as cursor:
|
||||
rows = await cursor.fetchall()
|
||||
for row in rows:
|
||||
@@ -604,7 +805,7 @@ async def get_guild_vanityroles(guild_id: int):
|
||||
async def post_guild_vanityroles(guild_id: int, data: VanityRoleSetup):
|
||||
import aiosqlite
|
||||
|
||||
async with aiosqlite.connect("db/vanity.db") as db:
|
||||
async with aiosqlite.connect(db_path("vanity.db")) as db:
|
||||
await db.execute(
|
||||
"INSERT OR REPLACE INTO vanity_roles (guild_id, vanity, role_id, log_channel_id, current_status) VALUES (?, ?, ?, ?, NULL)",
|
||||
(guild_id, data.vanity.lower(), data.role_id, data.log_channel_id)
|
||||
@@ -617,7 +818,7 @@ async def post_guild_vanityroles(guild_id: int, data: VanityRoleSetup):
|
||||
async def delete_guild_vanityroles(guild_id: int, vanity: str):
|
||||
import aiosqlite
|
||||
|
||||
async with aiosqlite.connect("db/vanity.db") as db:
|
||||
async with aiosqlite.connect(db_path("vanity.db")) as db:
|
||||
await db.execute("DELETE FROM vanity_roles WHERE guild_id = ? AND vanity = ?", (guild_id, vanity.lower()))
|
||||
await db.commit()
|
||||
|
||||
@@ -628,7 +829,7 @@ async def delete_guild_vanityroles(guild_id: int, vanity: str):
|
||||
async def get_guild_autorole(guild_id: int):
|
||||
import aiosqlite
|
||||
|
||||
async with aiosqlite.connect("db/autorole.db") as db:
|
||||
async with aiosqlite.connect(db_path("autorole.db")) as db:
|
||||
# Ensure table exists
|
||||
await db.execute("""
|
||||
CREATE TABLE IF NOT EXISTS autorole (
|
||||
@@ -662,7 +863,7 @@ async def get_guild_autorole(guild_id: int):
|
||||
async def patch_guild_autorole(guild_id: int, data: AutoRoleUpdate):
|
||||
import aiosqlite
|
||||
|
||||
async with aiosqlite.connect("db/autorole.db") as db:
|
||||
async with aiosqlite.connect(db_path("autorole.db")) as db:
|
||||
await db.execute("""
|
||||
CREATE TABLE IF NOT EXISTS autorole (
|
||||
guild_id INTEGER PRIMARY KEY,
|
||||
@@ -701,7 +902,7 @@ async def get_guild_welcome(guild_id: int):
|
||||
import aiosqlite
|
||||
import json
|
||||
|
||||
async with aiosqlite.connect("db/welcome.db") as db:
|
||||
async with aiosqlite.connect(db_path("welcome.db")) as db:
|
||||
async with db.execute("SELECT welcome_type, welcome_message, channel_id, embed_data, auto_delete_duration FROM welcome WHERE guild_id = ?", (guild_id,)) as cursor:
|
||||
row = await cursor.fetchone()
|
||||
|
||||
@@ -730,7 +931,7 @@ async def patch_guild_welcome(guild_id: int, data: WelcomeUpdate):
|
||||
import aiosqlite
|
||||
import json
|
||||
|
||||
async with aiosqlite.connect("db/welcome.db") as db:
|
||||
async with aiosqlite.connect(db_path("welcome.db")) as db:
|
||||
async with db.execute("SELECT welcome_type, welcome_message, channel_id, embed_data, auto_delete_duration FROM welcome WHERE guild_id = ?", (guild_id,)) as cursor:
|
||||
row = await cursor.fetchone()
|
||||
|
||||
@@ -766,7 +967,7 @@ async def patch_guild_welcome(guild_id: int, data: WelcomeUpdate):
|
||||
@router.delete("/{guild_id}/welcome", summary="Delete Welcome config")
|
||||
async def delete_guild_welcome(guild_id: int):
|
||||
import aiosqlite
|
||||
async with aiosqlite.connect("db/welcome.db") as db:
|
||||
async with aiosqlite.connect(db_path("welcome.db")) as db:
|
||||
await db.execute("DELETE FROM welcome WHERE guild_id = ?", (guild_id,))
|
||||
await db.commit()
|
||||
return {"status": "success"}
|
||||
@@ -775,7 +976,7 @@ async def delete_guild_welcome(guild_id: int):
|
||||
@router.get("/{guild_id}/tracking", response_model=TrackingConfig, summary="Get Tracking config")
|
||||
async def get_guild_tracking(guild_id: int):
|
||||
import aiosqlite
|
||||
async with aiosqlite.connect("db/invite.db") as db:
|
||||
async with aiosqlite.connect(db_path("invite.db")) as db:
|
||||
async with db.execute("SELECT channel_id FROM logging WHERE guild_id = ?", (guild_id,)) as cursor:
|
||||
row = await cursor.fetchone()
|
||||
return TrackingConfig(guild_id=guild_id, channel_id=row[0] if row else None)
|
||||
@@ -783,7 +984,7 @@ async def get_guild_tracking(guild_id: int):
|
||||
@router.patch("/{guild_id}/tracking", summary="Update Tracking config")
|
||||
async def patch_guild_tracking(guild_id: int, data: TrackingUpdate):
|
||||
import aiosqlite
|
||||
async with aiosqlite.connect("db/invite.db") as db:
|
||||
async with aiosqlite.connect(db_path("invite.db")) as db:
|
||||
await db.execute("INSERT OR REPLACE INTO logging (guild_id, channel_id) VALUES (?, ?)", (guild_id, data.channel_id))
|
||||
await db.commit()
|
||||
return {"status": "success"}
|
||||
@@ -820,7 +1021,7 @@ async def get_guild_j2c(guild_id: int):
|
||||
return J2CConfig(guild_id=str(guild_id))
|
||||
|
||||
@router.patch("/{guild_id}/j2c", summary="Update J2C config")
|
||||
async def patch_guild_j2c(guild_id: int, data: J2CUpdate, bot: "zyrox" = Depends(get_bot)):
|
||||
async def patch_guild_j2c(guild_id: int, data: J2CUpdate, bot: "Axiom" = Depends(get_bot)):
|
||||
import aiosqlite
|
||||
|
||||
def to_id(val):
|
||||
@@ -903,7 +1104,7 @@ async def patch_guild_j2c(guild_id: int, data: J2CUpdate, bot: "zyrox" = Depends
|
||||
|
||||
@router.get("/{guild_id}/joindm", response_model=JoinDMConfig, summary="Get JoinDM config")
|
||||
async def get_guild_joindm(guild_id: int):
|
||||
config_file = 'jsondb/joindm_messages.json'
|
||||
config_file = jsondb_path('joindm_messages.json')
|
||||
os.makedirs('jsondb', exist_ok=True)
|
||||
|
||||
if os.path.exists(config_file):
|
||||
@@ -925,7 +1126,7 @@ async def get_guild_joindm(guild_id: int):
|
||||
|
||||
@router.patch("/{guild_id}/joindm", summary="Update JoinDM config")
|
||||
async def patch_guild_joindm(guild_id: int, data: JoinDMUpdate):
|
||||
config_file = 'jsondb/joindm_messages.json'
|
||||
config_file = jsondb_path('joindm_messages.json')
|
||||
os.makedirs('jsondb', exist_ok=True)
|
||||
|
||||
messages = {}
|
||||
@@ -950,7 +1151,7 @@ async def patch_guild_joindm(guild_id: int, data: JoinDMUpdate):
|
||||
@router.get("/{guild_id}/customroles", response_model=CustomRoleConfig, summary="Get CustomRoles config")
|
||||
async def get_guild_customroles(guild_id: int):
|
||||
import aiosqlite
|
||||
async with aiosqlite.connect('db/customrole.db') as db:
|
||||
async with aiosqlite.connect(db_path('customrole.db')) as db:
|
||||
async with db.execute("SELECT staff, girl, vip, guest, frnd, reqrole FROM roles WHERE guild_id = ?", (guild_id,)) as cursor:
|
||||
row = await cursor.fetchone()
|
||||
if row:
|
||||
@@ -975,7 +1176,7 @@ async def patch_guild_customroles(guild_id: int, data: CustomRoleUpdate):
|
||||
try: return int(val)
|
||||
except: return None
|
||||
|
||||
async with aiosqlite.connect('db/customrole.db') as db:
|
||||
async with aiosqlite.connect(db_path('customrole.db')) as db:
|
||||
async with db.execute("SELECT * FROM roles WHERE guild_id = ?", (guild_id,)) as cursor:
|
||||
row = await cursor.fetchone()
|
||||
|
||||
@@ -1000,7 +1201,7 @@ async def patch_guild_customroles(guild_id: int, data: CustomRoleUpdate):
|
||||
return {"status": "success"}
|
||||
|
||||
@router.get("/{guild_id}/logging", response_model=LoggingConfig, summary="Get Logging config", description="Retrieves the event logging configuration and designated log channels.")
|
||||
async def get_guild_logging(guild_id: int, bot: "zyrox" = Depends(get_bot)):
|
||||
async def get_guild_logging(guild_id: int, bot: "Axiom" = Depends(get_bot)):
|
||||
"""
|
||||
Retrieves the logging configuration for a specific guild.
|
||||
"""
|
||||
@@ -1013,7 +1214,7 @@ async def get_guild_logging(guild_id: int, bot: "zyrox" = Depends(get_bot)):
|
||||
# Try reading from file as fallback
|
||||
import json
|
||||
import os
|
||||
config_file = "jsondb/logging_config.json"
|
||||
config_file = jsondb_path("logging_config.json")
|
||||
if os.path.exists(config_file):
|
||||
try:
|
||||
with open(config_file, "r") as f:
|
||||
@@ -1044,7 +1245,7 @@ async def get_guild_logging(guild_id: int, bot: "zyrox" = Depends(get_bot)):
|
||||
)
|
||||
|
||||
@router.patch("/{guild_id}/logging", summary="Update Logging config", description="Updates which Discord events are logged and where they are posted.")
|
||||
async def patch_guild_logging(guild_id: int, data: LoggingUpdate, bot: "zyrox" = Depends(get_bot)):
|
||||
async def patch_guild_logging(guild_id: int, data: LoggingUpdate, bot: "Axiom" = Depends(get_bot)):
|
||||
"""
|
||||
Updates the logging configuration for a specific guild.
|
||||
"""
|
||||
@@ -1076,8 +1277,8 @@ async def patch_guild_logging(guild_id: int, data: LoggingUpdate, bot: "zyrox" =
|
||||
return {"status": "success", "guild_id": guild_id}
|
||||
|
||||
@router.get("/{guild_id}/leveling/leaderboard", response_model=List[LeaderboardEntry], summary="Get leveling leaderboard", description="Returns top users by XP for a specific guild.")
|
||||
async def get_leveling_leaderboard(guild_id: int, bot: "zyrox" = Depends(get_bot)):
|
||||
db = await db_manager.get_connection('db/leveling.db')
|
||||
async def get_leveling_leaderboard(guild_id: int, bot: "Axiom" = Depends(get_bot)):
|
||||
db = await db_manager.get_connection(db_path('leveling.db'))
|
||||
cursor = await db.execute(
|
||||
"SELECT user_id, xp FROM user_xp WHERE guild_id = ? ORDER BY xp DESC LIMIT 100",
|
||||
(guild_id,)
|
||||
@@ -1116,7 +1317,7 @@ async def get_leveling_leaderboard(guild_id: int, bot: "zyrox" = Depends(get_bot
|
||||
return leaderboard
|
||||
|
||||
@router.get("/{guild_id}/channels", response_model=List[DiscordChannel], summary="Get guild channels", description="Returns a list of all channels for the specific guild.")
|
||||
async def get_guild_channels(guild_id: int, bot: "zyrox" = Depends(get_bot)):
|
||||
async def get_guild_channels(guild_id: int, bot: "Axiom" = Depends(get_bot)):
|
||||
guild = bot.get_guild(guild_id)
|
||||
if not guild:
|
||||
raise HTTPException(status_code=404, detail="Guild not found")
|
||||
@@ -1136,7 +1337,7 @@ async def get_guild_channels(guild_id: int, bot: "zyrox" = Depends(get_bot)):
|
||||
return channels
|
||||
|
||||
@router.get("/{guild_id}/roles", response_model=List[DiscordRole], summary="Get guild roles", description="Returns a list of roles for the specific guild.")
|
||||
async def get_guild_roles(guild_id: int, bot: "zyrox" = Depends(get_bot)):
|
||||
async def get_guild_roles(guild_id: int, bot: "Axiom" = Depends(get_bot)):
|
||||
guild = bot.get_guild(guild_id)
|
||||
if not guild:
|
||||
raise HTTPException(status_code=404, detail="Guild not found")
|
||||
@@ -1164,7 +1365,7 @@ async def get_guild_roles(guild_id: int, bot: "zyrox" = Depends(get_bot)):
|
||||
@router.get("/{guild_id}/autoreact", response_model=AutoReactConfig, summary="Get AutoReact config")
|
||||
async def get_guild_autoreact(guild_id: int):
|
||||
import aiosqlite
|
||||
async with aiosqlite.connect("db/autoreact.db") as db:
|
||||
async with aiosqlite.connect(db_path("autoreact.db")) as db:
|
||||
await db.execute("""
|
||||
CREATE TABLE IF NOT EXISTS autoreact (
|
||||
guild_id INTEGER,
|
||||
@@ -1185,7 +1386,7 @@ async def get_guild_autoreact(guild_id: int):
|
||||
|
||||
@router.get("/{guild_id}/invcrole", response_model=InvcConfig, summary="Get Invc Role config")
|
||||
async def get_guild_invcrole(guild_id: int):
|
||||
db = await db_manager.get_connection('db/invc.db')
|
||||
db = await db_manager.get_connection(db_path('invc.db'))
|
||||
# Use execute instead of with for shared connection
|
||||
await db.execute("""
|
||||
CREATE TABLE IF NOT EXISTS vcroles (
|
||||
@@ -1209,7 +1410,7 @@ async def get_guild_invcrole(guild_id: int):
|
||||
|
||||
@router.patch("/{guild_id}/invcrole", summary="Update Invc Role config")
|
||||
async def patch_guild_invcrole(guild_id: int, data: InvcUpdate):
|
||||
db = await db_manager.get_connection('db/invc.db')
|
||||
db = await db_manager.get_connection(db_path('invc.db'))
|
||||
|
||||
# Get existing row to merge
|
||||
cursor = await db.execute("SELECT role_id, enabled FROM vcroles WHERE guild_id = ?", (guild_id,))
|
||||
@@ -1246,7 +1447,7 @@ async def patch_guild_invcrole(guild_id: int, data: InvcUpdate):
|
||||
@router.get("/{guild_id}/autoreact", response_model=AutoReactConfig, summary="Get AutoReact config")
|
||||
async def get_guild_autoreact(guild_id: int):
|
||||
import aiosqlite
|
||||
async with aiosqlite.connect("db/autoreact.db") as db:
|
||||
async with aiosqlite.connect(db_path("autoreact.db")) as db:
|
||||
await db.execute("""
|
||||
CREATE TABLE IF NOT EXISTS autoreact (
|
||||
guild_id INTEGER,
|
||||
@@ -1264,7 +1465,7 @@ async def get_guild_autoreact(guild_id: int):
|
||||
|
||||
@router.patch("/{guild_id}/autoreact", summary="Update AutoReact config")
|
||||
async def patch_guild_autoreact(guild_id: int, data: AutoReactUpdate):
|
||||
db = await db_manager.get_connection("db/autoreact.db")
|
||||
db = await db_manager.get_connection(db_path("autoreact.db"))
|
||||
await db.execute("""
|
||||
CREATE TABLE IF NOT EXISTS autoreact (
|
||||
guild_id INTEGER,
|
||||
@@ -1287,7 +1488,7 @@ async def get_guild_invites(guild_id: int):
|
||||
table_name = f"invites_{guild_id}"
|
||||
data_list = []
|
||||
|
||||
db = await db_manager.get_connection("db/invite.db")
|
||||
db = await db_manager.get_connection(db_path("invite.db"))
|
||||
# Check if table exists
|
||||
async with db.execute("SELECT name FROM sqlite_master WHERE type='table' AND name=?", (table_name,)) as cursor:
|
||||
exists = await cursor.fetchone()
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
from pydantic import BaseModel, HttpUrl
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
# --- Bot Schemas ---
|
||||
|
||||
@@ -32,6 +31,8 @@ class BotStatus(BaseModel):
|
||||
guild_count: int
|
||||
user_count: int
|
||||
shards: Optional[int]
|
||||
shard_ids: Optional[List[int]] = None
|
||||
shard_latencies: Optional[List[Dict[str, Any]]] = None
|
||||
|
||||
# --- Guild Schemas ---
|
||||
|
||||
@@ -68,13 +69,24 @@ class PrefixConfig(BaseModel):
|
||||
guild_id: int
|
||||
prefix: str
|
||||
|
||||
class AutomodEventConfig(BaseModel):
|
||||
enabled: bool = False
|
||||
punishment: Optional[str] = None # Mute | Kick | Ban | block_message (NSFW)
|
||||
readonly_punishment: bool = False
|
||||
|
||||
|
||||
class AutomodConfig(BaseModel):
|
||||
guild_id: int
|
||||
enabled: bool
|
||||
punishments: Dict[str, str]
|
||||
ignored_roles: List[int]
|
||||
ignored_channels: List[int]
|
||||
logging_channel: Optional[int]
|
||||
# Legacy flat map (API event ids or bot names) — kept for older clients
|
||||
punishments: Dict[str, str] = {}
|
||||
events: Dict[str, AutomodEventConfig] = {}
|
||||
thresholds: Dict[str, Dict[str, float]] = {}
|
||||
threshold_meta: Dict[str, List[Dict[str, Any]]] = {}
|
||||
ignored_roles: List[int] = []
|
||||
ignored_channels: List[int] = []
|
||||
logging_channel: Optional[int] = None
|
||||
limits: Dict[str, int] = {"max_ignored_roles": 10, "max_ignored_channels": 10}
|
||||
|
||||
class TicketCategory(BaseModel):
|
||||
name: str
|
||||
@@ -300,10 +312,14 @@ class TicketUpdate(BaseModel):
|
||||
|
||||
class AutomodUpdate(BaseModel):
|
||||
enabled: Optional[bool] = None
|
||||
punishments: Optional[Dict[str, str]] = None
|
||||
punishments: Optional[Dict[str, str]] = None # legacy
|
||||
events: Optional[Dict[str, AutomodEventConfig]] = None
|
||||
thresholds: Optional[Dict[str, Dict[str, float]]] = None
|
||||
ignored_roles: Optional[List[int]] = None
|
||||
ignored_channels: Optional[List[int]] = None
|
||||
# Use a sentinel-friendly optional: omit = no change; null = clear logging
|
||||
logging_channel: Optional[int] = None
|
||||
clear_logging: Optional[bool] = None
|
||||
|
||||
class LevelingUpdate(BaseModel):
|
||||
enabled: Optional[bool] = None
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -53,8 +52,8 @@ async def lifespan(app: FastAPI):
|
||||
|
||||
def create_app() -> FastAPI:
|
||||
"""
|
||||
Initializes the FastAPI application for the CodeX Bot Dashboard.
|
||||
The bot instance will be attached to app.state.bot in CodeX.py at runtime.
|
||||
Initializes the FastAPI application for the Axiom Bot Dashboard.
|
||||
The bot instance will be attached to app.state.bot in Axiom.py at runtime.
|
||||
"""
|
||||
app = FastAPI(
|
||||
title=f"{BRAND_NAME} Bot API",
|
||||
|
||||
BIN
bot/assets/logo.png
Normal file
BIN
bot/assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 188 KiB |
3
bot/assets/logo.svg
Normal file
3
bot/assets/logo.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 500 KiB |
@@ -1,21 +1,22 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
from __future__ import annotations
|
||||
from core import zyrox
|
||||
from colorama import Fore, Style, init
|
||||
|
||||
from colorama import Fore, Style
|
||||
|
||||
from core import Axiom
|
||||
from utils.config import BotName
|
||||
|
||||
from .commands.help import Help
|
||||
from .commands.general import General
|
||||
@@ -25,7 +26,7 @@ from .commands.welcome import Welcomer
|
||||
from .commands.fun import Fun
|
||||
from .commands.Games import Games
|
||||
from .commands.extra import Extra
|
||||
from .commands.owner import Owner
|
||||
from .commands.owner import Owner, Badges
|
||||
from .commands.voice import Voice
|
||||
from .commands.afk import afk
|
||||
from .commands.ignore import Ignore
|
||||
@@ -39,8 +40,6 @@ from .commands.blacklist import Blacklist
|
||||
from .commands.block import Block
|
||||
from .commands.nightmode import Nightmode
|
||||
from .commands.tracking import Tracking
|
||||
from .commands.owner import Badges
|
||||
#from .commands.map import Map
|
||||
from .commands.autoresponder import AutoResponder
|
||||
from .commands.customrole import Customrole
|
||||
from .commands.autorole import AutoRole
|
||||
@@ -64,12 +63,12 @@ from .commands.filters import FilterCog
|
||||
from .commands.owner2 import Global
|
||||
from .commands.qr import QR
|
||||
from .commands.vanityroles import VanityRoles
|
||||
from .commands.reactionroles import ReactionRoles
|
||||
from .commands.reactionroles import ReactionRoles
|
||||
from .commands.messages import Messages
|
||||
from .commands.fastgreet import FastGreet
|
||||
from .commands.counting import Counting
|
||||
from .commands.j2c import JoinToCreate
|
||||
from .commands.ai import AI
|
||||
from .commands.ai import AI
|
||||
from .commands.dms import StaffDMCog
|
||||
from .commands.booster import Booster
|
||||
from .commands.leveling import Leveling
|
||||
@@ -83,9 +82,7 @@ from .commands.Birthday import Birthdays
|
||||
from .commands.nitro import Nitro
|
||||
from .commands.image import ImageCommands
|
||||
from .commands.youtube import Youtube
|
||||
#____________ Events _____________
|
||||
|
||||
#from .events.autoblacklist import AutoBlacklist
|
||||
from .events.Errors import Errors
|
||||
from .events.on_guild import Guild
|
||||
from .events.autorole import Autorole2
|
||||
@@ -94,43 +91,37 @@ from .events.greet2 import greet
|
||||
from .events.mention import Mention
|
||||
from .events.react import React
|
||||
from .events.autoreact import AutoReactListener
|
||||
#from .events.topgg import TopGG
|
||||
from .events.ai import AIResponses
|
||||
from .events.ai import AIResponses
|
||||
from .events.stickymessage import StickyMessageListener
|
||||
|
||||
########-------HELP-------########
|
||||
from .zyrox.antinuke import _antinuke
|
||||
from .zyrox.extra import _extra
|
||||
from .zyrox.general import _general
|
||||
from .zyrox.automod import _automod
|
||||
from .zyrox.moderation import _moderation
|
||||
#from .zyrox.inviteTracker import _inviteTracker
|
||||
from .zyrox.music import _music
|
||||
from .zyrox.fun import _fun
|
||||
from .zyrox.games import _games
|
||||
from .zyrox.ignore import _ignore
|
||||
from .zyrox.server import _server
|
||||
from .zyrox.voice import _voice
|
||||
from .zyrox.welcome import _welcome
|
||||
from .zyrox.giveaway import _giveaway
|
||||
from .zyrox.ticket import _ticket
|
||||
#from .axon.vanityroles import Vanityroles69999
|
||||
from .zyrox.logging import _logging
|
||||
from .zyrox.vanity import _vanity
|
||||
from .zyrox.inviteTracker import inviteTracker
|
||||
from .zyrox.counting import _Counting
|
||||
from .zyrox.j2c import _J2C
|
||||
from .zyrox.ai import _ai
|
||||
from .zyrox.booster import __boost
|
||||
from .zyrox.leveling import _leveling
|
||||
from .zyrox.sticky import _sticky
|
||||
from .zyrox.verify import _verify
|
||||
from .zyrox.encryption import _encrypt
|
||||
from .zyrox.mc import _mc
|
||||
from .zyrox.joindm import _joindm
|
||||
from .zyrox.birth import _birth
|
||||
|
||||
#########ANTINUKE#########
|
||||
from .axiom.antinuke import _antinuke
|
||||
from .axiom.extra import _extra
|
||||
from .axiom.general import _general
|
||||
from .axiom.automod import _automod
|
||||
from .axiom.moderation import _moderation
|
||||
from .axiom.music import _music
|
||||
from .axiom.fun import _fun
|
||||
from .axiom.games import _games
|
||||
from .axiom.ignore import _ignore
|
||||
from .axiom.server import _server
|
||||
from .axiom.voice import _voice
|
||||
from .axiom.welcome import _welcome
|
||||
from .axiom.giveaway import _giveaway
|
||||
from .axiom.ticket import _ticket
|
||||
from .axiom.logging import _logging
|
||||
from .axiom.vanity import _vanity
|
||||
from .axiom.inviteTracker import inviteTracker
|
||||
from .axiom.counting import _Counting
|
||||
from .axiom.j2c import _J2C
|
||||
from .axiom.ai import _ai
|
||||
from .axiom.booster import __boost
|
||||
from .axiom.leveling import _leveling
|
||||
from .axiom.sticky import _sticky
|
||||
from .axiom.verify import _verify
|
||||
from .axiom.encryption import _encrypt
|
||||
from .axiom.mc import _mc
|
||||
from .axiom.joindm import _joindm
|
||||
from .axiom.birth import _birth
|
||||
|
||||
from .antinuke.anti_member_update import AntiMemberUpdate
|
||||
from .antinuke.antiban import AntiBan
|
||||
@@ -150,15 +141,6 @@ from .antinuke.antiwebhook import AntiWebhookUpdate
|
||||
from .antinuke.antiwebhookcr import AntiWebhookCreate
|
||||
from .antinuke.antiwebhookdl import AntiWebhookDelete
|
||||
|
||||
#Extra Optional Events
|
||||
|
||||
#from .antinuke.antiemocr import AntiEmojiCreate
|
||||
#from .antinuke.antiemodl import AntiEmojiDelete
|
||||
#from .antinuke.antiemoup import AntiEmojiUpdate
|
||||
#from .antinuke.antisticker import AntiSticker
|
||||
#from .antinuke.antiunban import AntiUnban
|
||||
|
||||
############ AUTOMOD ############
|
||||
from .automod.antispam import AntiSpam
|
||||
from .automod.anticaps import AntiCaps
|
||||
from .automod.antilink import AntiLink
|
||||
@@ -166,7 +148,6 @@ from .automod.anti_invites import AntiInvite
|
||||
from .automod.anti_mass_mention import AntiMassMention
|
||||
from .automod.anti_emoji_spam import AntiEmojiSpam
|
||||
|
||||
|
||||
from .moderation.ban import Ban
|
||||
from .moderation.unban import Unban
|
||||
from .moderation.timeout import Mute
|
||||
@@ -180,197 +161,49 @@ from .moderation.warn import Warn
|
||||
from .moderation.role import Role
|
||||
from .moderation.message import Message
|
||||
from .moderation.moderation import Moderation
|
||||
from .moderation.mod_hub import ModHub
|
||||
from .moderation.topcheck import TopCheck
|
||||
from .moderation.snipe import Snipe
|
||||
|
||||
|
||||
from utils.config import BotName
|
||||
|
||||
async def setup(bot: zyrox):
|
||||
cogs_to_load = [
|
||||
Help, General, Moderation, Automod, Welcomer, Fun, Games, Extra,
|
||||
Voice, Owner, Customrole, afk, Embed, Media, Ignore, TicketCog, Logging,
|
||||
Invcrole, Steal, Timer,
|
||||
Blacklist, Block, Nightmode, Badges, Antinuke, Whitelist,
|
||||
Unwhitelist, Extraowner, Blackjack, Slots, Guild, Errors, Autorole2, Autorole, greet, AutoResponder,
|
||||
Mention, AutoRole, React, AntiMemberUpdate, AntiBan, AntiBotAdd,
|
||||
AntiChannelCreate, AntiChannelDelete, AntiChannelUpdate, AntiEveryone, AntiGuildUpdate,
|
||||
AntiIntegration, AntiKick, AntiPrune, AntiRoleCreate, AntiRoleDelete,
|
||||
AntiRoleUpdate, AntiWebhookUpdate, AntiWebhookCreate,
|
||||
AntiWebhookDelete, AntiSpam, AntiCaps, AntiLink, AntiInvite, AntiMassMention, Stats, Status, NoPrefix, FilterCog, AutoReaction, AutoReactListener, Ban, Unban, Mute, Unmute, Lock, Unlock, Hide, Unhide, Kick, Warn, Role, Message, Moderation, TopCheck, Snipe, Global, QR, VanityRoles, ReactionRoles, Messages, TranslateCog, FastGreet, Jail, inviteTracker,Counting,AI
|
||||
]
|
||||
# Load order preserved from legacy manual registration.
|
||||
COG_CLASSES: tuple[type, ...] = (
|
||||
Help, General, Music, Automod, Welcomer, Fun, Tracking, Games, Extra,
|
||||
Voice, Owner, Customrole, afk, Embed, Media, Ignore, Invcrole, Giveaway,
|
||||
Steal, Booster, Timer, Blacklist, Block, Nightmode, Badges, Antinuke,
|
||||
Whitelist, Unwhitelist, Extraowner, Slots, Blackjack, Stats, Emergency,
|
||||
Status, NoPrefix, FilterCog, Global, TicketCog, Logging, QR, VanityRoles,
|
||||
ReactionRoles, Messages, TranslateCog, FastGreet, Jail, JoinToCreate, AI,
|
||||
StaffDMCog, Leveling, StickyMessage, Verification, Minecraft, encryption,
|
||||
calculator, joindm, Birthdays, Nitro, ImageCommands, Youtube,
|
||||
_antinuke, _extra, _general, _automod, _moderation, _music, _fun, _games,
|
||||
_ignore, _server, _voice, _welcome, _giveaway, _ticket, _logging, _vanity,
|
||||
inviteTracker, Counting, _Counting, _J2C, _ai, __boost, _leveling, _sticky,
|
||||
_verify, _encrypt, _mc, _joindm, _birth,
|
||||
Guild, Errors, Autorole2, Autorole, greet, AutoResponder, Mention, AutoRole,
|
||||
React, AutoReaction, AutoReactListener, NotifCommands, StickyMessageListener,
|
||||
AIResponses,
|
||||
AntiMemberUpdate, AntiBan, AntiBotAdd, AntiChannelCreate, AntiChannelDelete,
|
||||
AntiChannelUpdate, AntiEveryone, AntiGuildUpdate, AntiIntegration, AntiKick,
|
||||
AntiPrune, AntiRoleCreate, AntiRoleDelete, AntiRoleUpdate, AntiWebhookUpdate,
|
||||
AntiWebhookCreate, AntiWebhookDelete,
|
||||
AntiSpam, AntiCaps, AntiInvite, AntiLink, AntiMassMention, AntiEmojiSpam,
|
||||
Ban, Unban, Mute, Unmute, Lock, Unlock, Hide, Unhide, Kick, Warn, Role,
|
||||
Message, Moderation, ModHub, TopCheck, Snipe,
|
||||
)
|
||||
|
||||
|
||||
await bot.add_cog(Help(bot))
|
||||
await bot.add_cog(General(bot))
|
||||
await bot.add_cog(Music(bot))
|
||||
await bot.add_cog(Automod(bot))
|
||||
await bot.add_cog(Welcomer(bot))
|
||||
await bot.add_cog(Fun(bot))
|
||||
await bot.add_cog(Tracking(bot))
|
||||
await bot.add_cog(Games(bot))
|
||||
await bot.add_cog(Extra(bot))
|
||||
await bot.add_cog(Voice(bot))
|
||||
await bot.add_cog(Owner(bot))
|
||||
await bot.add_cog(Customrole(bot))
|
||||
await bot.add_cog(afk(bot))
|
||||
await bot.add_cog(Embed(bot))
|
||||
await bot.add_cog(Media(bot))
|
||||
await bot.add_cog(Ignore(bot))
|
||||
await bot.add_cog(Invcrole(bot))
|
||||
await bot.add_cog(Giveaway(bot))
|
||||
await bot.add_cog(Steal(bot))
|
||||
await bot.add_cog(Booster(bot))
|
||||
await bot.add_cog(Timer(bot))
|
||||
await bot.add_cog(Blacklist(bot))
|
||||
await bot.add_cog(Block(bot))
|
||||
await bot.add_cog(Nightmode(bot))
|
||||
await bot.add_cog(Badges(bot))
|
||||
await bot.add_cog(Antinuke(bot))
|
||||
await bot.add_cog(Whitelist(bot))
|
||||
await bot.add_cog(Unwhitelist(bot))
|
||||
await bot.add_cog(Extraowner(bot))
|
||||
await bot.add_cog(Slots(bot))
|
||||
await bot.add_cog(Blackjack(bot))
|
||||
await bot.add_cog(Stats(bot))
|
||||
await bot.add_cog(Emergency(bot))
|
||||
await bot.add_cog(Status(bot))
|
||||
await bot.add_cog(NoPrefix(bot))
|
||||
await bot.add_cog(FilterCog(bot))
|
||||
await bot.add_cog(Global(bot))
|
||||
# await bot.add_cog(Map(bot))
|
||||
await bot.add_cog(TicketCog(bot))
|
||||
await bot.add_cog(Logging(bot))
|
||||
await bot.add_cog(QR(bot))
|
||||
await bot.add_cog(VanityRoles(bot))
|
||||
await bot.add_cog(ReactionRoles(bot))
|
||||
await bot.add_cog(Messages(bot))
|
||||
await bot.add_cog(TranslateCog(bot))
|
||||
await bot.add_cog(FastGreet(bot))
|
||||
await bot.add_cog(Jail(bot))
|
||||
await bot.add_cog(JoinToCreate(bot))
|
||||
await bot.add_cog(AI(bot))
|
||||
await bot.add_cog(StaffDMCog(bot))
|
||||
await bot.add_cog(Leveling(bot))
|
||||
await bot.add_cog(StickyMessage(bot))
|
||||
await bot.add_cog(Verification(bot))
|
||||
await bot.add_cog(Minecraft(bot))
|
||||
await bot.add_cog(encryption(bot))
|
||||
await bot.add_cog(calculator(bot))
|
||||
await bot.add_cog(joindm(bot))
|
||||
await bot.add_cog(Birthdays(bot))
|
||||
await bot.add_cog(Nitro(bot))
|
||||
await bot.add_cog(ImageCommands(bot))
|
||||
await bot.add_cog(Youtube(bot))
|
||||
async def setup(bot: Axiom) -> None:
|
||||
loaded = 0
|
||||
for cog_cls in COG_CLASSES:
|
||||
try:
|
||||
await bot.add_cog(cog_cls(bot))
|
||||
loaded += 1
|
||||
print(Fore.GREEN + Style.BRIGHT + f"Loaded cog: {cog_cls.__name__}")
|
||||
except Exception as e:
|
||||
print(
|
||||
Fore.RED
|
||||
+ Style.BRIGHT
|
||||
+ f"Failed cog {getattr(cog_cls, '__name__', cog_cls)}: {type(e).__name__}: {e}"
|
||||
)
|
||||
|
||||
await bot.add_cog(_antinuke(bot))
|
||||
await bot.add_cog(_extra(bot))
|
||||
await bot.add_cog(_general(bot))
|
||||
await bot.add_cog(_automod(bot))
|
||||
await bot.add_cog(_moderation(bot))
|
||||
await bot.add_cog(_music(bot))
|
||||
await bot.add_cog(_fun(bot))
|
||||
await bot.add_cog(_games(bot))
|
||||
await bot.add_cog(_ignore(bot))
|
||||
await bot.add_cog(_server(bot))
|
||||
await bot.add_cog(_voice(bot))
|
||||
await bot.add_cog(_welcome(bot))
|
||||
await bot.add_cog(_giveaway(bot))
|
||||
await bot.add_cog(_ticket(bot))
|
||||
await bot.add_cog(_logging(bot))
|
||||
await bot.add_cog(_vanity(bot))
|
||||
await bot.add_cog(inviteTracker(bot))
|
||||
await bot.add_cog(Counting(bot))
|
||||
await bot.add_cog(_Counting(bot))
|
||||
await bot.add_cog(_J2C(bot))
|
||||
await bot.add_cog(_ai(bot))
|
||||
await bot.add_cog(__boost(bot))
|
||||
await bot.add_cog(_leveling(bot))
|
||||
await bot.add_cog(_sticky(bot))
|
||||
await bot.add_cog(_verify(bot))
|
||||
await bot.add_cog(_encrypt(bot))
|
||||
await bot.add_cog(_mc(bot))
|
||||
await bot.add_cog(_joindm(bot))
|
||||
await bot.add_cog(_birth(bot))
|
||||
|
||||
|
||||
|
||||
#await bot.add_cog(AutoBlacklist(bot))
|
||||
await bot.add_cog(Guild(bot))
|
||||
await bot.add_cog(Errors(bot))
|
||||
await bot.add_cog(Autorole2(bot))
|
||||
await bot.add_cog(Autorole(bot))
|
||||
await bot.add_cog(greet(bot))
|
||||
await bot.add_cog(AutoResponder(bot))
|
||||
await bot.add_cog(Mention(bot))
|
||||
await bot.add_cog(AutoRole(bot))
|
||||
await bot.add_cog(React(bot))
|
||||
await bot.add_cog(AutoReaction(bot))
|
||||
await bot.add_cog(AutoReactListener(bot))
|
||||
await bot.add_cog(NotifCommands(bot))
|
||||
await bot.add_cog(StickyMessageListener(bot))
|
||||
await bot.add_cog(AIResponses(bot))
|
||||
|
||||
|
||||
await bot.add_cog(AntiMemberUpdate(bot))
|
||||
await bot.add_cog(AntiBan(bot))
|
||||
await bot.add_cog(AntiBotAdd(bot))
|
||||
await bot.add_cog(AntiChannelCreate(bot))
|
||||
await bot.add_cog(AntiChannelDelete(bot))
|
||||
await bot.add_cog(AntiChannelUpdate(bot))
|
||||
await bot.add_cog(AntiEveryone(bot))
|
||||
await bot.add_cog(AntiGuildUpdate(bot))
|
||||
await bot.add_cog(AntiIntegration(bot))
|
||||
await bot.add_cog(AntiKick(bot))
|
||||
await bot.add_cog(AntiPrune(bot))
|
||||
await bot.add_cog(AntiRoleCreate(bot))
|
||||
await bot.add_cog(AntiRoleDelete(bot))
|
||||
await bot.add_cog(AntiRoleUpdate(bot))
|
||||
await bot.add_cog(AntiWebhookUpdate(bot))
|
||||
await bot.add_cog(AntiWebhookCreate(bot))
|
||||
await bot.add_cog(AntiWebhookDelete(bot))
|
||||
|
||||
|
||||
#Extra Optional Events
|
||||
|
||||
#await bot.add_cog(AntiEmojiCreate(bot))
|
||||
#await bot.add_cog(AntiEmojiDelete(bot))
|
||||
#await bot.add_cog(AntiEmojiUpdate(bot))
|
||||
#await bot.add_cog(AntiSticker(bot))
|
||||
#await bot.add_cog(AntiUnban(bot))
|
||||
|
||||
|
||||
await bot.add_cog(AntiSpam(bot))
|
||||
await bot.add_cog(AntiCaps(bot))
|
||||
await bot.add_cog(AntiInvite(bot))
|
||||
await bot.add_cog(AntiLink(bot))
|
||||
await bot.add_cog(AntiMassMention(bot))
|
||||
await bot.add_cog(AntiEmojiSpam(bot))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
await bot.add_cog(Ban(bot))
|
||||
await bot.add_cog(Unban(bot))
|
||||
await bot.add_cog(Mute(bot))
|
||||
await bot.add_cog(Unmute(bot))
|
||||
await bot.add_cog(Lock(bot))
|
||||
await bot.add_cog(Unlock(bot))
|
||||
await bot.add_cog(Hide(bot))
|
||||
await bot.add_cog(Unhide(bot))
|
||||
await bot.add_cog(Kick(bot))
|
||||
await bot.add_cog(Warn(bot))
|
||||
await bot.add_cog(Role(bot))
|
||||
await bot.add_cog(Message(bot))
|
||||
await bot.add_cog(Moderation(bot))
|
||||
await bot.add_cog(TopCheck(bot))
|
||||
await bot.add_cog(Snipe(bot))
|
||||
|
||||
|
||||
|
||||
for cog in cogs_to_load:
|
||||
print(Fore.RED + Style.BRIGHT + f"Loaded cog: {cog.__name__}")
|
||||
print(Fore.RED + Style.BRIGHT + f"All {BotName} Cogs loaded successfully.")
|
||||
print(Fore.GREEN + Style.BRIGHT + f"Loaded {loaded}/{len(COG_CLASSES)} {BotName} cogs.")
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
@@ -61,7 +61,7 @@ class AntiIntegration(commands.Cog):
|
||||
return True
|
||||
|
||||
async def is_blacklisted_guild(self, guild_id):
|
||||
async with aiosqlite.connect('db/block.db') as block_db:
|
||||
async with aiosqlite.connect(db_path('block.db')) as block_db:
|
||||
cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),))
|
||||
return await cursor.fetchone() is not None
|
||||
|
||||
@@ -70,7 +70,7 @@ class AntiIntegration(commands.Cog):
|
||||
if await self.is_blacklisted_guild(guild.id):
|
||||
return
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
|
||||
antinuke_status = await cursor.fetchone()
|
||||
|
||||
@@ -89,7 +89,7 @@ class AntiIntegration(commands.Cog):
|
||||
if executor.id in {guild.owner_id, self.bot.user.id}:
|
||||
return
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT owner_id FROM extraowners WHERE guild_id = ? AND owner_id = ?",
|
||||
(guild.id, executor.id)) as cursor:
|
||||
extraowner_status = await cursor.fetchone()
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
@@ -26,7 +26,7 @@ class AntiMemberUpdate(commands.Cog):
|
||||
self.cooldowns = {}
|
||||
|
||||
async def is_blacklisted_guild(self, guild_id):
|
||||
async with aiosqlite.connect('db/block.db') as block_db:
|
||||
async with aiosqlite.connect(db_path('block.db')) as block_db:
|
||||
cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),))
|
||||
return await cursor.fetchone() is not None
|
||||
|
||||
@@ -71,7 +71,7 @@ class AntiMemberUpdate(commands.Cog):
|
||||
if await self.is_blacklisted_guild(guild.id):
|
||||
return
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
|
||||
antinuke_status = await cursor.fetchone()
|
||||
if not antinuke_status or not antinuke_status[0]:
|
||||
@@ -88,7 +88,7 @@ class AntiMemberUpdate(commands.Cog):
|
||||
if executor.id in {guild.owner_id, self.bot.user.id}:
|
||||
return
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT owner_id FROM extraowners WHERE guild_id = ? AND owner_id = ?",
|
||||
(guild.id, executor.id)) as cursor:
|
||||
extra_owner_status = await cursor.fetchone()
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
@@ -59,7 +59,7 @@ class AntiBan(commands.Cog):
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_member_ban(self, guild, user):
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
|
||||
antinuke_status = await cursor.fetchone()
|
||||
if not antinuke_status or not antinuke_status[0]:
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
@@ -63,7 +63,7 @@ class AntiBotAdd(commands.Cog):
|
||||
return
|
||||
|
||||
guild = member.guild
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
|
||||
antinuke_status = await cursor.fetchone()
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
@@ -89,7 +89,7 @@ class AntiChannelCreate(commands.Cog):
|
||||
async def on_guild_channel_create(self, channel):
|
||||
guild = channel.guild
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
|
||||
antinuke_status = await cursor.fetchone()
|
||||
if not antinuke_status or not antinuke_status[0]:
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
@@ -60,7 +60,7 @@ class AntiChannelDelete(commands.Cog):
|
||||
@commands.Cog.listener()
|
||||
async def on_guild_channel_delete(self, channel):
|
||||
guild = channel.guild
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
|
||||
antinuke_status = await cursor.fetchone()
|
||||
if not antinuke_status or not antinuke_status[0]:
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
@@ -60,7 +60,7 @@ class AntiChannelUpdate(commands.Cog):
|
||||
@commands.Cog.listener()
|
||||
async def on_guild_channel_update(self, before, after):
|
||||
guild = before.guild
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
|
||||
antinuke_status = await cursor.fetchone()
|
||||
if not antinuke_status or not antinuke_status[0]:
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
@@ -44,7 +44,7 @@ class AntiEveryone(commands.Cog):
|
||||
|
||||
guild = message.guild
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
|
||||
antinuke_status = await cursor.fetchone()
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
@@ -61,7 +61,7 @@ class AntiGuildUpdate(commands.Cog):
|
||||
return True
|
||||
|
||||
async def is_blacklisted_guild(self, guild_id):
|
||||
async with aiosqlite.connect('db/block.db') as block_db:
|
||||
async with aiosqlite.connect(db_path('block.db')) as block_db:
|
||||
cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),))
|
||||
return await cursor.fetchone() is not None
|
||||
|
||||
@@ -71,7 +71,7 @@ class AntiGuildUpdate(commands.Cog):
|
||||
if await self.is_blacklisted_guild(guild.id):
|
||||
return
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
|
||||
antinuke_status = await cursor.fetchone()
|
||||
|
||||
@@ -93,7 +93,7 @@ class AntiGuildUpdate(commands.Cog):
|
||||
if executor.id in {guild.owner_id, self.bot.user.id}:
|
||||
return
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT serverup FROM whitelisted_users WHERE guild_id = ? AND user_id = ?",
|
||||
(guild.id, executor.id)) as cursor:
|
||||
whitelist_status = await cursor.fetchone()
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
@@ -26,7 +26,7 @@ class AntiKick(commands.Cog):
|
||||
self.cooldowns = {}
|
||||
|
||||
async def is_blacklisted_guild(self, guild_id):
|
||||
async with aiosqlite.connect('db/block.db') as block_db:
|
||||
async with aiosqlite.connect(db_path('block.db')) as block_db:
|
||||
cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),))
|
||||
return await cursor.fetchone() is not None
|
||||
|
||||
@@ -70,7 +70,7 @@ class AntiKick(commands.Cog):
|
||||
if await self.is_blacklisted_guild(member.guild.id):
|
||||
return
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (member.guild.id,)) as cursor:
|
||||
antinuke_status = await cursor.fetchone()
|
||||
if not antinuke_status or not antinuke_status[0]:
|
||||
@@ -87,7 +87,7 @@ class AntiKick(commands.Cog):
|
||||
if executor.id in {member.guild.owner_id, self.bot.user.id}:
|
||||
return
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT owner_id FROM extraowners WHERE guild_id = ? AND owner_id = ?",
|
||||
(member.guild.id, executor.id)) as cursor:
|
||||
extraowner_status = await cursor.fetchone()
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
@@ -42,7 +42,7 @@ class AntiPrune(commands.Cog):
|
||||
@commands.Cog.listener()
|
||||
async def on_member_remove(self, member):
|
||||
guild = member.guild
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
|
||||
antinuke_status = await cursor.fetchone()
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
@@ -26,7 +26,7 @@ class AntiRoleCreate(commands.Cog):
|
||||
self.cooldowns = {}
|
||||
|
||||
async def is_blacklisted_guild(self, guild_id):
|
||||
async with aiosqlite.connect('db/block.db') as block_db:
|
||||
async with aiosqlite.connect(db_path('block.db')) as block_db:
|
||||
cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),))
|
||||
return await cursor.fetchone() is not None
|
||||
|
||||
@@ -71,7 +71,7 @@ class AntiRoleCreate(commands.Cog):
|
||||
if await self.is_blacklisted_guild(guild.id):
|
||||
return
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
|
||||
antinuke_status = await cursor.fetchone()
|
||||
if not antinuke_status or not antinuke_status[0]:
|
||||
@@ -89,7 +89,7 @@ class AntiRoleCreate(commands.Cog):
|
||||
if executor.id in {guild.owner_id, self.bot.user.id}:
|
||||
return
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT owner_id FROM extraowners WHERE guild_id = ? AND owner_id = ?",
|
||||
(guild.id, executor.id)) as cursor:
|
||||
extra_owner_status = await cursor.fetchone()
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
@@ -26,7 +26,7 @@ class AntiRoleDelete(commands.Cog):
|
||||
self.cooldowns = {}
|
||||
|
||||
async def is_blacklisted_guild(self, guild_id):
|
||||
async with aiosqlite.connect('db/block.db') as block_db:
|
||||
async with aiosqlite.connect(db_path('block.db')) as block_db:
|
||||
cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),))
|
||||
return await cursor.fetchone() is not None
|
||||
|
||||
@@ -71,7 +71,7 @@ class AntiRoleDelete(commands.Cog):
|
||||
if await self.is_blacklisted_guild(guild.id):
|
||||
return
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
|
||||
antinuke_status = await cursor.fetchone()
|
||||
if not antinuke_status or not antinuke_status[0]:
|
||||
@@ -89,7 +89,7 @@ class AntiRoleDelete(commands.Cog):
|
||||
if executor.id in {guild.owner_id, self.bot.user.id}:
|
||||
return
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT owner_id FROM extraowners WHERE guild_id = ? AND owner_id = ?",
|
||||
(guild.id, executor.id)) as cursor:
|
||||
extra_owner_status = await cursor.fetchone()
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
@@ -26,7 +26,7 @@ class AntiRoleUpdate(commands.Cog):
|
||||
self.cooldowns = {}
|
||||
|
||||
async def is_blacklisted_guild(self, guild_id):
|
||||
async with aiosqlite.connect('db/block.db') as block_db:
|
||||
async with aiosqlite.connect(db_path('block.db')) as block_db:
|
||||
cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),))
|
||||
return await cursor.fetchone() is not None
|
||||
|
||||
@@ -71,7 +71,7 @@ class AntiRoleUpdate(commands.Cog):
|
||||
if await self.is_blacklisted_guild(guild.id):
|
||||
return
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
|
||||
antinuke_status = await cursor.fetchone()
|
||||
if not antinuke_status or not antinuke_status[0]:
|
||||
@@ -89,7 +89,7 @@ class AntiRoleUpdate(commands.Cog):
|
||||
if executor.id in {guild.owner_id, self.bot.user.id}:
|
||||
return
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT rlup FROM whitelisted_users WHERE guild_id = ? AND user_id = ?",
|
||||
(guild.id, executor.id)) as cursor:
|
||||
whitelist_status = await cursor.fetchone()
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
@@ -58,7 +58,7 @@ class AntiWebhookUpdate(commands.Cog):
|
||||
return True
|
||||
|
||||
async def is_blacklisted_guild(self, guild_id):
|
||||
async with aiosqlite.connect('db/block.db') as block_db:
|
||||
async with aiosqlite.connect(db_path('block.db')) as block_db:
|
||||
cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),))
|
||||
return await cursor.fetchone() is not None
|
||||
|
||||
@@ -68,7 +68,7 @@ class AntiWebhookUpdate(commands.Cog):
|
||||
if await self.is_blacklisted_guild(guild.id):
|
||||
return
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
|
||||
antinuke_status = await cursor.fetchone()
|
||||
|
||||
@@ -87,7 +87,7 @@ class AntiWebhookUpdate(commands.Cog):
|
||||
if executor.id in {guild.owner_id, self.bot.user.id}:
|
||||
return
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT mngweb FROM whitelisted_users WHERE guild_id = ? AND user_id = ?",
|
||||
(guild.id, executor.id)) as cursor:
|
||||
whitelist_status = await cursor.fetchone()
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
@@ -58,7 +58,7 @@ class AntiWebhookCreate(commands.Cog):
|
||||
return True
|
||||
|
||||
async def is_blacklisted_guild(self, guild_id):
|
||||
async with aiosqlite.connect('db/block.db') as block_db:
|
||||
async with aiosqlite.connect(db_path('block.db')) as block_db:
|
||||
cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),))
|
||||
return await cursor.fetchone() is not None
|
||||
|
||||
@@ -68,7 +68,7 @@ class AntiWebhookCreate(commands.Cog):
|
||||
if await self.is_blacklisted_guild(guild.id):
|
||||
return
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
|
||||
antinuke_status = await cursor.fetchone()
|
||||
|
||||
@@ -87,7 +87,7 @@ class AntiWebhookCreate(commands.Cog):
|
||||
if executor.id in {guild.owner_id, self.bot.user.id}:
|
||||
return
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT mngweb FROM whitelisted_users WHERE guild_id = ? AND user_id = ?",
|
||||
(guild.id, executor.id)) as cursor:
|
||||
whitelist_status = await cursor.fetchone()
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
@@ -58,7 +58,7 @@ class AntiWebhookDelete(commands.Cog):
|
||||
return True
|
||||
|
||||
async def is_blacklisted_guild(self, guild_id):
|
||||
async with aiosqlite.connect('db/block.db') as block_db:
|
||||
async with aiosqlite.connect(db_path('block.db')) as block_db:
|
||||
cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),))
|
||||
return await cursor.fetchone() is not None
|
||||
|
||||
@@ -68,7 +68,7 @@ class AntiWebhookDelete(commands.Cog):
|
||||
if await self.is_blacklisted_guild(guild.id):
|
||||
return
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
|
||||
antinuke_status = await cursor.fetchone()
|
||||
|
||||
@@ -87,7 +87,7 @@ class AntiWebhookDelete(commands.Cog):
|
||||
if executor.id in {guild.owner_id, self.bot.user.id}:
|
||||
return
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT mngweb FROM whitelisted_users WHERE guild_id = ? AND user_id = ?",
|
||||
(guild.id, executor.id)) as cursor:
|
||||
whitelist_status = await cursor.fetchone()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from utils.db_paths import db_path
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
import aiosqlite
|
||||
@@ -29,7 +30,7 @@ class AntiEmojiCreate(commands.Cog):
|
||||
@commands.Cog.listener()
|
||||
async def on_guild_emojis_update(self, guild, before, after):
|
||||
if len(after) > len(before):
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
|
||||
antinuke_status = await cursor.fetchone()
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from utils.db_paths import db_path
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
import aiosqlite
|
||||
@@ -29,7 +30,7 @@ class AntiEmojiDelete(commands.Cog):
|
||||
@commands.Cog.listener()
|
||||
async def on_guild_emojis_update(self, guild, before, after):
|
||||
if len(after) < len(before):
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
|
||||
antinuke_status = await cursor.fetchone()
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from utils.db_paths import db_path
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
import aiosqlite
|
||||
@@ -29,7 +30,7 @@ class AntiEmojiUpdate(commands.Cog):
|
||||
@commands.Cog.listener()
|
||||
async def on_guild_emojis_update(self, guild, before, after):
|
||||
if len(after) == len(before): # An emoji was updated
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
|
||||
antinuke_status = await cursor.fetchone()
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from utils.db_paths import db_path
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
from datetime import timedelta, datetime
|
||||
@@ -34,7 +35,7 @@ class AntiSticker(commands.Cog):
|
||||
else:
|
||||
action = discord.AuditLogAction.sticker_update
|
||||
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
|
||||
antinuke_status = await cursor.fetchone()
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from utils.db_paths import db_path
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
import aiosqlite
|
||||
@@ -26,7 +27,7 @@ class AntiUnban(commands.Cog):
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_member_unban(self, guild, user):
|
||||
async with aiosqlite.connect('db/anti.db') as db:
|
||||
async with aiosqlite.connect(db_path('anti.db')) as db:
|
||||
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
|
||||
antinuke_status = await cursor.fetchone()
|
||||
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
from utils.automod_settings import get_thresholds
|
||||
|
||||
import discord
|
||||
from utils.emoji import TICK
|
||||
@@ -23,38 +24,37 @@ import asyncio
|
||||
class AntiEmojiSpam(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.emoji_threshold = 5
|
||||
|
||||
async def is_automod_enabled(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,))
|
||||
result = await cursor.fetchone()
|
||||
return result is not None and result[0] == 1
|
||||
|
||||
async def is_anti_emoji_spam_enabled(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti emoji spam'", (guild_id,))
|
||||
result = await cursor.fetchone()
|
||||
return result is not None
|
||||
|
||||
async def get_ignored_channels(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,))
|
||||
return [row[0] for row in await cursor.fetchall()]
|
||||
|
||||
async def get_ignored_roles(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,))
|
||||
return [row[0] for row in await cursor.fetchall()]
|
||||
|
||||
async def get_punishment(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti emoji spam'", (guild_id,))
|
||||
result = await cursor.fetchone()
|
||||
return result[0] if result else None
|
||||
|
||||
async def log_action(self, guild, user, channel, action, reason):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild.id,))
|
||||
log_channel_id = await cursor.fetchone()
|
||||
|
||||
@@ -118,17 +118,20 @@ class AntiEmojiSpam(commands.Cog):
|
||||
|
||||
|
||||
emoji_count = len(emoji_pattern.findall(message.content))
|
||||
th = await get_thresholds(guild_id, "anti_emoji_spam")
|
||||
emoji_threshold = int(th.get("max_emojis", 5))
|
||||
mute_minutes = float(th.get("mute_minutes", 1))
|
||||
|
||||
if emoji_count > self.emoji_threshold:
|
||||
if emoji_count > emoji_threshold:
|
||||
punishment = await self.get_punishment(guild_id)
|
||||
action_taken = None
|
||||
reason = f"Emoji Spam ({emoji_count} emojis)"
|
||||
|
||||
try:
|
||||
if punishment == "Mute":
|
||||
timeout_duration = discord.utils.utcnow() + timedelta(minutes=1)
|
||||
timeout_duration = discord.utils.utcnow() + timedelta(minutes=mute_minutes)
|
||||
await user.edit(timed_out_until=timeout_duration, reason=reason)
|
||||
action_taken = "Muted for 1 minute"
|
||||
action_taken = f"Muted for {int(mute_minutes)} minutes"
|
||||
elif punishment == "Kick":
|
||||
await user.kick(reason=reason)
|
||||
action_taken = "Kicked"
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
from utils.automod_settings import get_thresholds
|
||||
|
||||
import discord
|
||||
from utils.emoji import TICK
|
||||
@@ -26,35 +27,35 @@ class AntiInvite(commands.Cog):
|
||||
self.invite_pattern = re.compile(r'(https?://)?(www\.)?(discord\.gg|discordapp\.com/invite|discord\.com/invite)/\S+')
|
||||
|
||||
async def is_automod_enabled(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,))
|
||||
result = await cursor.fetchone()
|
||||
return result is not None and result[0] == 1
|
||||
|
||||
async def is_anti_invites_enabled(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti invites'", (guild_id,))
|
||||
result = await cursor.fetchone()
|
||||
return result is not None
|
||||
|
||||
async def get_ignored_channels(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,))
|
||||
return [row[0] for row in await cursor.fetchall()]
|
||||
|
||||
async def get_ignored_roles(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,))
|
||||
return [row[0] for row in await cursor.fetchall()]
|
||||
|
||||
async def get_punishment(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti invites'", (guild_id,))
|
||||
result = await cursor.fetchone()
|
||||
return result[0] if result else None
|
||||
|
||||
async def log_action(self, guild, user, channel, action, reason):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild.id,))
|
||||
log_channel_id = await cursor.fetchone()
|
||||
|
||||
@@ -105,15 +106,17 @@ class AntiInvite(commands.Cog):
|
||||
if any(invite.code == invite_code for invite in invite):
|
||||
return
|
||||
|
||||
th = await get_thresholds(guild_id, "anti_invites")
|
||||
mute_minutes = float(th.get("mute_minutes", 12))
|
||||
punishment = await self.get_punishment(guild_id)
|
||||
action_taken = None
|
||||
reason = "Posted an invite link"
|
||||
|
||||
try:
|
||||
if punishment == "Mute":
|
||||
timeout_duration = discord.utils.utcnow() + timedelta(minutes=12)
|
||||
timeout_duration = discord.utils.utcnow() + timedelta(minutes=mute_minutes)
|
||||
await user.edit(timed_out_until=timeout_duration, reason="Posted an invite link")
|
||||
action_taken = "Muted for 12 minutes"
|
||||
action_taken = f"Muted for {int(mute_minutes)} minutes"
|
||||
elif punishment == "Kick":
|
||||
await user.kick(reason="Posted an invite link")
|
||||
action_taken = "Kicked"
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
from utils.automod_settings import get_thresholds
|
||||
|
||||
import discord
|
||||
from utils.emoji import TICK
|
||||
@@ -22,39 +23,38 @@ import asyncio
|
||||
class AntiMassMention(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.mass_mention_threshold = 5
|
||||
|
||||
async def is_automod_enabled(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,))
|
||||
result = await cursor.fetchone()
|
||||
return result is not None and result[0] == 1
|
||||
|
||||
async def is_anti_mass_mention_enabled(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti mass mention'", (guild_id,))
|
||||
result = await cursor.fetchone()
|
||||
return result is not None
|
||||
|
||||
async def get_ignored_channels(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,))
|
||||
return [row[0] for row in await cursor.fetchall()]
|
||||
|
||||
async def get_ignored_roles(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,))
|
||||
return [row[0] for row in await cursor.fetchall()]
|
||||
|
||||
async def get_punishment(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti mass mention'", (guild_id,))
|
||||
result = await cursor.fetchone()
|
||||
return result[0] if result else None
|
||||
|
||||
|
||||
async def log_action(self, guild, user, channel, action, reason):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild.id,))
|
||||
log_channel_id = await cursor.fetchone()
|
||||
|
||||
@@ -97,17 +97,21 @@ class AntiMassMention(commands.Cog):
|
||||
return
|
||||
|
||||
|
||||
th = await get_thresholds(guild_id, "anti_mass_mention")
|
||||
mention_threshold = int(th.get("max_mentions", 5))
|
||||
mute_minutes = float(th.get("mute_minutes", 3))
|
||||
|
||||
mention_count = message.content.count("<@")
|
||||
if mention_count >= self.mass_mention_threshold:
|
||||
if mention_count >= mention_threshold:
|
||||
punishment = await self.get_punishment(guild_id)
|
||||
action_taken = None
|
||||
reason = f"Mass Mention ({mention_count} mentions)"
|
||||
|
||||
try:
|
||||
if punishment == "Mute":
|
||||
timeout_duration = discord.utils.utcnow() + timedelta(minutes=3)
|
||||
timeout_duration = discord.utils.utcnow() + timedelta(minutes=mute_minutes)
|
||||
await user.edit(timed_out_until=timeout_duration, reason=reason)
|
||||
action_taken = "Muted for 3 minutes"
|
||||
action_taken = f"Muted for {int(mute_minutes)} minutes"
|
||||
elif punishment == "Kick":
|
||||
await user.kick(reason=reason)
|
||||
action_taken = "Kicked"
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
from utils.automod_settings import get_thresholds
|
||||
|
||||
import discord
|
||||
from utils.emoji import TICK
|
||||
@@ -22,39 +23,37 @@ from datetime import timedelta
|
||||
class AntiCaps(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.caps_threshold = 70
|
||||
self.mute_duration = 2 * 60
|
||||
|
||||
async def is_automod_enabled(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,))
|
||||
result = await cursor.fetchone()
|
||||
return result is not None and result[0] == 1
|
||||
|
||||
async def is_anti_caps_enabled(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti caps'", (guild_id,))
|
||||
result = await cursor.fetchone()
|
||||
return result is not None
|
||||
|
||||
async def get_ignored_channels(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,))
|
||||
return [row[0] for row in await cursor.fetchall()]
|
||||
|
||||
async def get_ignored_roles(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,))
|
||||
return [row[0] for row in await cursor.fetchall()]
|
||||
|
||||
async def get_punishment(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti caps'", (guild_id,))
|
||||
result = await cursor.fetchone()
|
||||
return result[0] if result else None
|
||||
|
||||
async def log_action(self, guild, user, channel, action, reason):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild.id,))
|
||||
log_channel_id = await cursor.fetchone()
|
||||
|
||||
@@ -74,9 +73,6 @@ class AntiCaps(commands.Cog):
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_message(self, message):
|
||||
if len(message.content) < 45:
|
||||
return
|
||||
|
||||
if message.author.bot:
|
||||
return
|
||||
|
||||
@@ -85,6 +81,14 @@ class AntiCaps(commands.Cog):
|
||||
channel = message.channel
|
||||
guild_id = guild.id
|
||||
|
||||
th = await get_thresholds(guild_id, "anti_caps")
|
||||
min_length = int(th.get("min_length", 45))
|
||||
caps_threshold = float(th.get("percent", 70))
|
||||
mute_minutes = float(th.get("mute_minutes", 1))
|
||||
|
||||
if len(message.content) < min_length:
|
||||
return
|
||||
|
||||
if not await self.is_automod_enabled(guild_id) or not await self.is_anti_caps_enabled(guild_id):
|
||||
return
|
||||
|
||||
@@ -103,16 +107,16 @@ class AntiCaps(commands.Cog):
|
||||
caps_count = sum(1 for c in message.content if c.isupper())
|
||||
caps_percentage = (caps_count / len(message.content)) * 100
|
||||
|
||||
if caps_percentage > self.caps_threshold:
|
||||
if caps_percentage > caps_threshold:
|
||||
punishment = await self.get_punishment(guild_id)
|
||||
action_taken = None
|
||||
reason = "Excessive Caps"
|
||||
|
||||
try:
|
||||
if punishment == "Mute":
|
||||
timeout_duration = discord.utils.utcnow() + timedelta(minutes=1)
|
||||
timeout_duration = discord.utils.utcnow() + timedelta(minutes=mute_minutes)
|
||||
await user.edit(timed_out_until=timeout_duration, reason="Excessive Caps")
|
||||
action_taken = "Muted for 1 minutes"
|
||||
action_taken = f"Muted for {int(mute_minutes)} minutes"
|
||||
elif punishment == "Kick":
|
||||
await user.kick(reason="Excessive Caps")
|
||||
action_taken = "Kicked"
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
from utils.automod_settings import get_thresholds
|
||||
|
||||
import discord
|
||||
from utils.emoji import TICK
|
||||
@@ -29,35 +30,35 @@ class AntiLink(commands.Cog):
|
||||
self.spotify_pattern = re.compile(r'^https://open\.spotify\.com/track/\S+')
|
||||
|
||||
async def is_automod_enabled(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,))
|
||||
result = await cursor.fetchone()
|
||||
return result is not None and result[0] == 1
|
||||
|
||||
async def is_anti_link_enabled(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti link'", (guild_id,))
|
||||
result = await cursor.fetchone()
|
||||
return result is not None
|
||||
|
||||
async def get_ignored_channels(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,))
|
||||
return [row[0] for row in await cursor.fetchall()]
|
||||
|
||||
async def get_ignored_roles(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,))
|
||||
return [row[0] for row in await cursor.fetchall()]
|
||||
|
||||
async def get_punishment(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti link'", (guild_id,))
|
||||
result = await cursor.fetchone()
|
||||
return result[0] if result else None
|
||||
|
||||
async def log_action(self, guild, user, channel, action, reason):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild.id,))
|
||||
log_channel_id = await cursor.fetchone()
|
||||
|
||||
@@ -107,15 +108,17 @@ class AntiLink(commands.Cog):
|
||||
if self.spotify_pattern.search(message.content):
|
||||
return
|
||||
|
||||
th = await get_thresholds(guild_id, "anti_link")
|
||||
mute_minutes = float(th.get("mute_minutes", 7))
|
||||
punishment = await self.get_punishment(guild_id)
|
||||
action_taken = None
|
||||
reason = "Posted a link"
|
||||
|
||||
try:
|
||||
if punishment == "Mute":
|
||||
timeout_duration = discord.utils.utcnow() + timedelta(minutes=7)
|
||||
timeout_duration = discord.utils.utcnow() + timedelta(minutes=mute_minutes)
|
||||
await user.edit(timed_out_until=timeout_duration, reason=reason)
|
||||
action_taken = "Muted for 7 minutes"
|
||||
action_taken = f"Muted for {int(mute_minutes)} minutes"
|
||||
elif punishment == "Kick":
|
||||
await user.kick(reason=reason)
|
||||
action_taken = "Kicked"
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
from utils.automod_settings import get_thresholds
|
||||
|
||||
import discord
|
||||
from utils.emoji import TICK
|
||||
@@ -22,41 +23,39 @@ from datetime import timedelta
|
||||
class AntiSpam(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.spam_threshold = 5
|
||||
self.mute_duration = 12 * 60
|
||||
self.recent_messages = {}
|
||||
|
||||
async def is_automod_enabled(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,))
|
||||
result = await cursor.fetchone()
|
||||
return result is not None and result[0] == 1
|
||||
|
||||
async def is_anti_spam_enabled(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti spam'", (guild_id,))
|
||||
result = await cursor.fetchone()
|
||||
return result is not None
|
||||
|
||||
|
||||
async def get_ignored_channels(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,))
|
||||
return [row[0] for row in await cursor.fetchall()]
|
||||
|
||||
async def get_ignored_roles(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,))
|
||||
return [row[0] for row in await cursor.fetchall()]
|
||||
|
||||
async def get_punishment(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti spam'", (guild_id,))
|
||||
result = await cursor.fetchone()
|
||||
return result[0] if result else None
|
||||
|
||||
async def log_action(self, guild, user, channel, action, reason):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild.id,))
|
||||
log_channel_id = await cursor.fetchone()
|
||||
|
||||
@@ -99,21 +98,26 @@ class AntiSpam(commands.Cog):
|
||||
return
|
||||
|
||||
current_time = message.created_at.timestamp()
|
||||
th = await get_thresholds(guild_id, "anti_spam")
|
||||
window = float(th.get("window_seconds", 10))
|
||||
spam_threshold = int(th.get("max_messages", 5))
|
||||
mute_minutes = float(th.get("mute_minutes", 12))
|
||||
|
||||
user_messages = self.recent_messages.get(user.id, [])
|
||||
user_messages = [msg for msg in user_messages if current_time - msg < 10]
|
||||
user_messages = [msg for msg in user_messages if current_time - msg < window]
|
||||
user_messages.append(current_time)
|
||||
self.recent_messages[user.id] = user_messages
|
||||
|
||||
if len(user_messages) > self.spam_threshold:
|
||||
if len(user_messages) > spam_threshold:
|
||||
punishment = await self.get_punishment(guild_id)
|
||||
action_taken = None
|
||||
reason = "Spamming"
|
||||
|
||||
try:
|
||||
if punishment == "Mute":
|
||||
timeout_duration = discord.utils.utcnow() + timedelta(minutes=12)
|
||||
timeout_duration = discord.utils.utcnow() + timedelta(minutes=mute_minutes)
|
||||
await user.edit(timed_out_until=timeout_duration, reason="Spamming")
|
||||
action_taken = "Muted for 12 minutes"
|
||||
action_taken = f"Muted for {int(mute_minutes)} minutes"
|
||||
elif punishment == "Kick":
|
||||
await user.kick(reason="Spamming")
|
||||
action_taken = "Kicked"
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import jsondb_path
|
||||
|
||||
import discord
|
||||
from discord.ext import commands, tasks
|
||||
@@ -56,7 +56,7 @@ class Birthdays(commands.Cog):
|
||||
@commands.has_permissions(administrator=True)
|
||||
@commands.guild_only()
|
||||
async def birthday_setup(self, ctx: commands.Context, channel: discord.TextChannel, role: discord.Role):
|
||||
db = read_db('jsondb/birthday_logs.json')
|
||||
db = read_db(jsondb_path('birthday_logs.json'))
|
||||
guild_id = str(ctx.guild.id)
|
||||
|
||||
if guild_id not in db:
|
||||
@@ -65,7 +65,7 @@ class Birthdays(commands.Cog):
|
||||
db[guild_id]["birthday_channel_id"] = channel.id
|
||||
db[guild_id]["birthday_role_id"] = role.id
|
||||
|
||||
write_db('jsondb/birthday_logs.json', db)
|
||||
write_db(jsondb_path('birthday_logs.json'), db)
|
||||
|
||||
await ctx.send(view=CV2("Birthday Setup", f"Birthday log channel set to {channel.mention} and birthday role set to {role.mention}."))
|
||||
|
||||
@@ -104,9 +104,9 @@ class Birthdays(commands.Cog):
|
||||
return
|
||||
|
||||
date = f"{month}-{day}-{year}"
|
||||
db = read_db('jsondb/birthdays.json')
|
||||
db = read_db(jsondb_path('birthdays.json'))
|
||||
db[str(ctx.author.id)] = date
|
||||
write_db('jsondb/birthdays.json', db)
|
||||
write_db(jsondb_path('birthdays.json'), db)
|
||||
|
||||
await ctx.send(view=CV2("Success", f"Your birthday has been set to {date}."))
|
||||
except asyncio.TimeoutError:
|
||||
@@ -117,11 +117,11 @@ class Birthdays(commands.Cog):
|
||||
help="Remove your birthday.")
|
||||
@commands.guild_only()
|
||||
async def remove_birthday(self, ctx: commands.Context):
|
||||
db = read_db('jsondb/birthdays.json')
|
||||
db = read_db(jsondb_path('birthdays.json'))
|
||||
|
||||
if str(ctx.author.id) in db:
|
||||
del db[str(ctx.author.id)]
|
||||
write_db('jsondb/birthdays.json', db)
|
||||
write_db(jsondb_path('birthdays.json'), db)
|
||||
await ctx.send(view=CV2("Success", "Your birthday has been removed."))
|
||||
else:
|
||||
await ctx.send(view=CV2("Error", "You have no birthday set."))
|
||||
@@ -133,7 +133,7 @@ class Birthdays(commands.Cog):
|
||||
async def list_birthdays(self, ctx: commands.Context):
|
||||
now = datetime.datetime.now()
|
||||
today_date = now.strftime("%m-%d")
|
||||
db = read_db('jsondb/birthdays.json')
|
||||
db = read_db(jsondb_path('birthdays.json'))
|
||||
|
||||
members_with_birthday = [ctx.guild.get_member(int(user_id)) for user_id, date in db.items() if date.startswith(today_date)]
|
||||
|
||||
@@ -148,7 +148,7 @@ class Birthdays(commands.Cog):
|
||||
help="Check your birthday.")
|
||||
@commands.guild_only()
|
||||
async def check_birthday(self, ctx: commands.Context):
|
||||
db = read_db('jsondb/birthdays.json')
|
||||
db = read_db(jsondb_path('birthdays.json'))
|
||||
|
||||
if str(ctx.author.id) in db:
|
||||
date = db[str(ctx.author.id)]
|
||||
@@ -160,8 +160,8 @@ class Birthdays(commands.Cog):
|
||||
async def check_birthdays(self):
|
||||
now = datetime.datetime.now()
|
||||
today_date = now.strftime("%m-%d")
|
||||
db = read_db('jsondb/birthdays.json')
|
||||
guild_settings = read_db('jsondb/birthday_logs.json')
|
||||
db = read_db(jsondb_path('birthdays.json'))
|
||||
guild_settings = read_db(jsondb_path('birthday_logs.json'))
|
||||
|
||||
for user_id, birthday in db.items():
|
||||
if birthday.startswith(today_date):
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
import os
|
||||
from core import Cog, zyrox, Context
|
||||
from core import Cog, Axiom, Context
|
||||
import games as games
|
||||
from utils.Tools import *
|
||||
from utils.cv2 import CV2
|
||||
@@ -26,15 +25,30 @@ import asyncio
|
||||
|
||||
|
||||
class Games(Cog):
|
||||
"""Zyrox Games"""
|
||||
"""Axiom Games"""
|
||||
|
||||
def __init__(self, client: zyrox):
|
||||
def __init__(self, client: Axiom):
|
||||
self.client = client
|
||||
|
||||
@commands.hybrid_group(
|
||||
name="game",
|
||||
description="Play mini-games with friends or the bot.",
|
||||
fallback="help",
|
||||
invoke_without_command=True,
|
||||
)
|
||||
@blacklist_check()
|
||||
@ignore_check()
|
||||
@commands.cooldown(1, 3, commands.BucketType.user)
|
||||
@commands.guild_only()
|
||||
async def game(self, ctx: Context):
|
||||
"""Games root — use `/game <subcommand>` or `>game <subcommand>`."""
|
||||
if ctx.subcommand_passed is None:
|
||||
await ctx.send_help(ctx.command)
|
||||
ctx.command.reset_cooldown(ctx)
|
||||
|
||||
@commands.hybrid_command(name="chess",
|
||||
@game.command(name="chess",
|
||||
help="Play Chess with a user.",
|
||||
usage="Chess <user>")
|
||||
usage="game chess <user>")
|
||||
@blacklist_check()
|
||||
@ignore_check()
|
||||
@commands.cooldown(1, 3, commands.BucketType.user)
|
||||
@@ -50,10 +64,10 @@ class Games(Cog):
|
||||
await game.start(ctx)
|
||||
|
||||
|
||||
@commands.hybrid_command(name="rps",
|
||||
@game.command(name="rps",
|
||||
help="Play Rock Paper Scissor with bot/user.",
|
||||
aliases=["rockpaperscissors"],
|
||||
usage="Rockpaperscissors")
|
||||
usage="game rps [user]")
|
||||
@blacklist_check()
|
||||
@ignore_check()
|
||||
@commands.cooldown(1, 3, commands.BucketType.user)
|
||||
@@ -63,10 +77,10 @@ class Games(Cog):
|
||||
game = btn.BetaRockPaperScissors(player)
|
||||
await game.start(ctx, timeout=120)
|
||||
|
||||
@commands.hybrid_command(name="tic-tac-toe",
|
||||
@game.command(name="tictactoe",
|
||||
help="play tic-tac-toe game with a user.",
|
||||
aliases=["ttt", "tictactoe"],
|
||||
usage="Ticktactoe <member>")
|
||||
aliases=["ttt", "tic-tac-toe"],
|
||||
usage="game tictactoe <member>")
|
||||
@blacklist_check()
|
||||
@ignore_check()
|
||||
@commands.cooldown(1, 3, commands.BucketType.user)
|
||||
@@ -81,9 +95,9 @@ class Games(Cog):
|
||||
game = btn.BetaTictactoe(cross=ctx.author, circle=player)
|
||||
await game.start(ctx, timeout=30)
|
||||
|
||||
@commands.hybrid_command(name="wordle",
|
||||
@game.command(name="wordle",
|
||||
help="Wordle Game | Play with bot.",
|
||||
usage="Wordle")
|
||||
usage="game wordle")
|
||||
@blacklist_check()
|
||||
@ignore_check()
|
||||
@commands.cooldown(1, 3, commands.BucketType.user)
|
||||
@@ -93,10 +107,10 @@ class Games(Cog):
|
||||
game = games.Wordle()
|
||||
await game.start(ctx, timeout=120)
|
||||
|
||||
@commands.hybrid_command(name="2048",
|
||||
@game.command(name="2048",
|
||||
help="Play 2048 game with bot.",
|
||||
aliases=["twenty48"],
|
||||
usage="2048")
|
||||
usage="game 2048")
|
||||
@blacklist_check()
|
||||
@ignore_check()
|
||||
@commands.cooldown(1, 3, commands.BucketType.user)
|
||||
@@ -106,10 +120,10 @@ class Games(Cog):
|
||||
game = btn.BetaTwenty48()
|
||||
await game.start(ctx, win_at=2048)
|
||||
|
||||
@commands.hybrid_command(name="memory-game",
|
||||
@game.command(name="memory",
|
||||
help="How strong is your memory?",
|
||||
aliases=["memory"],
|
||||
usage="memory-game")
|
||||
aliases=["memory-game"],
|
||||
usage="game memory")
|
||||
@blacklist_check()
|
||||
@ignore_check()
|
||||
@commands.cooldown(1, 3, commands.BucketType.user)
|
||||
@@ -119,10 +133,10 @@ class Games(Cog):
|
||||
game = btn.MemoryGame()
|
||||
await game.start(ctx)
|
||||
|
||||
@commands.hybrid_command(name="number-slider",
|
||||
@game.command(name="slider",
|
||||
help="slide numbers with bot",
|
||||
aliases=["slider"],
|
||||
usage="slider")
|
||||
aliases=["number-slider"],
|
||||
usage="game slider")
|
||||
@blacklist_check()
|
||||
@ignore_check()
|
||||
@commands.cooldown(1, 3, commands.BucketType.user)
|
||||
@@ -132,10 +146,10 @@ class Games(Cog):
|
||||
game = btn.NumberSlider()
|
||||
await game.start(ctx)
|
||||
|
||||
@commands.hybrid_command(name="battleship",
|
||||
@game.command(name="battleship",
|
||||
help="Play battleship game with your friend.",
|
||||
aliases=["battle-ship"],
|
||||
usage="battleship <user>")
|
||||
usage="game battleship <user>")
|
||||
@blacklist_check()
|
||||
@ignore_check()
|
||||
@commands.cooldown(1, 3, commands.BucketType.user)
|
||||
@@ -165,10 +179,10 @@ class Games(Cog):
|
||||
async def _end_country_guesser(self, ctx: Context):
|
||||
await self.country_guesser_game.end_game_manually(ctx)"""
|
||||
|
||||
@commands.hybrid_command(name="connectfour",
|
||||
@game.command(name="connectfour",
|
||||
help="Play Connect Four game with user.",
|
||||
aliases=["c4", "connect-four", "connect4"],
|
||||
usage="connectfour <user>")
|
||||
usage="game connectfour <user>")
|
||||
@blacklist_check()
|
||||
@ignore_check()
|
||||
@commands.cooldown(1, 3, commands.BucketType.user)
|
||||
@@ -185,10 +199,10 @@ class Games(Cog):
|
||||
|
||||
|
||||
|
||||
@commands.hybrid_command(name="lights-out",
|
||||
@game.command(name="lightsout",
|
||||
help="Play Lights Show game with bot.",
|
||||
aliases=["lightsout"],
|
||||
usage="Lights-out")
|
||||
aliases=["lights-out"],
|
||||
usage="game lightsout")
|
||||
@blacklist_check()
|
||||
@ignore_check()
|
||||
@commands.cooldown(1, 3, commands.BucketType.user)
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
@@ -23,7 +23,7 @@ from utils.config import *
|
||||
class Invcrole(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.db_path = 'db/invc.db'
|
||||
self.db_path = db_path('invc.db')
|
||||
self.bot.loop.create_task(self.create_table())
|
||||
|
||||
async def create_table(self):
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
import aiosqlite
|
||||
@@ -27,7 +27,7 @@ class Media(commands.Cog):
|
||||
|
||||
|
||||
async def set_db(self):
|
||||
async with aiosqlite.connect('db/media.db') as db:
|
||||
async with aiosqlite.connect(db_path('media.db')) as db:
|
||||
await db.execute('''
|
||||
CREATE TABLE IF NOT EXISTS media_channels (
|
||||
guild_id INTEGER PRIMARY KEY,
|
||||
@@ -47,7 +47,13 @@ class Media(commands.Cog):
|
||||
async def on_ready(self):
|
||||
await self.set_db()
|
||||
|
||||
@commands.hybrid_group(name="media", help="Setup Media channel, Media channel will not allow users to send messages other than media files.", invoke_without_command=True)
|
||||
@commands.hybrid_group(
|
||||
name="media",
|
||||
description="Setup Media channel; only media files are allowed.",
|
||||
help="Setup Media channel, Media channel will not allow users to send messages other than media files.",
|
||||
fallback="help",
|
||||
invoke_without_command=True,
|
||||
)
|
||||
@blacklist_check()
|
||||
@ignore_check()
|
||||
@commands.cooldown(1, 3, commands.BucketType.user)
|
||||
@@ -62,7 +68,7 @@ class Media(commands.Cog):
|
||||
@commands.cooldown(1, 3, commands.BucketType.user)
|
||||
@commands.has_permissions(administrator=True)
|
||||
async def setup(self, ctx, *, channel: discord.TextChannel):
|
||||
async with aiosqlite.connect('db/media.db') as db:
|
||||
async with aiosqlite.connect(db_path('media.db')) as db:
|
||||
async with db.execute('SELECT channel_id FROM media_channels WHERE guild_id = ?', (ctx.guild.id,)) as cursor:
|
||||
result = await cursor.fetchone()
|
||||
if result:
|
||||
@@ -80,7 +86,7 @@ class Media(commands.Cog):
|
||||
@commands.cooldown(1, 3, commands.BucketType.user)
|
||||
@commands.has_permissions(administrator=True)
|
||||
async def remove(self, ctx):
|
||||
async with aiosqlite.connect('db/media.db') as db:
|
||||
async with aiosqlite.connect(db_path('media.db')) as db:
|
||||
async with db.execute('SELECT channel_id FROM media_channels WHERE guild_id = ?', (ctx.guild.id,)) as cursor:
|
||||
result = await cursor.fetchone()
|
||||
if not result:
|
||||
@@ -98,7 +104,7 @@ class Media(commands.Cog):
|
||||
@commands.cooldown(1, 3, commands.BucketType.user)
|
||||
@commands.has_permissions(administrator=True)
|
||||
async def config(self, ctx):
|
||||
async with aiosqlite.connect('db/media.db') as db:
|
||||
async with aiosqlite.connect(db_path('media.db')) as db:
|
||||
async with db.execute('SELECT channel_id FROM media_channels WHERE guild_id = ?', (ctx.guild.id,)) as cursor:
|
||||
result = await cursor.fetchone()
|
||||
if not result:
|
||||
@@ -124,7 +130,7 @@ class Media(commands.Cog):
|
||||
@commands.cooldown(1, 3, commands.BucketType.user)
|
||||
@commands.has_permissions(administrator=True)
|
||||
async def bypass_add(self, ctx, user: discord.Member):
|
||||
async with aiosqlite.connect('db/media.db') as db:
|
||||
async with aiosqlite.connect(db_path('media.db')) as db:
|
||||
async with db.execute('SELECT COUNT(*) FROM media_bypass WHERE guild_id = ?', (ctx.guild.id,)) as cursor:
|
||||
count = await cursor.fetchone()
|
||||
if count[0] >= 25:
|
||||
@@ -148,7 +154,7 @@ class Media(commands.Cog):
|
||||
@commands.cooldown(1, 3, commands.BucketType.user)
|
||||
@commands.has_permissions(administrator=True)
|
||||
async def bypass_remove(self, ctx, user: discord.Member):
|
||||
async with aiosqlite.connect('db/media.db') as db:
|
||||
async with aiosqlite.connect(db_path('media.db')) as db:
|
||||
async with db.execute('SELECT 1 FROM media_bypass WHERE guild_id = ? AND user_id = ?', (ctx.guild.id, user.id)) as cursor:
|
||||
result = await cursor.fetchone()
|
||||
if not result:
|
||||
@@ -166,7 +172,7 @@ class Media(commands.Cog):
|
||||
@commands.cooldown(1, 3, commands.BucketType.user)
|
||||
@commands.has_permissions(administrator=True)
|
||||
async def bypass_show(self, ctx):
|
||||
async with aiosqlite.connect('db/media.db') as db:
|
||||
async with aiosqlite.connect(db_path('media.db')) as db:
|
||||
async with db.execute('SELECT user_id FROM media_bypass WHERE guild_id = ?', (ctx.guild.id,)) as cursor:
|
||||
result = await cursor.fetchall()
|
||||
if not result:
|
||||
@@ -183,16 +189,16 @@ class Media(commands.Cog):
|
||||
if message.author.bot:
|
||||
return
|
||||
|
||||
async with aiosqlite.connect('db/media.db') as db:
|
||||
async with aiosqlite.connect(db_path('media.db')) as db:
|
||||
async with db.execute('SELECT channel_id FROM media_channels WHERE guild_id = ?', (message.guild.id,)) as cursor:
|
||||
media_channel = await cursor.fetchone()
|
||||
|
||||
if media_channel and message.channel.id == media_channel[0]:
|
||||
async with aiosqlite.connect('db/block.db') as block_db:
|
||||
async with aiosqlite.connect(db_path('block.db')) as block_db:
|
||||
async with block_db.execute('SELECT 1 FROM user_blacklist WHERE user_id = ?', (message.author.id,)) as cursor:
|
||||
blacklisted = await cursor.fetchone()
|
||||
|
||||
async with aiosqlite.connect('db/media.db') as db:
|
||||
async with aiosqlite.connect(db_path('media.db')) as db:
|
||||
async with db.execute('SELECT 1 FROM media_bypass WHERE guild_id = ? AND user_id = ?', (message.guild.id, message.author.id)) as cursor:
|
||||
bypassed = await cursor.fetchone()
|
||||
|
||||
@@ -221,7 +227,7 @@ class Media(commands.Cog):
|
||||
]
|
||||
|
||||
if len(self.infractions[message.author.id]) >= 5:
|
||||
async with aiosqlite.connect('db/block.db') as block_db:
|
||||
async with aiosqlite.connect(db_path('block.db')) as block_db:
|
||||
await block_db.execute('INSERT OR IGNORE INTO user_blacklist (user_id) VALUES (?)', (message.author.id,))
|
||||
|
||||
await block_db.commit()
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
@@ -24,7 +24,7 @@ from utils.cv2 import CV2, build_container
|
||||
from utils.emoji import TICK, MENTION, SEED, TIME
|
||||
from utils.config import *
|
||||
|
||||
DB_PATH = "db/afk.db"
|
||||
DB_PATH = db_path("afk.db")
|
||||
THEME_COLOR = 0xFF0000
|
||||
FOOTER_TEXT = f"Developed by {BRAND_NAME}"
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import os
|
||||
import discord
|
||||
@@ -323,19 +323,19 @@ class AI (commands .Cog ):
|
||||
import os
|
||||
|
||||
|
||||
db_path ="db/ai_data.db"
|
||||
if os .path .exists (db_path ):
|
||||
ai_db = db_path("ai_data.db")
|
||||
if os .path .exists (ai_db ):
|
||||
try :
|
||||
|
||||
test_conn =await aiosqlite .connect (db_path )
|
||||
test_conn =await aiosqlite .connect (ai_db )
|
||||
await test_conn .execute ("SELECT name FROM sqlite_master WHERE type='table';")
|
||||
await test_conn .close ()
|
||||
except Exception as e :
|
||||
|
||||
os .remove (db_path )
|
||||
os .remove (ai_db )
|
||||
logger .info ("Removed corrupted AI database, creating new one")
|
||||
|
||||
self .bot .db =await aiosqlite .connect (db_path )
|
||||
self .bot .db =await aiosqlite .connect (ai_db )
|
||||
logger .info ("AI database connection initialized")
|
||||
|
||||
await self .bot .db .execute ("""
|
||||
@@ -401,12 +401,12 @@ class AI (commands .Cog ):
|
||||
import aiosqlite
|
||||
import os
|
||||
|
||||
db_path ="db/ai_data.db"
|
||||
if not os .path .exists (db_path ):
|
||||
ai_db = db_path("ai_data.db")
|
||||
if not os .path .exists (ai_db ):
|
||||
logger .info ("AI database doesn't exist, will be created on first use")
|
||||
return
|
||||
|
||||
self .bot .db =await aiosqlite .connect (db_path )
|
||||
self .bot .db =await aiosqlite .connect (ai_db )
|
||||
logger .info ("AI database connection initialized for loading")
|
||||
|
||||
|
||||
@@ -590,7 +590,7 @@ class AI (commands .Cog ):
|
||||
|
||||
system_context .append ({
|
||||
"role":"system",
|
||||
"content":"You are a Discord bot with many features including moderation, entertainment, music, games, AI capabilities, and utilities. Support server: https://discord.gg/codexdev"
|
||||
"content":"You are a Discord bot with many features including moderation, entertainment, music, games, AI capabilities, and utilities. Support server: https://discord.gg/hexahost"
|
||||
})
|
||||
else :
|
||||
|
||||
@@ -602,7 +602,7 @@ You have a caring, helpful personality and can remember conversations with users
|
||||
|
||||
Be natural, conversational, and genuine in your responses. Don't be overly formal or robotic. Use the conversation history to provide personalized responses that feel like talking to a real friend who happens to be very knowledgeable and helpful.
|
||||
|
||||
Support server: https://discord.gg/codexdev"""
|
||||
Support server: https://discord.gg/hexahost"""
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from utils.emoji import CROSS, MANAGER, REDDOT, TICK
|
||||
@@ -31,7 +31,7 @@ class Unwhitelist(commands.Cog):
|
||||
|
||||
#@commands.Cog.listener()
|
||||
async def initialize_db(self):
|
||||
self.db = await aiosqlite.connect('db/anti.db')
|
||||
self.db = await aiosqlite.connect(db_path('anti.db'))
|
||||
|
||||
@commands.hybrid_command(name='unwhitelist', aliases=['unwl'], help="Unwhitelist a user from antinuke")
|
||||
@commands.has_permissions(administrator=True)
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from utils.emoji import ARROWRED, CROSS, DISABLE, ENABLE, MANAGER, TICK
|
||||
@@ -32,7 +32,7 @@ class Whitelist(commands.Cog):
|
||||
|
||||
#@commands.Cog.listener()
|
||||
async def initialize_db(self):
|
||||
self.db = await aiosqlite.connect('db/anti.db')
|
||||
self.db = await aiosqlite.connect(db_path('anti.db'))
|
||||
await self.db.execute('''
|
||||
CREATE TABLE IF NOT EXISTS whitelisted_users (
|
||||
guild_id INTEGER,
|
||||
@@ -57,16 +57,34 @@ class Whitelist(commands.Cog):
|
||||
''')
|
||||
await self.db.commit()
|
||||
|
||||
@commands.hybrid_command(name='whitelist', aliases=['wl'], help="Whitelists a user from antinuke for a specific action.")
|
||||
|
||||
@commands.hybrid_group(
|
||||
name="whitelist",
|
||||
aliases=["wl"],
|
||||
description="Manage antinuke whitelist.",
|
||||
fallback="help",
|
||||
invoke_without_command=True,
|
||||
help="Whitelists a user from antinuke for a specific action.",
|
||||
)
|
||||
@blacklist_check()
|
||||
@ignore_check()
|
||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||
@commands.max_concurrency(1, per=commands.BucketType.default, wait=False)
|
||||
@commands.guild_only()
|
||||
@commands.has_permissions(administrator=True)
|
||||
async def whitelist(self, ctx):
|
||||
"""Whitelist root — use `/whitelist <subcommand>` or `>whitelist <subcommand>`."""
|
||||
if ctx.subcommand_passed is None:
|
||||
await ctx.send_help(ctx.command)
|
||||
ctx.command.reset_cooldown(ctx)
|
||||
|
||||
async def whitelist(self, ctx, member: discord.Member = None):
|
||||
@whitelist.command(name="add", help="Whitelists a user from antinuke for a specific action.")
|
||||
@blacklist_check()
|
||||
@ignore_check()
|
||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||
@commands.max_concurrency(1, per=commands.BucketType.default, wait=False)
|
||||
@commands.guild_only()
|
||||
@commands.has_permissions(administrator=True)
|
||||
async def whitelist_add(self, ctx, member: discord.Member = None):
|
||||
if ctx.guild.member_count < 2:
|
||||
view = CV2(f"{CROSS} Error", "Your Server Doesn't Meet My 30 Member Criteria")
|
||||
return await ctx.send(view=view)
|
||||
@@ -101,7 +119,7 @@ class Whitelist(commands.Cog):
|
||||
view = CV2(
|
||||
"__Whitelist Commands__",
|
||||
"**Adding a user to the whitelist means that no actions will be taken against them if they trigger the Anti-Nuke Module.**",
|
||||
f"**Usage**\n{ARROWRED} `{prefix}whitelist @user/id`\n{ARROWRED} `{prefix}wl @user`"
|
||||
f"**Usage**\n{ARROWRED} `{prefix}whitelist add @user/id`\n{ARROWRED} `{prefix}wl add @user`"
|
||||
)
|
||||
return await ctx.send(view=view)
|
||||
|
||||
@@ -252,7 +270,7 @@ class Whitelist(commands.Cog):
|
||||
await msg.edit(view=None)
|
||||
|
||||
|
||||
@commands.hybrid_command(name='whitelisted', aliases=['wlist'], help="Shows the list of whitelisted users.")
|
||||
@whitelist.command(name="list", aliases=["whitelisted", "wlist"], help="Shows the list of whitelisted users.")
|
||||
@blacklist_check()
|
||||
@ignore_check()
|
||||
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||
@@ -308,7 +326,7 @@ class Whitelist(commands.Cog):
|
||||
await ctx.send(view=view)
|
||||
|
||||
|
||||
@commands.hybrid_command(name="whitelistreset", aliases=['wlreset'], help="Resets the whitelisted users.")
|
||||
@whitelist.command(name="reset", aliases=["whitelistreset", "wlreset"], help="Resets the whitelisted users.")
|
||||
@blacklist_check()
|
||||
@ignore_check()
|
||||
@commands.cooldown(1, 10, commands.BucketType.user)
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from utils.emoji import CROSS, EMOTE, TICK, ZSAFE, ZSETTINGS
|
||||
@@ -31,7 +31,7 @@ class Antinuke(commands.Cog):
|
||||
self.bot.loop.create_task(self.initialize_db())
|
||||
|
||||
async def initialize_db(self):
|
||||
self.db = await aiosqlite.connect('db/anti.db')
|
||||
self.db = await aiosqlite.connect(db_path('anti.db'))
|
||||
await self.db.execute('''
|
||||
CREATE TABLE IF NOT EXISTS antinuke (
|
||||
guild_id INTEGER PRIMARY KEY,
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from utils.emoji import CROSS, DISABLE, ENABLE, TICK, TICK_ALT
|
||||
@@ -113,7 +113,7 @@ class Automod(commands.Cog):
|
||||
self.bot.loop.create_task(self.init_db())
|
||||
|
||||
async def get_exempt_roles_channels(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
roles_cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,))
|
||||
channels_cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,))
|
||||
|
||||
@@ -124,18 +124,18 @@ class Automod(commands.Cog):
|
||||
|
||||
|
||||
async def is_automod_enabled(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,))
|
||||
result = await cursor.fetchone()
|
||||
return result is not None and result[0] == 1
|
||||
|
||||
async def update_punishments(self, guild_id, event, punishment):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
await db.execute("INSERT OR REPLACE INTO automod_punishments (guild_id, event, punishment) VALUES (?, ?, ?)", (guild_id, event, punishment))
|
||||
await db.commit()
|
||||
|
||||
async def get_current_punishments(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
async with db.execute(
|
||||
"SELECT event, punishment FROM automod_punishments WHERE guild_id = ? AND event != 'Anti NSFW link'",
|
||||
(guild_id,)
|
||||
@@ -143,7 +143,7 @@ class Automod(commands.Cog):
|
||||
return await cursor.fetchall()
|
||||
|
||||
async def is_anti_nsfw_enabled(self, guild_id):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti NSFW link'", (guild_id,))
|
||||
result = await cursor.fetchone()
|
||||
return result is not None
|
||||
@@ -151,7 +151,7 @@ class Automod(commands.Cog):
|
||||
|
||||
|
||||
async def init_db(self):
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
await db.execute("""
|
||||
CREATE TABLE IF NOT EXISTS automod (
|
||||
guild_id INTEGER PRIMARY KEY,
|
||||
@@ -181,13 +181,30 @@ class Automod(commands.Cog):
|
||||
PRIMARY KEY (guild_id)
|
||||
)
|
||||
""")
|
||||
await db.execute("""
|
||||
CREATE TABLE IF NOT EXISTS automod_thresholds (
|
||||
guild_id INTEGER,
|
||||
event TEXT,
|
||||
key TEXT,
|
||||
value REAL,
|
||||
PRIMARY KEY (guild_id, event, key)
|
||||
)
|
||||
""")
|
||||
await db.commit()
|
||||
|
||||
@commands.hybrid_group(invoke_without_command=True)
|
||||
@commands.hybrid_group(
|
||||
name="automod",
|
||||
aliases=["am"],
|
||||
invoke_without_command=True,
|
||||
with_app_command=True,
|
||||
description="Configure server Automod (enable, disable, punishments, ignores).",
|
||||
fallback="help",
|
||||
)
|
||||
@blacklist_check()
|
||||
@ignore_check()
|
||||
@commands.cooldown(1, 4, commands.BucketType.user)
|
||||
async def automod(self, ctx):
|
||||
"""Automod root — use `/automod <subcommand>` or `>automod <subcommand>`."""
|
||||
if ctx.subcommand_passed is None:
|
||||
await ctx.send_help(ctx.command)
|
||||
ctx.command.reset_cooldown(ctx)
|
||||
@@ -271,7 +288,7 @@ class Automod(commands.Cog):
|
||||
|
||||
async def enable_automod(self, ctx, guild_id, selected_events, interaction):
|
||||
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
await db.execute("INSERT OR REPLACE INTO automod (guild_id, enabled) VALUES (?, 1)", (guild_id,))
|
||||
for event in selected_events:
|
||||
await db.execute("INSERT OR REPLACE INTO automod_punishments (guild_id, event, punishment) VALUES (?, ?, ?)", (guild_id, event, self.default_punishment))
|
||||
@@ -328,7 +345,7 @@ class Automod(commands.Cog):
|
||||
log_channel = await interaction.guild.create_text_channel(f"{BRAND_NAME.lower()}-automod", overwrites=overwrites)
|
||||
guild_id = interaction.guild.id
|
||||
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
await db.execute("INSERT OR REPLACE INTO automod_logging (guild_id, log_channel) VALUES (?, ?)", (guild_id, log_channel.id))
|
||||
await db.commit()
|
||||
|
||||
@@ -440,7 +457,7 @@ class Automod(commands.Cog):
|
||||
await ctx.send(view=CV2(f"Automod Settings for {ctx.guild.name}", f"Uhh, looks like your server hasn\'t enabled Automoderation.\n\nCurrent Status: {DISABLE} Disabled\nTo Enable use `{ctx.prefix}automod enable`"))
|
||||
return
|
||||
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT 1 FROM automod_ignored WHERE guild_id = ? AND type = 'channel' AND id = ?", (guild_id, channel.id))
|
||||
if await cursor.fetchone() is not None:
|
||||
await ctx.send(view=CV2("__Channel Already Whitelisted!__", f"{CROSS} The channel {channel.mention} is already in the ignore list.\n\n➜ Use **{ctx.prefix}automod unignore channel {channel.mention}** to remove it."))
|
||||
@@ -491,7 +508,7 @@ class Automod(commands.Cog):
|
||||
await ctx.send(view=CV2(f"Automod Settings for {ctx.guild.name}", f"Uhh, looks like your server hasn\'t enabled Automoderation.\n\nCurrent Status: {DISABLE} Disabled\nTo Enable use `{ctx.prefix}automod enable`"))
|
||||
return
|
||||
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT 1 FROM automod_ignored WHERE guild_id = ? AND type = 'role' AND id = ?", (guild_id, role.id))
|
||||
|
||||
if await cursor.fetchone() is not None:
|
||||
@@ -545,7 +562,7 @@ class Automod(commands.Cog):
|
||||
return
|
||||
|
||||
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT type, id FROM automod_ignored WHERE guild_id = ?", (guild_id,))
|
||||
ignored_items = await cursor.fetchall()
|
||||
|
||||
@@ -592,7 +609,7 @@ class Automod(commands.Cog):
|
||||
await ctx.send(view=CV2(f"Automod Settings for {ctx.guild.name}", f"Uhh, looks like your server hasn\'t enabled Automoderation.\n\nCurrent Status: {DISABLE} Disabled\nTo Enable use `{ctx.prefix}automod enable`"))
|
||||
return
|
||||
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
await db.execute("DELETE FROM automod_ignored WHERE guild_id = ?", (guild_id,))
|
||||
await db.commit()
|
||||
await ctx.send(view=CV2(f"Automod Settings for {ctx.guild.name}", f"** {TICK} | All ignored channels and roles have been reset!**\n\nTo view current Automod settings use `{ctx.prefix}automod config`"))
|
||||
@@ -639,7 +656,7 @@ class Automod(commands.Cog):
|
||||
except discord.HTTPException:
|
||||
pass
|
||||
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
result = await db.execute("DELETE FROM automod_ignored WHERE guild_id = ? AND type = 'channel' AND id = ?", (guild_id, channel.id))
|
||||
await db.commit()
|
||||
|
||||
@@ -682,7 +699,7 @@ class Automod(commands.Cog):
|
||||
pass
|
||||
|
||||
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
result = await db.execute("DELETE FROM automod_ignored WHERE guild_id = ? AND type = 'role' AND id = ?", (guild_id, role.id))
|
||||
await db.commit()
|
||||
|
||||
@@ -719,7 +736,7 @@ class Automod(commands.Cog):
|
||||
|
||||
elif view.value:
|
||||
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
await db.execute("DELETE FROM automod WHERE guild_id = ?", (guild_id,))
|
||||
await db.execute("DELETE FROM automod_punishments WHERE guild_id = ?", (guild_id,))
|
||||
await db.execute("DELETE FROM automod_ignored WHERE guild_id = ?", (guild_id,))
|
||||
@@ -768,7 +785,7 @@ class Automod(commands.Cog):
|
||||
items_str.append(f"**{event}**: {punishment or 'None'}")
|
||||
if await self.is_anti_nsfw_enabled(guild_id):
|
||||
items_str.append("**Anti NSFW Links**: Block Message")
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild_id,))
|
||||
log_channel_id = await cursor.fetchone()
|
||||
if log_channel_id and log_channel_id[0]:
|
||||
@@ -799,7 +816,7 @@ class Automod(commands.Cog):
|
||||
await ctx.send(view=CV2(f"Automod Settings for {ctx.guild.name}", f"Uhh, looks like your server hasn\'t enabled Automoderation.\n\nCurrent Status: {DISABLE} Disabled\nTo Enable use `{ctx.prefix}automod enable`"))
|
||||
return
|
||||
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
await db.execute("INSERT OR REPLACE INTO automod_logging (guild_id, log_channel) VALUES (?, ?)", (guild_id, channel.id))
|
||||
await db.commit()
|
||||
await ctx.send(view=CV2(f"Automod Settings for {ctx.guild.name}", f"**{TICK} | Automoderation Logging channel set to {channel.mention}.**\n\n➜ Use `{ctx.prefix}automod config` to view current Automod settings."))
|
||||
@@ -809,7 +826,7 @@ class Automod(commands.Cog):
|
||||
async def on_guild_remove(self, guild):
|
||||
guild_id = guild.id
|
||||
|
||||
async with aiosqlite.connect("db/automod.db") as db:
|
||||
async with aiosqlite.connect(db_path("automod.db")) as db:
|
||||
await db.execute("DELETE FROM automod WHERE guild_id = ?", (guild_id,))
|
||||
await db.execute("DELETE FROM automod_punishments WHERE guild_id = ?", (guild_id,))
|
||||
await db.execute("DELETE FROM automod_ignored WHERE guild_id = ?", (guild_id,))
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from utils.emoji import CROSS, ICONS_WARNING, TICK
|
||||
@@ -28,7 +28,7 @@ from utils.cv2 import CV2, build_container
|
||||
class AutoReaction(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.db_path = 'db/autoreact.db'
|
||||
self.db_path = db_path('autoreact.db')
|
||||
self.bot.loop.create_task(self.setup_database())
|
||||
|
||||
async def setup_database(self):
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from utils.emoji import CROSS, TICK
|
||||
@@ -25,7 +25,7 @@ from utils.cv2 import CV2, build_container
|
||||
|
||||
|
||||
|
||||
DB_PATH = "db/autoresponder.db"
|
||||
DB_PATH = db_path("autoresponder.db")
|
||||
|
||||
class AutoResponder(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
from __future__ import annotations
|
||||
from utils.db_paths import db_path
|
||||
import discord
|
||||
from utils.emoji import CROSS, ICONS_WARNING, TICK
|
||||
import aiosqlite
|
||||
@@ -33,7 +33,7 @@ logging.basicConfig(
|
||||
datefmt="%H:%M:%S",
|
||||
)
|
||||
|
||||
DATABASE_PATH = 'db/autorole.db'
|
||||
DATABASE_PATH = db_path('autorole.db')
|
||||
|
||||
class BasicView(discord.ui.View):
|
||||
def __init__(self, ctx: commands.Context, timeout=60):
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ |H|e|x|a|H|o|s|t| ║
|
||||
# ║ +-+-+-+-+-+-+-+-+ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ © 2026 HexaHost — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ discord ── https://discord.gg/hexahost ║
|
||||
# ║ github ── https://github.com/theoneandonlymace ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
from utils.db_paths import db_path
|
||||
|
||||
import discord
|
||||
from utils.emoji import CROSS, TICK
|
||||
@@ -55,7 +55,7 @@ class BlacklistWordSource(menus.ListPageSource):
|
||||
return embed
|
||||
|
||||
|
||||
DB_PATH = "db/blword.db"
|
||||
DB_PATH = db_path("blword.db")
|
||||
|
||||
|
||||
async def create_blacklist_table():
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user