stove bug
This commit is contained in:
+53
-6
@@ -671,7 +671,42 @@ def fetch_stove_free():
|
|||||||
"rating_count": 0,
|
"rating_count": 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
def _collect_games(payload, seen):
|
detail_price_re = re.compile(
|
||||||
|
r"-100%\s+[^0-9]{0,5}([0-9][0-9,]*(?:\.[0-9]+)?)\s+[^0-9]{0,5}(0(?:\.0+)?)\b"
|
||||||
|
)
|
||||||
|
detail_cache = {}
|
||||||
|
|
||||||
|
def _verify_detail_free_promo(session, store_url):
|
||||||
|
if store_url in detail_cache:
|
||||||
|
return detail_cache[store_url]
|
||||||
|
try:
|
||||||
|
html = _stove_get(session, store_url, html=True, headers=html_headers).text
|
||||||
|
except Exception as e:
|
||||||
|
log.warning("STOVE detail fetch failed: %s (%s)", store_url, e)
|
||||||
|
detail_cache[store_url] = None
|
||||||
|
return None
|
||||||
|
|
||||||
|
text = " ".join(BeautifulSoup(html, "html.parser").stripped_strings)
|
||||||
|
match = detail_price_re.search(text)
|
||||||
|
if not match:
|
||||||
|
detail_cache[store_url] = None
|
||||||
|
return None
|
||||||
|
|
||||||
|
original_price = _to_float(match.group(1))
|
||||||
|
current_price = _to_float(match.group(2))
|
||||||
|
if original_price <= 0.0 or current_price != 0.0:
|
||||||
|
detail_cache[store_url] = None
|
||||||
|
return None
|
||||||
|
|
||||||
|
verified = {
|
||||||
|
"original_price": original_price,
|
||||||
|
"current_price": current_price,
|
||||||
|
"discount_pct": 100,
|
||||||
|
}
|
||||||
|
detail_cache[store_url] = verified
|
||||||
|
return verified
|
||||||
|
|
||||||
|
def _collect_games(payload, seen, session):
|
||||||
games = []
|
games = []
|
||||||
items = None
|
items = None
|
||||||
if isinstance(payload, dict):
|
if isinstance(payload, dict):
|
||||||
@@ -688,6 +723,10 @@ def fetch_stove_free():
|
|||||||
game = _build_game(item)
|
game = _build_game(item)
|
||||||
if not game:
|
if not game:
|
||||||
continue
|
continue
|
||||||
|
verified = _verify_detail_free_promo(session, game["store_url"])
|
||||||
|
if not verified:
|
||||||
|
continue
|
||||||
|
game.update(verified)
|
||||||
if game["external_id"] in seen:
|
if game["external_id"] in seen:
|
||||||
continue
|
continue
|
||||||
seen.add(game["external_id"])
|
seen.add(game["external_id"])
|
||||||
@@ -698,6 +737,10 @@ def fetch_stove_free():
|
|||||||
game = _build_game(item)
|
game = _build_game(item)
|
||||||
if not game:
|
if not game:
|
||||||
continue
|
continue
|
||||||
|
verified = _verify_detail_free_promo(session, game["store_url"])
|
||||||
|
if not verified:
|
||||||
|
continue
|
||||||
|
game.update(verified)
|
||||||
if game["external_id"] in seen:
|
if game["external_id"] in seen:
|
||||||
continue
|
continue
|
||||||
seen.add(game["external_id"])
|
seen.add(game["external_id"])
|
||||||
@@ -756,7 +799,7 @@ def fetch_stove_free():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.warning("STOVE API fetch failed: %s (%s)", api_url, e)
|
log.warning("STOVE API fetch failed: %s (%s)", api_url, e)
|
||||||
continue
|
continue
|
||||||
results.extend(_collect_games(payload, seen))
|
results.extend(_collect_games(payload, seen, session))
|
||||||
if results:
|
if results:
|
||||||
log.info("STOVE free: %d game(s) found via API", len(results))
|
log.info("STOVE free: %d game(s) found via API", len(results))
|
||||||
return results
|
return results
|
||||||
@@ -769,7 +812,7 @@ def fetch_stove_free():
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
for payload in _extract_json_from_html(html):
|
for payload in _extract_json_from_html(html):
|
||||||
results.extend(_collect_games(payload, seen))
|
results.extend(_collect_games(payload, seen, session))
|
||||||
if results:
|
if results:
|
||||||
log.info("STOVE free: %d game(s) found via embedded JSON", len(results))
|
log.info("STOVE free: %d game(s) found via embedded JSON", len(results))
|
||||||
return results
|
return results
|
||||||
@@ -824,6 +867,10 @@ def fetch_stove_free():
|
|||||||
if image_node is not None:
|
if image_node is not None:
|
||||||
image_url = image_node.get("src") or image_node.get("data-src") or image_node.get("data-lazy-src") or ""
|
image_url = image_node.get("src") or image_node.get("data-src") or image_node.get("data-lazy-src") or ""
|
||||||
|
|
||||||
|
verified = _verify_detail_free_promo(session, _abs_url(href))
|
||||||
|
if not verified:
|
||||||
|
continue
|
||||||
|
|
||||||
seen.add(external_id)
|
seen.add(external_id)
|
||||||
results.append({
|
results.append({
|
||||||
"external_id": external_id,
|
"external_id": external_id,
|
||||||
@@ -831,9 +878,9 @@ def fetch_stove_free():
|
|||||||
"title": title,
|
"title": title,
|
||||||
"image_url": _abs_url(str(image_url).strip()),
|
"image_url": _abs_url(str(image_url).strip()),
|
||||||
"store_url": _abs_url(href),
|
"store_url": _abs_url(href),
|
||||||
"original_price": original_price,
|
"original_price": verified["original_price"],
|
||||||
"current_price": 0.0,
|
"current_price": verified["current_price"],
|
||||||
"discount_pct": 100,
|
"discount_pct": verified["discount_pct"],
|
||||||
"is_free_period": True,
|
"is_free_period": True,
|
||||||
"free_start": None,
|
"free_start": None,
|
||||||
"free_end": None,
|
"free_end": None,
|
||||||
|
|||||||
Reference in New Issue
Block a user