# LZT Market Sniper — C++ rewrite A from-scratch C++ port of the original single-file `app.py` (Flask + Selenium + a mobile web dashboard). This version is a native background service with no browser/webpage at all — you control it entirely from Discord with slash commands. ## What changed vs. the Python version | Python (`app.py`) | C++ rewrite | |---|---| | Flask web server + mobile HTML/CSS/JS dashboard | Gone. Control is via Discord slash commands instead. | | Selenium driving a real (headless) Chrome profile | `libcurl` HTTP GET of the search page's raw HTML (no JS execution — see **Scraping caveat** below). | | Discord **webhook** only | Bot posts through its own REST API (`/channels/{id}/messages`) using the bot token; a legacy webhook URL is still supported as a fallback. | | In-memory `state` dict, SSE stream to browser | Thread-safe `SniperState`, no streaming needed since Discord is the UI. | | One 1185-line file | Split into `Config`, `State`, `Logger`, `HttpClient`, `Scraper`, `DiscordNotifier`, `SniperEngine`, `DiscordBot`, `main`. | ## Layout ``` include/ headers (one per component) Config.hpp JSON config load/save (bot token, links, filters, interval) State.hpp thread-safe shared state (running flag, last offers, history) Logger.hpp timestamped console logger HttpClient.hpp libcurl GET/POST wrapper Scraper.hpp page fetch + offer-card text extraction + price/keyword filter DiscordNotifier.hpp builds/sends the stock-update embed SniperEngine.hpp the watch loop + all mutating operations (start/stop/add/remove/pause/scan) DiscordBot.hpp D++ slash-command bot wired into SniperEngine src/ same files, implementations CMakeLists.txt config.example.json ``` ## Building Dependencies: a C++17 compiler, CMake, `libcurl`, `nlohmann-json`, and [D++](https://dpp.dev/) (the Discord library). ```bash # Debian/Ubuntu sudo apt install build-essential cmake libcurl4-openssl-dev nlohmann-json3-dev mkdir build && cd build cmake .. make -j$(nproc) ``` CMake first looks for an installed D++ (`find_package(DPP)`); if it's not found it downloads and builds D++ v10.0.35 from source automatically via `FetchContent` the first time you configure (this takes a few minutes — D++ is a fairly large library). If you'd rather build D++ once and reuse it, follow the install instructions at https://dpp.dev/installing.html and CMake will pick up the installed copy instead. ## Configuring ```bash cp config.example.json config.json ``` Fill in: - `discord_bot_token` — from the Discord Developer Portal, with the `applications.commands` and `bot` scopes and the "Send Messages" permission. - `discord_channel_id` — the channel the bot should post stock-change alerts to. - `command_guild_id` *(optional)* — set this to your server's ID while testing so slash commands sync instantly; leave blank for global commands (Discord can take up to an hour to propagate those). - `links` — your initial watch list (you can also manage this entirely from Discord with `/addlink`, `/removelink`, `/pause` once the bot is running). Run it: ```bash ./build/lzt_sniper config.json ``` ## Discord commands - `/start` — begin watching all configured links - `/stop` — stop watching - `/status` — running state, total scans/changes, current stock per link - `/links` — list watched links with pause state and filters - `/addlink url [label] [min_price] [max_price] [keywords]` - `/removelink url` - `/pause url` — toggle pause on one link - `/scan url` — force an immediate one-off scan - `/interval seconds` — change the polling interval - `/history` — last 15 scan results ## Scraping caveat The Python version drove a real headless Chrome browser through a logged-in profile, so it saw the fully JS-rendered, authenticated page. This C++ version fetches the raw page HTML over HTTP instead — no JavaScript is executed. LZT Market's search results are server-rendered, so public listings work fine; if a page ever needs an authenticated session, copy your browser's `Cookie:` header value into `cookie_header` in `config.json`. The offer-card extraction (`Scraper::extractOfferBlocks`) is a heuristic text parser tuned to reproduce the original's "any div/li/article whose text mentions 'followers'" logic — inspect it and adjust the tag/keyword filters in `src/Scraper.cpp` if LZT Market's markup changes.