#!/usr/bin/env python3 """ ANAF Monitor v2 - Extrage și compară versiuni soft A/J din numele fișierelor """ import json import re import urllib.request import ssl from datetime import datetime from pathlib import Path SCRIPT_DIR = Path(__file__).parent CONFIG_FILE = SCRIPT_DIR / "config.json" VERSIONS_FILE = SCRIPT_DIR / "versions.json" LOG_FILE = SCRIPT_DIR / "monitor.log" DASHBOARD_STATUS = SCRIPT_DIR.parent.parent / "dashboard" / "status.json" SSL_CTX = ssl.create_default_context() SSL_CTX.check_hostname = False SSL_CTX.verify_mode = ssl.CERT_NONE def log(msg): timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") with open(LOG_FILE, "a") as f: f.write(f"[{timestamp}] {msg}\n") def load_json(path, default=None): try: with open(path) as f: return json.load(f) except: return default if default is not None else {} def save_json(path, data): with open(path, "w") as f: json.dump(data, f, indent=2, ensure_ascii=False) def fetch_page(url, timeout=30): try: req = urllib.request.Request(url, headers={ 'User-Agent': 'Mozilla/5.0 (compatible; ANAF-Monitor/2.0)' }) with urllib.request.urlopen(req, timeout=timeout, context=SSL_CTX) as resp: return resp.read().decode('utf-8', errors='ignore') except Exception as e: log(f"ERROR fetching {url}: {e}") return None def parse_date_from_filename(filename): """Extrage data din numele fișierului (ex: D394_26092025.pdf -> 26.09.2025)""" # Pattern: _DDMMYYYY. sau _DDMMYYYY_ sau _YYYYMMDD match = re.search(r'_(\d{8})[\._]', filename) if match: d = match.group(1) # Verifică dacă e DDMMYYYY sau YYYYMMDD if int(d[:2]) <= 31 and int(d[2:4]) <= 12: return f"{d[:2]}.{d[2:4]}.{d[4:]}" elif int(d[4:6]) <= 12 and int(d[6:]) <= 31: return f"{d[6:]}.{d[4:6]}.{d[:4]}" # Pattern: _DDMMYY match = re.search(r'_(\d{6})[\._]', filename) if match: d = match.group(1) if int(d[:2]) <= 31 and int(d[2:4]) <= 12: return f"{d[:2]}.{d[2:4]}.20{d[4:]}" return None def extract_versions(html): """Extrage primul soft A și soft J din HTML""" versions = {} # Găsește primul link soft A (PDF) soft_a_match = re.search( r']+href=["\']([^"\']*\.pdf)["\'][^>]*>\s*soft\s*A\s*', html, re.IGNORECASE ) if soft_a_match: url = soft_a_match.group(1) versions['soft_a_url'] = url date = parse_date_from_filename(url) if date: versions['soft_a_date'] = date # Găsește primul link soft J (ZIP) soft_j_match = re.search( r']+href=["\']([^"\']*\.zip)["\'][^>]*>\s*soft\s*J', html, re.IGNORECASE ) if soft_j_match: url = soft_j_match.group(1) versions['soft_j_url'] = url date = parse_date_from_filename(url) if date: versions['soft_j_date'] = date # Găsește data publicării din text publish_match = re.search( r'publicat\s+[îi]n\s*(?:data\s+de\s*)?(\d{2}[./]\d{2}[./]\d{4})', html, re.IGNORECASE ) if publish_match: versions['published'] = publish_match.group(1).replace('/', '.') return versions def format_date(d): """Formatează data pentru afișare""" if not d: return "N/A" return d def compare_versions(old, new, page_name): """Compară versiunile și returnează diferențele""" changes = [] fields = [ ('soft_a_date', 'Soft A'), ('soft_j_date', 'Soft J'), ('published', 'Publicat') ] for field, label in fields: old_val = old.get(field) new_val = new.get(field) if new_val and old_val != new_val: if old_val: changes.append(f"{label}: {old_val} → {new_val}") else: changes.append(f"{label}: {new_val} (nou)") return changes def check_page(page, saved_versions): """Verifică o pagină și returnează modificările""" page_id = page["id"] name = page["name"] url = page["url"] html = fetch_page(url) if html is None: return None new_versions = extract_versions(html) old_versions = saved_versions.get(page_id, {}) # Prima rulare - doar salvează, nu raportează if not old_versions: log(f"INIT: {page_id} - {new_versions}") saved_versions[page_id] = new_versions return None changes = compare_versions(old_versions, new_versions, name) saved_versions[page_id] = new_versions if changes: log(f"CHANGES in {page_id}: {changes}") return { "id": page_id, "name": name, "url": url, "changes": changes, "current": { "soft_a": new_versions.get('soft_a_date', 'N/A'), "soft_j": new_versions.get('soft_j_date', 'N/A') } } else: log(f"OK: {page_id}") return None def update_dashboard_status(has_changes, changes_count): """Actualizează status.json pentru dashboard""" try: status = load_json(DASHBOARD_STATUS, {}) status['anaf'] = { 'ok': not has_changes, 'status': 'MODIFICĂRI' if has_changes else 'OK', 'message': f'{changes_count} modificări detectate' if has_changes else 'Nicio modificare detectată', 'lastCheck': datetime.now().strftime('%d %b %Y, %H:%M'), 'changesCount': changes_count } save_json(DASHBOARD_STATUS, status) except Exception as e: log(f"ERROR updating dashboard status: {e}") def main(): log("=== Starting ANAF monitor v2 ===") config = load_json(CONFIG_FILE, {"pages": []}) saved_versions = load_json(VERSIONS_FILE, {}) all_changes = [] for page in config["pages"]: result = check_page(page, saved_versions) if result: all_changes.append(result) save_json(VERSIONS_FILE, saved_versions) # Update dashboard status update_dashboard_status(len(all_changes) > 0, len(all_changes)) log("=== Monitor complete ===") print(json.dumps({"changes": all_changes}, ensure_ascii=False, indent=2)) return len(all_changes) if __name__ == "__main__": exit(main())