This commit is contained in:
2026-04-17 10:42:17 +09:00
parent c576ace082
commit 3cfe1f6ed9
+19 -14
View File
@@ -218,7 +218,8 @@ def _steam_game_dict(appid: int, detail: dict):
if permanently_free: if permanently_free:
return None return None
is_free_period = (current == 0.0 and original > 0.0) or free_weekend # discount_percent=100 을 우선 신뢰 (final 값이 0이 아닌 경우도 있음 — Steam API 불일치)
is_free_period = (original > 0.0 and (current == 0.0 or discount == 100)) or free_weekend
if not is_free_period: if not is_free_period:
return None return None
@@ -312,32 +313,36 @@ def _fetch_steam_featured_appids() -> list:
def fetch_steam_free(max_detail_calls: int = 60) -> list: def fetch_steam_free(max_detail_calls: int = 60) -> list:
import time from concurrent.futures import ThreadPoolExecutor, as_completed
seen, candidates = set(), [] seen, candidates = set(), []
for aid in _fetch_steam_search_appids() + _fetch_steam_featured_appids(): for aid in _fetch_steam_search_appids() + _fetch_steam_featured_appids():
if aid not in seen: if aid not in seen:
seen.add(aid) seen.add(aid)
candidates.append(aid) candidates.append(aid)
candidates = candidates[:max_detail_calls]
log.info("Steam: %d candidate(s) to validate", len(candidates)) log.info("Steam: %d candidate(s) to validate", len(candidates))
results, calls = [], 0
for appid in candidates: def _process(appid):
if calls >= max_detail_calls:
break
detail = _steam_appdetails(appid) detail = _steam_appdetails(appid)
calls += 1
if not detail: if not detail:
continue return None
# game/bundle만 허용 — dlc, mod, application, demo, soundtrack 등 제외
if detail.get("type", "").lower() not in ("game", "bundle", ""): if detail.get("type", "").lower() not in ("game", "bundle", ""):
continue return None
title = detail.get("name", "") title = detail.get("name", "")
if _DEMO_TITLE_RE.search(title): if _DEMO_TITLE_RE.search(title):
log.debug("Steam: skipping demo/trial: %s", title) log.debug("Steam: skipping demo/trial: %s", title)
continue return None
game = _steam_game_dict(appid, detail) game = _steam_game_dict(appid, detail)
if game: return game if game and game.get("is_free_period") else None
results.append(game)
time.sleep(0.3) results = []
with ThreadPoolExecutor(max_workers=8) as executor:
futures = {executor.submit(_process, aid): aid for aid in candidates}
for future in as_completed(futures):
game = future.result()
if game:
results.append(game)
log.info("Steam free: %d game(s) found", len(results)) log.info("Steam free: %d game(s) found", len(results))
return results return results