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:**
- `/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
- `/help` - Ajutor

View File

@@ -7,6 +7,8 @@ import os
import sys
import subprocess
import logging
import json
import zipfile
from pathlib import Path
from datetime import datetime
import glob
@@ -55,6 +57,8 @@ class TelegramTriggerBot:
url = f"{self.base_url}/setMyCommands"
commands = [
{"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": "help", "description": "Ajutor comenzi"}
]
@@ -97,10 +101,11 @@ class TelegramTriggerBot:
return True
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"""
# 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
try:
message_id = response.json()['result']['message_id']
@@ -110,12 +115,17 @@ class TelegramTriggerBot:
try:
# 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
env = os.environ.copy()
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_MESSAGE_ID'] = str(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:
# Succes - mesajul final va fi editat de notifications.py
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:
# Eroare
logging.error(f"Scraper eșuat cu cod {result.returncode}")
@@ -153,6 +168,120 @@ class TelegramTriggerBot:
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 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):
"""Procesează comenzi primite"""
chat_id = message['chat']['id']
@@ -185,6 +314,8 @@ class TelegramTriggerBot:
welcome_msg += (
"Comenzi disponibile:\n"
"`/scrape` - Ruleaza scraper-ul\n"
"`/scrape_zip` - Ruleaza scraper + trimite ZIP\n"
"`/zip` - Trimite ultimele fisiere ca ZIP\n"
"`/status` - Status sistem\n"
"`/help` - Ajutor"
)
@@ -194,6 +325,14 @@ class TelegramTriggerBot:
logging.info(f"Comandă /scrape primită în {context}")
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':
data_dir = Path('data')
csv_count = len(list(data_dir.glob('*.csv')))
@@ -220,13 +359,24 @@ class TelegramTriggerBot:
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"
"*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"
"3. Aproba in aplicatia George\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"
"- Asigura-te ca VM-ul are browser vizibil"
"- VM-ul trebuie sa aiba browser vizibil"
)
self.send_message(chat_id, help_msg, message_id)