Compare commits

...

4 Commits

Author SHA1 Message Date
bc353308b5 Documentare comandă /scrape_zip în README
- Actualizare listă comenzi Telegram bot
- Clarificare diferențe între /scrape, /scrape_zip, /zip

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-06 21:23:12 +02:00
463b51da99 Adaugă comanda /scrape_zip în Telegram bot
Funcționalitate:
- /scrape_zip - Rulează scraper + trimite rezultatele ca ZIP
- Dezactivează notificările automate din scraper
- Bot trimite manual ZIP-ul după scraping

Logică:
- run_scraper() primește parametru send_as_zip
- Dacă send_as_zip=True:
  - Setează ENABLE_NOTIFICATIONS=false în env
  - După scraping, apelează send_zip_files()
- Rezultat: un singur ZIP în loc de fișiere individuale

Comenzi disponibile:
- /scrape - Fisiere individuale (comportament original)
- /scrape_zip - Un singur ZIP (nou)
- /zip - Trimite fișierele existente ca ZIP (fără scraping)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-06 21:22:48 +02:00
f088308323 Documentare comandă /zip în README
- Actualizare listă comenzi Telegram bot
- Clarificare: /zip trimite fără scraping

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-06 21:20:43 +02:00
c665ad7813 Adaugă comanda /zip în Telegram bot
Funcționalitate:
- /zip - Trimite ultimele fișiere ca arhivă ZIP
- Găsește automat fișierele din ultima sesiune
- Include solduri per cont + total RON în caption
- Verifică limita Telegram (50 MB)
- Șterge automat ZIP-ul temporar după trimitere

Avantaje:
- Mai rapid decât /scrape (nu rulează scraper-ul)
- Un singur fișier în loc de mai multe
- Include toate datele (CSV + JSON)
- Afișează solduri complete în mesaj

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-06 21:20:17 +02:00
2 changed files with 161 additions and 9 deletions

View File

@@ -287,7 +287,9 @@ python send_notifications.py
``` ```
3. **Comenzi disponibile:** 3. **Comenzi disponibile:**
- `/scrape` - Execută BTGO scraper - `/scrape` - Execută BTGO scraper + trimite fișiere individuale
- `/scrape_zip` - Execută BTGO scraper + trimite arhivă ZIP
- `/zip` - Trimite ultimele fișiere ca arhivă ZIP (fără scraping)
- `/status` - Status bot - `/status` - Status bot
- `/help` - Ajutor - `/help` - Ajutor

View File

