Azeroth Auction Assassin Architecture: A Deep Dive into the WoW Auction House Scanner

Azeroth Auction Assassin is a Qt-based desktop application that uses a multi-threaded Python backend to scan World of Warcraft Auction House data against JSON configuration files and dispatch Discord alerts.

The ff14-advanced-market-search/azerothauctionassassin repository implements a modular, three-layer architecture designed for real-time auction monitoring. The codebase separates presentation concerns from business logic and infrastructure, enabling both GUI-driven and headless operation modes while maintaining responsive performance through Python's threading capabilities.

Three-Layer Architecture

The application follows a clean separation of concerns across presentation, business logic, and infrastructure layers.

Presentation Layer (Qt GUI)

The user interface resides primarily in AzerothAuctionAssassin.py, which implements a Qt5 desktop application. This layer handles:

  • Main window initialization: The App class sets up the primary interface, including realm selectors, item/pet configuration panels, and log viewers.
  • Thread management: Spawns Item_And_Pet_Statistics threads to fetch price statistics from the Saddlebag Exchange API without blocking the main window.
  • Log redirection: Uses a custom StreamToFile class to capture stdout and stderr to timestamped files under AzerothAuctionAssassinData/logs/.

An optional Electron front-end exists in the node-ui/ directory, providing an alternative web-based interface that communicates with the same Python backend via IPC.

Business Logic Layer

The scanning engine lives in mega_alerts.py and utils/mega_data_setup.py. This layer manages:

  • Configuration parsing: The MegaData class loads and validates user-defined snipe lists from JSON files (desired_items.json, desired_pets.json, desired_ilvl_list.json).
  • Auction scanning: The Alerts class (a QThread subclass) orchestrates the continuous scanning loop, utilizing ThreadPoolExecutor for parallel realm processing.
  • Alert formatting: Converts matching auctions into Discord embed payloads via create_embed functions.

Infrastructure Layer

Low-level API interactions and data utilities are encapsulated in utils/:

  • API communication: utils/api_requests.py and MegaData methods like make_ah_api_request handle Blizzard OAuth token management (cached via access_token_creation_unix_time) and HTTP requests with Tenacity retry logic.
  • Static data: utils/realm_data.py provides realm ID mappings, while utils/ilvl_resolver.py resolves bonus ID sets for item level calculations.
  • Helper utilities: utils/helpers.py contains logging utilities, link generators, and Russian-realm specific handling.

Data Flow Through the Application

The scanning pipeline follows a precise four-stage lifecycle:

1. Application Startup

When python AzerothAuctionAssassin.py executes, the App.__init__ method initializes the environment:

log_path = os.path.join(os.getcwd(), "AzerothAuctionAssassinData", "logs")
log_file = os.path.join(
    log_path, f"aaa_log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
)
self.stream_handler = StreamToFile(log_file)

The system then loads static configuration and spawns background threads for statistics gathering.

2. Configuration Loading

The MegaData class in utils/mega_data_setup.py parses user configuration during initialization:

raw_mega_data = json.load(open("AzerothAuctionAssassinData/mega_data.json"))
self.DESIRED_ITEMS = self.__set_desired_items("desired_items", path_to_desired_items)
self.DESIRED_PETS = self.__set_desired_items("desired_pets", path_to_desired_pets)
self.DESIRED_ILVL_LIST = self.__set_desired_ilvl_list(path_to_desired_ilvl_list)

Environment variables like MEGA_WEBHOOK_URL and WOW_CLIENT_ID are resolved through __set_mega_vars, and OAuth tokens are validated via check_access_token.

3. Scanning Execution

When the user clicks Start Alerts (or invokes Alerts.run() programmatically), the scanning loop begins:

while self.running:
    current_min = int(datetime.now().minute)
    
    matching_realms = [
        realm["dataSetID"]
        for realm in mega_data.get_upload_time_list()
        if is_in_scan_window(
            current_min,
            realm["lastUploadMinute"],
            mega_data.SCAN_TIME_MIN,
            mega_data.SCAN_TIME_MAX,
        )
    ]
    
    pool = ThreadPoolExecutor(max_workers=mega_data.THREADS)
    for connected_id in matching_realms:
        pool.submit(pull_single_realm_data, connected_id)
    pool.shutdown(wait=True)

The pull_single_realm_data function calls MegaData.get_listings_single to fetch auction snapshots, then passes results through the filtering pipeline.

4. Filtering and Alert Dispatch

Raw auction data undergoes multi-stage filtering in mega_alerts.py:

if "itemID" in auction:
    if auction["itemID"] in mega_data.DESIRED_ITEMS:
        # Price checks and optional ilvl/bonus verification

        pass
