добавлен скрипт отправки сообщений

This commit is contained in:
vrubelroman 2025-12-12 11:25:25 +03:00
parent 77fd4b15a3
commit 28b9e3b163
2 changed files with 210 additions and 3 deletions

207
broadcast.py Executable file
View file

@ -0,0 +1,207 @@
#!/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:
confirm = input("Продолжить? (y/N): ").strip().lower()
if confirm != 'y':
print("❌ Отменено")
sys.exit(0)
# Отправляем
parse_mode = 'HTML' if args.html else None
broadcast(text, parse_mode)
if __name__ == '__main__':
main()

View file

@ -38,15 +38,15 @@ rusoska.com FALSE / FALSE 1799795493 userToken a01e24c3-c94f-4a4e-b11b-751b72046
.bongacams.com TRUE / FALSE 1796771469 ls01 %7B%22th_type%22%3A%22live%22%2C%22display%22%3A%22medium%22%7D .bongacams.com TRUE / FALSE 1796771469 ls01 %7B%22th_type%22%3A%22live%22%2C%22display%22%3A%22medium%22%7D
.mozilla.org TRUE / FALSE 1799925684 _ga_B9CY1C9VBC GS2.1.s1765365263$o1$g1$t1765365684$j60$l0$h0 .mozilla.org TRUE / FALSE 1799925684 _ga_B9CY1C9VBC GS2.1.s1765365263$o1$g1$t1765365684$j60$l0$h0
.mozilla.org TRUE / FALSE 1799925263 _ga GA1.2.1451822324.1765365263 .mozilla.org TRUE / FALSE 1799925263 _ga GA1.2.1451822324.1765365263
.instagram.com TRUE / TRUE 1800085241 csrftoken CnChQ6nTz8cfm_U7q2ur9w .instagram.com TRUE / TRUE 1800087827 csrftoken CnChQ6nTz8cfm_U7q2ur9w
.instagram.com TRUE / TRUE 1799925292 datr LFY5aVDEvvzQRTypNm_NZ0d3 .instagram.com TRUE / TRUE 1799925292 datr LFY5aVDEvvzQRTypNm_NZ0d3
.instagram.com TRUE / TRUE 1796901312 ig_did B0879634-89D6-4098-9B3E-958B6BC00183 .instagram.com TRUE / TRUE 1796901312 ig_did B0879634-89D6-4098-9B3E-958B6BC00183
.instagram.com TRUE / TRUE 1765970112 dpr 2 .instagram.com TRUE / TRUE 1765970112 dpr 2
.instagram.com TRUE / TRUE 1799925293 mid aTlWLAAEAAEBRoS_PfrA_i5UP0w1 .instagram.com TRUE / TRUE 1799925293 mid aTlWLAAEAAEBRoS_PfrA_i5UP0w1
.instagram.com TRUE / TRUE 1766008776 wd 1920x944 .instagram.com TRUE / TRUE 1766008776 wd 1920x944
.instagram.com TRUE / TRUE 1796939890 sessionid 42059678244%3AD0GdfKmaFZWqXp%3A10%3AAYgpCODjycI3EWMR6G5Uh6kXjroGZ6pb1IRJmXGX3g .instagram.com TRUE / TRUE 1796939890 sessionid 42059678244%3AD0GdfKmaFZWqXp%3A10%3AAYgpCODjycI3EWMR6G5Uh6kXjroGZ6pb1IRJmXGX3g
.instagram.com TRUE / TRUE 1773301241 ds_user_id 42059678244 .instagram.com TRUE / TRUE 1773303827 ds_user_id 42059678244
.instagram.com TRUE / TRUE 0 rur "LDC\05442059678244\0541797061240:01fe985ff74de9ed73460fbffd0fb6620fd751ad0a7ff4257430368aa35e2866cf4f184a" .instagram.com TRUE / TRUE 0 rur "LDC\05442059678244\0541797063826:01fe4af62175a80bcbb48930ff03aa6c92740a54197d1ba96c088c3e257156b522f8ba94"
addons.mozilla.org FALSE / TRUE 0 taarId 4dffa50e49cca797bb48f2f4f11803c251746ad45af1fef3ba1ad37379a24fea addons.mozilla.org FALSE / TRUE 0 taarId 4dffa50e49cca797bb48f2f4f11803c251746ad45af1fef3ba1ad37379a24fea
.facebook.com TRUE / TRUE 1799963979 datr S-05aRMEAJEaLLwYCMb4y3JM .facebook.com TRUE / TRUE 1799963979 datr S-05aRMEAJEaLLwYCMb4y3JM
.facebook.com TRUE / TRUE 1766008781 wd 1920x944 .facebook.com TRUE / TRUE 1766008781 wd 1920x944