Local HOTS news crawler plus Discord bot for browsing cached articles.
- Fetches HOTS news metadata + article pages from Blizzard.
- Stores local index + full article JSON.
- Supports incremental updates with date-range filtering.
- Imports HeroesProfile general API data into local cache files.
- Exposes Discord slash commands for local news browsing:
/latest/news year:<optional>/hero name:<optional>/map name:<optional>/patch version:<optional>/talentbuilder hero:<optional> talent_string:<optional>
- Runs a daily non-blocking update loop inside the bot process.
news/index.json: lightweight index, sorted bytimestamp(newest first).news/articles/YYYY/MM/DD/{news_id}.json: full per-article record includingbody_html.heroesprofile/patches/index.json: cached HeroesProfile patch families + builds.heroesprofile/maps/index.json: cached HeroesProfile maps.heroesprofile/heroes/index.json: cached hero summaries.heroesprofile/heroes/by_name/{slug}.json: full hero records.heroesprofile/talents/by_hero/{slug}.json: cached talents grouped by tier for each hero.
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtpython news/update_news.pyThis fetches feed + articles, writes updated files, and prints update stats:
newupdatedunchangedfailed
Common options:
python news/update_news.py --months 3
python news/update_news.py --from 2025-01-01 --to 2025-12-31python heroesprofile/update_data.pyCommon options:
python heroesprofile/update_data.py --only heroes,talents
python heroesprofile/update_data.py --workers 4 --verboseCreate .env from .env.example, then fill in the values you need:
cp .env.example .envFor local env mode:
BOT_CONFIG_SOURCE=env
BOT_TOKEN=your_discord_bot_token
GUILD_ID=123456789012345678
NEWS_CHANNEL_ID=123456789012345678
DAILY_UPDATE_CRON="0 15 * * *"Start bot:
python bot/run.pyManual cache update:
./scripts/update_cache.sh
./scripts/update_cache.sh news --months 3
./scripts/update_cache.sh heroes --only heroes,talentsRun all tests:
./scripts/run_tests.shDebian supports systemd directly, so a user service is a good way to keep the bot running and restart it automatically.
Setup notes and an example unit file are documented separately in:
plans/discord/systemd-service-setup.md
For GCP Secret Manager-backed config, keep only the source selector and project id in the environment:
BOT_CONFIG_SOURCE=gcp
GCP_PROJECT_ID=your-gcp-project-idExpected Secret Manager secret names:
BOT_TOKENGUILD_IDNEWS_CHANNEL_IDDAILY_UPDATE_CRON(optional, defaults to0 15 * * *)
This keeps Discord command/runtime reads local while moving bot credentials and schedule config out of .env. Authentication for Secret Manager uses standard Google Cloud application default credentials.
Optional bootstrap controls for service startup:
BOOTSTRAP_SYNC_ON_EMPTY=true
BOOTSTRAP_SYNC_FORCE=false
BOOTSTRAP_SYNC_SKIP=false
BOOTSTRAP_NEWS_MAX_AGE_HOURS=24By default, the systemd startup path runs a one-time cache bootstrap if news/index.json or heroesprofile/manifest.json is missing, or if the news index is older than 24 hours. Set BOOTSTRAP_NEWS_MAX_AGE_HOURS=0 to disable the stale-cache startup refresh.
If .venv is missing when scripts/start_bot.sh or scripts/update_cache.sh runs, the scripts create it with python3 and install requirements.txt before continuing.
Behavior:
/latestshows latest local article in a rich embed with Prev/Next buttons for article pages./newsshows paginated local list (5 per page), optionalyearfilter, and interactive article selection.- Selecting an article opens a rich embed with button-based page navigation.
/hero,/map, and/patchaccept an optional lookup value; when omitted, each command opens a cache-backed paginated list with a select menu for drilling into a local record./herodetail views show direct buttons forSummaryand each talent tier page./mapreads cached HeroesProfile map data./patchreads cached HeroesProfile patch-family data, including full build lookups./talentbuilderopens an ephemeral, cache-only builder for choosing a hero, selecting talents tier by tier, revising prior tiers, optionally naming the build, and exporting a HOTS talent string in a copy-friendly code block./talentbuildercan also parse an existing HOTS talent string such as[T3211221,Leoric], validate it against the local cache, and open a paginated per-tier breakdown.- Daily job runs on the configured UTC cron schedule, updates local cache, and posts update summary + newest article when changes exist.
- Command responses read from local files only (no fetch on user read request).
- Article body rendering maps HTML structure (headings/lists/quotes/code/links) to compact Discord markdown.
python -m pytest -q
./scripts/run_tests.sh- Discord-related implementation plans:
plans/discord/ - News crawler/updater plans:
plans/news/ - HeroesProfile API plans:
plans/heroesprofile/
- Uses
requests+beautifulsoup4for crawler parsing. - Uses
requestsfor HeroesProfile API syncing. - Uses
discord.pyfor slash commands and interaction components. - Discord message chunking uses a conservative
1900character limit.