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>
This commit is contained in:
2025-11-06 21:20:17 +02:00
parent 2439d0b62a
commit c665ad7813

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,7 @@ 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": "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"}
] ]
@@ -153,6 +156,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 +302,7 @@ class TelegramTriggerBot:
welcome_msg += ( welcome_msg += (
"Comenzi disponibile:\n" "Comenzi disponibile:\n"
"`/scrape` - Ruleaza scraper-ul\n" "`/scrape` - Ruleaza scraper-ul\n"
"`/zip` - Trimite ultimele fisiere ca ZIP\n"
"`/status` - Status sistem\n" "`/status` - Status sistem\n"
"`/help` - Ajutor" "`/help` - Ajutor"
) )
@@ -194,6 +312,10 @@ 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 == '/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 +342,20 @@ 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-ul + trimite fisiere\n"
"`/zip` - Trimite ultimele fisiere ca arhiva ZIP\n"
"`/status` - Informatii sistem\n"
"`/help` - Acest mesaj\n\n"
"*GHID SCRAPER:*\n"
"1. Trimite `/scrape`\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" "*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\n"
"- `/zip` trimite datele existente (fara scraping)"
) )
self.send_message(chat_id, help_msg, message_id) self.send_message(chat_id, help_msg, message_id)