first commit
This commit is contained in:
commit
7349b743e3
21 files changed
+1527
No files matched your search
@@ -0,0 +1,102 @@
|
||||
# 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.
|
||||
Reference in new issue
Block a user