Since the ITAD API only sorts by discount or price (no time-based sort),
fetching the full 200-deal window per country ensures our client-side
filtering sees every available deal rather than just the top N by discount.
The dedup database already prevents reposting, so the extra data is cheap.
https://claude.ai/code/session_01EfPjktyrF24DBNHWsY1KBP
- ITAD deals can now be fetched from multiple countries simultaneously via
ITAD_COUNTRIES (e.g. US,CA,GB,DE). Deals are merged across regions and
deduplicated by game+shop, with the first country taking priority.
- Prices from non-USD regions are normalised to USD using exchange rates
so filtering (max price) works consistently across countries.
- ITAD results are now sorted by newest deals first (client-side by
timestamp) instead of only by highest discount, reducing missed deals.
- Default fetch limit raised from 20 to 100 to capture more deals.
- Display currency is now configurable: DEFAULT_CURRENCY sets the primary
currency shown first, EXTRA_CURRENCIES sets additional ones. All
Frankfurter-supported currencies are available with proper symbols.
- Filtering is now per-source with dedicated env vars:
CHEAPSHARK_MIN_DISCOUNT, CHEAPSHARK_MIN_RATING, CHEAPSHARK_MAX_PRICE,
ITAD_MIN_DISCOUNT, ITAD_MAX_PRICE, ITAD_DEALS_LIMIT. Shared fallbacks
(MIN_DISCOUNT_PERCENT, MAX_PRICE) are still supported. Legacy
MAX_PRICE_USD and MIN_DEAL_RATING continue to work as fallbacks.
https://claude.ai/code/session_01EfPjktyrF24DBNHWsY1KBP
Adds a background asyncio.Task that calls set_presence("online") every
60 seconds to keep the homeserver presence status fresh. On startup the
bot sets itself online and spawns the heartbeat; on shutdown the task is
cancelled and presence is set to offline before closing the client.
https://claude.ai/code/session_01Nu3N2okrfJV3meatEmYdrB
The markdown library's conversion collapsed blockquote lines into a
single paragraph, causing all deal info to render on one line in Matrix
clients. Build HTML directly with <br> tags for reliable line breaks.
Also adds html.escape() for proper escaping of titles and prices, and
removes the unused markdown dependency.
https://claude.ai/code/session_01B7YPGrE3NatkwadCXVjv2j
Users can now choose between CheapShark, ITAD, or both via the
DEAL_SOURCES env var (comma-separated, default: "cheapshark"). When
"itad" is included, the bot polls GET /deals/v2 for current deals with
discount/price filtering and posts them with the same formatting style.
ITAD deals include built-in historical low detection via the API's
deal flags. Preflight checks enforce ITAD_API_KEY when ITAD is a
configured deal source.
https://claude.ai/code/session_01B7YPGrE3NatkwadCXVjv2j
The ITAD v2 API requires POST (not GET) for /games/overview/v2, and
expects ITAD game UUIDs in the JSON body rather than Steam app IDs.
Added a lookup step via GET /games/lookup/v1 to convert Steam app IDs
to ITAD UUIDs before calling the overview endpoint. Updated preflight
check to use the lookup endpoint for API key validation.
https://claude.ai/code/session_01B7YPGrE3NatkwadCXVjv2j
On first startup, _populate_initial_state() was marking current Epic free
games as "posted" without actually sending them to the room. This meant
users had to wait until the next cycle of new games before seeing anything.
Now only CheapShark deals are silently recorded on first run (there can be
dozens). Epic free games are left for check_epic_free_games() to pick up
and post immediately, since they are few in number and time-limited.
https://claude.ai/code/session_017eMsVwUopgmnEyd6JJedpV
When SEND_INTRO_MESSAGE=true, the bot sends "The deals must flow." as
an m.notice to the Matrix room right after startup, before the first
scheduled deal checks. Defaults to off.
https://claude.ai/code/session_017eMsVwUopgmnEyd6JJedpV
The bot polls periodically for new deals, but sorting by "Deal Rating"
meant it always returned the same top-rated deals and would never
discover new listings that aren't in the top 10 by rating. Sorting by
"recent" ensures newly added or updated deals are seen on each poll.
https://claude.ai/code/session_017eMsVwUopgmnEyd6JJedpV
Two bugs fixed:
1. Function signature used old 0-100 scale defaults (min_rating: int = 80)
but dealRating from CheapShark is 0-10. Updated to float = 8.0.
2. Deals with dealRating of 0.0 (unrated/insufficient data) were being
filtered out as "poorly rated". Now treats 0.0 as unrated and skips
the rating check, so games like Leisure Suit Larry that lack a
CheapShark deal rating aren't incorrectly excluded.
https://claude.ai/code/session_017eMsVwUopgmnEyd6JJedpV
Log the raw deal count before filtering and log each filtered-out
deal with the reason (savings too low, rating too low) at DEBUG level.
Use --debug flag to enable verbose output for troubleshooting.
https://claude.ai/code/session_01LPpSZFfyh6vdV5HGFWjoQX
The previous 0-100 scale with a * 10 conversion was confusing —
CheapShark returns deal ratings as floats (e.g. 9.8, 7.5) so the
config should match. Default is now 8.0 instead of 80.
https://claude.ai/code/session_01LPpSZFfyh6vdV5HGFWjoQX
Running directly with `python -m gaming_deals_bot` didn't pick up
variables from .env — only the Docker path (--env-file) did. Now
dotenv is loaded before config parsing so both workflows work.
https://claude.ai/code/session_01LPpSZFfyh6vdV5HGFWjoQX
`python -m gaming_deals_bot --check` tests each external dependency
before starting the bot:
- Matrix: verifies access token (whoami) and room membership
- CheapShark: hits the deals endpoint
- Epic Games Store: hits the free-games endpoint
- Frankfurter: fetches exchange rates
- IsThereAnyDeal: validates the API key (skipped if not set)
Exits 0/1 so it works in CI pipelines and Docker health-checks.
https://claude.ai/code/session_01LPpSZFfyh6vdV5HGFWjoQX
Fetches live exchange rates from the Frankfurter API (ECB data, free,
no API key) and displays converted prices alongside USD in every deal
message. Rates are cached in memory and auto-refreshed hourly.
https://claude.ai/code/session_01LPpSZFfyh6vdV5HGFWjoQX
Implements a Matrix bot that posts PC gaming deals and free game alerts:
- CheapShark API integration (Steam, GOG, Humble, GMG) polled every 2 hours
- Epic Games Store free games detection polled daily
- IsThereAnyDeal historical low price flagging (optional)
- SQLite deduplication with 30-day pruning
- First-run population (records existing deals without posting)
- Matrix-flavored HTML + plain text fallback messages
- Dockerfile for containerized deployment
https://claude.ai/code/session_01LPpSZFfyh6vdV5HGFWjoQX