-
Notifications
You must be signed in to change notification settings - Fork 130
Description
import telebot
from telebot import types
import json
import os
import time
import traceback
---------------- CONFIG ----------------
TOKEN = "8423750560:AAG3gDkTOm7xAStsCVi8odz2yp9Utf4jY6I" # <-- kept your token
ADMIN_ID = 7888447240 # <-- kept your admin id
DB_FILE = "bot_data.json"
WATCHDOG_SLEEP = 5
REF_BONUS = 3 # referal uchun necha tanga berilishi
REQUIRED_CHANNEL_DEFAULT = "@polo_chitlar" # boshlang'ich kanal (admin o'zgartirishi mumkin)
----------------------------------------
---------- INIT DB ----------
default_db = {
"users": {}, # user_id -> {"coins": int, "inviter": inviter_id_or_None, "invited": int}
"chits": [], # list of {"title": str, "price": int, "file_id": str or None, "desc": str}
"channels": [REQUIRED_CHANNEL_DEFAULT], # majburiy kanallar listi
"start_count": 0,
"purchases": {} # timestamp -> {"user": id, "chit": title}
}
if not os.path.exists(DB_FILE):
with open(DB_FILE, "w") as f:
json.dump(default_db, f, indent=2)
def load_db():
with open(DB_FILE, "r") as f:
return json.load(f)
def save_db(db):
with open(DB_FILE, "w") as f:
json.dump(db, f, indent=2)
db = load_db()
bot = telebot.TeleBot(TOKEN, threaded=True, skip_pending=True)
---------- HELPERS ----------
def ensure_user(uid, ref=None):
uid_s = str(uid)
db = load_db()
if uid_s not in db["users"]:
db["users"][uid_s] = {"coins": 0, "inviter": None, "invited": 0}
db["start_count"] = db.get("start_count", 0) + 1
# handle referral: give REF_BONUS to inviter only if valid and not self
if ref and str(ref) in db["users"] and str(ref) != uid_s:
# only credit inviter if new user (we are in branch where user is new)
db["users"][str(ref)]["coins"] = db["users"][str(ref)].get("coins",0) + REF_BONUS
db["users"][str(ref)]["invited"] = db["users"][str(ref)].get("invited",0) + 1
db["users"][uid_s]["inviter"] = str(ref)
try:
bot.send_message(int(ref), f"π Siz yangi foydalanuvchini taklif qildingiz β +{REF_BONUS} tanga!")
except:
pass
save_db(db)
return db["users"][uid_s]
def get_balance(uid):
db = load_db()
return db["users"].get(str(uid), {}).get("coins", 0)
def change_balance(uid, delta):
db = load_db()
u = db["users"].get(str(uid))
if not u:
return False
new = u.get("coins",0) + delta
if new < 0:
return False
u["coins"] = new
save_db(db)
return True
def add_chit_record(title, price, desc=""):
db = load_db()
db.setdefault("chits", []).append({"title": title, "price": int(price), "file_id": None, "desc": desc})
save_db(db)
def attach_file_to_last_chit(file_id):
# last created chit with file_id == None
db = load_db()
for c in reversed(db.get("chits", [])):
if not c.get("file_id"):
c["file_id"] = file_id
save_db(db)
return c["title"]
return None
def del_chit_by_title(title):
db = load_db()
before = len(db.get("chits",[]))
db["chits"] = [c for c in db.get("chits",[]) if c["title"] != title]
save_db(db)
return len(db.get("chits",[])) < before
def list_chits_text():
db = load_db()
if not db.get("chits"):
return "π Hozircha chitlar mavjud emas."
txt = "π Chitlar ro'yxati:\n\n"
for c in db["chits"]:
txt += f"β’ {c['title']} β {c['price']} t\n"
return txt
def is_subscribed_to_all(uid):
db = load_db()
missing = []
for ch in db.get("channels", []):
try:
# ensure starts with @
ch_use = ch if ch.startswith("@") else f"@{ch}"
member = bot.get_chat_member(ch_use, uid)
if member.status in ("left", "kicked"):
missing.append(ch_use)
except Exception:
missing.append(ch if ch.startswith("@") else f"@{ch}")
return (len(missing) == 0, missing)
---------- KEYBOARDS ----------
def main_reply_keyboard(is_admin=False):
kb = types.ReplyKeyboardMarkup(resize_keyboard=True, row_width=2)
kb.add("π Chitlar", "π³ Hisobim")
kb.add("π₯ Referal", "π Aloqa")
if is_admin:
kb.add("π Admin panel")
return kb
def admin_reply_keyboard():
kb = types.ReplyKeyboardMarkup(resize_keyboard=True, row_width=2)
kb.add("π« Chit qo'shish", "π Chit o'chirish")
kb.add("π Chitlar ro'yxati", "β Kanal qo'shish")
kb.add("β Kanal o'chirish", "π£ Habarnoma yuborish")
kb.add("π Statistika", "π Orqaga")
return kb
def chits_inline_markup():
ik = types.InlineKeyboardMarkup()
for c in load_db().get("chits", []):
ik.add(types.InlineKeyboardButton(f"{c['title']} β {c['price']} t", callback_data=f"buy|{c['title']}"))
return ik if ik.keyboard else None
---------- /start handler ----------
@bot.message_handler(commands=['start'])
def cmd_start(m):
args = m.text.split()
inviter = None
if len(args) > 1 and args[1].isdigit():
inviter = args[1]
u = m.from_user
ensure_user(u.id, inviter)
ok, missing = is_subscribed_to_all(u.id)
if not ok:
kb = types.InlineKeyboardMarkup()
for ch in load_db().get("channels", []):
ch_use = ch if ch.startswith("@") else f"@{ch}"
kb.add(types.InlineKeyboardButton(f"β {ch_use}", url=f"https://t.me/{ch_use.replace('@','')}"))
kb.add(types.InlineKeyboardButton("β»οΈ Obunani tekshirish", callback_data="check_sub"))
bot.send_message(u.id, "π Botdan foydalanish uchun quyidagi kanal(lar)ga obuna bo'ling:", reply_markup=kb)
return
# show main menu (reply keyboard)
is_admin = (u.id == ADMIN_ID)
bot.send_message(u.id, f"π Assalomu alaykum, {u.first_name}!\nQuyidagi tugmalardan foydalaning.", reply_markup=main_reply_keyboard(is_admin))
---------- callback handler ----------
@bot.callback_query_handler(func=lambda call: True)
def callback_handler(call):
data = call.data
uid = call.from_user.id
# check subscription pressed
if data == "check_sub":
ok, missing = is_subscribed_to_all(uid)
if ok:
bot.answer_callback_query(call.id, "β
Obuna tasdiqlandi. /start ni bosing.")
bot.send_message(uid, "β
Obuna tasdiqlandi. /start ni qayta bosing.")
else:
bot.answer_callback_query(call.id, "β Hali to'liq obuna bo'lmadingiz!", show_alert=True)
return
# buy handler
if data.startswith("buy|"):
title = data.split("|",1)[1]
db_local = load_db()
chit = next((c for c in db_local.get("chits",[]) if c["title"]==title), None)
if not chit:
bot.answer_callback_query(call.id, "β Chit topilmadi", show_alert=True)
return
price = chit.get("price",0)
balance = get_balance(uid)
if balance < price:
bot.answer_callback_query(call.id, f"β Tangalar yetarli emas. Sizda: {balance} t", show_alert=True)
return
# deduct
ok = change_balance(uid, -price)
if not ok:
bot.answer_callback_query(call.id, "β Tanga yechishda xato", show_alert=True)
return
# send file if exists
file_id = chit.get("file_id")
if file_id:
try:
bot.send_document(uid, file_id, caption=f"β
{title} β muvaffaqiyatli sotib olindi.")
bot.answer_callback_query(call.id, "β
Sotib olindi!")
# record purchase
db_record = load_db()
db_record.setdefault("purchases", {})[str(int(time.time()))] = {"user": uid, "chit": title}
save_db(db_record)
except Exception as e:
bot.answer_callback_query(call.id, "β Fayl yuborishda xato. Adminga xabar berildi.", show_alert=True)
bot.send_message(ADMIN_ID, f"Fayl yuborishda xato: {e}\nChit:{title}\nUser:{uid}")
else:
bot.answer_callback_query(call.id, "
bot.send_message(ADMIN_ID, f"Foydalanuvchi {uid} {title} sotib oldi β lekin file mavjud emas.")
return
# other inline callbacks for admin deletion
if data.startswith("delchit|"):
title = data.split("|",1)[1]
if call.from_user.id != ADMIN_ID:
bot.answer_callback_query(call.id, "β Faqat admin!", show_alert=True)
return
ok = del_chit_by_title(title)
if ok:
bot.answer_callback_query(call.id, f"π {title} o'chirildi.")
else:
bot.answer_callback_query(call.id, "β O'chirishda xato.")
return
---------- Text message handler (menus & admin flows) ----------
@bot.message_handler(func=lambda m: True)
def on_message(m):
uid = m.from_user.id
txt = m.text.strip() if m.text else ""
ensure_user(uid)
# ADMIN BUTTONS
if uid == ADMIN_ID:
# Add chit
if txt == "π« Chit qo'shish":
sent = bot.send_message(uid, "π Chit nomi va narxini kiriting (format: NAME | PRICE | OPTIONAL_DESC)\nMasalan: Skin Hack | 20 | iOS/Android")
bot.register_next_step_handler(sent, admin_receive_chit_info)
return
# Delete chit (show inline buttons)
if txt == "π Chit o'chirish":
chs = load_db().get("chits", [])
if not chs:
bot.send_message(uid, "π Chitlar bo'sh.")
return
ik = types.InlineKeyboardMarkup()
for c in chs:
ik.add(types.InlineKeyboardButton(f"π {c['title']}", callback_data=f"delchit|{c['title']}"))
bot.send_message(uid, "π O'chirmoqchi bo'lgan chitni tanlang:", reply_markup=ik)
return
# list chits
if txt == "π Chitlar ro'yxati":
bot.send_message(uid, list_chits_text())
return
# add channel
if txt == "β Kanal qo'shish":
sent = bot.send_message(uid, "π¨ Kanal username-ni kiriting (misol: @kanal_user):")
bot.register_next_step_handler(sent, admin_add_channel_step)
return
# remove channel
if txt == "β Kanal o'chirish":
sent = bot.send_message(uid, "β O'chirmoqchi bo'lgan kanal username-ni kiriting (misol: @kanal_user):")
bot.register_next_step_handler(sent, admin_remove_channel_step)
return
# broadcast
if txt == "π£ Habarnoma yuborish":
sent = bot.send_message(uid, "π’ Xabar matnini yoki media bilan reply yuboring:")
bot.register_next_step_handler(sent, admin_broadcast_step)
return
# stats
if txt == "π Statistika":
d = load_db()
users_count = len(d.get("users",{}))
chits_count = len(d.get("chits",[]))
channels_count = len(d.get("channels",[]))
bot.send_message(uid, f"π Statistika:\nFoydalanuvchilar: {users_count}\nChitlar: {chits_count}\nMajburiy kanallar: {channels_count}\n/start bosganlar: {d.get('start_count',0)}")
return
if txt == "π Orqaga":
bot.send_message(uid, "Admin menyuga qaytdingiz.", reply_markup=admin_reply_keyboard())
return
# USER BUTTONS (outside admin)
if txt == "π Chitlar":
chs = load_db().get("chits", [])
if not chs:
bot.send_message(uid, "π Hozir hech qanday chit yo'q.")
return
ik = chits_inline_markup()
bot.send_message(uid, "π Quyidagi chitlar mavjud:", reply_markup=ik)
return
if txt == "π³ Hisobim":
u = load_db().get("users", {}).get(str(uid), {"coins":0,"inviter":None,"invited":0})
bot.send_message(uid, f"π€ Hisobim:\nID: {uid}\nπ° Tangalar: {u.get('coins',0)}\nπ₯ Takliflar: {u.get('invited',0)}")
return
if txt == "π₯ Referal":
link = f"https://t.me/{bot.get_me().username}?start={uid}"
bot.send_message(uid, f"π₯ Referal link:\n{link}\nHar bir yangi taklif uchun +{REF_BONUS} tanga beriladi.")
return
if txt == "π Aloqa":
bot.send_message(uid, "π© Admin bilan bog'lanish: @IBROHIMPUBGM")
return
if txt == "π Admin panel" and uid == ADMIN_ID:
bot.send_message(uid, "π Admin panel:", reply_markup=admin_reply_keyboard())
return
# fallback: show main menu
bot.send_message(uid, "Menyudan tanlang yoki /start bosing.", reply_markup=main_reply_keyboard(uid==ADMIN_ID))
---------- Admin step handlers ----------
def admin_receive_chit_info(msg):
uid = msg.from_user.id
if uid != ADMIN_ID:
return
text = msg.text or ""
parts = [p.strip() for p in text.split("|")]
if len(parts) < 2:
bot.send_message(uid, "β Format xato. Misol: Skin Hack | 20 | optional description")
return
title = parts[0]
try:
price = int(parts[1])
except:
bot.send_message(uid, "β Narx butun son bo'lishi kerak (misol: 20).")
return
desc = parts[2] if len(parts) >= 3 else ""
add_chit_record(title, price, desc)
bot.send_message(uid, f"β
Chit yaratildi: {title} β {price} t\nEndi shu chitga tegishli fayl yuboring (document: ZIP/RAR/APK).")
# next document will attach to last created chit (attach_file_to_last_chit)
@bot.message_handler(content_types=['document'])
def handle_document(m):
# If admin uploads a document after creating a chit, attach it.
uid = m.from_user.id
if uid != ADMIN_ID:
# optionally allow users to upload (ignored)
return
file_id = m.document.file_id
attached_title = attach_file_to_last_chit(file_id)
if attached_title:
bot.send_message(uid, f"β
Fayl biriktirildi: {attached_title}")
else:
bot.send_message(uid, "
def admin_add_channel_step(msg):
uid = msg.from_user.id
if uid != ADMIN_ID:
return
ch = msg.text.strip()
d = load_db()
if ch.startswith("@"):
ch_store = ch
else:
ch_store = "@" + ch
if ch_store in d.get("channels", []):
bot.send_message(uid, "Bu kanal allaqachon mavjud.")
return
d.setdefault("channels", []).append(ch_store)
save_db(d)
bot.send_message(uid, f"β
Kanal qo'shildi: {ch_store}")
def admin_remove_channel_step(msg):
uid = msg.from_user.id
if uid != ADMIN_ID:
return
ch = msg.text.strip()
if not ch.startswith("@"):
ch = "@" + ch
d = load_db()
if ch in d.get("channels", []):
d["channels"].remove(ch)
save_db(d)
bot.send_message(uid, f"π Kanal o'chirildi: {ch}")
else:
bot.send_message(uid, "β Bunday kanal topilmadi.")
def admin_broadcast_step(msg):
uid = msg.from_user.id
if uid != ADMIN_ID:
return
text = msg.text or ""
d = load_db()
users = list(d.get("users", {}).keys())
sent = 0
for u in users:
try:
bot.send_message(int(u), text)
sent += 1
time.sleep(0.04)
except Exception:
pass
bot.send_message(uid, f"β
Habarnoma yuborildi: {sent} ta foydalanuvchiga.")
---------- Utility functions ----------
def send_chits_inline(uid):
db_local = load_db()
if not db_local.get("chits"):
bot.send_message(uid, "π Hozir hech qanday chit yo'q.")
return
ik = types.InlineKeyboardMarkup()
for c in db_local.get("chits", []):
ik.add(types.InlineKeyboardButton(f"{c['title']} β {c['price']} t", callback_data=f"buy|{c['title']}"))
bot.send_message(uid, "π Quyidagi chitlar mavjud:", reply_markup=ik)
---------- RUN / WATCHDOG ----------
def run_bot():
print("Bot ishga tushmoqda...")
bot.infinity_polling(timeout=60, long_polling_timeout=60)
if name == "main":
# ensure DB loaded
db = load_db()
while True:
try:
run_bot()
except KeyboardInterrupt:
print("Bot to'xtatildi (KeyboardInterrupt).")
break
except Exception as e:
print("Xatolik:", e)
traceback.print_exc()
time.sleep(WATCHDOG_SLEEP)