#!/usr/bin/env python3 import requests import json import hashlib import logging 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) DEBUG_LEVEL = logging.DEBUG logging.basicConfig( level=DEBUG_LEVEL, format="%(asctime)s [%(levelname)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S" ) logger = logging.getLogger(__name__) # Basis-Klasse für SQLAlchemy-Modelle (SQLAlchemy 2.0-konform) Base = declarative_base() # Tabelle für das Bundle (statische Identifikation) class Bundle(Base): __tablename__ = 'bundles' id = Column(Integer, primary_key=True) machine_name = Column(String, unique=True) human_name = Column(String) # current_version_id verweist auf die aktuelle Version in bundle_versions current_version_id = Column(Integer, ForeignKey('bundle_versions.id')) # 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) # Alle Versionen (historisch) versions = relationship("BundleVersion", back_populates="bundle", foreign_keys=lambda: [BundleVersion.bundle_id]) # Verkaufshistorie sales_history = relationship("BundleSalesHistory", back_populates="bundle") # Tabelle für Versionen eines Bundles class BundleVersion(Base): __tablename__ = 'bundle_versions' 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 timestamp = Column(DateTime, default=datetime.utcnow) # Eindeutige Beziehung: wir verwenden hier explizit bundle_id bundle = relationship("Bundle", back_populates="versions", foreign_keys=[bundle_id]) # Tabelle für Verkaufshistorie class BundleSalesHistory(Base): __tablename__ = 'bundle_sales_history' id = Column(Integer, primary_key=True) bundle_id = Column(Integer, ForeignKey('bundles.id')) bundles_sold = Column(Float) timestamp = Column(DateTime, default=datetime.utcnow) bundle = relationship("Bundle", back_populates="sales_history") def calculate_hash(data: dict) -> str: """Berechnet einen SHA-256 Hash aus dem sortierten JSON-String der relevanten 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 fetch_bundle_data(url: str) -> dict: """Lädt die Detailseite eines Bundles und extrahiert den JSON-Inhalt aus dem