|
|
| import asyncio |
| import logging |
| import sqlite3 |
| import os |
| from datetime import datetime |
| import pytz |
|
|
| from aiogram import Bot, Dispatcher, types, F |
| from aiogram.filters import Command |
| from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton |
| from aiogram.fsm.context import FSMContext |
| from aiogram.fsm.state import State, StatesGroup |
|
|
| |
| |
| TOKEN = os.getenv("BOT_TOKEN") or "8670682692:AAFM0jiSTY7z30O-PKkUZgj8QSpKX-GwHyo" |
| ADMIN_ID = 1753037099 |
| CHANNEL_ID = "@TWIXER_MUSIC" |
| CHANNEL_URL = "https://t.me/TWIXER_MUSIC" |
| MOSCOW_TZ = pytz.timezone('Europe/Moscow') |
|
|
| |
| def init_db(): |
| conn = sqlite3.connect('database.db') |
| cur = conn.cursor() |
| |
| cur.execute('''CREATE TABLE IF NOT EXISTS users |
| (user_id INTEGER PRIMARY KEY, username TEXT, received INTEGER, date TEXT)''') |
| |
| cur.execute('''CREATE TABLE IF NOT EXISTS settings |
| (key TEXT PRIMARY KEY, value TEXT)''') |
| |
| cur.execute("INSERT OR IGNORE INTO settings (key, value) VALUES ('downloads', '0')") |
| conn.commit() |
| conn.close() |
|
|
| def get_setting(key): |
| conn = sqlite3.connect('database.db') |
| cur = conn.cursor() |
| cur.execute("SELECT value FROM settings WHERE key=?", (key,)) |
| res = cur.fetchone() |
| conn.close() |
| return res[0] if res else None |
|
|
| def update_setting(key, value): |
| conn = sqlite3.connect('database.db') |
| cur = conn.cursor() |
| cur.execute("INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)", (key, value)) |
| conn.commit() |
| conn.close() |
|
|
| def log_user(user_id, username, received): |
| conn = sqlite3.connect('database.db') |
| cur = conn.cursor() |
| now = datetime.now(MOSCOW_TZ).strftime("%d.%m.%Y %H:%M") |
| cur.execute("INSERT OR REPLACE INTO users VALUES (?, ?, ?, ?)", (user_id, username, received, now)) |
| conn.commit() |
| conn.close() |
|
|
| def get_all_users(): |
| conn = sqlite3.connect('database.db') |
| cur = conn.cursor() |
| cur.execute("SELECT * FROM users") |
| data = cur.fetchall() |
| conn.close() |
| return data |
|
|
| |
| bot = Bot(token=TOKEN) |
| dp = Dispatcher() |
|
|
| class AdminStates(StatesGroup): |
| waiting_for_file = State() |
|
|
| |
| def get_sub_kb(): |
| return InlineKeyboardMarkup(inline_keyboard=[ |
| [InlineKeyboardButton(text="1. Подписаться на TWIXER", url=CHANNEL_URL)], |
| [InlineKeyboardButton(text="2. Получить Драм Кит", callback_data="check_sub")] |
| ]) |
|
|
| |
|
|
| @dp.message(Command("start")) |
| async def start_handler(message: types.Message): |
| await message.answer( |
| f"Привет, {message.from_user.first_name}!\n" |
| f"Чтобы получить данный драм кит, нужно быть подписанным на канал TWIXER", |
| reply_markup=get_sub_kb() |
| ) |
|
|
| @dp.callback_query(F.data == "check_sub") |
| async def check_sub_callback(callback: types.CallbackQuery): |
| user_id = callback.from_user.id |
| try: |
| |
| chat_member = await bot.get_chat_member(chat_id=CHANNEL_ID, user_id=user_id) |
| |
| if chat_member.status in ['member', 'administrator', 'creator']: |
| file_id = get_setting("drum_kit_file_id") |
| |
| if not file_id: |
| await callback.message.answer("Админ еще не загрузил файл в бота.") |
| await callback.answer() |
| return |
|
|
| |
| count = int(get_setting("downloads") or 0) + 1 |
| update_setting("downloads", str(count)) |
| |
| |
| log_user(user_id, callback.from_user.username, 1) |
|
|
| |
| await callback.message.answer_document( |
| file_id, |
| caption=f"Драм кит успешно получен!\n\n🔥 Общее количество скачиваний: {count}" |
| ) |
| await callback.answer("Файл отправлен!") |
| else: |
| |
| await callback.answer("Вы не подписаны на канал!", show_alert=True) |
| await callback.message.answer( |
| "К сожалению вы не подписаны на канал.\n" |
| "Чтобы получить драм кит, надо быть подписанным на канал!", |
| reply_markup=get_sub_kb() |
| ) |
| except Exception as e: |
| logging.error(e) |
| await callback.answer("Ошибка! Убедитесь, что бот добавлен в админы канала.", show_alert=True) |
|
|
| |
|
|
| @dp.message(Command("admin")) |
| async def admin_menu(message: types.Message): |
| if message.from_user.id != ADMIN_ID: |
| return |
| text = ( |
| "⚙️ Меню администратора:\n\n" |
| "/admin - Показать список команд\n" |
| "/FileDK - Загрузить/изменить файл драм кита\n" |
| "/Stata - Посмотреть статистику и подписчиков" |
| ) |
| await message.answer(text) |
|
|
| @dp.message(Command("FileDK")) |
| async def admin_file_dk(message: types.Message, state: FSMContext): |
| if message.from_user.id != ADMIN_ID: return |
| await message.answer("Пришлите файл (документ), который бот будет выдавать пользователям.") |
| await state.set_state(AdminStates.waiting_for_file) |
|
|
| @dp.message(AdminStates.waiting_for_file, F.document) |
| async def save_file_id(message: types.Message, state: FSMContext): |
| file_id = message.document.file_id |
| update_setting("drum_kit_file_id", file_id) |
| await message.answer("✅ Файл успешно сохранен! Теперь пользователи будут получать его.") |
| await state.clear() |
|
|
| @dp.message(Command("Stata")) |
| async def admin_stata(message: types.Message): |
| if message.from_user.id != ADMIN_ID: return |
| |
| users = get_all_users() |
| if not users: |
| await message.answer("Статистика пока пуста.") |
| return |
|
|
| report = "📊 Детальная статистика:\n\n" |
| for uid, name, received, date in users: |
| |
| try: |
| member = await bot.get_chat_member(chat_id=CHANNEL_ID, user_id=uid) |
| sub_status = "подписан" if member.status in ['member', 'administrator', 'creator'] else "не подписан" |
| except: |
| sub_status = "неизвестно (бот заблокирован?)" |
| |
| rec_status = "получил(-а) файл" if received == 1 else "не получил(-а)" |
| username = f"@{name}" if name else f"ID: {uid}" |
| |
| report += f"👤 {username} {sub_status} {rec_status}\n📅 {date}\n\n" |
| |
| if len(report) > 3800: |
| await message.answer(report) |
| report = "" |
| |
| if report: |
| await message.answer(report) |
|
|
| |
| async def main(): |
| init_db() |
| logging.basicConfig(level=logging.INFO) |
| print("Бот запущен!") |
| await dp.start_polling(bot) |
|
|
| if __name__ == "__main__": |
| try: |
| asyncio.run(main()) |
| except (KeyboardInterrupt, SystemExit): |
| logging.info("Бот остановлен") |
|
|