tkc / main.py
Skydata001's picture
Update main.py
c1cc14b verified
import discord
from discord import app_commands
from discord.ext import commands
import datetime
import random
import string
import io
import asyncio
import re
# --- الإعدادات الثابتة ---
OWNER_ID = 1429183440485486679
ERROR_LOG_CHANNEL_ID = 1488536752691085552
TICKETS_CHANNEL_ID = 1488536530019549344
LOG_CHANNEL_ID = 1488536921813680218
STAFF_ROLES_IDS = [
1488187501142216826, 1488187641424773140, 1488187816201687181,
1488188612313874733, 1488537308700344490, 1488537566910218260
]
PING_ROLES = "<@&1488187816201687181> <@&1488188612313874733> <@&1488537308700344490> <@&1488537566910218260>"
# --- نظام الحماية والقيود ---
active_tickets = {} # user_id: thread_id
cooldowns = {} # user_id: datetime
class MyBot(commands.Bot):
def __init__(self):
intents = discord.Intents.default()
intents.message_content = True
intents.members = True
super().__init__(command_prefix="!", intents=intents)
async def setup_hook(self):
self.add_view(TicketPanelView())
self.add_view(TicketControls())
await self.tree.sync()
async def on_error(self, event, *args, **kwargs):
channel = self.get_channel(ERROR_LOG_CHANNEL_ID)
if channel:
await channel.send(f"⚠️ **Crash Detected / خطأ في النظام**\n`{event}`\n<@{OWNER_ID}>")
bot = MyBot()
# --- أدوات مساعدة ---
def is_staff(interaction: discord.Interaction):
return any(role.id in STAFF_ROLES_IDS for role in interaction.user.roles) or interaction.user.id == OWNER_ID
# --- نظام واجهة التذاكر ---
class TicketPanelView(discord.ui.View):
def __init__(self):
super().__init__(timeout=None)
@discord.ui.select(
custom_id="ticket_select",
placeholder="Choose ticket type / اختر نوع التذكرة",
options=[
discord.SelectOption(label="Complaint against staff / شكوى ضد إداري", value="staff_complaint", emoji="⚖️"),
discord.SelectOption(label="Complaint against user / شكوى ضد لاعب", value="user_complaint", emoji="👥"),
discord.SelectOption(label="Bug report / بلاغ عن ثغرة", value="bug_report", emoji="🐛"),
discord.SelectOption(label="Technical support / دعم فني", value="tech_support", emoji="🛠️"),
]
)
async def select_callback(self, interaction: discord.Interaction, select: discord.ui.Select):
user_id = interaction.user.id
# تحقق من التذكرة المفتوحة
if user_id in active_tickets:
return await interaction.response.send_message("❌ You already have an open ticket! / لديك تذكرة مفتوحة بالفعل!", ephemeral=True)
# تحقق من الـ Cooldown
if user_id in cooldowns:
diff = (datetime.datetime.now() - cooldowns[user_id]).total_seconds()
if diff < 60:
return await interaction.response.send_message(f"⏳ Wait {int(60-diff)}s / انتظر {int(60-diff)} ثانية", ephemeral=True)
await interaction.response.defer(ephemeral=True)
# إنشاء Thread
channel = bot.get_channel(TICKETS_CHANNEL_ID)
ticket_id = ''.join(random.choices(string.ascii_lowercase + string.digits, k=4))
thread_name = f"ticket-{random.randint(1000,9999)}-{ticket_id}"
thread = await channel.create_thread(
name=thread_name,
type=discord.ChannelType.private_thread,
invitable=False
)
active_tickets[user_id] = thread.id
await thread.add_user(interaction.user)
await thread.edit(slowmode_delay=10)
# رسالة الترحيب
embed = discord.Embed(
title="Ticket Created / تم إنشاء التذكرة",
description=f"Welcome {interaction.user.mention}\n{PING_ROLES}\nYour ticket has been created, please wait...\n\nمرحباً بك، تم إنشاء تذكرتك، يرجى الانتظار...",
color=discord.Color.blue()
)
await thread.send(embed=embed, view=TicketControls())
# إرسال DM
try:
await interaction.user.send(f"✅ Your ticket has been created: {thread.jump_url}\nتم إنشاء تذكرتك بنجاح.")
except: pass
await interaction.followup.send(f"✅ Ticket Created: {thread.mention}", ephemeral=True)
class TicketControls(discord.ui.View):
def __init__(self):
super().__init__(timeout=None)
@discord.ui.button(label="Claim / استلام", style=discord.ButtonStyle.green, custom_id="claim_btn")
async def claim(self, interaction: discord.Interaction, button: discord.ui.Button):
if not is_staff(interaction):
return await interaction.response.send_message("❌ Staff only / للموظفين فقط", ephemeral=True)
button.disabled = True
await interaction.response.edit_message(view=self)
await interaction.followup.send(f"📌 Ticket claimed by / تم استلام التذكرة من قبل: {interaction.user.mention}")
# إرسال DM للمستخدم
thread_owner_id = next((k for k, v in active_tickets.items() if v == interaction.channel_id), None)
if thread_owner_id:
user = await bot.fetch_user(thread_owner_id)
try: await user.send(f"👋 Your ticket has been claimed by **{interaction.user.name}**\nتم استلام تذكرتك بواسطة الموظف.")
except: pass
@discord.ui.button(label="Close / إغلاق", style=discord.ButtonStyle.red, custom_id="close_btn")
async def close(self, interaction: discord.Interaction, button: discord.ui.Button):
if not is_staff(interaction):
return await interaction.response.send_message("❌ Staff only / للموظفين فقط", ephemeral=True)
await interaction.response.send_modal(CloseModal())
class CloseModal(discord.ui.Modal, title="Close Ticket / إغلاق التذكرة"):
reason = discord.ui.TextInput(label="Reason / السبب", placeholder="Enter closing reason...", min_length=5, required=True)
async def on_submit(self, interaction: discord.Interaction):
thread = interaction.channel
messages = [msg async for msg in thread.history(limit=None, oldest_first=True)]
# إنشاء ملف سجل
transcript = ""
for m in messages:
transcript += f"[{m.created_at.strftime('%Y-%m-%d %H:%M')}] {m.author}: {m.content}\n"
file = discord.File(io.BytesIO(transcript.encode()), filename=f"{thread.name}.txt")
# إرسال اللوق
log_channel = bot.get_channel(LOG_CHANNEL_ID)
user_id = next((k for k, v in active_tickets.items() if v == thread.id), "Unknown")
embed = discord.Embed(title="Ticket Closed / إغلاق تذكرة", color=discord.Color.red())
embed.add_field(name="User / المستخدم", value=f"<@{user_id}>")
embed.add_field(name="Staff / الموظف", value=interaction.user.mention)
embed.add_field(name="Reason / السبب", value=self.reason.value)
embed.add_field(name="Open Time / وقت الفتح", value=thread.created_at.strftime('%Y-%m-%d %H:%M'))
await log_channel.send(embed=embed, file=file)
# تنظيف البيانات
if user_id != "Unknown":
active_tickets.pop(int(user_id), None)
cooldowns[int(user_id)] = datetime.datetime.now()
await interaction.response.send_message("Closing... / جارِ الإغلاق...")
await thread.delete()
# --- الأوامر ---
@bot.tree.command(name="setup-ticket-panel", description="Setup the ticket panel (Owner Only)")
async def setup_ticket(interaction: discord.Interaction):
if interaction.user.id != OWNER_ID:
return await interaction.response.send_message("❌ Access Denied", ephemeral=True)
embed = discord.Embed(
title="Support System / نظام الدعم الفني",
description=(
"**Rules / القوانين:**\n"
"❌ No spamming tickets / يمنع فتح تذاكر عشوائية\n"
"✅ Use for complaints or support / استخدم التذاكر للشكاوى والدعم فقط\n\n"
"**Options / الخيارات:**\n"
"• Staff Complaint / شكوى إداري\n"
"• User Complaint / شكوى لاعب\n"
"• Bug Report / بلاغ ثغرة\n"
"• Technical Support / دعم فني"
),
color=discord.Color.green()
)
await interaction.response.send_message("Panel Sent!", ephemeral=True)
await interaction.channel.send(embed=embed, view=TicketPanelView())
@bot.tree.command(name="help", description="Show help information")
async def help_cmd(interaction: discord.Interaction):
await interaction.response.send_message(f"To open a ticket, go to <#{TICKETS_CHANNEL_ID}>\nلفتح تذكرة، توجه إلى القناة المخصصة.", ephemeral=True)
# --- نظام الحماية (Anti-Spam & Content Filter) ---
@bot.event
async def on_message(message):
if message.author.bot: return
if not isinstance(message.channel, discord.Thread): return
if message.channel.parent_id != TICKETS_CHANNEL_ID: return
# منع الروابط، الملفات، والبصمات الصوتية
if re.search(r'http[s]?://', message.content) or message.attachments or message.flags.voice:
# السماح فقط بالصور والفيديو
allowed = True
if message.attachments:
for att in message.attachments:
if not att.content_type or (not att.content_type.startswith('image/') and not att.content_type.startswith('video/')):
allowed = False
if not allowed or re.search(r'http[s]?://', message.content) or message.flags.voice:
await message.delete()
return await message.channel.send(f"{message.author.mention} ❌ Only text, images, and videos are allowed.\nمسموح فقط بالنصوص، الصور، والفيديو.", delete_after=5)
# منع السبام (أحرف عشوائية طويلة)
if len(message.content) > 50 and len(set(message.content)) < 10:
await message.delete()
return await message.channel.send("❌ Random characters/spam detected.", delete_after=5)
import os
from dotenv import load_dotenv
load_dotenv()
bot.run(os.getenv('TOKEN'))