From 29abc836d562ad7678ec82f8c13c8febd8064d16 Mon Sep 17 00:00:00 2001 From: prosolis <5590409+prosolis@users.noreply.github.com> Date: Sun, 22 Mar 2026 02:09:27 -0700 Subject: [PATCH] Fix CheapShark returning zero deals by using dual-fetch strategy and relaxing filters The bot stopped posting because sortBy=recent only returned low-discount deals, and desc=1 was inverting the sort order for savings/DealRating queries. Now fetches both recent and top-rated deals, merges with dedup. Lowered default thresholds to 20% min discount, 7.0 min rating, and $45 max price. Co-Authored-By: Claude Opus 4.6 --- .env.example | 4 ++-- internal/config/config.go | 6 ++--- internal/deals/cheapshark.go | 46 ++++++++++++++++++++++++++++++++---- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/.env.example b/.env.example index cd77217..8a5e2e1 100644 --- a/.env.example +++ b/.env.example @@ -36,8 +36,8 @@ EXTRA_CURRENCIES=CAD,EUR,GBP #ITAD_DEALS_LIMIT=200 # Shared filter defaults (used when source-specific values are not set) -MIN_DISCOUNT_PERCENT=50 -MAX_PRICE=20 +MIN_DISCOUNT_PERCENT=20 +MAX_PRICE=45 # Matrix threads — post deals into per-category threads instead of the room # Categories: Game Deals, DLC Deals, Epic Free Games, Non-Game Deals diff --git a/internal/config/config.go b/internal/config/config.go index a76862d..2743915 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -63,9 +63,9 @@ func Load() (*Config, error) { } } - c.MinDealRating = envFloat("MIN_DEAL_RATING", 8.0) - c.MinDiscountPercent = envInt("MIN_DISCOUNT_PERCENT", 50) - c.MaxPriceUSD = envFloat("MAX_PRICE_USD", 20) + c.MinDealRating = envFloat("MIN_DEAL_RATING", 7.0) + c.MinDiscountPercent = envInt("MIN_DISCOUNT_PERCENT", 20) + c.MaxPriceUSD = envFloat("MAX_PRICE_USD", 45) c.DatabasePath = envStr("DATABASE_PATH", "deals.db") intro := strings.ToLower(os.Getenv("SEND_INTRO_MESSAGE")) diff --git a/internal/deals/cheapshark.go b/internal/deals/cheapshark.go index 3ff7d41..6ca5428 100644 --- a/internal/deals/cheapshark.go +++ b/internal/deals/cheapshark.go @@ -47,13 +47,49 @@ type cheapSharkRaw struct { SteamAppID string `json:"steamAppID"` } -// FetchCheapSharkDeals fetches deals from CheapShark API. +// FetchCheapSharkDeals fetches deals from CheapShark API using multiple +// sort strategies to ensure both new and high-value deals are captured. func FetchCheapSharkDeals(maxPrice float64, pageSize int) ([]CheapSharkDeal, error) { - reqURL := fmt.Sprintf( - "https://www.cheapshark.com/api/1.0/deals?storeID=1,7,11,23&upperPrice=%d&sortBy=recent&desc=1&pageSize=%d", - int(maxPrice), pageSize, - ) + // Fetch recent deals and top-rated deals, then merge. + // CheapShark's desc=0 (default) returns highest values first for savings/DealRating. + queries := []string{ + fmt.Sprintf( + "https://www.cheapshark.com/api/1.0/deals?storeID=1,7,11,23&upperPrice=%d&sortBy=recent&pageSize=%d", + int(maxPrice), pageSize, + ), + fmt.Sprintf( + "https://www.cheapshark.com/api/1.0/deals?storeID=1,7,11,23&upperPrice=%d&sortBy=DealRating&pageSize=%d", + int(maxPrice), pageSize, + ), + } + seen := make(map[string]bool) + var allDeals []CheapSharkDeal + + for _, reqURL := range queries { + fetched, err := fetchCheapSharkPage(reqURL) + if err != nil { + slog.Warn("cheapshark: fetch failed for query", "url", reqURL, "error", err) + continue + } + for _, d := range fetched { + if seen[d.DedupID] { + continue + } + seen[d.DedupID] = true + allDeals = append(allDeals, d) + } + } + + if len(allDeals) == 0 { + return nil, fmt.Errorf("cheapshark: all queries failed or returned no results") + } + + return allDeals, nil +} + +// fetchCheapSharkPage fetches and parses a single CheapShark API page. +func fetchCheapSharkPage(reqURL string) ([]CheapSharkDeal, error) { resp, err := http.Get(reqURL) if err != nil { return nil, fmt.Errorf("cheapshark request failed: %w", err)