import json import os from dataclasses import dataclass from pathlib import Path from typing import Optional, Tuple BASE_URL = "https://www.adultdvdmarketplace.com/xcart" HOME_URL = f"{BASE_URL}/" LOGIN_URL = f"{BASE_URL}/home.php?area=G" DISCLAIMER_URL = "https://www.adultdvdmarketplace.com/xcart/adult_dvd/disclaimer.php" DEFAULT_CREDENTIALS_FILE = ".browser_state/credentials.json" def load_credentials(credentials_file: str = DEFAULT_CREDENTIALS_FILE) -> Tuple[Optional[str], Optional[str], str]: username = os.getenv("ADULTDVD_USERNAME") password = os.getenv("ADULTDVD_PASSWORD") if username and password: return username, password, "env" path = Path(credentials_file) if not path.exists(): return None, None, "missing" try: data = json.loads(path.read_text(encoding="utf-8")) except Exception: return None, None, "invalid-file" username = (data.get("username") or "").strip() password = data.get("password") or "" if username and password: return username, password, "credentials-file" return None, None, "invalid-file" def save_credentials(username: str, password: str, credentials_file: str = DEFAULT_CREDENTIALS_FILE) -> None: path = Path(credentials_file) path.parent.mkdir(parents=True, exist_ok=True) payload = {"username": username, "password": password} path.write_text(json.dumps(payload, indent=2), encoding="utf-8") @dataclass class BotConfig: username: str password: str studio_url: str min_price: float output_format: str = "csv" # csv | excel | both output_file: Optional[str] = None headless: bool = False max_items: Optional[int] = None timeout: int = 30000 # ms retry_count: int = 3 state_dir: str = ".browser_state" def get_studio_url_with_sort(self) -> str: url = self.studio_url if "order_by=" not in url: sep = "&" if "?" in url else "?" url = f"{url}{sep}order_by=price" return url