File size: 7,996 Bytes
458f2ac 3da3f86 458f2ac aa597c1 458f2ac aa597c1 458f2ac ccd4e1a 458f2ac | 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 | import os
import json
import logging
from pathlib import Path
from dotenv import load_dotenv
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup, WebAppInfo
from telegram.ext import Application, CommandHandler, ContextTypes, MessageHandler, filters
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
import uvicorn
import asyncio
import threading
load_dotenv()
BOT_TOKEN = os.getenv("BOT_TOKEN", "")
WEBAPP_URL = os.getenv("WEBAPP_URL", "") # e.g. https://your-space.hf.space
ADMIN_ID = 6069597294
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
DATA_DIR = Path("data")
DATA_DIR.mkdir(exist_ok=True)
DB_FILE = DATA_DIR / "users.json"
# Gift catalog with prices (TON) and public images
GIFTS = [
{"id": "plush_pepe", "name": "Plush Pepe", "price": 25.0, "img": "https://cdn.jsdelivr.net/gh/ssamy2/TG_Photos@main/webp/by_name/plush_pepe.webp"},
{"id": "durovs_cap", "name": "Durov's Cap", "price": 18.5, "img": "https://cdn.jsdelivr.net/gh/ssamy2/TG_Photos@main/webp/by_name/durovs_cap.webp"},
{"id": "heart_locket", "name": "Heart Locket", "price": 12.0, "img": "https://cdn.jsdelivr.net/gh/ssamy2/TG_Photos@main/webp/by_name/heart_locket.webp"},
{"id": "bonded_ring", "name": "Bonded Ring", "price": 9.5, "img": "https://cdn.jsdelivr.net/gh/ssamy2/TG_Photos@main/webp/by_name/bonded_ring.webp"},
{"id": "precious_peach", "name": "Precious Peach", "price": 7.0, "img": "https://cdn.jsdelivr.net/gh/ssamy2/TG_Photos@main/webp/by_name/precious_peach.webp"},
{"id": "lollipop", "name": "Lollipop", "price": 3.5, "img": "https://cdn.jsdelivr.net/gh/ssamy2/TG_Photos@main/webp/by_name/lollipop.webp"},
{"id": "helmet", "name": "Helmet", "price": 4.2, "img": "https://cdn.jsdelivr.net/gh/ssamy2/TG_Photos@main/webp/by_name/helmet.webp"},
{"id": "mushroom", "name": "Mushroom", "price": 2.8, "img": "https://cdn.jsdelivr.net/gh/ssamy2/TG_Photos@main/webp/by_name/mushroom.webp"},
]
def load_db():
if DB_FILE.exists():
return json.loads(DB_FILE.read_text())
return {}
def save_db(db):
DB_FILE.write_text(json.dumps(db, indent=2, ensure_ascii=False))
def get_user(uid: int):
db = load_db()
key = str(uid)
if key not in db:
db[key] = {"ton": 0.0, "gifts": []}
save_db(db)
return db[key]
def set_user(uid: int, data):
db = load_db()
db[str(uid)] = data
save_db(db)
# ---------- Bot Handlers ----------
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
user = update.effective_user
get_user(user.id) # ensure exists
webapp = WEBAPP_URL or "https://example.com"
keyboard = [
[InlineKeyboardButton("🎁 فتح Epic Gift", web_app=WebAppInfo(url=webapp))],
[InlineKeyboardButton("💎 رصيدي", callback_data="balance")],
]
reply_markup = InlineKeyboardMarkup(keyboard)
text = (
f"مرحباً {user.first_name} 🎁\n\n"
"أهلاً بك في **Epic Gift**\n"
"افتح التطبيق من الزر تحت وابدأ اللعب.\n\n"
"🚀 Rocket • ⚔️ PvP • 🎮 Games • 📦 Free Boxes"
)
await update.message.reply_text(text, reply_markup=reply_markup, parse_mode="Markdown")
async def balance_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE):
uid = update.effective_user.id
u = get_user(uid)
gifts_txt = ", ".join(u["gifts"]) if u["gifts"] else "لا يوجد"
await update.message.reply_text(
f"💎 رصيدك: **{u['ton']:.3f} TON**\n🎁 هداياك: {gifts_txt}",
parse_mode="Markdown"
)
async def addton(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Admin only: /addton <amount> or /addton <user_id> <amount>"""
if update.effective_user.id != ADMIN_ID:
await update.message.reply_text("غير مصرح.")
return
args = context.args
if not args:
await update.message.reply_text("استخدم: /addton <كمية> أو /addton <user_id> <كمية>")
return
try:
if len(args) == 1:
amount = float(args[0])
target = ADMIN_ID
else:
target = int(args[0])
amount = float(args[1])
u = get_user(target)
u["ton"] += amount
set_user(target, u)
await update.message.reply_text(f"✅ تمت إضافة {amount} TON للمستخدم {target}\nالرصيد الحالي: {u['ton']:.3f}")
except Exception as e:
await update.message.reply_text(f"خطأ: {e}")
async def addgift(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Admin only: /addgift <gift_id> or /addgift <user_id> <gift_id>"""
if update.effective_user.id != ADMIN_ID:
await update.message.reply_text("غير مصرح.")
return
args = context.args
if not args:
ids = ", ".join(g["id"] for g in GIFTS)
await update.message.reply_text(f"استخدم: /addgift <gift_id>\nالمتاح: {ids}")
return
try:
if len(args) == 1:
gift_id = args[0]
target = ADMIN_ID
else:
target = int(args[0])
gift_id = args[1]
if not any(g["id"] == gift_id for g in GIFTS):
await update.message.reply_text("gift_id غير موجود")
return
u = get_user(target)
u["gifts"].append(gift_id)
set_user(target, u)
await update.message.reply_text(f"✅ تمت إضافة الهدية `{gift_id}` للمستخدم {target}", parse_mode="Markdown")
except Exception as e:
await update.message.reply_text(f"خطأ: {e}")
async def gifts_list(update: Update, context: ContextTypes.DEFAULT_TYPE):
lines = [f"• `{g['id']}` — {g['name']} — {g['price']} TON" for g in GIFTS]
await update.message.reply_text("قائمة الهدايا:\n" + "\n".join(lines), parse_mode="Markdown")
async def button_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
query = update.callback_query
await query.answer()
if query.data == "balance":
u = get_user(query.from_user.id)
gifts_txt = ", ".join(u["gifts"]) if u["gifts"] else "لا يوجد"
await query.edit_message_text(
f"💎 رصيدك: **{u['ton']:.3f} TON**\n🎁 هداياك: {gifts_txt}",
parse_mode="Markdown"
)
# ---------- FastAPI for WebApp ----------
app = FastAPI()
@app.get("/")
async def root():
return FileResponse("static/index.html")
@app.get("/api/gifts")
async def api_gifts():
return GIFTS
@app.get("/api/me")
async def api_me(uid: int = 0):
if uid == 0:
return {"ton": 0, "gifts": []}
return get_user(uid)
app.mount("/static", StaticFiles(directory="static"), name="static")
def run_web():
port = int(os.getenv("PORT", 7860))
uvicorn.run(app, host="0.0.0.0", port=port, log_level="info")
def main():
if not BOT_TOKEN:
logger.error("BOT_TOKEN غير موجود. ضعه في Secrets أو .env")
# still start web so Space doesn't die
run_web()
return
application = Application.builder().token(BOT_TOKEN).build()
application.add_handler(CommandHandler("start", start))
application.add_handler(CommandHandler("balance", balance_cmd))
application.add_handler(CommandHandler("addton", addton))
application.add_handler(CommandHandler("addgift", addgift))
application.add_handler(CommandHandler("gifts", gifts_list))
application.add_handler(MessageHandler(filters.StatusUpdate.WEB_APP_DATA, lambda u, c: None))
from telegram.ext import CallbackQueryHandler
application.add_handler(CallbackQueryHandler(button_handler))
# run web in background thread
t = threading.Thread(target=run_web, daemon=True)
t.start()
logger.info("Bot starting...")
application.run_polling(allowed_updates=Update.ALL_TYPES)
if __name__ == "__main__":
main()
|