214 lines
6.3 KiB
Python
214 lines
6.3 KiB
Python
#!/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'<a[^>]+href=["\']([^"\']*\.pdf)["\'][^>]*>\s*soft\s*A\s*</a>',
|
|
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'<a[^>]+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())
|