CodeX
This commit is contained in:
@@ -2,12 +2,30 @@ TOKEN = TOKEN_HERE
|
|||||||
brand_name='ZyroX'
|
brand_name='ZyroX'
|
||||||
NEXT_PUBLIC_BRAND_NAME='ZyroX'
|
NEXT_PUBLIC_BRAND_NAME='ZyroX'
|
||||||
|
|
||||||
|
# LAVALINK CONFIG
|
||||||
|
LAVALINK_HOST="lavalink.jirayu.net"
|
||||||
|
LAVALINK_PASSWORD="youshallnotpass"
|
||||||
|
|
||||||
|
# Set to true if the node uses HTTPS/WSS (secure), false for HTTP/WS
|
||||||
|
LAVALINK_SECURE="false"
|
||||||
|
|
||||||
|
# Only needed when LAVALINK_SECURE is false (e.g. 2333)
|
||||||
|
LAVALINK_PORT="13592"
|
||||||
|
|
||||||
|
|
||||||
|
# EMOJI SYNC CONFIG
|
||||||
|
# Set to true to enable automatic application emoji sync on startup
|
||||||
|
EMOJI_SYNC="true"
|
||||||
|
|
||||||
|
# API SERVER CONFIG
|
||||||
|
# Set to true to enable the dashboard API server
|
||||||
|
API_ENABLED="true"
|
||||||
|
# Port the API server listens on
|
||||||
|
API_PORT="8000"
|
||||||
|
|
||||||
# ON CMD RUN
|
# ON CMD RUN
|
||||||
WEBHOOK_URL="https://discord.com/api/webhooks/"
|
WEBHOOK_URL="https://discord.com/api/webhooks/"
|
||||||
|
|
||||||
DASHBOARD_API_KEY="ZYROX_SECURE_API_KEY_12345"
|
DASHBOARD_API_KEY="ZYROX_SECURE_API_KEY_12345_CHANGE_THIS_ASAP_BY_CODEX_DEVS"
|
||||||
|
|
||||||
# DASHBOARD WILL BE UPLOADED LATER
|
# CODEX DEVS
|
||||||
# CODEX DEVS
|
|
||||||
14
bot/CodeX.py
14
bot/CodeX.py
@@ -19,6 +19,7 @@ from core.zyrox import zyrox
|
|||||||
from utils.Tools import *
|
from utils.Tools import *
|
||||||
from utils.config import *
|
from utils.config import *
|
||||||
from utils.emoji import SUCCESS, ERROR, TICK, CROSS, REACTION_TEST_EMOJIS
|
from utils.emoji import SUCCESS, ERROR, TICK, CROSS, REACTION_TEST_EMOJIS
|
||||||
|
from utils.sync_emojis import run_sync
|
||||||
|
|
||||||
import jishaku
|
import jishaku
|
||||||
import cogs
|
import cogs
|
||||||
@@ -85,6 +86,10 @@ async def on_ready():
|
|||||||
print(f"Logged in as: {client.user}")
|
print(f"Logged in as: {client.user}")
|
||||||
print(f"Connected to: {len(client.guilds)} guilds")
|
print(f"Connected to: {len(client.guilds)} guilds")
|
||||||
print(f"Connected to: {len(client.users)} users")
|
print(f"Connected to: {len(client.users)} users")
|
||||||
|
|
||||||
|
# Sync application emojis on startup
|
||||||
|
await run_sync(TOKEN)
|
||||||
|
|
||||||
async def sync_commands():
|
async def sync_commands():
|
||||||
try:
|
try:
|
||||||
synced = await client.tree.sync()
|
synced = await client.tree.sync()
|
||||||
@@ -299,10 +304,17 @@ fastapi_app = create_app()
|
|||||||
fastapi_app.state.bot = client
|
fastapi_app.state.bot = client
|
||||||
set_bot(client)
|
set_bot(client)
|
||||||
|
|
||||||
|
API_ENABLED = os.getenv("API_ENABLED", "true").strip().lower() == "true"
|
||||||
|
API_PORT = int(os.getenv("API_PORT", "8000"))
|
||||||
|
|
||||||
def run_api():
|
def run_api():
|
||||||
uvicorn.run(fastapi_app, host='0.0.0.0', port=8000, log_level="warning")
|
uvicorn.run(fastapi_app, host='0.0.0.0', port=API_PORT, log_level="warning")
|
||||||
|
|
||||||
def keep_alive():
|
def keep_alive():
|
||||||
|
if not API_ENABLED:
|
||||||
|
print(f"\033[33m◈ API Server: Disabled via API_ENABLED=false\033[0m")
|
||||||
|
return
|
||||||
|
print(f"\033[32m◈ API Server: Starting on port {API_PORT}\033[0m")
|
||||||
server = Thread(target=run_api, daemon=True)
|
server = Thread(target=run_api, daemon=True)
|
||||||
server.start()
|
server.start()
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import os
|
||||||
import random
|
import random
|
||||||
import discord
|
import discord
|
||||||
from utils.emoji import FORWARD, ICONLOAD, ICONS_MUSIC, ICONS_PAUSE, ICONS_WARNING_ALT1, MUSICSTOP_ICONS, MUSIC_ALT1, MUTE, REWIND, REWIND_ALT1, SHUFFLE, SKIP, TICK, WARNING, ZMUSICPAUSE, ZPLUS, ZUNMUTE
|
from utils.emoji import FORWARD, ICONLOAD, ICONS_MUSIC, ICONS_PAUSE, ICONS_WARNING_ALT1, MUSICSTOP_ICONS, MUSIC_ALT1, MUTE, REWIND, REWIND_ALT1, SHUFFLE, SKIP, TICK, WARNING, ZMUSICPAUSE, ZPLUS, ZUNMUTE
|
||||||
@@ -377,7 +378,17 @@ class Music(commands.Cog):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
async def connect_nodes(self) -> None:
|
async def connect_nodes(self) -> None:
|
||||||
nodes = [wavelink.Node(uri="https://lava-v4.ajieblogs.eu.org", password="https://dsc.gg/ajidevserver")]
|
host = os.getenv("LAVALINK_HOST", "lava-v4.ajieblogs.eu.org")
|
||||||
|
password = os.getenv("LAVALINK_PASSWORD", "https://dsc.gg/ajidevserver")
|
||||||
|
secure = os.getenv("LAVALINK_SECURE", "true").strip().lower() == "true"
|
||||||
|
port = os.getenv("LAVALINK_PORT", "").strip()
|
||||||
|
|
||||||
|
if secure:
|
||||||
|
uri = f"https://{host}"
|
||||||
|
else:
|
||||||
|
uri = f"http://{host}:{port}" if port else f"http://{host}"
|
||||||
|
|
||||||
|
nodes = [wavelink.Node(uri=uri, password=password)]
|
||||||
await wavelink.Pool.connect(nodes=nodes, client=self.client, cache_capacity=None)
|
await wavelink.Pool.connect(nodes=nodes, client=self.client, cache_capacity=None)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
201
bot/utils/sync_emojis.py
Normal file
201
bot/utils/sync_emojis.py
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
"""
|
||||||
|
Application Emoji Sync Utility
|
||||||
|
Reads all custom Discord emojis from utils/emoji.py, checks them against
|
||||||
|
the bot's application emojis, uploads any that are missing, and patches
|
||||||
|
emoji.py in-place with corrected IDs.
|
||||||
|
|
||||||
|
Controlled by EMOJI_SYNC in .env:
|
||||||
|
EMOJI_SYNC="true" → runs on every startup
|
||||||
|
EMOJI_SYNC="false" → skipped entirely
|
||||||
|
|
||||||
|
If emoji.py is patched (new uploads or ID fixes), the bot automatically
|
||||||
|
restarts so the fresh IDs are loaded into memory.
|
||||||
|
|
||||||
|
Call `run_sync(token)` once inside on_ready.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import base64
|
||||||
|
import asyncio
|
||||||
|
import aiohttp
|
||||||
|
from colorama import Fore, Style, init
|
||||||
|
|
||||||
|
init(autoreset=True)
|
||||||
|
|
||||||
|
EMOJI_PY_PATH = os.path.join(os.path.dirname(__file__), "emoji.py")
|
||||||
|
|
||||||
|
|
||||||
|
def _log(level: str, color: str, symbol: str, msg: str) -> None:
|
||||||
|
print(f"{color}{symbol} {level}:{Style.RESET_ALL} {msg}")
|
||||||
|
|
||||||
|
def info(msg): _log("EmojiSync", Fore.CYAN, "◈", msg)
|
||||||
|
def success(msg): _log("EmojiSync", Fore.GREEN, "✔", msg)
|
||||||
|
def warning(msg): _log("EmojiSync", Fore.YELLOW, "↻", msg)
|
||||||
|
def error(msg): _log("EmojiSync", Fore.RED, "✖", msg)
|
||||||
|
def system(msg): _log("EmojiSync", Fore.MAGENTA, "★", msg)
|
||||||
|
|
||||||
|
|
||||||
|
def _restart() -> None:
|
||||||
|
"""Replace the current process with a fresh copy of itself."""
|
||||||
|
system(f"Restarting bot to load updated emoji IDs...")
|
||||||
|
# Flush stdout so the message is visible before the process is replaced
|
||||||
|
sys.stdout.flush()
|
||||||
|
os.execv(sys.executable, [sys.executable] + sys.argv)
|
||||||
|
|
||||||
|
|
||||||
|
async def _fetch_emoji_image(session: aiohttp.ClientSession, emoji_id: str, animated: bool):
|
||||||
|
ext = "gif" if animated else "webp"
|
||||||
|
url = f"https://cdn.discordapp.com/emojis/{emoji_id}.{ext}"
|
||||||
|
try:
|
||||||
|
async with session.get(url, allow_redirects=True) as r:
|
||||||
|
if r.status == 200:
|
||||||
|
return await r.read()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
async def run_sync(token: str) -> None:
|
||||||
|
"""
|
||||||
|
Async emoji sync. Pass the bot token directly.
|
||||||
|
Respects the EMOJI_SYNC env var — set to "false" to disable.
|
||||||
|
Triggers an automatic restart when emoji.py is patched.
|
||||||
|
"""
|
||||||
|
# ── Toggle check ──────────────────────────────────────────────────────────
|
||||||
|
enabled = os.getenv("EMOJI_SYNC", "true").strip().lower()
|
||||||
|
if enabled != "true":
|
||||||
|
info(f"Disabled via EMOJI_SYNC={enabled!r} — skipping.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not token:
|
||||||
|
warning("No token provided — skipping EmojiSync.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# ── Read emoji.py ─────────────────────────────────────────────────────────
|
||||||
|
try:
|
||||||
|
with open(EMOJI_PY_PATH, "r", encoding="utf-8") as f:
|
||||||
|
content = f.read()
|
||||||
|
except Exception as err:
|
||||||
|
error(f"Could not read emoji.py ({err})")
|
||||||
|
return
|
||||||
|
|
||||||
|
matches = set(re.findall(r"<(a?):(\w+):(\d+)>", content))
|
||||||
|
if not matches:
|
||||||
|
info("No custom emojis found in emoji.py — nothing to sync.")
|
||||||
|
return
|
||||||
|
|
||||||
|
system(f"Starting Application Emoji Sync — {len(matches)} unique emojis found in emoji.py")
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"Bot {token}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
|
||||||
|
async with aiohttp.ClientSession(headers=headers) as session:
|
||||||
|
# Fetch bot application ID
|
||||||
|
async with session.get("https://discord.com/api/v10/users/@me") as r:
|
||||||
|
if r.status != 200:
|
||||||
|
error(f"Failed to fetch bot info [HTTP {r.status}]")
|
||||||
|
return
|
||||||
|
app_id = (await r.json()).get("id")
|
||||||
|
|
||||||
|
# Fetch existing application emojis
|
||||||
|
async with session.get(f"https://discord.com/api/v10/applications/{app_id}/emojis") as r:
|
||||||
|
if r.status != 200:
|
||||||
|
error(f"Failed to fetch application emojis [HTTP {r.status}]")
|
||||||
|
return
|
||||||
|
data = await r.json()
|
||||||
|
app_emojis: list = data.get("items", []) if isinstance(data, dict) else data
|
||||||
|
|
||||||
|
info(
|
||||||
|
f"Found {Fore.YELLOW}{len(matches)}{Style.RESET_ALL} templates "
|
||||||
|
f"{Fore.LIGHTBLACK_EX}|{Style.RESET_ALL} "
|
||||||
|
f"Application hosts {Fore.GREEN}{len(app_emojis)}{Style.RESET_ALL} emojis"
|
||||||
|
)
|
||||||
|
|
||||||
|
updated = False
|
||||||
|
skipped = uploaded = fixed = failed = 0
|
||||||
|
|
||||||
|
for animated_str, name, old_id in matches:
|
||||||
|
animated = animated_str == "a"
|
||||||
|
|
||||||
|
existing = (
|
||||||
|
next((e for e in app_emojis if e["id"] == old_id), None)
|
||||||
|
or next((e for e in app_emojis if e["name"] == name), None)
|
||||||
|
)
|
||||||
|
|
||||||
|
if existing:
|
||||||
|
new_id = existing["id"]
|
||||||
|
if old_id != new_id:
|
||||||
|
old_str = f"<{animated_str}:{name}:{old_id}>"
|
||||||
|
new_str = f"<{animated_str}:{existing['name']}:{new_id}>"
|
||||||
|
content = content.replace(old_str, new_str)
|
||||||
|
updated = True
|
||||||
|
fixed += 1
|
||||||
|
warning(f"Auto-fixing ID: {name} {Fore.LIGHTBLACK_EX}-> {new_id}")
|
||||||
|
else:
|
||||||
|
skipped += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Not found — upload it
|
||||||
|
info(f"Uploading: {name} {Fore.LIGHTBLACK_EX}(not in application emojis)")
|
||||||
|
|
||||||
|
image_data = await _fetch_emoji_image(session, old_id, animated)
|
||||||
|
if not image_data:
|
||||||
|
error(f"Could not download image for {name} [ID: {old_id}]")
|
||||||
|
failed += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
mime = "image/gif" if animated else "image/webp"
|
||||||
|
b64 = base64.b64encode(image_data).decode("utf-8")
|
||||||
|
image_uri = f"data:{mime};base64,{b64}"
|
||||||
|
|
||||||
|
async with session.post(
|
||||||
|
f"https://discord.com/api/v10/applications/{app_id}/emojis",
|
||||||
|
json={"name": name, "image": image_uri},
|
||||||
|
) as r2:
|
||||||
|
if r2.status in (200, 201):
|
||||||
|
new_emoji = await r2.json()
|
||||||
|
new_id = new_emoji["id"]
|
||||||
|
old_str = f"<{animated_str}:{name}:{old_id}>"
|
||||||
|
new_str = f"<{animated_str}:{new_emoji['name']}:{new_id}>"
|
||||||
|
content = content.replace(old_str, new_str)
|
||||||
|
app_emojis.append(new_emoji)
|
||||||
|
updated = True
|
||||||
|
uploaded += 1
|
||||||
|
success(f"Uploaded: {name} {Fore.LIGHTBLACK_EX}[saved as ID: {new_id}]")
|
||||||
|
else:
|
||||||
|
resp_text = await r2.text()
|
||||||
|
error(f"Discord rejected {name} -> {resp_text}")
|
||||||
|
failed += 1
|
||||||
|
|
||||||
|
# Small delay to respect Discord rate limits
|
||||||
|
await asyncio.sleep(0.5)
|
||||||
|
|
||||||
|
# ── Write patched emoji.py ────────────────────────────────────────────────
|
||||||
|
if updated:
|
||||||
|
try:
|
||||||
|
with open(EMOJI_PY_PATH, "w", encoding="utf-8") as f:
|
||||||
|
f.write(content)
|
||||||
|
success("emoji.py patched in-place to reflect current API state.")
|
||||||
|
except Exception as err:
|
||||||
|
error(f"Could not write patched emoji.py ({err})")
|
||||||
|
updated = False # don't restart if we couldn't save
|
||||||
|
|
||||||
|
# ── Summary ───────────────────────────────────────────────────────────────
|
||||||
|
parts = []
|
||||||
|
if skipped: parts.append(f"{Fore.GREEN}{skipped} already matching{Style.RESET_ALL}")
|
||||||
|
if fixed: parts.append(f"{Fore.YELLOW}{fixed} ID mismatches fixed{Style.RESET_ALL}")
|
||||||
|
if uploaded: parts.append(f"{Fore.CYAN}{uploaded} newly uploaded{Style.RESET_ALL}")
|
||||||
|
if failed: parts.append(f"{Fore.RED}{failed} failures{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
if parts:
|
||||||
|
system("Sync complete: " + f" {Fore.LIGHTBLACK_EX}|{Style.RESET_ALL} ".join(parts))
|
||||||
|
else:
|
||||||
|
system("Sync complete: nothing to do.")
|
||||||
|
|
||||||
|
# ── Auto-restart if emoji.py was changed ─────────────────────────────────
|
||||||
|
if updated:
|
||||||
|
_restart()
|
||||||
@@ -2,11 +2,11 @@
|
|||||||
NEXT_PUBLIC_API_URL=http://localhost:8000/api/v1
|
NEXT_PUBLIC_API_URL=http://localhost:8000/api/v1
|
||||||
|
|
||||||
# API Key for authentication (if used)
|
# API Key for authentication (if used)
|
||||||
NEXT_PUBLIC_DASHBOARD_API_KEY=ZYROX_SECURE_API_KEY_12345
|
NEXT_PUBLIC_DASHBOARD_API_KEY=ZYROX_SECURE_API_KEY_12345_CHANGE_THIS_ASAP_BY_CODEX_DEVS
|
||||||
|
|
||||||
# NextAuth Configuration
|
# NextAuth Configuration
|
||||||
NEXTAUTH_URL=http://localhost:3000
|
NEXTAUTH_URL=http://localhost:3000
|
||||||
NEXTAUTH_SECRET=zyrox_nextauth_default_secret_string_2026_change_me
|
NEXTAUTH_SECRET=zyrox_nextauth_default_secret_string_2026_change_me_BY_CODEX_DEVS
|
||||||
|
|
||||||
# Discord OAuth configuration
|
# Discord OAuth configuration
|
||||||
DISCORD_CLIENT_ID=
|
DISCORD_CLIENT_ID=
|
||||||
|
|||||||
Reference in New Issue
Block a user