Spaces:
Sleeping
Sleeping
File size: 29,190 Bytes
b22819e 4340a48 b22819e 28520ff b22819e 28520ff b22819e 4340a48 b22819e 4340a48 b22819e 28520ff b22819e 4340a48 b22819e 4340a48 b22819e 4340a48 b22819e 4340a48 b22819e 4340a48 b22819e 4340a48 b22819e 4340a48 b22819e 4340a48 b22819e 4340a48 b22819e 4340a48 b22819e 4340a48 b22819e 4340a48 b22819e 4340a48 b22819e 4340a48 b22819e 4340a48 28520ff 4340a48 b22819e 4340a48 28520ff 4340a48 b22819e 28520ff 4340a48 28520ff 4340a48 28520ff 4340a48 b22819e 4340a48 b22819e 4340a48 b22819e 4340a48 b22819e 4340a48 b22819e 4340a48 b22819e 4340a48 b22819e 4340a48 b22819e 28520ff | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 | import discord
from discord.ext import commands, tasks
from discord import app_commands
from discord.ui import Button, View, Select
import asyncio
import random
import os
from datetime import datetime
# =======================================================
# الإعدادات الأساسية (الثوابت)
# =======================================================
TARGET_GUILD_ID = 1463693244897693779 # أيدي السيرفر المسموح
OWNER_ROLE_ID = 1492516779598155877 # أيدي رتبة المالك للتحكم
# =======================================================
# الأذكار والتذكيرات (القائمة الكاملة)
# =======================================================
REMINDERS = [
"🌸 سبحان الله وبحمده، سبحان الله العظيم",
"✨ اللهم صل وسلم على نبينا محمد",
"📿 أستغفر الله العظيم وأتوب إليه",
"🕊️ لا حول ولا قوة إلا بالله",
"🌿 سبحان الله، والحمد لله، ولا إله إلا الله، والله أكبر",
"🌸 سبحان الله", "✨ الحمد لله", "📿 الله أكبر", "🕊️ لا إله إلا الله",
"🌿 اللهم اغفر لي", "🌸 اللهم ارحمني", "✨ اللهم تب علي", "📿 اللهم ارزقني",
"🕊️ حسبي الله ونعم الوكيل", "🌿 توكلت على الله", "🌸 رب اغفر لي ولوالدي",
"✨ اللهم اجعلني من الصالحين", "📿 اللهم اهدني", "🕊️ اللهم ثبتني",
"🌿 اللهم ارزقني الجنة", "🌸 اللهم أجرني من النار", "✨ يا رب", "📿 يا الله",
"🕊️ يا حي يا قيوم برحمتك أستغيث", "🌿 اللهم إني أسألك العافية",
"🌸 اللهم إني أسألك الهدى والتقى", "✨ اللهم إني أعوذ بك من الهم والحزن",
"📿 اللهم إني أعوذ بك من العجز والكسل", "🕊️ اللهم إني أعوذ بك من الجبن والبخل",
"🌿 اللهم إني أعوذ بك من غلبة الدين وقهر الرجال", "🌸 اللهم اجعل القرآن ربيع قلبي",
"✨ اللهم نور قلبي", "📿 اللهم طهر قلبي", "🕊️ اللهم أصلح حالي",
"🌿 اللهم اجعلني من الذاكرين", "🌸 اللهم اجعلني من الشاكرين",
"✨ اللهم اجعلني من الصابرين", "📿 اللهم اجعلني من التوابين",
"🕊️ اللهم اجعلني من المتقين", "🌿 اللهم اجعلني من المحسنين",
"🌸 اللهم ارزقني الإخلاص", "✨ اللهم ارزقني الصدق", "📿 اللهم ارزقني حسن الخاتمة",
"🕊️ اللهم اجعل قبري روضة من رياض الجنة", "🌿 اللهم اجعلني من أهل الجنة",
"🌸 اللهم ارزقني الفردوس الأعلى", "✨ اللهم لا تحرمني من رحمتك",
"📿 اللهم لا تكلني إلى نفسي", "🕊️ اللهم ارحم موتانا", "🌿 اللهم اشف مرضانا",
"🌸 اللهم فرج همومنا", "✨ اللهم اقض ديوننا", "📿 اللهم وسع رزقنا",
"🕊️ اللهم بارك لنا", "🌿 اللهم احفظنا", "🌸 اللهم انصرنا",
"✨ اللهم اجعلنا من عبادك الصالحين", "📿 اللهم ارزقنا رضاك",
"🕊️ اللهم اجعلنا من أهل الذكر", "🌿 اللهم ارزقنا حبك", "🌸 اللهم ارزقنا حب نبيك",
"✨ اللهم اجعلنا من المتوكلين", "📿 اللهم ارزقنا الصبر", "🕊️ اللهم ارزقنا اليقين",
"🌿 اللهم اجعلنا من الذاكرين الله كثيرا", "🌸 اللهم اجعلنا من القانتين",
"✨ اللهم ارزقنا حسن الظن بك", "📿 اللهم اجعلنا من المقبولين",
"🕊️ اللهم ارزقنا لذة النظر إلى وجهك", "🌿 اللهم اجعلنا من الفائزين",
"🌸 اللهم اجعلنا من أهل الفردوس", "✨ اللهم اجعلنا من عتقائك من النار",
"📿 اللهم اجعلنا من المستغفرين", "🕊️ اللهم اجعلنا من الراجعين إليك",
"🌿 اللهم اجعلنا من المنيبين", "🌸 اللهم ارزقنا التوبة النصوح",
"✨ اللهم تقبل منا", "📿 اللهم اغفر لنا", "🕊️ اللهم ارحمنا", "🌿 اللهم تب علينا",
"🌸 اللهم اهدنا", "✨ اللهم احفظنا من كل سوء", "📿 اللهم اجعلنا من الصالحين",
"🕊️ اللهم ارزقنا الجنة بغير حساب", "🌿 اللهم اجعلنا من أهل القرآن",
"🌸 اللهم اجعل القرآن شفيعاً لنا", "✨ اللهم اجعل القرآن حجة لنا",
"📿 اللهم اجعلنا من الذين يستمعون القول فيتبعون أحسنه",
"🕊️ اللهم اجعلنا من أولي الألباب", "🌿 اللهم ارزقنا العلم النافع",
"🌸 اللهم ارزقنا العمل الصالح", "✨ اللهم ارزقنا الإيمان الكامل",
"📿 اللهم اجعلنا من أهل التقوى", "🕊️ اللهم اجعلنا من الصادقين",
"🌿 اللهم اجعلنا من المخلصين", "🌸 اللهم اجعلنا من عبادك المقربين",
"✨ اللهم اجعلنا من الذاكرين الشاكرين", "📿 اللهم اجعلنا من الصابرين المحتسبين"
]
# =======================================================
# قائمة 30 قارئ (بدون اختصار)
# =======================================================
RECITERS = [
{"name": "إذاعة تلاوات منوعة", "desc": "بث مباشر لتلاوات مختارة", "url": "https://qurango.net/radio/tarateel"},
{"name": "عبدالباسط عبدالصمد", "desc": "تلاوة مجودة بصوت خاشع", "url": "https://qurango.net/radio/abdulbasit_abdulsamad_mjawwad"},
{"name": "مشاري العفاسي", "desc": "تلاوة هادئة ومريحة", "url": "https://qurango.net/radio/mishary_alafasi"},
{"name": "ياسر الدوسري", "desc": "تلاوات مميزة من الحرم", "url": "https://qurango.net/radio/yasser_aldosari"},
{"name": "ماهر المعيقلي", "desc": "تلاوة عذبة وشهيرة", "url": "https://qurango.net/radio/maher_al_muaiqly"},
{"name": "أحمد بن علي العجمي", "desc": "تلاوة خاشعة", "url": "https://qurango.net/radio/ahmad_alajmy"},
{"name": "سعد الغامدي", "desc": "تلاوة مريحة للقلب", "url": "https://qurango.net/radio/saad_alghamidi"},
{"name": "سعود الشريم", "desc": "من تلاوات الحرم المكي", "url": "https://qurango.net/radio/saud_alshuraim"},
{"name": "عبدالرحمن السديس", "desc": "تلاوة الحرم المكي الشريف", "url": "https://qurango.net/radio/abdulrahman_alsudaes"},
{"name": "محمود خليل الحصري", "desc": "تلاوة مرتلة دقيقة", "url": "https://qurango.net/radio/mahmoud_khalil_alhussary"},
{"name": "علي عبدالله جابر", "desc": "تلاوة مميزة", "url": "https://qurango.net/radio/ali_jaber"},
{"name": "محمد أيوب", "desc": "تلاوة حجازية", "url": "https://qurango.net/radio/mohammed_ayyub"},
{"name": "محمد صديق المنشاوي", "desc": "تلاوة خاشعة جداً", "url": "https://qurango.net/radio/mohammed_siddiq_alminshawi"},
{"name": "أبوبكر الشاطري", "desc": "تلاوة هادئة", "url": "https://qurango.net/radio/abubakr_alshatri"},
{"name": "عبدالله بصفر", "desc": "تلاوة عذبة", "url": "https://qurango.net/radio/abdullah_basfer"},
{"name": "عبدالمحسن القاسم", "desc": "إمام المسجد النبوي", "url": "https://qurango.net/radio/abdulmohsin_alqasim"},
{"name": "عبدالودود حنيف", "desc": "تلاوة رائعة", "url": "https://qurango.net/radio/abdulwadood_haneef"},
{"name": "علي عبدالرحمن الحذيفي", "desc": "من تلاوات المسجد النبوي", "url": "https://qurango.net/radio/ali_alhuthaifi"},
{"name": "فارس عباد", "desc": "تلاوة مؤثرة", "url": "https://qurango.net/radio/fares_abbad"},
{"name": "محمد جبريل", "desc": "تلاوة مشهورة", "url": "https://qurango.net/radio/mohammed_jibreel"},
{"name": "محمد الطبلاوي", "desc": "من كبار القراء", "url": "https://qurango.net/radio/mohammad_altablaway"},
{"name": "محمود علي البنا", "desc": "تلاوة كلاسيكية", "url": "https://qurango.net/radio/mahmoud_ali__albanna"},
{"name": "مصطفى إسماعيل", "desc": "تلاوة مجودة", "url": "https://qurango.net/radio/mustafa_ismail"},
{"name": "هاني الرفاعي", "desc": "تلاوة بكائية", "url": "https://qurango.net/radio/hani_arrifai"},
{"name": "يحيى حوا", "desc": "تلاوة هادئة", "url": "https://qurango.net/radio/yahya_hawwa"},
{"name": "خالد القحطاني", "desc": "تلاوة خاشعة", "url": "https://qurango.net/radio/khalid_alqahtani"},
{"name": "صلاح البدير", "desc": "إمام المسجد النبوي", "url": "https://qurango.net/radio/salah_albudair"},
{"name": "صلاح بو خاطر", "desc": "تلاوة ندية", "url": "https://qurango.net/radio/salah_bukhatir"},
{"name": "عبدالرشيد صوفي", "desc": "تلاوة مميزة بروايات", "url": "https://qurango.net/radio/abdulrasheed_soufi"},
{"name": "عبدالله عواد الجهني", "desc": "إمام الحرم المكي", "url": "https://qurango.net/radio/abdullah_aljuhani"}
]
# --- متغيرات التحكم بالبث ---
current_reciter_index = 0
current_volume = 1.0
# إعدادات أكثر أماناً لتجنب حظر IP من السيرفرات الصوتية
FFMPEG_OPTIONS = {
'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5',
'options': '-vn -sn -dn -bufsize 500k -max_muxing_queue_size 1024'
}
# =======================================================
# تجهيز واجهة الأزرار (Control Panel)
# =======================================================
class ReciterSelect(Select):
def __init__(self):
options = []
for i, r in enumerate(RECITERS[:25]):
options.append(discord.SelectOption(label=r['name'], description=r['desc'][:50], value=str(i)))
super().__init__(placeholder="اختر القارئ من القائمة السريعة...", min_values=1, max_values=1, options=options, custom_id="select_reciter")
async def callback(self, interaction: discord.Interaction):
role = interaction.guild.get_role(OWNER_ROLE_ID)
if role not in interaction.user.roles:
return await interaction.response.send_message("❌ لا تملك صلاحية.", ephemeral=True)
global current_reciter_index
current_reciter_index = int(self.values[0])
vc = interaction.guild.voice_client
if vc: await play_current_reciter(vc)
try:
await interaction.response.send_message(f"🎙️ تم التغيير إلى: {RECITERS[current_reciter_index]['name']}", ephemeral=True)
await log_event(interaction.guild, f"🎙️ **{interaction.user.name}** قام بتغيير القارئ إلى: {RECITERS[current_reciter_index]['name']}")
except: pass
class ControlPanelView(View):
def __init__(self):
super().__init__(timeout=None)
self.add_item(ReciterSelect())
async def check_owner(self, interaction: discord.Interaction):
role = interaction.guild.get_role(OWNER_ROLE_ID)
if role and role in interaction.user.roles:
return True
try:
await interaction.response.send_message("❌ عذراً، لا تملك الصلاحية (رتبة المالك المطلوبة).", ephemeral=True)
except: pass
return False
@discord.ui.button(label="⏸️ / ▶️ إيقاف وتشغيل", style=discord.ButtonStyle.primary, custom_id="btn_toggle")
async def toggle_btn(self, interaction: discord.Interaction, button: Button):
if not await self.check_owner(interaction): return
vc = interaction.guild.voice_client
try:
if vc:
if vc.is_paused():
vc.resume()
await interaction.response.send_message("▶️ تم استئناف البث.", ephemeral=True)
await log_event(interaction.guild, f"▶️ **{interaction.user.name}** قام باستئناف البث.")
elif vc.is_playing():
vc.pause()
await interaction.response.send_message("⏸️ تم إيقاف البث مؤقتاً.", ephemeral=True)
await log_event(interaction.guild, f"⏸️ **{interaction.user.name}** قام بإيقاف البث يدوياً.")
else:
await play_current_reciter(vc)
await interaction.response.send_message("▶️ تم تشغيل البث.", ephemeral=True)
else:
await interaction.response.send_message("❌ البوت غير متصل.", ephemeral=True)
except: pass
@discord.ui.button(label="⏭️ التالي", style=discord.ButtonStyle.secondary, custom_id="btn_next")
async def next_btn(self, interaction: discord.Interaction, button: Button):
if not await self.check_owner(interaction): return
global current_reciter_index
current_reciter_index = (current_reciter_index + 1) % len(RECITERS)
vc = interaction.guild.voice_client
if vc: await play_current_reciter(vc)
try:
await interaction.response.send_message(f"⏭️ تم الانتقال إلى: {RECITERS[current_reciter_index]['name']}", ephemeral=True)
await log_event(interaction.guild, f"⏭️ **{interaction.user.name}** انتقل للقارئ: {RECITERS[current_reciter_index]['name']}")
except: pass
@discord.ui.button(label="⏮️ السابق", style=discord.ButtonStyle.secondary, custom_id="btn_prev")
async def prev_btn(self, interaction: discord.Interaction, button: Button):
if not await self.check_owner(interaction): return
global current_reciter_index
current_reciter_index = (current_reciter_index - 1) % len(RECITERS)
vc = interaction.guild.voice_client
if vc: await play_current_reciter(vc)
try:
await interaction.response.send_message(f"⏮️ تم الرجوع إلى: {RECITERS[current_reciter_index]['name']}", ephemeral=True)
await log_event(interaction.guild, f"⏮️ **{interaction.user.name}** رجع للقارئ: {RECITERS[current_reciter_index]['name']}")
except: pass
class QuranBot(commands.Bot):
def __init__(self):
intents = discord.Intents.default()
intents.message_content = True
intents.voice_states = True
intents.guilds = True
super().__init__(command_prefix="!", intents=intents)
async def setup_hook(self):
self.add_view(ControlPanelView())
await self.tree.sync()
print("✅ تم مزامنة الأوامر والأزرار بنجاح.")
bot = QuranBot()
# =======================================================
# دوال مساعدة وحماية من الحظر
# =======================================================
async def log_event(guild: discord.Guild, message: str):
log_channel = discord.utils.get(guild.text_channels, name="📜-سجلات-البوت")
time_now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
if log_channel:
try:
await log_channel.send(f"`[{time_now}]` {message}")
except: pass # منع توقف البوت إذا رفض ديسكورد إرسال الرسالة بسبب Rate Limit
print(f"[{time_now}] {message}")
def is_owner_and_in_control():
async def predicate(interaction: discord.Interaction):
if not interaction.guild:
try: await interaction.response.send_message("❌ هذا الأمر مخصص للاستخدام داخل السيرفر فقط.", ephemeral=True)
except: pass
return False
if interaction.channel.name != "🛠️ غرفة التحكم (للمالك)":
try: await interaction.response.send_message("❌ عذراً، لا يمكنك استخدام الأوامر إلا داخل 🛠️ غرفة التحكم.", ephemeral=True)
except: pass
return False
role = interaction.guild.get_role(OWNER_ROLE_ID)
if role and role in interaction.user.roles:
return True
try: await interaction.response.send_message("❌ عذراً، لا تملك الصلاحية (رتبة المالك المطلوبة).", ephemeral=True)
except: pass
return False
return app_commands.check(predicate)
async def play_current_reciter(vc: discord.VoiceClient):
try:
if vc.is_playing() or vc.is_paused():
vc.stop()
await asyncio.sleep(1) # تأخير بسيط لحماية الـ API من ضغط الطلبات
reciter = RECITERS[current_reciter_index]
audio_source = discord.FFmpegPCMAudio(reciter["url"], **FFMPEG_OPTIONS)
vc.play(discord.PCMVolumeTransformer(audio_source, volume=current_volume))
except Exception as e:
print(f"⚠️ خطأ أثناء التشغيل (تم تجاوزه): {e}")
# =======================================================
# هندسة القنوات والأحداث
# =======================================================
@bot.event
async def on_ready():
# حالة مستقرة وآمنة تظهر للمستخدمين
await bot.change_presence(status=discord.Status.online, activity=discord.Activity(type=discord.ActivityType.listening, name="القرآن الكريم 24/7 🎧"))
print(f"🤖 البوت {bot.user} متصل بشبكة ديسكورد بنجاح وهو الآن (Online).")
# فحص هادئ للسيرفرات
for guild in bot.guilds:
if guild.id != TARGET_GUILD_ID:
print(f"👢 جاري مغادرة سيرفر غريب بهدوء: {guild.name}")
await asyncio.sleep(2) # تأخير لمنع الطرد المتعدد السريع
try: await guild.leave()
except: pass
else:
await check_and_create_channels(guild)
await log_event(guild, "🚀 **تم إقلاع النظام والبوت متصل الآن.**")
# تشغيل نبض القلب (فحص كل 5 دقائق)
if not heartbeat_task.is_running():
heartbeat_task.start()
@bot.event
async def on_guild_join(guild):
print(f"📥 البوت دخل سيرفر جديد: {guild.name}")
await asyncio.sleep(2) # حماية API ديسكورد
if guild.id != TARGET_GUILD_ID:
try: await guild.leave()
except: pass
else:
await check_and_create_channels(guild)
await log_event(guild, "🚀 **تم إضافة البوت للسيرفر الصحيح وبدء التشغيل!**")
async def check_and_create_channels(guild):
category_name = "إذاعة القرآن الكريم"
broadcast_vc_name = "🎧 استماع القرآن (بث عام)"
control_vc_name = "🛠️ غرفة التحكم (للمالك)"
log_channel_name = "📜-سجلات-البوت"
category = discord.utils.get(guild.categories, name=category_name)
broadcast_vc = discord.utils.get(guild.voice_channels, name=broadcast_vc_name)
control_vc = discord.utils.get(guild.voice_channels, name=control_vc_name)
log_tc = discord.utils.get(guild.text_channels, name=log_channel_name)
owner_role = guild.get_role(OWNER_ROLE_ID)
try:
if not category:
category = await guild.create_category(category_name)
await asyncio.sleep(1)
if not log_tc:
overwrites_log = {
guild.default_role: discord.PermissionOverwrite(view_channel=False),
bot.user: discord.PermissionOverwrite(view_channel=True, send_messages=True, read_message_history=True)
}
if owner_role: overwrites_log[owner_role] = discord.PermissionOverwrite(view_channel=True, read_message_history=True)
log_tc = await guild.create_text_channel(log_channel_name, category=category, overwrites=overwrites_log)
await asyncio.sleep(1)
if not broadcast_vc:
overwrites_broadcast = {
guild.default_role: discord.PermissionOverwrite(
view_channel=True, connect=True, read_message_history=True,
speak=False, send_messages=False, add_reactions=False, stream=False
),
bot.user: discord.PermissionOverwrite(connect=True, speak=True, send_messages=True, administrator=True)
}
broadcast_vc = await guild.create_voice_channel(broadcast_vc_name, category=category, overwrites=overwrites_broadcast)
await asyncio.sleep(1)
if not control_vc:
overwrites_control = {
guild.default_role: discord.PermissionOverwrite(view_channel=False, connect=False),
bot.user: discord.PermissionOverwrite(view_channel=True, connect=True, send_messages=True)
}
if owner_role: overwrites_control[owner_role] = discord.PermissionOverwrite(view_channel=True, connect=True, send_messages=True)
control_vc = await guild.create_voice_channel(control_vc_name, category=category, overwrites=overwrites_control, user_limit=99)
embed = discord.Embed(
title="🎛️ لوحة تحكم الإذاعة الذكية",
description="استخدم الأزرار أدناه للتحكم السريع في البث، أو اختر القارئ من القائمة المنسدلة.\n\n*ملاحظة: يمكنك أيضاً استخدام الأوامر مثل `/volume` هنا فقط.*",
color=discord.Color.dark_theme()
)
embed.set_footer(text="SaaS Pro Dashboard")
await control_vc.send(embed=embed, view=ControlPanelView())
# اتصال البوت
if not guild.voice_client:
vc = await broadcast_vc.connect()
await asyncio.sleep(2) # استقرار الاتصال
await play_current_reciter(vc)
human_members = sum(1 for m in broadcast_vc.members if not m.bot)
if human_members == 0:
vc.pause()
await log_event(guild, "⏸️ القناة فارغة، تم وضع البث في وضع الاستعداد (لتجنب ضغط الشبكة).")
else:
await log_event(guild, "▶️ تم البدء بالبث لوجود مستمعين في القناة.")
except Exception as e:
print(f"⚠️ تحذير أثناء إنشاء القنوات (قد يكون بسبب ضغط الطلبات): {e}")
@bot.event
async def on_voice_state_update(member, before, after):
if member.bot: return
guild = member.guild
if guild.id != TARGET_GUILD_ID: return
bot_vc = guild.voice_client
if not bot_vc: return
try:
# حالة دخول عضو
if after.channel and after.channel.id == bot_vc.channel.id:
if bot_vc.is_paused():
bot_vc.resume()
await log_event(guild, f"▶️ استئناف البث التلقائي لدخول مستمع.")
embed = discord.Embed(
title="أهلاً بك في مجلس الذكر 🕊️",
description=random.choice(REMINDERS),
color=discord.Color.gold()
)
embed.set_footer(text=f"القارئ الحالي: {RECITERS[current_reciter_index]['name']}")
try:
await after.channel.send(content=f"مرحباً بك {member.mention}", embed=embed, delete_after=60)
except: pass
# حالة خروج عضو
elif before.channel and before.channel.id == bot_vc.channel.id:
human_members = sum(1 for m in before.channel.members if not m.bot)
if human_members == 0 and bot_vc.is_playing():
bot_vc.pause()
except: pass # منع أي خطأ مفاجئ من إيقاف البوت
# =======================================================
# مهمة الفحص الهادئ (Heartbeat)
# =======================================================
@tasks.loop(minutes=5)
async def heartbeat_task():
"""هذه الدالة تفحص البوت كل 5 دقائق لضمان عدم فصله من ديسكورد"""
try:
guild = bot.get_guild(TARGET_GUILD_ID)
if guild and guild.voice_client:
human_members = sum(1 for m in guild.voice_client.channel.members if not m.bot)
# إذا كان هناك ناس والصوت متوقف بالخطأ، نقوم بتشغيله
if human_members > 0 and not guild.voice_client.is_playing() and not guild.voice_client.is_paused():
await play_current_reciter(guild.voice_client)
await log_event(guild, "🔄 تم إعادة إنعاش البث التلقائي بواسطة نظام الحماية (Heartbeat).")
except: pass
# =======================================================
# أوامر السلاش (محصورة في غرفة التحكم)
# =======================================================
@bot.tree.command(name="play_radio", description="▶️ تشغيل بث القرآن إجبارياً")
@is_owner_and_in_control()
async def play_radio(interaction: discord.Interaction):
vc = interaction.guild.voice_client
try:
if not vc: return await interaction.response.send_message("❌ البوت غير متصل.", ephemeral=True)
if vc.is_paused(): vc.resume()
else: await play_current_reciter(vc)
await interaction.response.send_message(f"▶️ تم التشغيل: **{RECITERS[current_reciter_index]['name']}**", ephemeral=True)
await log_event(interaction.guild, f"▶️ تم التشغيل عبر أمر /play_radio")
except: pass
@bot.tree.command(name="stop_radio", description="⏹️ إيقاف البث مؤقتاً")
@is_owner_and_in_control()
async def stop_radio(interaction: discord.Interaction):
vc = interaction.guild.voice_client
try:
if vc and vc.is_playing():
vc.pause()
await interaction.response.send_message("⏹️ تم الإيقاف.", ephemeral=True)
await log_event(interaction.guild, f"⏹️ تم الإيقاف عبر أمر /stop_radio")
else:
await interaction.response.send_message("⚠️ متوقف بالفعل.", ephemeral=True)
except: pass
@bot.tree.command(name="volume", description="🔊 التحكم بدرجة الصوت (من 1 إلى 100)")
@app_commands.describe(level="درجة الصوت من 1 إلى 100")
@is_owner_and_in_control()
async def set_volume(interaction: discord.Interaction, level: int):
global current_volume
try:
if level < 1 or level > 100:
return await interaction.response.send_message("❌ يرجى إدخال رقم بين 1 و 100.", ephemeral=True)
current_volume = level / 100.0
vc = interaction.guild.voice_client
if vc and vc.source: vc.source.volume = current_volume
await interaction.response.send_message(f"🔊 تم تغيير درجة الصوت إلى: **{level}%**", ephemeral=True)
await log_event(interaction.guild, f"🔊 تم تغيير درجة الصوت إلى {level}%")
except: pass
# =======================================================
# التشغيل والـ Keep Alive
# =======================================================
try:
from keep_alive import keep_alive
keep_alive()
except Exception: pass
if __name__ == "__main__":
TOKEN = os.environ.get("DISCORD_TOKEN")
if TOKEN: bot.run(TOKEN)
else: print("❌ التوكن مفقود! يرجى التأكد من وضعه في المتغيرات البيئية (Secrets).")
|