bot_v4 / utils /html.py
qqqsfasdf's picture
Upload 70 files
036b534 verified
# ============================================
# utils/html.py — أدوات تنسيق HTML لتيليجرام
# ============================================
# لماذا HTML وليس MarkdownV2؟
# - HTML أقل أخطاءً: نحتاج escape لثلاثة رموز فقط (&, <, >)
# - يدعم <blockquote> و<blockquote expandable>
# - أوضح في القراءة داخل الكود
# ============================================
def esc(text: str) -> str:
"""
Escape رموز HTML الخاصة الثلاثة.
يجب استدعاؤها على أي نص يأتي من مصدر خارجي
قبل إدراجه في رسالة HTML.
"""
if not text:
return ""
return (
str(text)
.replace("&", "&amp;")
.replace("<", "&lt;")
.replace(">", "&gt;")
)
def b(text: str) -> str:
"""نص عريض"""
return f"<b>{esc(text)}</b>"
def i(text: str) -> str:
"""نص مائل"""
return f"<i>{esc(text)}</i>"
def u(text: str) -> str:
"""نص تحته خط"""
return f"<u>{esc(text)}</u>"
def code(text: str) -> str:
"""نص كـ code"""
return f"<code>{esc(text)}</code>"
def link(label: str, url: str) -> str:
"""رابط مخفي"""
return f'<a href="{url}">{esc(label)}</a>'
def blockquote(text: str, expandable: bool = False) -> str:
"""
blockquote عادي أو قابل للتوسيع.
expandable=True: يُظهر زر "اقرأ المزيد" إذا كان الحجم كبيراً.
"""
if expandable:
return f"<blockquote expandable>{text}</blockquote>"
return f"<blockquote>{text}</blockquote>"
def row(*cells: str, sep: str = " | ") -> str:
"""صف بيانات: المفتاح | القيمة"""
return sep.join(str(c) for c in cells if c)
# ════════════════════════════════════════
# بناء رسائل اللعبة
# ════════════════════════════════════════
def build_game_info_message(details: dict, game_link_in_lib: str | None = None) -> str:
"""
بناء رسالة تفاصيل اللعبة الكاملة بتنسيق HTML.
الترتيب:
1. رابط الصورة (كرابط نصي → يولّد Preview تلقائياً)
2. اسم اللعبة (عريض)
3. معلومات أساسية داخل blockquote
4. اللغات داخل blockquote expandable
5. التصنيفات والخصائص داخل blockquote expandable
6. القصة (3 أسطر)
"""
parts = []
# ── رابط الصورة فوق الرسالة ──
cover_url = details.get("cover_url", "")
if cover_url:
parts.append(cover_url)
parts.append("")
# ── اسم اللعبة ──
parts.append(f"🎮 <b>{esc(details.get('name', ''))}</b>")
parts.append("")
# ── المعلومات الأساسية ──
basic_lines = []
if details.get("release_date"):
basic_lines.append(f"• تاريخ الإصدار: {esc(details['release_date'])}")
if details.get("developer"):
basic_lines.append(f"• المطور: {esc(details['developer'])}")
if details.get("publisher") and details["publisher"] != details.get("developer"):
basic_lines.append(f"• الناشر: {esc(details['publisher'])}")
if details.get("platforms_str"):
basic_lines.append(f"• المنصات: {esc(details['platforms_str'])}")
# التقييمات
ur = details.get("user_rating", "")
uc = details.get("user_rating_count", 0)
cr = details.get("crit_rating", "")
cc = details.get("crit_rating_count", 0)
rating_line_parts = []
if ur:
rating_line_parts.append(f"{esc(ur)} ⭐ (بناء على {esc(str(uc))} مستخدم)")
if cr:
rating_line_parts.append(f"{esc(cr)} 🌟 (بناء على {esc(str(cc))} نقاد)")
if rating_line_parts:
basic_lines.append(f"• التقييمات: {' — '.join(rating_line_parts)}")
# التصنيف العمري
age_lines = details.get("age_rating_lines", [])
if age_lines:
basic_lines.append("• التصنيف العمري:")
for al in age_lines:
basic_lines.append(f" {esc(al)}")
if basic_lines:
parts.append(blockquote("\n".join(basic_lines)))
parts.append("")
# ── اللغات (expandable) ──
lang_sections = details.get("language_sections", {})
if any(lang_sections.values()):
lang_lines = []
if lang_sections.get("audio"):
lang_lines.append(f"🔊 <b>الصوت / الدبلجة:</b>")
lang_lines.append(esc(" • ".join(lang_sections["audio"])))
if lang_sections.get("interface"):
lang_lines.append(f"🖥️ <b>الواجهة:</b>")
lang_lines.append(esc(" • ".join(lang_sections["interface"])))
if lang_sections.get("subtitles"):
lang_lines.append(f"📝 <b>الترجمة النصية:</b>")
lang_lines.append(esc(" • ".join(lang_sections["subtitles"])))
if lang_lines:
parts.append(f"<b>اللغات المدعومة:</b>")
parts.append(blockquote("\n".join(lang_lines), expandable=True))
parts.append("")
# ── التصنيفات والخصائص (expandable) ──
cat_lines = []
if details.get("genres_ar"):
cat_lines.append(f"• الأنواع: {esc(details['genres_ar'])}")
if details.get("themes_ar"):
cat_lines.append(f"• المواضيع: {esc(details['themes_ar'])}")
if details.get("game_modes_ar"):
cat_lines.append(f"• أسلوب اللعب: {esc(details['game_modes_ar'])}")
if details.get("perspectives_ar"):
cat_lines.append(f"• منظور اللاعب: {esc(details['perspectives_ar'])}")
if details.get("engine"):
cat_lines.append(f"• المحرك: {esc(details['engine'])}")
if details.get("franchise"):
cat_lines.append(f"• السلسلة: {esc(details['franchise'])}")
if details.get("parent_game"):
cat_lines.append(f"• هو فرعي من: {esc(details['parent_game'])}")
if details.get("collection"):
cat_lines.append(f"• سلسلة أعمال: {esc(details['collection'])}")
if cat_lines:
parts.append(blockquote("\n".join(cat_lines), expandable=True))
parts.append("")
# ── القصة ──
if details.get("summary"):
parts.append(f"<b>📖 نبذة عن القصة:</b>")
parts.append(esc(details["summary"]))
# ── رابط التعريب ──
if game_link_in_lib:
parts.append("")
parts.append(f"🎌 {link('شاهد التعريب في مكتبتنا', game_link_in_lib)}")
return "\n".join(p for p in parts)
def build_pc_specs_message(game_name: str, game_info: dict, pc_specs: dict) -> str:
"""
رسالة متطلبات تشغيل PC كاملة بتنسيق HTML.
كل حقل في blockquote منفصل حسب التصميم المطلوب.
"""
parts = []
# ── رأس الرسالة ──
parts.append(f"🎮 <b>{esc(game_name)}</b>")
# هاشتاقات الأنواع
genres_raw = game_info.get("genres_ar", "")
if genres_raw:
tags = []
for g in genres_raw.split("|"):
g = g.strip()
# إزالة الإيموجي للهاشتاق
tag_text = ''.join(c for c in g if c.isalpha() or c in ' _').strip().replace(' ', '_')
if tag_text:
tags.append(f"#{tag_text}")
if tags:
parts.append(" ".join(tags[:3]))
# التصنيف العمري وتاريخ الإصدار
age_lines = game_info.get("age_rating_lines", [])
if age_lines:
parts.append(f"🔞 تصنيف العمر: {esc(age_lines[0].split()[1] if len(age_lines[0].split()) > 1 else age_lines[0])}")
if game_info.get("release_date"):
parts.append(f"🗓️ الإصدار: {esc(game_info['release_date'])}")
parts.append("")
# ── الحد الأدنى ──
min_specs = pc_specs.get("minimum", {})
if min_specs:
parts.append(f"<b>🔹 الحد الأدنى (Minimum)</b>")
_SPEC_LABELS_AR = {
"OS": "نظام التشغيل",
"CPU": "المعالج (CPU)",
"RAM": "الذاكرة (RAM)",
"GPU": "كرت الشاشة (GPU)",
"DirectX": "DirectX",
"Storage": "التخزين",
"Network": "الشبكة",
"Sound": "كارت الصوت",
}
for key, val in min_specs.items():
if val:
label = _SPEC_LABELS_AR.get(key, key)
parts.append(blockquote(f"{esc(label)} | {esc(str(val))}"))
# ── الموصى به ──
rec_specs = pc_specs.get("recommended", {})
if rec_specs:
parts.append("")
parts.append(f"<b>🔹 الموصى بها (Recommended)</b>")
_SPEC_LABELS_AR = {
"OS": "نظام التشغيل",
"CPU": "المعالج (CPU)",
"RAM": "الذاكرة (RAM)",
"GPU": "كرت الشاشة (GPU)",
"DirectX": "DirectX",
"Storage": "التخزين",
"Network": "الشبكة",
"Sound": "كارت الصوت",
}
for key, val in rec_specs.items():
if val:
label = _SPEC_LABELS_AR.get(key, key)
parts.append(blockquote(f"{esc(label)} | {esc(str(val))}"))
if not min_specs and not rec_specs:
parts.append(blockquote("لم يتم العثور على متطلبات رسمية لهذه اللعبة."))
return "\n".join(parts)
def build_new_post_notification(
game_title: str, platform: str,
game_link: str, channel_username: str
) -> str:
"""رسالة إشعار تعريب جديد (HTML)"""
emoji = "🖥" if platform == "pc" else "🎮" if platform == "ps" else "📁"
plat_ar = "PC" if platform == "pc" else "PlayStation" if platform == "ps" else "عام"
ch_part = f"\n📢 @{esc(channel_username)}" if channel_username else ""
return (
f"🔔 <b>تعريب جديد!</b>\n\n"
f"🎮 <b>{esc(game_title)}</b>\n"
f"{emoji} المنصة: {esc(plat_ar)}\n"
f"🔗 <a href='{game_link}'>شاهد التعريب</a>"
f"{ch_part}"
)
def build_update_notification(
game_title: str, update_note: str,
game_link: str, channel_username: str
) -> str:
"""رسالة إشعار تحديث تعريب (HTML)"""
ch_part = f"\n📢 @{esc(channel_username)}" if channel_username else ""
note_part = f"\n✏️ {esc(update_note)}" if update_note else ""
return (
f"🔄 <b>تم تحديث تعريب!</b>\n\n"
f"🎮 <b>{esc(game_title)}</b>"
f"{note_part}\n"
f"🔗 <a href='{game_link}'>شاهد التحديث</a>"
f"{ch_part}"
)