@@ -7,6 +7,8 @@ import os
import sys import sys
import subprocess import subprocess
import logging import logging
import json
import zipfile
from pathlib import Path from pathlib import Path
from datetime import datetime from datetime import datetime
import glob import glob
@@ -55,6 +57,8 @@ class TelegramTriggerBot:
url = f"{self.base_url}/setMyCommands" url = f"{self.base_url}/setMyCommands"
commands = [ commands = [
{"command": "scrape", "description": "Rulează scraper-ul BTGO"}, {"command": "scrape", "description": "Rulează scraper-ul BTGO"},
{"command": "scrape_zip", "description": "Rulează scraper + trimite ZIP"},
{"command": "zip", "description": "Trimite ultimele fișiere ca ZIP"},
{"command": "status", "description": "Status sistem"}, {"command": "status", "description": "Status sistem"},
{"command": "help", "description": "Ajutor comenzi"} {"command": "help", "description": "Ajutor comenzi"}
] ]
@@ -97,10 +101,11 @@ class TelegramTriggerBot:
return True return True
return user_id in self.allowed_users return user_id in self.allowed_users
def run_scraper(self, chat_id, reply_to_message_id=None): def run_scraper(self, chat_id, reply_to_message_id=None, send_as_zip=False):
"""Execută scraper-ul""" """Execută scraper-ul"""
# Trimite mesaj inițial și salvează message_id pentru editare ulterioară # 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) zip_msg = " (arhiva ZIP)" if send_as_zip else ""
response = self.send_message(chat_id, f"*BTGO Scraper pornit{zip_msg}*\n\nAsteapta 2FA pe telefon.", reply_to_message_id)
message_id = None message_id = None
try: try:
message_id = response.json()['result']['message_id'] message_id = response.json()['result']['message_id']
@@ -110,12 +115,17 @@ class TelegramTriggerBot:
try: try:
# Rulează scraper-ul # Rulează scraper-ul
logging.info("Pornire scraper...") logging.info(f"Pornire scraper (send_as_zip={send_as_zip})...")
# Prepare environment with global playwright path + Telegram progress info # Prepare environment with global playwright path + Telegram progress info
env = os.environ.copy() env = os.environ.copy()
env['PLAYWRIGHT_BROWSERS_PATH'] = 'C:\\playwright-browsers' env['PLAYWRIGHT_BROWSERS_PATH'] = 'C:\\playwright-browsers'
if message_id:
# Dacă send_as_zip, dezactivează notificările - bot-ul va trimite ZIP-ul manual
if send_as_zip:
env['ENABLE_NOTIFICATIONS'] = 'false'
logging.info("Notificări dezactivate - bot va trimite ZIP manual")
elif message_id:
env['TELEGRAM_CHAT_ID'] = str(chat_id) env['TELEGRAM_CHAT_ID'] = str(chat_id)
env['TELEGRAM_MESSAGE_ID'] = str(message_id) env['TELEGRAM_MESSAGE_ID'] = str(message_id)
logging.info(f"Setting environment: TELEGRAM_CHAT_ID={chat_id}, TELEGRAM_MESSAGE_ID={message_id}") logging.info(f"Setting environment: TELEGRAM_CHAT_ID={chat_id}, TELEGRAM_MESSAGE_ID={message_id}")
@@ -132,9 +142,14 @@ class TelegramTriggerBot:
) )
if result.returncode == 0: if result.returncode == 0:
# Succes - mesajul final va fi editat de notifications.py
logging.info("Scraper finalizat cu succes") logging.info("Scraper finalizat cu succes")
# Dacă send_as_zip, trimite ZIP manual
if send_as_zip:
logging.info("Trimitere rezultate ca ZIP...")
self.send_zip_files(chat_id, reply_to_message_id)
# Altfel, mesajul final va fi editat de notifications.py
else: else:
# Eroare # Eroare
logging.error(f"Scraper eșuat cu cod {result.returncode}") logging.error(f"Scraper eșuat cu cod {result.returncode}")
@@ -153,6 +168,120 @@ class TelegramTriggerBot:
logging.error(f"Eroare execuție: {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) self.send_message(chat_id, f"*EROARE EXECUTIE*\n\n```\n{str(e)}\n```", reply_to_message_id)
def send_zip_files(self, chat_id, reply_to_message_id=None):
"""Trimite ultimele fișiere ca arhivă ZIP"""
try:
data_dir = Path('data')
if not data_dir.exists():
self.send_message(chat_id, "*EROARE*\n\nDirectorul 'data' nu există!", reply_to_message_id)
return
# Găsește ultimul fișier solduri
solduri_files = sorted(data_dir.glob('solduri_*.csv'), key=lambda x: x.stat().st_mtime, reverse=True)
if not solduri_files:
self.send_message(chat_id, "*EROARE*\n\nNu s-au găsit fișiere solduri!", reply_to_message_id)
return
latest_solduri = solduri_files[0]
solduri_time = latest_solduri.stat().st_mtime
# Găsește fișierele tranzacții din aceeași sesiune (ultimele 5 minute)
time_window = 300 # 5 minute
transaction_files = []
for tf in data_dir.glob('tranzactii_*.csv'):
if abs(tf.stat().st_mtime - solduri_time) <= time_window:
transaction_files.append(tf)
# Găsește fișierul JSON corespunzător
json_file = data_dir / (latest_solduri.stem + '.json')
accounts_data = []
if json_file.exists():
try:
with open(json_file, 'r', encoding='utf-8') as f:
json_data = json.load(f)
accounts_data = json_data.get('conturi', [])
except Exception as e:
logging.warning(f"Nu s-a putut citi JSON: {e}")
# Creează arhiva ZIP
timestamp = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
zip_filename = f'btgo_export_{timestamp}.zip'
zip_path = data_dir / zip_filename
files_to_zip = [latest_solduri] + transaction_files
if json_file.exists():
files_to_zip.append(json_file)
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
for file_path in files_to_zip:
zipf.write(file_path, file_path.name)
zip_size = zip_path.stat().st_size / (1024 * 1024) # MB
logging.info(f"Arhivă ZIP creată: {zip_filename} ({zip_size:.2f} MB)")
# Verifică limita Telegram (50 MB)
if zip_size > 50:
self.send_message(
chat_id,
f"*EROARE*\n\nArhiva ZIP este prea mare ({zip_size:.2f} MB)\n"
f"Limita Telegram: 50 MB",
reply_to_message_id
)
zip_path.unlink() # Șterge fișierul
return
# Construiește mesaj cu solduri
caption = f"📦 *BTGO Export (ZIP)*\n\n"
caption += f"Timp: {datetime.fromtimestamp(solduri_time).strftime('%Y-%m-%d %H:%M:%S')}\n"
caption += f"Dimensiune: {zip_size:.2f} MB\n"
caption += f"Fișiere: {len(files_to_zip)}\n\n"
if accounts_data:
total_ron = sum(acc['sold'] for acc in accounts_data if acc.get('moneda') == 'RON')
caption += "*SOLDURI:*\n"
for acc in accounts_data:
nume = acc['nume_cont']
sold = acc['sold']
moneda = acc['moneda']
caption += f"{nume}: {sold:,.2f} {moneda}\n"
caption += f"\n*TOTAL: {total_ron:,.2f} RON*"
else:
caption += f"Conturi: {len(transaction_files)}"
# Trimite ZIP-ul
self.send_message(chat_id, "📦 *Creare arhivă ZIP...*", reply_to_message_id)
url = f"{self.base_url}/sendDocument"
with open(zip_path, 'rb') as f:
files = {'document': f}
data = {
'chat_id': chat_id,
'caption': caption,
'parse_mode': 'Markdown'
}
if reply_to_message_id:
data['reply_to_message_id'] = reply_to_message_id
response = requests.post(url, data=data, files=files)
if response.status_code == 200:
logging.info("✓ ZIP trimis cu succes pe Telegram")
else:
logging.error(f"Eroare trimitere ZIP: {response.text}")
self.send_message(chat_id, f"*EROARE*\n\nNu s-a putut trimite arhiva.", reply_to_message_id)
# Șterge fișierul ZIP temporar
zip_path.unlink()
except Exception as e:
logging.error(f"Eroare send_zip_files: {e}", exc_info=True)
self.send_message(chat_id, f"*EROARE*\n\n```\n{str(e)}\n```", reply_to_message_id)
def handle_command(self, message): def handle_command(self, message):
"""Procesează comenzi primite""" """Procesează comenzi primite"""
chat_id = message['chat']['id'] chat_id = message['chat']['id']
@@ -185,6 +314,8 @@ class TelegramTriggerBot:
welcome_msg += ( welcome_msg += (
"Comenzi disponibile:\n" "Comenzi disponibile:\n"
"`/scrape` - Ruleaza scraper-ul\n" "`/scrape` - Ruleaza scraper-ul\n"
"`/scrape_zip` - Ruleaza scraper + trimite ZIP\n"
"`/zip` - Trimite ultimele fisiere ca ZIP\n"
"`/status` - Status sistem\n" "`/status` - Status sistem\n"
"`/help` - Ajutor" "`/help` - Ajutor"
) )
@@ -194,6 +325,14 @@ class TelegramTriggerBot:
logging.info(f"Comandă /scrape primită în {context}") logging.info(f"Comandă /scrape primită în {context}")
self.run_scraper(chat_id, message_id) self.run_scraper(chat_id, message_id)
elif text == '/scrape_zip':
logging.info(f"Comandă /scrape_zip primită în {context}")
self.run_scraper(chat_id, message_id, send_as_zip=True)
elif text == '/zip':
logging.info(f"Comandă /zip primită în {context}")
self.send_zip_files(chat_id, message_id)
elif text == '/status': elif text == '/status':
data_dir = Path('data') data_dir = Path('data')
csv_count = len(list(data_dir.glob('*.csv'))) csv_count = len(list(data_dir.glob('*.csv')))
@@ -220,13 +359,24 @@ class TelegramTriggerBot:
if chat_type in ['group', 'supergroup']: if chat_type in ['group', 'supergroup']:
help_msg += "IN GRUP: Toti membrii vad comenzile si rezultatele\n\n" help_msg += "IN GRUP: Toti membrii vad comenzile si rezultatele\n\n"
help_msg += ( help_msg += (
"1. Trimite `/scrape` pentru a porni scraper-ul\n" "*COMENZI:*\n"
"`/scrape` - Ruleaza scraper + trimite fisiere individuale\n"
"`/scrape_zip` - Ruleaza scraper + trimite arhiva ZIP\n"
"`/zip` - Trimite ultimele fisiere ca arhiva ZIP (fara scraping)\n"
"`/status` - Informatii sistem\n"
"`/help` - Acest mesaj\n\n"
"*GHID SCRAPER:*\n"
"1. Trimite `/scrape` sau `/scrape_zip`\n"
"2. Asteapta notificarea de 2FA pe telefon\n" "2. Asteapta notificarea de 2FA pe telefon\n"
"3. Aproba in aplicatia George\n" "3. Aproba in aplicatia George\n"
"4. Primesti fisierele automat\n\n" "4. Primesti fisierele automat\n\n"
"NOTE:\n" "*DIFERENTE:*\n"
"• `/scrape` - Fisiere individuale (CSV + JSON)\n"
"• `/scrape_zip` - Un singur ZIP cu toate fisierele\n"
"• `/zip` - Rapid, foloseste datele existente\n\n"
"*NOTE:*\n"
"- Scraper-ul ruleaza ~2-3 minute\n" "- Scraper-ul ruleaza ~2-3 minute\n"
"- Asigura-te ca VM-ul are browser vizibil" "- VM-ul trebuie sa aiba browser vizibil"
) )
self.send_message(chat_id, help_msg, message_id) self.send_message(chat_id, help_msg, message_id)