Adauga comenzi Telegram pentru solduri si repara get_telegram_chat_id
- Adauga /scrape_solduri - scraping rapid doar solduri (fara CSV tranzactii) - Adauga /solduri - afisare instant solduri din cache (fara 2FA) - Redenumeste comenzi pentru consistenta - Adauga suport BALANCES_ONLY in scraper (skip download tranzactii) - Repara get_telegram_chat_id.py - elimina input() interactiv - Imbunatateste output get_telegram_chat_id.py cu info bot si formatare Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -93,8 +93,14 @@ class BTGoScraper:
|
||||
def run(self):
|
||||
"""Entry point principal - orchestreaza tot flow-ul"""
|
||||
try:
|
||||
# Check dacă rulăm în mod balances_only
|
||||
balances_only = os.getenv('BALANCES_ONLY', 'false').lower() == 'true'
|
||||
|
||||
logging.info("=" * 60)
|
||||
logging.info("Start BTGO Scraper")
|
||||
if balances_only:
|
||||
logging.info("Start BTGO Scraper (DOAR SOLDURI)")
|
||||
else:
|
||||
logging.info("Start BTGO Scraper")
|
||||
logging.info("=" * 60)
|
||||
|
||||
with sync_playwright() as p:
|
||||
@@ -115,9 +121,11 @@ class BTGoScraper:
|
||||
accounts = self.read_accounts()
|
||||
csv_path, json_path = self.save_results(accounts)
|
||||
|
||||
# Descarcă tranzacții pentru toate conturile (optional)
|
||||
# Descarcă tranzacții pentru toate conturile (doar dacă nu e balances_only)
|
||||
downloaded_files = []
|
||||
if self.config.DOWNLOAD_TRANSACTIONS:
|
||||
if balances_only:
|
||||
logging.info("Mod DOAR SOLDURI - skip download tranzactii")
|
||||
elif self.config.DOWNLOAD_TRANSACTIONS:
|
||||
downloaded_files = self.download_transactions(accounts)
|
||||
else:
|
||||
logging.info("Download tranzacții dezactivat (DOWNLOAD_TRANSACTIONS=false)")
|
||||
|
||||
@@ -4,6 +4,7 @@ Helper script pentru obținerea Chat ID Telegram (pentru DM și grupuri)
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import requests
|
||||
from dotenv import load_dotenv
|
||||
|
||||
@@ -13,11 +14,20 @@ load_dotenv()
|
||||
BOT_TOKEN = os.getenv('TELEGRAM_BOT_TOKEN')
|
||||
|
||||
if not BOT_TOKEN:
|
||||
print("❌ TELEGRAM_BOT_TOKEN nu este setat în .env!")
|
||||
print("=" * 60)
|
||||
print("EROARE: TELEGRAM_BOT_TOKEN nu este setat în .env")
|
||||
print("=" * 60)
|
||||
print("\nAdaugă în .env:")
|
||||
print("TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrs")
|
||||
print("=" * 60)
|
||||
exit(1)
|
||||
|
||||
def get_bot_info():
|
||||
"""Preia informații despre bot"""
|
||||
url = f"https://api.telegram.org/bot{BOT_TOKEN}/getMe"
|
||||
response = requests.get(url)
|
||||
return response.json()
|
||||
|
||||
def get_updates():
|
||||
"""Preia ultimele update-uri de la bot"""
|
||||
url = f"https://api.telegram.org/bot{BOT_TOKEN}/getUpdates"
|
||||
@@ -28,96 +38,102 @@ def main():
|
||||
print("=" * 60)
|
||||
print(" Telegram Chat ID Helper")
|
||||
print("=" * 60)
|
||||
print()
|
||||
print("📱 Instrucțiuni:")
|
||||
print("1. Trimite /start către bot (DM)")
|
||||
print(" SAU")
|
||||
print("2. Trimite /start în grupul unde ai bot-ul")
|
||||
print()
|
||||
print("Apasă Enter după ce ai trimis mesajul...")
|
||||
input()
|
||||
|
||||
print("\n🔍 Căutare mesaje...")
|
||||
# Verifică info bot
|
||||
bot_data = get_bot_info()
|
||||
if bot_data.get('ok'):
|
||||
bot = bot_data['result']
|
||||
print(f"\nBot: @{bot.get('username')} ({bot.get('first_name')})")
|
||||
print(f"Bot ID: {bot.get('id')}")
|
||||
print(f"Status: ACTIV")
|
||||
else:
|
||||
print(f"\nERORE: Token invalid - {bot_data}")
|
||||
exit(1)
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("Căutare mesaje...")
|
||||
print("=" * 60)
|
||||
|
||||
data = get_updates()
|
||||
|
||||
if not data.get('ok'):
|
||||
print(f"❌ Eroare API: {data}")
|
||||
print(f"\nERORE API: {data}")
|
||||
return
|
||||
|
||||
results = data.get('result', [])
|
||||
if not results:
|
||||
print("❌ Niciun mesaj găsit!")
|
||||
print("\nAsigură-te că:")
|
||||
print("• Ai trimis /start către bot SAU în grup")
|
||||
print("• Bot-ul este adăugat în grup (dacă folosești grup)")
|
||||
print("• Token-ul este corect")
|
||||
print("\nNU S-AU GĂSIT MESAJE!")
|
||||
print("\n" + "=" * 60)
|
||||
print("INSTRUCȚIUNI:")
|
||||
print("=" * 60)
|
||||
print("1. Deschide Telegram")
|
||||
print(f"2. Caută @{bot.get('username')} SAU deschide grupul cu bot-ul")
|
||||
print("3. Trimite un mesaj (ex: /start sau /info)")
|
||||
print("4. Rulează din nou acest script")
|
||||
print("=" * 60)
|
||||
return
|
||||
|
||||
print(f"\n✅ Găsit {len(results)} mesaje!\n")
|
||||
print(f"\nGăsit {len(results)} mesaje în total")
|
||||
|
||||
# Procesează ultimele mesaje (ultimele 20)
|
||||
seen_chats = {}
|
||||
user_ids = set()
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("CHAT IDs DETECTATE:")
|
||||
print("=" * 60)
|
||||
|
||||
# Procesează ultimele mesaje
|
||||
seen_chats = {}
|
||||
|
||||
for update in results:
|
||||
for update in results[-20:]: # Ultimele 20 mesaje
|
||||
if 'message' in update:
|
||||
msg = update['message']
|
||||
chat = msg['chat']
|
||||
chat_id = chat['id']
|
||||
chat_type = chat['type']
|
||||
user = msg['from']
|
||||
user_ids.add(user['id'])
|
||||
text = msg.get('text', '(no text)')
|
||||
|
||||
# Evită duplicate
|
||||
if chat_id in seen_chats:
|
||||
continue
|
||||
|
||||
seen_chats[chat_id] = True
|
||||
seen_chats[chat_id] = chat
|
||||
|
||||
# Detalii chat
|
||||
if chat_type == 'private':
|
||||
# DM
|
||||
user = msg['from']
|
||||
print(f"📱 DM cu {user.get('first_name', 'Unknown')}")
|
||||
print(f" User ID: {user['id']}")
|
||||
print(f" Username: @{user.get('username', 'N/A')}")
|
||||
print(f" Chat ID: {chat_id}")
|
||||
print(f"\n[DM] {user.get('first_name', '')} {user.get('last_name', '')}")
|
||||
print(f" Username: @{user.get('username', 'N/A')}")
|
||||
print(f" User ID: {user['id']}")
|
||||
print(f" Chat ID: {chat_id}")
|
||||
elif chat_type in ['group', 'supergroup']:
|
||||
# Grup
|
||||
print(f"👥 Grup: {chat.get('title', 'Unknown')}")
|
||||
print(f" Chat ID: {chat_id} ⚠️ NEGATIV pentru grupuri!")
|
||||
print(f" Tip: {chat_type}")
|
||||
# User care a trimis mesajul
|
||||
user = msg['from']
|
||||
print(f" Mesaj de la: @{user.get('username', 'Unknown')} (ID: {user['id']})")
|
||||
print(f"\n[GRUP] {chat.get('title', 'Unknown')}")
|
||||
print(f" Chat ID: {chat_id}")
|
||||
print(f" Tip: {chat_type}")
|
||||
print(f" User: @{user.get('username', 'Unknown')} (ID: {user['id']})")
|
||||
|
||||
print()
|
||||
print(f" Mesaj: \"{text[:60]}\"")
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("CONFIGURARE .env:")
|
||||
print("=" * 60)
|
||||
print("\n💡 Pentru configurare .env:")
|
||||
print()
|
||||
|
||||
# Recomandări
|
||||
for chat_id, chat_data in seen_chats.items():
|
||||
for chat_id, chat in seen_chats.items():
|
||||
if chat_id < 0: # Grup
|
||||
print(f"# Pentru grup (notificări + comenzi):")
|
||||
print(f"\n# Grup: {chat.get('title', 'Unknown')}")
|
||||
print(f"TELEGRAM_CHAT_ID={chat_id}")
|
||||
else: # DM
|
||||
print(f"# Pentru DM:")
|
||||
print(f"\n# DM")
|
||||
print(f"TELEGRAM_CHAT_ID={chat_id}")
|
||||
|
||||
print()
|
||||
print("# User IDs autorizați (pot rula /scrape):")
|
||||
print("TELEGRAM_ALLOWED_USER_IDS=", end="")
|
||||
if user_ids:
|
||||
user_ids_str = ",".join(str(uid) for uid in sorted(user_ids))
|
||||
print(f"\n# User IDs autorizați")
|
||||
print(f"TELEGRAM_ALLOWED_USER_IDS={user_ids_str}")
|
||||
|
||||
# Colectează user IDs unice
|
||||
user_ids = set()
|
||||
for update in results:
|
||||
if 'message' in update:
|
||||
user_id = update['message']['from']['id']
|
||||
user_ids.add(user_id)
|
||||
|
||||
print(",".join(str(uid) for uid in sorted(user_ids)))
|
||||
print()
|
||||
print("=" * 60)
|
||||
print("\n" + "=" * 60)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -9,6 +9,7 @@ import io
|
||||
import subprocess
|
||||
import logging
|
||||
import json
|
||||
import csv
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
@@ -65,6 +66,8 @@ class TelegramTriggerBot:
|
||||
commands = [
|
||||
{"command": "scrape", "description": "Rulează scraper-ul BTGO"},
|
||||
{"command": "scrape_zip", "description": "Rulează scraper + trimite ZIP"},
|
||||
{"command": "scrape_solduri", "description": "Extrage doar soldurile (fără CSV)"},
|
||||
{"command": "solduri", "description": "Afișează ultimul fișier solduri"},
|
||||
{"command": "zip", "description": "Trimite ultimele fișiere ca ZIP"},
|
||||
{"command": "status", "description": "Status sistem"},
|
||||
{"command": "help", "description": "Ajutor comenzi"}
|
||||
@@ -108,11 +111,12 @@ class TelegramTriggerBot:
|
||||
return True
|
||||
return user_id in self.allowed_users
|
||||
|
||||
def run_scraper(self, chat_id, reply_to_message_id=None, send_as_zip=False):
|
||||
def run_scraper(self, chat_id, reply_to_message_id=None, send_as_zip=False, balances_only=False):
|
||||
"""Execută scraper-ul"""
|
||||
# Trimite mesaj inițial și salvează message_id pentru editare ulterioară
|
||||
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)
|
||||
balances_msg = " - DOAR SOLDURI" if balances_only else ""
|
||||
response = self.send_message(chat_id, f"*BTGO Scraper pornit{zip_msg}{balances_msg}*\n\nAsteapta 2FA pe telefon.", reply_to_message_id)
|
||||
message_id = None
|
||||
try:
|
||||
message_id = response.json()['result']['message_id']
|
||||
@@ -122,7 +126,7 @@ class TelegramTriggerBot:
|
||||
|
||||
try:
|
||||
# Rulează scraper-ul
|
||||
logging.info(f"Pornire scraper (send_as_zip={send_as_zip})...")
|
||||
logging.info(f"Pornire scraper (send_as_zip={send_as_zip}, balances_only={balances_only})...")
|
||||
|
||||
# Prepare environment with global playwright path + Telegram progress info
|
||||
env = os.environ.copy()
|
||||
@@ -138,6 +142,11 @@ class TelegramTriggerBot:
|
||||
if send_as_zip:
|
||||
env['SEND_AS_ZIP'] = 'true'
|
||||
logging.info("Mod ZIP activat - va trimite arhivă ZIP")
|
||||
|
||||
# Dacă balances_only, comunică să nu descarce tranzacții
|
||||
if balances_only:
|
||||
env['BALANCES_ONLY'] = 'true'
|
||||
logging.info("Mod DOAR SOLDURI activat - nu va descărca tranzacții")
|
||||
else:
|
||||
logging.warning("No message_id available for progress updates")
|
||||
|
||||
@@ -172,6 +181,59 @@ 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 show_cached_balances(self, chat_id, reply_to_message_id=None):
|
||||
"""Afișează soldurile din cel mai recent fișier solduri.csv"""
|
||||
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
|
||||
file_datetime = datetime.fromtimestamp(solduri_time).strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
# Citește fișierul CSV
|
||||
accounts = []
|
||||
with open(latest_solduri, 'r', encoding='utf-8') as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
accounts.append({
|
||||
'nume_cont': row['nume_cont'],
|
||||
'sold': float(row['sold']),
|
||||
'moneda': row['moneda']
|
||||
})
|
||||
|
||||
# Construiește mesaj cu solduri
|
||||
total_ron = sum(acc['sold'] for acc in accounts if acc.get('moneda') == 'RON')
|
||||
|
||||
message = f"*SOLDURI BANCARE*\n\n"
|
||||
message += f"Data: {file_datetime}\n"
|
||||
message += f"Conturi: {len(accounts)}\n\n"
|
||||
|
||||
for acc in accounts:
|
||||
nume = acc['nume_cont']
|
||||
sold = acc['sold']
|
||||
moneda = acc['moneda']
|
||||
message += f" • {nume}: {sold:,.2f} {moneda}\n"
|
||||
|
||||
message += f"\n*TOTAL: {total_ron:,.2f} RON*"
|
||||
|
||||
self.send_message(chat_id, message, reply_to_message_id)
|
||||
logging.info(f"Afișat solduri cached din {latest_solduri.name}")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Eroare show_cached_balances: {e}", exc_info=True)
|
||||
self.send_message(chat_id, f"*EROARE*\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:
|
||||
@@ -332,8 +394,10 @@ class TelegramTriggerBot:
|
||||
welcome_msg += f"Bot activ in grupul *{chat_title}*\n\n"
|
||||
welcome_msg += (
|
||||
"Comenzi disponibile:\n"
|
||||
"`/scrape` - Ruleaza scraper-ul\n"
|
||||
"`/scrape` - Ruleaza scraper-ul complet\n"
|
||||
"`/scrape_zip` - Ruleaza scraper + trimite ZIP\n"
|
||||
"`/scrape_solduri` - Extrage doar soldurile (rapid)\n"
|
||||
"`/solduri` - Afiseaza ultimul fisier solduri\n"
|
||||
"`/zip` - Trimite ultimele fisiere ca ZIP\n"
|
||||
"`/status` - Status sistem\n"
|
||||
"`/help` - Ajutor"
|
||||
@@ -348,6 +412,14 @@ class TelegramTriggerBot:
|
||||
logging.info(f"Comandă /scrape_zip primită în {context}")
|
||||
self.run_scraper(chat_id, message_id, send_as_zip=True)
|
||||
|
||||
elif text == '/scrape_solduri':
|
||||
logging.info(f"Comandă /scrape_solduri primită în {context}")
|
||||
self.run_scraper(chat_id, message_id, balances_only=True)
|
||||
|
||||
elif text == '/solduri':
|
||||
logging.info(f"Comandă /solduri primită în {context}")
|
||||
self.show_cached_balances(chat_id, message_id)
|
||||
|
||||
elif text == '/zip':
|
||||
logging.info(f"Comandă /zip primită în {context}")
|
||||
self.send_zip_files(chat_id, message_id)
|
||||
@@ -381,20 +453,25 @@ class TelegramTriggerBot:
|
||||
"*COMENZI:*\n"
|
||||
"`/scrape` - Ruleaza scraper + trimite fisiere individuale\n"
|
||||
"`/scrape_zip` - Ruleaza scraper + trimite arhiva ZIP\n"
|
||||
"`/scrape_solduri` - Extrage doar soldurile (fara CSV tranzactii)\n"
|
||||
"`/solduri` - Afiseaza ultimul fisier solduri (instant)\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"
|
||||
"1. Trimite `/scrape`, `/scrape_zip` sau `/scrape_solduri`\n"
|
||||
"2. Asteapta notificarea de 2FA pe telefon\n"
|
||||
"3. Aproba in aplicatia George\n"
|
||||
"4. Primesti fisierele automat\n\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"
|
||||
"• `/scrape_solduri` - Doar solduri (RAPID - fara CSV tranzactii)\n"
|
||||
"• `/solduri` - Vizualizare rapida (fara 2FA)\n"
|
||||
"• `/zip` - Fisiere existente (fara scraping)\n\n"
|
||||
"*NOTE:*\n"
|
||||
"- Scraper-ul ruleaza ~2-3 minute\n"
|
||||
"- Scraper complet: ~2-3 minute\n"
|
||||
"- Scraper solduri: ~30-40 secunde\n"
|
||||
"- VM-ul trebuie sa aiba browser vizibil"
|
||||
)
|
||||
self.send_message(chat_id, help_msg, message_id)
|
||||
|
||||
Reference in New Issue
Block a user