Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import logging
- from typing import Dict, List, Optional, Tuple
- from dataclasses import dataclass
- from datetime import datetime, timedelta
- import pytz
- from threading import Timer
- import random
- from telegram import Update, ChatMember
- from telegram.ext import (
- Updater,
- CommandHandler,
- MessageHandler,
- Filters,
- CallbackContext,
- ConversationHandler,
- )
- # Настройка логгирования
- logging.basicConfig(
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
- level=logging.INFO
- )
- logger = logging.getLogger(name)
- # Состояния для ConversationHandler
- CURRENCY_NAME, CURRENCY_EMOJI = range(2)
- # Структуры данных
- @dataclass
- class Currency:
- name: str
- emoji: str
- daily_reward: Optional[int] = None
- chat_reward: Optional[int] = None
- class GroupData:
- def init(self):
- self.currencies: Dict[str, Currency] = {} # name -> Currency
- self.user_balances: Dict[int, Dict[str, int]] = {} # user_id -> {currency_name -> amount}
- # Глобальные хранилища данных
- groups: Dict[int, GroupData] = {}
- last_daily_rewards: Dict[int, datetime] = {} # chat_id -> last reward time
- user_last_message: Dict[int, Dict[int, datetime]] = {} # chat_id -> user_id -> last message time
- def get_group_data(chat_id: int) -> GroupData:
- if chat_id not in groups:
- groups[chat_id] = GroupData()
- return groups[chat_id]
- # Проверка на администратора
- def is_admin(update: Update) -> bool:
- if not update.effective_chat or update.effective_chat.type == 'private':
- return False
- user_id = update.effective_user.id
- chat_id = update.effective_chat.id
- try:
- member = update.effective_chat.get_member(user_id)
- return member.status in ['creator', 'administrator']
- except Exception as e:
- logger.error(f"Error checking admin status: {e}")
- return False
- # ====================
- # Команды администраторов
- # ====================
- def start_currency_creation(update: Update, context: CallbackContext) -> int:
- if not is_admin(update):
- update.message.reply_text("Только администраторы могут создавать валюты.")
- return ConversationHandler.END
- update.message.reply_text(
- "Введите название новой валюты (одним словом без пробелов):"
- )
- return CURRENCY_NAME
- def process_currency_name(update: Update, context: CallbackContext) -> int:
- currency_name = update.message.text.strip()
- if ' ' in currency_name:
- update.message.reply_text("Название валюты не должно содержать пробелов. Попробуйте еще раз:")
- return CURRENCY_NAME
- context.user_data['new_currency_name'] = currency_name
- update.message.reply_text(
- f"Введите смайлик для валюты {currency_name} (например, 🪙):"
- )
- return CURRENCY_EMOJI
- def process_currency_emoji(update: Update, context: CallbackContext) -> int:
- emoji = update.message.text.strip()
- currency_name = context.user_data['new_currency_name']
- chat_id = update.effective_chat.id
- group_data = get_group_data(chat_id)
- if currency_name in group_data.currencies:
- update.message.reply_text("Валюта с таким названием уже существует!")
- return ConversationHandler.END
- group_data.currencies[currency_name] = Currency(name=currency_name, emoji=emoji)
- update.message.reply_text(
- f"Валюта {currency_name} {emoji} успешно создана!\n"
- f"Теперь вы можете настроить:\n"
- f"/setdaily {currency_name} [количество] - ежедневные награды\n"
- f"/setchatreward {currency_name} [количество] - награды за сообщения"
- )
- return ConversationHandler.END
- def cancel_creation(update: Update, context: CallbackContext) -> int:
- update.message.reply_text("Создание валюты отменено.")
- return ConversationHandler.END
- def set_daily_reward(update: Update, context: CallbackContext):
- if not is_admin(update):
- update.message.reply_text("Только администраторы могут настраивать ежедневные награды.")
- return
- if len(context.args) != 2:
- update.message.reply_text(
- "Использование: /setdaily [название валюты] [количество]\n"
- "Используйте 0 чтобы отключить ежедневные награды."
- )
- return
- currency_name, amount_str = context.args
- try:
- amount = int(amount_str)
- except ValueError:
- update.message.reply_text("Пожалуйста, введите корректное число.")
- return
- chat_id = update.effective_chat.id
- group_data = get_group_data(chat_id)
- if currency_name not in group_data.currencies:
- update.message.reply_text("Валюта с таким названием не найдена.")
- return
- group_data.currencies[currency_name].daily_reward = amount if amount > 0 else None
- if amount > 0:
- update.message.reply_text(
- f"Ежедневная награда для валюты {currency_name} установлена: {amount} {group_data.currencies[currency_name].emoji}"
- )
- else:
- update.message.reply_text(
- f"Ежедневная награда для валюты {currency_name} отключена."
- )
- def set_chat_reward(update: Update, context: CallbackContext):
- if not is_admin(update):
- update.message.reply_text("Только администраторы могут настраивать награды за сообщения.")
- return
- if len(context.args) != 2:
- update.message.reply_text(
- "Использование: /setchatreward [название валюты] [количество]\n"
- "Используйте 0 чтобы отключить награды за сообщения."
- )
- return
- currency_name, amount_str = context.args
- try:
- amount = int(amount_str)
- except ValueError:
- update.message.reply_text("Пожалуйста, введите корректное число.")
- return
- chat_id = update.effective_chat.id
- group_data = get_group_data(chat_id)
- if currency_name not in group_data.currencies:
- update.message.reply_text("Валюта с таким названием не найдена.")
- return
- group_data.currencies[currency_name].chat_reward = amount if amount > 0 else None
- if amount > 0:
- update.message.reply_text(
- f"Награда за сообщения для валюты {currency_name} установлена: {amount} {group_data.currencies[currency_name].emoji}"
- )
- else:
- update.message.reply_text(
- f"Награда за сообщения для валюты {currency_name} отключена."
- )
- def generate_currency(update: Update, context: CallbackContext):
- if not is_admin(update):
- update.message.reply_text("Только администраторы могут создавать валюту.")
- return
- if len(context.args) != 3:
- update.message.reply_text(
- "Использование: /generate [@username] [название валюты] [количество]\n"
- "Пример: /generate @user1 coins 100"
- )
- return
- username, currency_name, amount_str = context.args
- try:
- amount = int(amount_str)
- if amount <= 0:
- raise ValueError
- except ValueError:
- update.message.reply_text("Пожалуйста, введите положительное целое число.")
- return
- chat_id = update.effective_chat.id
- group_data = get_group_data(chat_id)
- if currency_name not in group_data.currencies:
- update.message.reply_text("Валюта с таким названием не найдена.")
- return
- # Получаем ID пользователя
- if username.startswith('@'):
- username = username[1:]
- try:
- user = context.bot.get_chat_member(chat_id, username)
- user_id = user.user.id
- except Exception as e:
- update.message.reply_text(f"Не удалось найти пользователя {username}.")
- logger.error(f"Error finding user: {e}")
- return
- else:
- try:
- user_id = int(username)
- except ValueError:
- update.message.reply_text("Пожалуйста, укажите @username или ID пользователя.")
- return
- if user_id not in group_data.user_balances:
- group_data.user_balances[user_id] = {}
- if currency_name not in group_data.user_balances[user_id]:
- group_data.user_balances[user_id][currency_name] = 0
- group_data.user_balances[user_id][currency_name] += amount
- try:
- user = context.bot.get_chat_member(chat_id, user_id).user
- user_name = user.username or user.first_name
- except:
- user_name = str(user_id)
- update.message.reply_text(
- f"Пользователю {user_name} выдано {amount} {group_data.currencies[currency_name].emoji}!"
- )
- # ====================
- # Команды пользователей
- # ====================
- def give_currency(update: Update, context: CallbackContext):
- if update.effective_chat.type == 'private':
- update.message.reply_text("Эта команда работает только в группах!")
- return
- if len(context.args) != 3:
- update.message.reply_text(
- "Использование: /give [@username] [название валюты] [количество]\n"
- "Пример: /give @user1 coins 50"
- )
- return
- username, currency_name, amount_str = context.args
- try:
- amount = int(amount_str)
- if amount <= 0:
- raise ValueError
- except ValueError:
- update.message.reply_text("Пожалуйста, введите положительное целое число.")
- return
- chat_id = update.effective_chat.id
- group_data = get_group_data(chat_id)
- if currency_name not in group_data.currencies:
- update.message.reply_text("Валюта с таким названием не найдена.")
- return
- sender_id = update.effective_user.id
- # Проверка баланса отправителя
- if sender_id not in group_data.user_balances or currency_name not in group_data.user_balances[sender_id]:
- update.message.reply_text(f"У вас нет валюты {currency_name}!")
- return
- if group_data.user_balances[sender_id][currency_name] < amount:
- update.message.reply_text("У вас недостаточно средств для перевода!")
- return
- # Получаем получателя
- if username.startswith('@'):
- username = username[1:]
- try:
- receiver = context.bot.get_chat_member(chat_id, username)
- receiver_id = receiver.user.id
- except Exception as e:
- update.message.reply_text(f"Не удалось найти пользователя {username}.")
- logger.error(f"Error finding user: {e}")
- return
- else:
- try:
- receiver_id = int(username)
- except ValueError:
- update.message.reply_text("Пожалуйста, укажите @username или ID пользователя.")
- return
- # Проверяем что пользователь не отправляет себе
- if sender_id == receiver_id:
- update.message.reply_text("Вы не можете отправить валюту самому себе!")
- return
- # Снимаем валюту у отправителя
- group_data.user_balances[sender_id][currency_name] -= amount
- # Добавляем получателю
- if receiver_id not in group_data.user_balances:
- group_data.user_balances[receiver_id] = {}
- if currency_name not in group_data.user_balances[receiver_id]:
- group_data.user_balances[receiver_id][currency_name] = 0
- group_data.user_balances[receiver_id][currency_name] += amount
- # Получаем имена для сообщения
- try:
- sender_name = update.effective_user.username or update.effective_user.first_name
- receiver_user = context.bot.get_chat_member(chat_id, receiver_id).user
- receiver_name = receiver_user.username or receiver_user.first_name
- except Exception as e:
- logger.error(f"Error getting user names: {e}")
- sender_name = "Отправитель"
- receiver_name = username
- currency = group_data.currencies[currency_name]
- update.message.reply_text(
- f"✅ {sender_name} передал {receiver_name} {amount} {currency.emoji}!"
- )
- def show_balance(update: Update, context: CallbackContext):
- if update.effective_chat.type == 'private':
- update.message.reply_text("Эта команда работает только в группах!")
- return
- chat_id = update.effective_chat.id
- user_id = update.effective_user.id
- group_data = get_group_data(chat_id)
- if not group_data.currencies:
- update.message.reply_text("В этой группе пока нет созданных валют.")
- return
- if user_id not in group_data.user_balances or not group_data.user_balances[user_id]:
- update.message.reply_text("У вас пока нет валюты.")
- return
- balance_text = "💰 Ваш баланс:\n\n"
- for currency_name, amount in group_data.user_balances[user_id].items():
- currency = group_data.currencies.get(currency_name)
- if currency:
- balance_text += f"{currency.emoji} {currency.name}: {amount}\n"
- update.message.reply_text(balance_text)
- def list_currencies(update: Update, context: CallbackContext):
- """Показывает список всех валют в чате"""
- if update.effective_chat.type == 'private':
- update.message.reply_text("Эта команда работает только в группах!")
- return
- chat_id = update.effective_chat.id
- group_data = get_group_data(chat_id)
- if not group_data.currencies:
- update.message.reply_text("В этой группе пока нет созданных валют.")
- return
- message = "📊 Доступные валюты:\n\n"
- for currency in group_data.currencies.values():
- message += f"{currency.emoji} <b>{currency.name}</b>"
- if currency.daily_reward:
- message += f" | Ежедневно: +{currency.daily_reward}"
- if currency.chat_reward:
- message += f" | За сообщения: +{currency.chat_reward}"
- message += "\n"
- update.message.reply_text(message, parse_mode='HTML')
- def top_users(update: Update, context: CallbackContext):
- """Показывает топ пользователей по валюте"""
- if update.effective_chat.type == 'private':
- update.message.reply_text("Эта команда работает только в группах!")
- return
- if len(context.args) == 0:
- update.message.reply_text("Использование: /top [название валюты]")
- return
- currency_name = context.args[0]
- chat_id = update.effective_chat.id
- group_data = get_group_data(chat_id)
- if currency_name not in group_data.currencies:
- update.message.reply_text("Валюта с таким названием не найдена.")
- return
- # Собираем данные о пользователях
- user_balances = []
- for user_id, currencies in group_data.user_balances.items():
- if currency_name in currencies:
- user_balances.append((user_id, currencies[currency_name]))
- if not user_balances:
- update.message.reply_text("Никто еще не получил эту валюту.")
- return
- # Сортируем по убыванию баланса
- user_balances.sort(key=lambda x: x[1], reverse=True)
- # Формируем сообщение (первые 10)
- currency = group_data.currencies[currency_name]
- message = f"🏆 Топ пользователей по валюте {currency.emoji} <b>{currency.name}</b>:\n\n"
- for i, (user_id, balance) in enumerate(user_balances[:10], 1):
- try:
- user = context.bot.get_chat_member(chat_id, user_id).user
- username = f"@{user.username}" if user.username else user.first_name
- except:
- username = f"ID:{user_id}"
- message += f"{i}. {username}: {balance} {currency.emoji}\n"
- update.message.reply_text(message, parse_mode='HTML')
- # ====================
- # Система автоматических наград
- # ====================
- def schedule_daily_tasks(updater: Updater):
- """Запускает задачу для ежедневной выдачи наград"""
- now = datetime.now(pytz.utc)
- # Вычисляем время до следующего дня (00:00 UTC)
- next_day = now.replace(hour=0, minute=0, second=0, microsecond=0) + timedelta(days=1)
- delay = (next_day - now).total_seconds()
- # Запускаем таймер
- t = Timer(delay, daily_rewards_task, args=[updater])
- t.start()
- def daily_rewards_task(updater: Updater):
- """Выдача ежедневных наград всем участникам чатов"""
- try:
- for chat_id, group_data in groups.items():
- # Проверяем, есть ли валюты с ежедневными наградами
- currencies_with_rewards = [
- currency for currency in group_data.currencies.values()
- if currency.daily_reward is not None and currency.daily_reward > 0
- ]
- if not currencies_with_rewards:
- continue
- # Получаем всех участников чата
- try:
- chat_members = updater.bot.get_chat_members(chat_id)
- member_ids = [member.user.id for member in chat_members]
- except Exception as e:
- logger.error(f"Error getting chat members for chat {chat_id}: {e}")
- continue
- for user_id in member_ids:
- for currency in currencies_with_rewards:
- if user_id not in group_data.user_balances:
- group_data.user_balances[user_id] = {}
- if currency.name not in group_data.user_balances[user_id]:
- group_data.user_balances[user_id][currency.name] = 0
- group_data.user_balances[user_id][currency.name] += currency.daily_reward
- # Отправляем уведомление в чат
- message = "🎉 Ежедневные награды выданы!\n\n"
- for currency in currencies_with_rewards:
- message += f"{currency.emoji} {currency.name}: +{currency.daily_reward}\n"
- try:
- updater.bot.send_message(chat_id=chat_id, text=message)
- except Exception as e:
- logger.error(f"Error sending daily reward message to chat {chat_id}: {e}")
- # Планируем следующую задачу
- schedule_daily_tasks(updater)
- except Exception as e:
- logger.error(f"Error in daily rewards task: {e}")
- def handle_message(update: Update, context: CallbackContext):
- """Обработчик сообщений для выдачи наград за активность"""
- if not update.message or not update.effective_chat or update.effective_chat.type == 'private':
- return
- chat_id = update.effective_chat.id
- user_id = update.effective_user.id
- # Игнорируем служебные сообщения
- if update.message.left_chat_member or update.message.new_chat_members:
- return
- # Инициализация структур данных если нужно
- if chat_id not in user_last_message:
- user_last_message[chat_id] = {}
- # Проверяем время последнего сообщения пользователя
- last_message_time = user_last_message[chat_id].get(user_id)
- now = datetime.now(pytz.utc)
- # Если сообщение отправлено слишком рано после предыдущего - игнорируем
- if last_message_time and (now - last_message_time).total_seconds() < 60:
- return
- user_last_message[chat_id][user_id] = now
- group_data = get_group_data(chat_id)
- # Выдаем награды за сообщения если есть
- rewards_given = False
- reward_message = ""
- for currency in group_data.currencies.values():
- if currency.chat_reward and currency.chat_reward > 0:
- if user_id not in group_data.user_balances:
- group_data.user_balances[user_id] = {}
- if currency.name not in group_data.user_balances[user_id]:
- group_data.user_balances[user_id][currency.name] = 0
- # Добавляем случайность
- base_reward = currency.chat_reward
- reward = base_reward
- # 30% шанс получить бонус
- if random.random() < 0.3:
- reward = base_reward + random.randint(1, base_reward // 2)
- bonus = reward - base_reward
- reward_message = f" (+{bonus} бонус!)"
- group_data.user_balances[user_id][currency.name] += reward
- rewards_given = True
- if rewards_given and random.random() < 0.2: # 20% шанс уведомить о награде
- try:
- update.message.reply_text(
- f"💎 Вы получили награду за активность!{reward_message}",
- reply_to_message_id=update.message.message_id
- )
- except Exception as e:
- logger.error(f"Error sending reward notification: {e}")
- # ====================
- # Основная функция
- # ====================
- def main() -> None:
- # MyToken - токен моего бота (полученный от @BotFather)
- updater = Updater("MyToken", use_context=True)
- dispatcher = updater.dispatcher
- # ConversationHandler для создания валюты
- conv_handler = ConversationHandler(
- entry_points=[CommandHandler('createcurrency', start_currency_creation)],
- states={
- CURRENCY_NAME: [MessageHandler(Filters.text & ~Filters.command, process_currency_name)],
- CURRENCY_EMOJI: [MessageHandler(Filters.text & ~Filters.command, process_currency_emoji)],
- },
- fallbacks=[CommandHandler('cancel', cancel_creation)],
- )
- # Обработчики команд администраторов
- dispatcher.add_handler(conv_handler)
- dispatcher.add_handler(CommandHandler("setdaily", set_daily_reward))
- dispatcher.add_handler(CommandHandler("setchatreward", set_chat_reward))
- dispatcher.add_handler(CommandHandler("generate", generate_currency))
- # Обработчики команд пользователей
- dispatcher.add_handler(CommandHandler("give", give_currency))
- dispatcher.add_handler(CommandHandler("balance", show_balance))
- dispatcher.add_handler(CommandHandler("currencies", list_currencies))
- dispatcher.add_handler(CommandHandler("top", top_users))
- # Обработчик сообщений для наград за активность
- dispatcher.add_handler(MessageHandler(Filters.text & ~Filters.command, handle_message))
- # Запускаем задачу для ежедневных наград
- schedule_daily_tasks(updater)
- # Запуск бота
- updater.start_polling()
- logger.info("Бот запущен и работает...")
- updater.idle()
- if name == 'main':
- main()
Advertisement
Add Comment
Please, Sign In to add comment