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:
@@ -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)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user