videoDownloadTGbot/broadcast.py

210 lines
6.7 KiB
Python
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
Скрипт для рассылки сообщений всем пользователям бота.
Использование:
python broadcast.py "Текст сообщения"
python broadcast.py --html "<b>Жирный</b> текст"
python broadcast.py --file message.txt
"""
import os
import sys
import sqlite3
import argparse
from pathlib import Path
# Загружаем переменные окружения из .env если есть
def load_env_file():
env_file = Path(__file__).resolve().parent / '.env'
if env_file.exists():
with open(env_file, 'r') as f:
for line in f:
line = line.strip()
if line and not line.startswith('#') and '=' in line:
key, value = line.split('=', 1)
os.environ.setdefault(key.strip(), value.strip())
load_env_file()
import requests
import time
# Настройки
BASE_DIR = Path(__file__).resolve().parent
DB_FILE = BASE_DIR / 'data' / 'bot.db'
TELEGRAM_BOT_TOKEN = os.getenv('TELEGRAM_BOT_TOKEN')
def get_telegram_api_url():
return f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}"
def get_all_users() -> list[tuple[int, str, str]]:
"""Получает всех пользователей из базы данных"""
if not DB_FILE.exists():
print(f"❌ База данных не найдена: {DB_FILE}")
sys.exit(1)
conn = sqlite3.connect(str(DB_FILE))
cursor = conn.cursor()
cursor.execute('SELECT chat_id, username, locale FROM users')
users = cursor.fetchall()
conn.close()
return users
def send_message(chat_id: int, text: str, parse_mode: str = None) -> bool:
"""Отправляет сообщение пользователю"""
payload = {
"chat_id": chat_id,
"text": text,
}
if parse_mode:
payload["parse_mode"] = parse_mode
try:
response = requests.post(
f"{get_telegram_api_url()}/sendMessage",
json=payload,
timeout=30
)
if response.status_code == 200:
return True
else:
result = response.json()
error = result.get('description', 'Unknown error')
# Пользователь заблокировал бота или удалил чат
if 'blocked' in error.lower() or 'chat not found' in error.lower():
return False
print(f" ⚠️ {chat_id}: {error}")
return False
except Exception as e:
print(f"{chat_id}: {e}")
return False
def broadcast(text: str, parse_mode: str = None):
"""Рассылает сообщение всем пользователям"""
users = get_all_users()
if not users:
print("❌ Нет пользователей в базе данных")
return
print(f"📤 Начинаю рассылку для {len(users)} пользователей...")
print(f"📝 Сообщение:\n{text[:100]}{'...' if len(text) > 100 else ''}\n")
success = 0
failed = 0
for chat_id, username, locale in users:
result = send_message(chat_id, text, parse_mode)
if result:
success += 1
print(f"{chat_id} (@{username or 'no_username'})")
else:
failed += 1
# Небольшая задержка чтобы не превысить лимиты Telegram
time.sleep(0.05)
print(f"\n📊 Результат:")
print(f" ✅ Успешно: {success}")
print(f" ❌ Ошибок: {failed}")
print(f" 📨 Всего: {len(users)}")
def main():
parser = argparse.ArgumentParser(
description='Рассылка сообщений всем пользователям бота',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Примеры:
python broadcast.py "Привет! Это важное сообщение."
python broadcast.py --html "<b>Важно!</b> Новая функция добавлена."
python broadcast.py --file announcement.txt
python broadcast.py --file announcement.txt --html
"""
)
parser.add_argument(
'message',
nargs='?',
help='Текст сообщения для рассылки'
)
parser.add_argument(
'--html',
action='store_true',
help='Использовать HTML-разметку в сообщении'
)
parser.add_argument(
'--file', '-f',
type=str,
help='Файл с текстом сообщения'
)
parser.add_argument(
'--list', '-l',
action='store_true',
help='Показать список пользователей без отправки'
)
parser.add_argument(
'--yes', '-y',
action='store_true',
help='Пропустить подтверждение'
)
args = parser.parse_args()
# Проверяем токен
if not TELEGRAM_BOT_TOKEN:
print("❌ TELEGRAM_BOT_TOKEN не установлен!")
print(" Установите переменную окружения или создайте .env файл")
sys.exit(1)
# Показать список пользователей
if args.list:
users = get_all_users()
print(f"👥 Всего пользователей: {len(users)}\n")
for chat_id, username, locale in users:
print(f" {chat_id:>12} | @{username or 'no_username':<20} | {locale}")
sys.exit(0)
# Получаем текст сообщения
if args.file:
file_path = Path(args.file)
if not file_path.exists():
print(f"❌ Файл не найден: {args.file}")
sys.exit(1)
text = file_path.read_text(encoding='utf-8')
elif args.message:
text = args.message
else:
parser.print_help()
sys.exit(1)
if not text.strip():
print("❌ Сообщение не может быть пустым")
sys.exit(1)
# Подтверждение
users = get_all_users()
print(f"⚠️ Вы собираетесь отправить сообщение {len(users)} пользователям.")
if not args.yes:
try:
confirm = input("Продолжить? (y/N): ").strip().lower()
except (UnicodeDecodeError, EOFError):
confirm = ''
if confirm not in ('y', 'yes', 'д', 'да'):
print("❌ Отменено")
sys.exit(0)
# Отправляем
parse_mode = 'HTML' if args.html else None
broadcast(text, parse_mode)
if __name__ == '__main__':
main()