"""
Telegram бот для тайного Санты - ИСПРАВЛЕННАЯ ВЕРСИЯ
Требует: pip install pyTelegramBotAPI
"""
import telebot
import json
import os
import random
from datetime import datetime
# ===== НАСТРОЙКИ =====
# Замените на ваш токен от BotFather
BOT_TOKEN = "8585166053:AAEsgD2ioOc-SmV2uCae7xNkrAblxYQyajg"
# ID владельца (вас) - просто укажите ТОЛЬКО ВАШ ID
OWNER_ID = 1132670685
DATA_FILE = "santa_data.json"
DEFAULT_DATA = {
"groups": {},
"distributions": {}
}
# ===== ИНИЦИАЛИЗАЦИЯ =====
bot = telebot.TeleBot(BOT_TOKEN)
# ===== ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ =====
def load_data():
"""Загружает данные из JSON"""
if os.path.exists(DATA_FILE):
with open(DATA_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
return DEFAULT_DATA.copy()
def save_data(data):
"""Сохраняет данные в JSON"""
with open(DATA_FILE, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
def is_owner(user_id):
"""Проверяет, владелец ли пользователь"""
return user_id == OWNER_ID
def secret_santa_algorithm(participants):
"""Алгоритм распределения"""
names = list(participants.keys())
receivers = names.copy()
random.shuffle(receivers)
for _ in range(100):
valid = True
for i, giver in enumerate(names):
if giver == receivers[i]:
valid = False
break
if valid:
break
random.shuffle(receivers)
result = {}
for giver, receiver in zip(names, receivers):
result[giver] = receiver
return result
def get_keyboard(buttons, row_width=2):
"""Создает клавиатуру с кнопками"""
markup = telebot.types.ReplyKeyboardMarkup(row_width=row_width, resize_keyboard=True)
markup.add(*[telebot.types.KeyboardButton(btn) for btn in buttons])
return markup
def show_admin_menu(chat_id):
"""Показывает админ-панель"""
markup = get_keyboard([
'➕ Создать группу',
'📋 Список групп',
'✨ Генерировать распределение',
'📢 Отправить результаты',
'🔙 Назад'
], row_width=1)
bot.send_message(
chat_id,
"🔑 Панель администратора\n\nВыберите действие:",
reply_markup=markup,
parse_mode='html'
)
def show_participant_menu(chat_id):
"""Показывает меню участника"""
markup = get_keyboard([
'✏️ Присоединиться к группе',
'📋 Мои группы',
'🔙 Назад'
], row_width=1)
bot.send_message(
chat_id,
"👥 Меню участника\n\nВыберите действие:",
reply_markup=markup,
parse_mode='html'
)
# ===== КОМАНДЫ =====
@bot.message_handler(commands=['start'])
def start(message):
"""Команда /start"""
markup = get_keyboard(['👑 Администратор', '👥 Участник'], row_width=1)
bot.send_message(
message.chat.id,
"🎄 Добро пожаловать в бота для тайного Санты!\n\n"
"Выберите вашу роль:",
reply_markup=markup
)
@bot.message_handler(commands=['help'])
def help_cmd(message):
"""Справка"""
help_text = """
🎄 Справка по боту
Для администраторов:
• Создайте группу
• Посмотрите список групп и участников
• Генерируйте распределение (когда все добавлены)
• Отправьте результаты
Для участников:
• Присоединитесь к группе (вводите свое имя и название группы)
• Получите личное сообщение с получателем подарка
Важно: Все должны быть в приватном чате с ботом!
"""
bot.send_message(message.chat.id, help_text, parse_mode='html')
@bot.message_handler(commands=['mystatus'])
def my_status(message):
"""Показывает статус пользователя"""
user_id = message.from_user.id
username = message.from_user.username or message.from_user.first_name
if is_owner(user_id):
status = "👑 Вы владелец бота (администратор)"
else:
status = "👤 Обычный участник"
bot.send_message(
message.chat.id,
f"Ваш статус:\n{status}\n\n"
f"ID: {user_id}\n"
f"Username: @{username}",
parse_mode='html'
)
# ===== АДМИНИСТРАТОР =====
@bot.message_handler(func=lambda m: m.text == '👑 Администратор')
def admin_role(message):
"""Выбор роли администратора"""
if not is_owner(message.from_user.id):
bot.send_message(message.chat.id, "❌ Только владелец бота может быть администратором.")
return
show_admin_menu(message.chat.id)
@bot.message_handler(func=lambda m: m.text == '➕ Создать группу')
def create_group(message):
"""Создание новой группы"""
if not is_owner(message.from_user.id):
return
msg = bot.send_message(
message.chat.id,
"📝 Введите название группы (например: 'Друзья 2025'):"
)
bot.register_next_step_handler(msg, process_group_name)
def process_group_name(message):
"""Обработка названия группы"""
group_name = message.text.strip()
data = load_data()
if group_name in data["groups"]:
bot.send_message(message.chat.id, "❌ Группа с таким названием уже существует!")
show_admin_menu(message.chat.id)
return
data["groups"][group_name] = {
"created_by": message.from_user.id,
"created_at": datetime.now().isoformat(),
"participants": {},
"distributed": False
}
save_data(data)
bot.send_message(
message.chat.id,
f"✅ Группа '{group_name}' создана!\n\n"
f"Скажите друзьям:\n"
f"Напишите мне в приватный чат, выберите '👥 Участник',\n"
f"затем '✏️ Присоединиться к группе',\n"
f"введите название группы '{group_name}' и своё имя.",
parse_mode='html'
)
show_admin_menu(message.chat.id)
@bot.message_handler(func=lambda m: m.text == '📋 Список групп')
def list_groups(message):
"""Список всех групп"""
if not is_owner(message.from_user.id):
return
data = load_data()
groups = data["groups"]
if not groups:
bot.send_message(message.chat.id, "📭 Групп еще не создано.")
show_admin_menu(message.chat.id)
return
text = "📋 Список групп:\n\n"
for i, (name, info) in enumerate(groups.items(), 1):
count = len(info["participants"])
status = "✅ Распределено" if info["distributed"] else "⏳ Ожидание"
text += f"{i}. {name}\n Участников: {count}\n Статус: {status}\n"
if info["participants"]:
text += " Участники: "
names = list(info["participants"].keys())
text += ", ".join(names)
text += "\n"
text += "\n"
bot.send_message(message.chat.id, text, parse_mode='html')
show_admin_menu(message.chat.id)
@bot.message_handler(func=lambda m: m.text == '✨ Генерировать распределение')
def generate_distribution(message):
"""Генерирование распределения Санты"""
if not is_owner(message.from_user.id):
return
data = load_data()
groups = list(data["groups"].keys())
if not groups:
bot.send_message(message.chat.id, "❌ Групп не найдено!")
show_admin_menu(message.chat.id)
return
markup = get_keyboard(groups, row_width=1)
msg = bot.send_message(message.chat.id, "Выберите группу:", reply_markup=markup)
bot.register_next_step_handler(msg, lambda m: process_distribution(m, groups))
def process_distribution(message, groups):
"""Обработка генерирования распределения"""
if message.text not in groups:
bot.send_message(message.chat.id, "❌ Неверная группа!")
show_admin_menu(message.chat.id)
return
group_name = message.text
data = load_data()
group = data["groups"][group_name]
if len(group["participants"]) < 2:
bot.send_message(
message.chat.id,
f"❌ В группе '{group_name}' должно быть минимум 2 участника!\n"
f"Сейчас в группе: {len(group['participants'])} участников.",
parse_mode='html'
)
show_admin_menu(message.chat.id)
return
# Генерируем распределение
distribution = secret_santa_algorithm(group["participants"])
# Сохраняем результат
data["distributions"][group_name] = {
"generated_at": datetime.now().isoformat(),
"distribution": distribution
}
data["groups"][group_name]["distributed"] = True
save_data(data)
bot.send_message(
message.chat.id,
f"✅ Распределение для группы '{group_name}' сгенерировано!\n\n"
f"Участников: {len(distribution)}\n\n"
f"Готово к отправке результатов!",
parse_mode='html'
)
show_admin_menu(message.chat.id)
@bot.message_handler(func=lambda m: m.text == '📢 Отправить результаты')
def send_results(message):
"""Отправка результатов участникам"""
if not is_owner(message.from_user.id):
return
data = load_data()
distributions = list(data["distributions"].keys())
if not distributions:
bot.send_message(message.chat.id, "❌ Нет сгенерированных распределений!")
show_admin_menu(message.chat.id)
return
markup = get_keyboard(distributions, row_width=1)
msg = bot.send_message(message.chat.id, "Выберите группу:", reply_markup=markup)
bot.register_next_step_handler(msg, lambda m: send_group_results(m, distributions, data))
def send_group_results(message, distributions, data):
"""Отправка результатов группе"""
if message.text not in distributions:
bot.send_message(message.chat.id, "❌ Неверная группа!")
show_admin_menu(message.chat.id)
return
group_name = message.text
distribution = data["distributions"][group_name]["distribution"]
sent_count = 0
failed_count = 0
for giver_name, receiver_name in distribution.items():
# Получаем user_id дарителя из сохранённых данных
participant_data = data["groups"][group_name]["participants"][giver_name]
user_id = participant_data["user_id"]
try:
bot.send_message(
user_id,
f"🎄 Тайный Санта!\n\n"
f"Вы дарите подарок: {receiver_name}\n\n"
f"Группа: {group_name}\n\n"
f"Сохраняйте в секрете! 🤫",
parse_mode='html'
)
sent_count += 1
except Exception as e:
failed_count += 1
print(f"Ошибка отправки {user_id} ({giver_name}): {e}")
result_msg = (
f"✅ Результаты отправлены!\n\n"
f"Успешно отправлено: {sent_count}\n"
)
if failed_count > 0:
result_msg += f"Ошибок: {failed_count}\n"
bot.send_message(message.chat.id, result_msg, parse_mode='html')
show_admin_menu(message.chat.id)
# ===== УЧАСТНИК =====
@bot.message_handler(func=lambda m: m.text == '👥 Участник')
def participant_role(message):
"""Выбор роли участника"""
show_participant_menu(message.chat.id)
@bot.message_handler(func=lambda m: m.text == '✏️ Присоединиться к группе')
def join_group(message):
"""Присоединение к группе"""
data = load_data()
groups = list(data["groups"].keys())
if not groups:
bot.send_message(message.chat.id, "❌ Групп еще не создано. Попросите администратора создать группу.")
show_participant_menu(message.chat.id)
return
markup = get_keyboard(groups, row_width=1)
msg = bot.send_message(
message.chat.id,
"Выберите группу, к которой хотите присоединиться:",
reply_markup=markup
)
bot.register_next_step_handler(msg, lambda m: select_group_to_join(m, groups, message.from_user.id))
def select_group_to_join(message, groups, user_id):
"""Выбор группы для присоединения"""
if message.text not in groups:
bot.send_message(message.chat.id, "❌ Неверная группа!")
show_participant_menu(message.chat.id)
return
selected_group = message.text
msg = bot.send_message(
message.chat.id,
f"📝 Введите своё имя для группы '{selected_group}':",
parse_mode='html'
)
bot.register_next_step_handler(msg, lambda m: add_self_to_group(m, selected_group, user_id))
def add_self_to_group(message, group_name, user_id):
"""Добавление себя в группу"""
participant_name = message.text.strip()
data = load_data()
if participant_name in data["groups"][group_name]["participants"]:
bot.send_message(
message.chat.id,
f"❌ В группе '{group_name}' уже есть участник с именем '{participant_name}'.\n"
f"Введите другое имя или прозвище.",
parse_mode='html'
)
show_participant_menu(message.chat.id)
return
# ⭐ ГЛАВНОЕ: сохраняем user_id участника!
data["groups"][group_name]["participants"][participant_name] = {
"user_id": user_id,
"added_at": datetime.now().isoformat()
}
save_data(data)
bot.send_message(
message.chat.id,
f"✅ Отлично! Вы добавлены в группу '{group_name}' под именем '{participant_name}'.\n\n"
f"Администратор пришлёт вам результаты, когда сгенерирует распределение.",
parse_mode='html'
)
show_participant_menu(message.chat.id)
@bot.message_handler(func=lambda m: m.text == '📋 Мои группы')
def my_groups(message):
"""Показывает группы пользователя"""
user_id = message.from_user.id
data = load_data()
user_groups = []
for group_name, group_info in data["groups"].items():
for participant_name, participant_info in group_info["participants"].items():
if participant_info["user_id"] == user_id:
user_groups.append((group_name, participant_name, group_info["distributed"]))
if not user_groups:
bot.send_message(message.chat.id, "📭 Вы еще не присоединились ни к одной группе.")
show_participant_menu(message.chat.id)
return
text = "📋 Ваши группы:\n\n"
for group_name, participant_name, distributed in user_groups:
status = "✅ Распределено" if distributed else "⏳ Ожидание"
text += f"• {group_name}\n Ваше имя: {participant_name}\n Статус: {status}\n\n"
bot.send_message(message.chat.id, text, parse_mode='html')
show_participant_menu(message.chat.id)
# ===== НАВИГАЦИЯ =====
@bot.message_handler(func=lambda m: m.text == '🔙 Назад')
def back(message):
"""Возврат в главное меню"""
markup = get_keyboard(['👑 Администратор', '👥 Участник'], row_width=1)
bot.send_message(
message.chat.id,
"Выберите вашу роль:",
reply_markup=markup
)
@bot.message_handler(commands=['about'])
def about(message):
"""Информация о боте"""
bot.send_message(
message.chat.id,
"🎄 Telegram бот для тайного Санты v1.2\n\n"
"✨ Как работает:\n"
"1. Администратор создаёт группу\n"
"2. Участники сами присоединяются к группе\n"
"3. Администратор генерирует распределение\n"
"4. Каждый получает личное сообщение с получателем\n\n"
"/help - справка",
parse_mode='html'
)
@bot.message_handler(func=lambda m: True)
def unknown_message(message):
"""Обработка неизвестных сообщений"""
bot.send_message(
message.chat.id,
"❓ Команда не распознана.\n\n"
"Используйте /start для начала работы или /help для справки."
)
# ===== ЗАПУСК БОТА =====
if __name__ == '__main__':
print("🤖 Бот запущен! (Нажмите Ctrl+C для остановки)")
try:
bot.infinity_polling()
except KeyboardInterrupt:
print("⛔ Бот остановлен.")