else:
    if auction["petID"] in mega_data.DESIRED_PETS:
        # Pet level and breed validation

        pass

Advanced item filtering occurs in check_tertiary_stats_generic, which validates bonus IDs against RaidBots data. When USE_POST_MIDNIGHT_ILVL is enabled, the system calls utils.ilvl_resolver.resolve_post_midnight_ilvl for accurate item level calculations.

Matches are formatted as Discord embeds and dispatched to the webhook URL stored in MEGA_WEBHOOK_URL.

Core Components Deep Dive

UI Initialization (AzerothAuctionAssassin.py)

The main entry point creates the Qt application context and sets up the logging infrastructure. It instantiates the Item_And_Pet_Statistics thread to pre-load market data before the user begins scanning.

Configuration Management (MegaData)

Located in utils/mega_data_setup.py, this class serves as the central configuration hub. It handles:

  • Region-aware API construction: The construct_api_url method builds appropriate endpoints (us.api.blizzard.com vs eu.api.blizzard.com) and adapts to Classic/SoD namespaces.
  • Bonus ID resolution: Fetches socket, leech, avoidance, and speed bonus sets from RaidBots via get_bonus_id_sets.
  • Token refresh: Automatically renews Blizzard OAuth tokens every ~20 hours using check_access_token.

Scanning Engine (Alerts Thread)

The Alerts class in mega_alerts.py extends QThread to run independently of the UI. It manages:

  • Time-window scanning: Respects SCAN_TIME_MIN and SCAN_TIME_MAX to check realms only during their upload windows.
  • Parallel processing: Uses ThreadPoolExecutor with mega_data.THREADS workers to concurrent fetch auction data across multiple realms.
  • Graceful shutdown: Responds to self.running = False (set by the UI's Stop Alerts button or Ctrl-C in CLI mode).

Practical Usage Examples

Running the Desktop GUI


# Install dependencies (Python ≥3.8, Qt5)

pip install -r requirements.txt

# Launch the Qt interface

python AzerothAuctionAssassin.py

Headless CLI Scanning

from mega_alerts import Alerts

alerts = Alerts(
    path_to_data_files="AzerothAuctionAssassinData/mega_data.json",
    path_to_desired_items="AzerothAuctionAssassinData/desired_items.json",
    path_to_desired_pets="AzerothAuctionAssassinData/desired_pets.json",
    path_to_desired_ilvl_items="AzerothAuctionAssassinData/desired_ilvl.json",
    path_to_desired_ilvl_list="AzerothAuctionAssassinData/desired_ilvl_list.json",
)

alerts.run()  # Blocks until alerts.running = False

Programmatic Configuration Updates

import json
import pathlib

data_path = pathlib.Path("AzerothAuctionAssassinData/desired_items.json")
items = json.loads(data_path.read_text()) if data_path.exists() else {}

# Add Thunderfury (itemID 19019) with 10 gold target

items["19019"] = 10.0
data_path.write_text(json.dumps(items, indent=2))

Summary

  • Azeroth Auction Assassin implements a three-tier architecture separating Qt presentation, Python business logic, and API infrastructure concerns.
  • The scanning engine uses QThread and ThreadPoolExecutor to maintain UI responsiveness while concurrently polling multiple realm auction houses.
  • Configuration-as-JSON allows users to define snipe targets via editable files in AzerothAuctionAssassinData/ without modifying source code.
  • Blizzard API integration includes automatic OAuth token management and region-specific endpoint handling through the MegaData class.
  • Discord integration formats matching auctions as rich embeds and dispatches them via configurable webhooks.

Frequently Asked Questions

How does Azeroth Auction Assassin authenticate with the Blizzard API?

The application uses OAuth 2.0 client credentials flow. The MegaData class in utils/mega_data_setup.py caches access tokens with their creation timestamp (access_token_creation_unix_time) and automatically refreshes them via check_access_token after approximately 20 hours.

What threading model prevents the GUI from freezing during scans?

The UI runs on Qt's main thread while the scanning logic executes in a separate QThread subclass named Alerts (defined in mega_alerts.py). Inside this thread, a ThreadPoolExecutor parallelizes API calls across realms, allowing the interface to remain responsive during heavy network I/O.

How does the scanner determine which realms to check?

The system calls MegaData.get_upload_time_list() to retrieve each realm's last upload minute. It then compares this against the current time using is_in_scan_window, respecting the user's SCAN_TIME_MIN and SCAN_TIME_MAX settings to only scan realms that have recently received fresh auction data.

Can the application run without the Qt graphical interface?

Yes. While AzerothAuctionAssassin.py provides the primary Qt interface, the core Alerts class can be instantiated and executed programmatically. Additionally, an Electron-based UI exists in the node-ui/ directory for users preferring a web-based frontend.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →