initializare

This commit is contained in:
2025-11-06 20:55:35 +02:00
commit 9956e9c11e
32 changed files with 5500 additions and 0 deletions

276
telegram_trigger_bot.py Normal file
View File

@@ -0,0 +1,276 @@
#!/usr/bin/env python3
"""
Telegram Trigger Bot - Declanșează BTGO Scraper prin comandă Telegram
"""
import os
import sys
import subprocess
import logging
from pathlib import Path
from datetime import datetime
import glob
import requests
from dotenv import load_dotenv
# Load environment
load_dotenv()
# Configuration
BOT_TOKEN = os.getenv('TELEGRAM_BOT_TOKEN')
ALLOWED_USER_IDS = os.getenv('TELEGRAM_ALLOWED_USER_IDS', '').split(',') # Ex: "123456,789012"
CHAT_ID = os.getenv('TELEGRAM_CHAT_ID')
POLL_TIMEOUT = int(os.getenv('TELEGRAM_POLL_TIMEOUT', 60)) # Default 60 secunde
# Logging - force stdout instead of stderr (for Windows service logging)
logging.basicConfig(
level=logging.INFO,
format='[%(asctime)s] [%(levelname)s] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
stream=sys.stdout,
force=True
)
class TelegramTriggerBot:
def __init__(self):
self.bot_token = BOT_TOKEN
self.allowed_users = [int(uid.strip()) for uid in ALLOWED_USER_IDS
if uid.strip() and not uid.strip().startswith('#')]
self.base_url = f"https://api.telegram.org/bot{self.bot_token}"
self.last_update_id = 0
self.poll_timeout = POLL_TIMEOUT
if not self.bot_token:
raise ValueError("TELEGRAM_BOT_TOKEN nu este setat în .env!")
logging.info(f"Bot inițializat. Useri autorizați: {self.allowed_users}")
logging.info(f"Long polling timeout: {self.poll_timeout}s")
# Înregistrare comenzi în meniul Telegram
self._register_commands()
def _register_commands(self):
"""Înregistrează comenzile bot în meniul Telegram (pentru DM și grupuri)"""
try:
url = f"{self.base_url}/setMyCommands"
commands = [
{"command": "scrape", "description": "Rulează scraper-ul BTGO"},
{"command": "status", "description": "Status sistem"},
{"command": "help", "description": "Ajutor comenzi"}
]
response = requests.post(url, json={"commands": commands})
if response.status_code == 200 and response.json().get('ok'):
logging.info("✓ Comenzi înregistrate în meniul Telegram")
else:
logging.warning(f"Nu am putut înregistra comenzile: {response.text}")
except Exception as e:
logging.warning(f"Eroare înregistrare comenzi: {e}")
def send_message(self, chat_id, text, reply_to_message_id=None):
"""Trimite mesaj text"""
url = f"{self.base_url}/sendMessage"
data = {
'chat_id': chat_id,
'text': text,
'parse_mode': 'Markdown'
}
if reply_to_message_id:
data['reply_to_message_id'] = reply_to_message_id
response = requests.post(url, json=data)
return response
def send_document(self, chat_id, file_path, caption=None):
"""Trimite document (CSV/JSON)"""
url = f"{self.base_url}/sendDocument"
with open(file_path, 'rb') as file:
files = {'document': file}
data = {'chat_id': chat_id}
if caption:
data['caption'] = caption
response = requests.post(url, data=data, files=files)
return response.json()
def is_user_allowed(self, user_id):
"""Verifică dacă user-ul are permisiune"""
if not self.allowed_users: # Dacă lista e goală, permite oricui
return True
return user_id in self.allowed_users
def run_scraper(self, chat_id, reply_to_message_id=None):
"""Execută scraper-ul"""
# Trimite mesaj inițial și salvează message_id pentru editare ulterioară
response = self.send_message(chat_id, "*BTGO Scraper pornit*\n\nAsteapta 2FA pe telefon.", reply_to_message_id)
message_id = None
try:
message_id = response.json()['result']['message_id']
logging.info(f"Mesaj progress creat cu ID: {message_id}")
except:
logging.warning("Nu am putut salva message_id pentru progress updates")
try:
# Rulează scraper-ul
logging.info("Pornire scraper...")
# Prepare environment with global playwright path + Telegram progress info
env = os.environ.copy()
env['PLAYWRIGHT_BROWSERS_PATH'] = 'C:\\playwright-browsers'
if message_id:
env['TELEGRAM_CHAT_ID'] = str(chat_id)
env['TELEGRAM_MESSAGE_ID'] = str(message_id)
logging.info(f"Setting environment: TELEGRAM_CHAT_ID={chat_id}, TELEGRAM_MESSAGE_ID={message_id}")
else:
logging.warning("No message_id available for progress updates")
result = subprocess.run(
[sys.executable, 'btgo_scraper.py'],
capture_output=True,
text=True,
timeout=600, # 10 minute timeout
cwd=os.path.dirname(os.path.abspath(__file__)), # Run in bot's directory
env=env # Pass environment with playwright path
)
if result.returncode == 0:
# Succes - mesajul final va fi editat de notifications.py
logging.info("Scraper finalizat cu succes")
else:
# Eroare
logging.error(f"Scraper eșuat cu cod {result.returncode}")
error_msg = result.stderr[-1000:] if result.stderr else "Eroare necunoscută"
self.send_message(
chat_id,
f"*EROARE SCRAPER*\n\n```\n{error_msg}\n```",
reply_to_message_id
)
except subprocess.TimeoutExpired:
logging.error("Timeout scraper")
self.send_message(chat_id, "*TIMEOUT*\n\nScraper-ul a depasit 10 minute.", reply_to_message_id)
except Exception as e:
logging.error(f"Eroare execuție: {e}")
self.send_message(chat_id, f"*EROARE EXECUTIE*\n\n```\n{str(e)}\n```", reply_to_message_id)
def handle_command(self, message):
"""Procesează comenzi primite"""
chat_id = message['chat']['id']
chat_type = message['chat']['type'] # 'private', 'group', 'supergroup'
chat_title = message['chat'].get('title', 'DM')
user_id = message['from']['id']
username = message['from'].get('username', 'Unknown')
text = message.get('text', '')
message_id = message.get('message_id')
# Normalizează comanda - elimină @username pentru grupuri (ex: /scrape@botname → /scrape)
if '@' in text:
text = text.split('@')[0]
# Log context
context = f"grup '{chat_title}'" if chat_type in ['group', 'supergroup'] else "DM"
logging.info(f"Mesaj de la {username} (ID: {user_id}) în {context}: {text}")
# Verifică autorizare
if not self.is_user_allowed(user_id):
logging.warning(f"User neautorizat: {user_id} în {context}")
self.send_message(chat_id, "*ACCES INTERZIS*\n\nNu ai permisiunea sa folosesti acest bot.", message_id)
return
# Procesează comenzi
if text == '/start':
welcome_msg = "*BTGO Scraper Trigger Bot*\n\n"
if chat_type in ['group', 'supergroup']:
welcome_msg += f"Bot activ in grupul *{chat_title}*\n\n"
welcome_msg += (
"Comenzi disponibile:\n"
"`/scrape` - Ruleaza scraper-ul\n"
"`/status` - Status sistem\n"
"`/help` - Ajutor"
)
self.send_message(chat_id, welcome_msg, message_id)
elif text == '/scrape':
logging.info(f"Comandă /scrape primită în {context}")
self.run_scraper(chat_id, message_id)
elif text == '/status':
data_dir = Path('data')
csv_count = len(list(data_dir.glob('*.csv')))
json_count = len(list(data_dir.glob('*.json')))
# Ultimul fișier
all_files = sorted(data_dir.glob('solduri_*.csv'), key=os.path.getmtime, reverse=True)
last_run = "N/A"
if all_files:
last_run = datetime.fromtimestamp(os.path.getmtime(all_files[0])).strftime('%Y-%m-%d %H:%M:%S')
self.send_message(
chat_id,
f"*STATUS SISTEM*\n\n"
f"Ultima rulare: `{last_run}`\n"
f"Fisiere CSV: {csv_count}\n"
f"Fisiere JSON: {json_count}\n"
f"Working dir: `{os.getcwd()}`",
message_id
)
elif text == '/help':
help_msg = "*GHID DE UTILIZARE*\n\n"
if chat_type in ['group', 'supergroup']:
help_msg += "IN GRUP: Toti membrii vad comenzile si rezultatele\n\n"
help_msg += (
"1. Trimite `/scrape` pentru a porni scraper-ul\n"
"2. Asteapta notificarea de 2FA pe telefon\n"
"3. Aproba in aplicatia George\n"
"4. Primesti fisierele automat\n\n"
"NOTE:\n"
"- Scraper-ul ruleaza ~2-3 minute\n"
"- Asigura-te ca VM-ul are browser vizibil"
)
self.send_message(chat_id, help_msg, message_id)
else:
self.send_message(chat_id, f"*COMANDA NECUNOSCUTA*\n\n`{text}`\n\nFoloseste /help pentru comenzi.", message_id)
def get_updates(self):
"""Preia update-uri de la Telegram"""
url = f"{self.base_url}/getUpdates"
params = {
'offset': self.last_update_id + 1,
'timeout': self.poll_timeout
}
response = requests.get(url, params=params, timeout=self.poll_timeout + 5)
return response.json()
def run(self):
"""Loop principal bot"""
logging.info("Bot pornit. Așteaptă comenzi...")
while True:
try:
updates = self.get_updates()
if updates.get('ok'):
for update in updates.get('result', []):
self.last_update_id = update['update_id']
if 'message' in update:
self.handle_command(update['message'])
except KeyboardInterrupt:
logging.info("Bot oprit de utilizator")
break
except Exception as e:
logging.error(f"Eroare loop: {e}")
import time
time.sleep(5)
if __name__ == "__main__":
try:
bot = TelegramTriggerBot()
bot.run()
except Exception as e:
logging.error(f"Eroare fatală: {e}")
raise