diff --git a/bundle_checker.py b/bundle_checker.py index b4a493a..4b37dff 100644 --- a/bundle_checker.py +++ b/bundle_checker.py @@ -3,13 +3,14 @@ import requests import json import hashlib import logging +import difflib from datetime import datetime from bs4 import BeautifulSoup from sqlalchemy import create_engine, Column, Integer, String, Float, DateTime, ForeignKey, Text from sqlalchemy.orm import declarative_base, relationship, sessionmaker -# Konfiguriere Logging – passe das Level bei Bedarf an (DEBUG, INFO, WARNING, ERROR) +# Konfiguriere Logging – ändere das Level bei Bedarf (DEBUG, INFO, WARNING, ERROR) DEBUG_LEVEL = logging.DEBUG logging.basicConfig( level=DEBUG_LEVEL, @@ -18,7 +19,7 @@ logging.basicConfig( ) logger = logging.getLogger(__name__) -# Basis-Klasse für SQLAlchemy-Modelle (SQLAlchemy 2.0-konform) +# Basis-Klasse für SQLAlchemy-Modelle (2.0-konform) Base = declarative_base() # --------------------------- @@ -29,10 +30,10 @@ class Bundle(Base): __tablename__ = 'bundles' id = Column(Integer, primary_key=True) machine_name = Column(String, unique=True) - human_name = Column(String) # Falls vorhanden; kann leer bleiben, wenn nicht extrahiert + human_name = Column(String) # Kann leer bleiben, wenn nicht extrahiert current_version_id = Column(Integer, ForeignKey('bundle_versions.id')) - # Beziehung zur aktuellen Version; post_update=True hilft bei zirkulären Abhängigkeiten + # Beziehung zur aktuellen Version (post_update=True hilft bei zirkulären Abhängigkeiten) current_version = relationship("BundleVersion", uselist=False, foreign_keys=[current_version_id], post_update=True) @@ -41,7 +42,7 @@ class Bundle(Base): foreign_keys=lambda: [BundleVersion.bundle_id]) # Verkaufshistorie sales_history = relationship("BundleSalesHistory", back_populates="bundle") - # Einzelne Elemente des Bundles (z. B. die enthaltenen Bücher, Spiele etc.) + # Einzelne Elemente des Bundles (z. B. enthaltene Bücher, Spiele etc.) items = relationship("BundleItem", back_populates="bundle") class BundleVersion(Base): @@ -49,7 +50,7 @@ class BundleVersion(Base): id = Column(Integer, primary_key=True) bundle_id = Column(Integer, ForeignKey('bundles.id')) version_hash = Column(String) - version_data = Column(Text) # Relevante Bundle-Daten als JSON-String + version_data = Column(Text) # JSON-Daten als String timestamp = Column(DateTime, default=datetime.utcnow) # Explizite Angabe des Fremdschlüssels @@ -70,7 +71,7 @@ class BundleItem(Base): bundle_id = Column(Integer, ForeignKey('bundles.id')) title = Column(String) # Titel des Elements (z. B. Buch- oder Spielname) category = Column(String) # Kategorie, z. B. "book", "game" oder "software" - details = Column(Text) # Optional: ganze Detaildaten als JSON-String + details = Column(Text) # Optionale Detaildaten als JSON-String bundle = relationship("Bundle", back_populates="items") @@ -79,16 +80,27 @@ class BundleItem(Base): # --------------------------- def calculate_hash(data: dict) -> str: - """Berechnet einen SHA-256-Hash aus dem sortierten JSON-String der relevanten Daten.""" + """Berechnet einen SHA-256-Hash aus dem sortierten JSON-String der Daten.""" json_string = json.dumps(data, sort_keys=True, ensure_ascii=False) hash_value = hashlib.sha256(json_string.encode('utf-8')).hexdigest() logger.debug(f"Berechneter Hash: {hash_value}") return hash_value +def log_diff(old_data: dict, new_data: dict): + """ + Vergleicht zwei JSON-Daten (als dict) und gibt einen unified diff als String aus. + Nur im DEBUG-Level wird der detaillierte Vergleich ausgegeben. + """ + old_str = json.dumps(old_data, sort_keys=True, indent=4, ensure_ascii=False).splitlines() + new_str = json.dumps(new_data, sort_keys=True, indent=4, ensure_ascii=False).splitlines() + diff = difflib.unified_diff(old_str, new_str, fromfile="alte_version", tofile="neue_version", lineterm="") + diff_text = "\n".join(diff) + logger.debug("Unterschiede zwischen den Versionen:\n" + diff_text) + def fetch_bundle_data(url: str) -> dict: """ Lädt die Detailseite eines Bundles und extrahiert den JSON-Inhalt aus dem