186 lines
6.9 KiB
Python
186 lines
6.9 KiB
Python
|
|
"""
|
|||
|
|
Admin Telegram Bot
|
|||
|
|
Админский бот для получения статистики и всех скачанных видео
|
|||
|
|
"""
|
|||
|
|
import os
|
|||
|
|
import logging
|
|||
|
|
import sqlite3
|
|||
|
|
from pathlib import Path
|
|||
|
|
from telegram import Update
|
|||
|
|
from telegram.ext import Application, CommandHandler, ContextTypes, MessageHandler, filters
|
|||
|
|
from telegram.request import HTTPXRequest
|
|||
|
|
|
|||
|
|
# Настройка логирования
|
|||
|
|
logging.basicConfig(
|
|||
|
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
|||
|
|
level=logging.INFO
|
|||
|
|
)
|
|||
|
|
logger = logging.getLogger(__name__)
|
|||
|
|
|
|||
|
|
# Токен админ бота из переменных окружения
|
|||
|
|
ADMIN_BOT_TOKEN = os.getenv('ADMIN_BOT_TOKEN')
|
|||
|
|
|
|||
|
|
# Базовая директория проекта
|
|||
|
|
BASE_DIR = Path(__file__).resolve().parent
|
|||
|
|
DATA_DIR = BASE_DIR / 'data'
|
|||
|
|
DB_FILE = DATA_DIR / 'bot.db'
|
|||
|
|
ADMIN_CHAT_ID_FILE = DATA_DIR / 'admin_chat_id.txt'
|
|||
|
|
|
|||
|
|
|
|||
|
|
def get_total_downloads() -> int:
|
|||
|
|
"""Возвращает общее количество скачанных видео"""
|
|||
|
|
try:
|
|||
|
|
conn = sqlite3.connect(str(DB_FILE))
|
|||
|
|
cursor = conn.cursor()
|
|||
|
|
cursor.execute('SELECT total_downloads FROM stats WHERE id = 1')
|
|||
|
|
result = cursor.fetchone()
|
|||
|
|
conn.close()
|
|||
|
|
return result[0] if result else 0
|
|||
|
|
except Exception as e:
|
|||
|
|
logger.error(f"Ошибка при получении количества скачанных видео: {e}")
|
|||
|
|
return 0
|
|||
|
|
|
|||
|
|
|
|||
|
|
def get_total_users() -> int:
|
|||
|
|
"""Возвращает общее количество уникальных пользователей"""
|
|||
|
|
try:
|
|||
|
|
conn = sqlite3.connect(str(DB_FILE))
|
|||
|
|
cursor = conn.cursor()
|
|||
|
|
cursor.execute('SELECT COUNT(*) FROM users')
|
|||
|
|
result = cursor.fetchone()
|
|||
|
|
conn.close()
|
|||
|
|
return result[0] if result else 0
|
|||
|
|
except Exception as e:
|
|||
|
|
logger.error(f"Ошибка при получении количества пользователей: {e}")
|
|||
|
|
return 0
|
|||
|
|
|
|||
|
|
|
|||
|
|
def get_error_stats() -> dict[str, int]:
|
|||
|
|
"""Возвращает статистику ошибок по сервисам"""
|
|||
|
|
try:
|
|||
|
|
conn = sqlite3.connect(str(DB_FILE))
|
|||
|
|
cursor = conn.cursor()
|
|||
|
|
cursor.execute('SELECT service, error_count FROM error_stats ORDER BY service')
|
|||
|
|
results = cursor.fetchall()
|
|||
|
|
conn.close()
|
|||
|
|
return {service: count for service, count in results}
|
|||
|
|
except Exception as e:
|
|||
|
|
logger.error(f"Ошибка при получении статистики ошибок: {e}")
|
|||
|
|
return {}
|
|||
|
|
|
|||
|
|
|
|||
|
|
def save_admin_chat_id(chat_id: int):
|
|||
|
|
"""Сохраняет chat_id админа в файл"""
|
|||
|
|
try:
|
|||
|
|
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
|||
|
|
with open(ADMIN_CHAT_ID_FILE, 'w') as f:
|
|||
|
|
f.write(str(chat_id))
|
|||
|
|
logger.info(f"Сохранен chat_id админа: {chat_id}")
|
|||
|
|
except Exception as e:
|
|||
|
|
logger.error(f"Ошибка при сохранении chat_id админа: {e}")
|
|||
|
|
|
|||
|
|
|
|||
|
|
def get_admin_chat_id() -> int | None:
|
|||
|
|
"""Получает сохраненный chat_id админа"""
|
|||
|
|
try:
|
|||
|
|
if ADMIN_CHAT_ID_FILE.exists():
|
|||
|
|
with open(ADMIN_CHAT_ID_FILE, 'r') as f:
|
|||
|
|
chat_id = f.read().strip()
|
|||
|
|
if chat_id:
|
|||
|
|
return int(chat_id)
|
|||
|
|
except Exception as e:
|
|||
|
|
logger.error(f"Ошибка при чтении chat_id админа: {e}")
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def stat_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|||
|
|
"""Обрабатывает команду /stat"""
|
|||
|
|
# Сохраняем chat_id админа при первом использовании
|
|||
|
|
chat_id = update.message.chat_id
|
|||
|
|
saved_chat_id = get_admin_chat_id()
|
|||
|
|
if saved_chat_id != chat_id:
|
|||
|
|
save_admin_chat_id(chat_id)
|
|||
|
|
if saved_chat_id is None:
|
|||
|
|
await update.message.reply_text("✅ Админ бот активирован! Теперь вы будете получать все скачанные видео.")
|
|||
|
|
|
|||
|
|
total_downloads = get_total_downloads()
|
|||
|
|
total_users = get_total_users()
|
|||
|
|
error_stats = get_error_stats()
|
|||
|
|
|
|||
|
|
# Форматируем статистику ошибок
|
|||
|
|
error_stats_text = ""
|
|||
|
|
service_names = {
|
|||
|
|
'youtube': 'YouTube',
|
|||
|
|
'instagram': 'Instagram',
|
|||
|
|
'tiktok': 'TikTok',
|
|||
|
|
'vk': 'VK',
|
|||
|
|
'yapfiles': 'Yapfiles',
|
|||
|
|
'unknown': 'Unknown'
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for service, count in sorted(error_stats.items()):
|
|||
|
|
if count > 0:
|
|||
|
|
service_name = service_names.get(service, service)
|
|||
|
|
error_stats_text += f" • {service_name}: {count}\n"
|
|||
|
|
|
|||
|
|
if not error_stats_text:
|
|||
|
|
error_stats_text = " Нет ошибок"
|
|||
|
|
|
|||
|
|
stat_message = (
|
|||
|
|
f"📊 Статистика бота:\n\n"
|
|||
|
|
f"👥 Всего пользователей: {total_users}\n"
|
|||
|
|
f"📹 Всего скачано видео: {total_downloads}\n\n"
|
|||
|
|
f"❌ Ошибки по сервисам:\n{error_stats_text.strip()}"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
await update.message.reply_text(stat_message)
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|||
|
|
"""Обрабатывает все сообщения (на случай если админ отправит что-то)"""
|
|||
|
|
# Сохраняем chat_id админа при первом сообщении
|
|||
|
|
chat_id = update.message.chat_id
|
|||
|
|
saved_chat_id = get_admin_chat_id()
|
|||
|
|
if saved_chat_id != chat_id:
|
|||
|
|
save_admin_chat_id(chat_id)
|
|||
|
|
if saved_chat_id is None:
|
|||
|
|
await update.message.reply_text("✅ Админ бот активирован! Теперь вы будете получать все скачанные видео.\n\nДоступные команды: /stat")
|
|||
|
|
else:
|
|||
|
|
await update.message.reply_text("Это админский бот. Доступные команды: /stat")
|
|||
|
|
else:
|
|||
|
|
if update.message and update.message.text:
|
|||
|
|
await update.message.reply_text("Это админский бот. Доступные команды: /stat")
|
|||
|
|
|
|||
|
|
|
|||
|
|
def main():
|
|||
|
|
"""Главная функция для запуска админ бота"""
|
|||
|
|
if not ADMIN_BOT_TOKEN:
|
|||
|
|
logger.error("ADMIN_BOT_TOKEN не установлен!")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
# Создаем приложение
|
|||
|
|
request = HTTPXRequest(
|
|||
|
|
read_timeout=120,
|
|||
|
|
connect_timeout=60
|
|||
|
|
)
|
|||
|
|
application = (
|
|||
|
|
Application.builder()
|
|||
|
|
.token(ADMIN_BOT_TOKEN)
|
|||
|
|
.request(request)
|
|||
|
|
.get_updates_request(HTTPXRequest(read_timeout=120, connect_timeout=60))
|
|||
|
|
.build()
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# Регистрируем обработчики
|
|||
|
|
application.add_handler(CommandHandler("stat", stat_command))
|
|||
|
|
application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
|
|||
|
|
|
|||
|
|
# Запускаем бота
|
|||
|
|
logger.info("Админ бот запущен")
|
|||
|
|
application.run_polling(allowed_updates=Update.ALL_TYPES)
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == '__main__':
|
|||
|
|
main()
|
|||
|
|
|