4.4 KiB
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++ (the Discord library).
# 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
cp config.example.json config.json
Fill in:
discord_bot_token— from the Discord Developer Portal, with theapplications.commandsandbotscopes 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,/pauseonce the bot is running).
Run it:
./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.