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
Appclass sets up the primary interface, including realm selectors, item/pet configuration panels, and log viewers. - Thread management: Spawns
Item_And_Pet_Statisticsthreads to fetch price statistics from the Saddlebag Exchange API without blocking the main window. - Log redirection: Uses a custom
StreamToFileclass to capturestdoutandstderrto timestamped files underAzerothAuctionAssassinData/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
MegaDataclass loads and validates user-defined snipe lists from JSON files (desired_items.json,desired_pets.json,desired_ilvl_list.json). - Auction scanning: The
Alertsclass (aQThreadsubclass) orchestrates the continuous scanning loop, utilizingThreadPoolExecutorfor parallel realm processing. - Alert formatting: Converts matching auctions into Discord embed payloads via
create_embedfunctions.
Infrastructure Layer
Low-level API interactions and data utilities are encapsulated in utils/:
- API communication:
utils/api_requests.pyandMegaDatamethods likemake_ah_api_requesthandle Blizzard OAuth token management (cached viaaccess_token_creation_unix_time) and HTTP requests with Tenacity retry logic. - Static data:
utils/realm_data.pyprovides realm ID mappings, whileutils/ilvl_resolver.pyresolves bonus ID sets for item level calculations. - Helper utilities:
utils/helpers.pycontains 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_urlmethod builds appropriate endpoints (us.api.blizzard.comvseu.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_MINandSCAN_TIME_MAXto check realms only during their upload windows. - Parallel processing: Uses
ThreadPoolExecutorwithmega_data.THREADSworkers to concurrent fetch auction data across multiple realms. - Graceful shutdown: Responds to
self.running = False(set by the UI's Stop Alerts button orCtrl-Cin 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
QThreadandThreadPoolExecutorto 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
MegaDataclass. - 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →