v0.5.84: matches origin filter, mobile gate, refresh reliability.
Ship Web refresh cache/lock, mobile demand gate, matches 职业/国服 filter, and related site updates through 0.5.84. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+27
-23
@@ -1,16 +1,17 @@
|
||||
"""Fetch recent league/tournament matches for OpenDota registered pros.
|
||||
"""Fetch recent league/tournament (+ optional ranked) matches for OpenDota pros.
|
||||
|
||||
Default source: web/data/pro_player_watchlist.json (hand-curated star IDs).
|
||||
Falls back to /proPlayers auto-pick only with --all-pros.
|
||||
|
||||
Per player: /players/{id}/matches (lobby practice + tournament), then
|
||||
/matches/{id} for final items + skill builds.
|
||||
Per player: /players/{id}/matches per lobby_type (practice/tournament, and
|
||||
ranked with --include-pubs), up to --limit newest each; then /matches/{id}
|
||||
for final items + skill builds. League rows do not crowd out ranked pubs.
|
||||
|
||||
Output: web/data/pro_matches.json (Climperor web only; not used by recommend).
|
||||
|
||||
Usage:
|
||||
python web/fetch_pro_matches.py
|
||||
python web/fetch_pro_matches.py --limit 12
|
||||
python web/fetch_pro_matches.py --include-pubs --limit 8
|
||||
python web/fetch_pro_matches.py --players 898754153,Ame
|
||||
python web/fetch_pro_matches.py --all-pros --limit-pros 20 --with-team
|
||||
"""
|
||||
@@ -29,7 +30,7 @@ import urllib.error
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from shared.grid import hero_table
|
||||
from shared.http_utils import http_json
|
||||
from shared.http_utils import http_json, write_json_atomic
|
||||
from shared.paths import DATA
|
||||
|
||||
from fetch_hero_matches import (
|
||||
@@ -220,11 +221,15 @@ def player_match_metas(
|
||||
*,
|
||||
lobby_types: tuple[int, ...] = LOBBY_LEAGUE,
|
||||
) -> list[dict]:
|
||||
"""Recent match list rows for a pro (deduped, newest first)."""
|
||||
per_lt = max(limit, limit // max(1, len(lobby_types)) + 2)
|
||||
"""Recent match list rows for a pro (deduped, newest first).
|
||||
|
||||
Fetches up to ``limit`` newest matches **per lobby_type**, then merges.
|
||||
With league + ranked pubs this can return up to ``limit * len(lobby_types)``
|
||||
rows — important so recent league games do not crowd out ranked pubs.
|
||||
"""
|
||||
by_id: dict[int, dict] = {}
|
||||
for lt in lobby_types:
|
||||
url = f"{OPENDOTA}/players/{account_id}/matches?limit={per_lt}&lobby_type={lt}"
|
||||
url = f"{OPENDOTA}/players/{account_id}/matches?limit={limit}&lobby_type={lt}"
|
||||
try:
|
||||
raw = http_json(url)
|
||||
except (
|
||||
@@ -258,11 +263,10 @@ def player_match_metas(
|
||||
if st_new >= st_old:
|
||||
by_id[mid] = row
|
||||
|
||||
ranked = sorted(
|
||||
return sorted(
|
||||
by_id.values(),
|
||||
key=lambda r: (-int(r.get("start_time") or 0), -int(r.get("match_id") or 0)),
|
||||
)
|
||||
return ranked[:limit]
|
||||
|
||||
|
||||
def fetch_player_matches(
|
||||
@@ -285,6 +289,12 @@ def fetch_player_matches(
|
||||
continue
|
||||
if mid <= 0 or hid <= 0:
|
||||
continue
|
||||
lt_raw = meta.get("lobby_type")
|
||||
try:
|
||||
lt_i = int(lt_raw) if lt_raw is not None else None
|
||||
except (TypeError, ValueError):
|
||||
lt_i = None
|
||||
row_origin = "public" if lt_i == 7 else "pro"
|
||||
detail = fetch_match(mid)
|
||||
if delay > 0:
|
||||
time.sleep(delay)
|
||||
@@ -293,7 +303,7 @@ def fetch_player_matches(
|
||||
slim = extract_player_row(
|
||||
detail,
|
||||
hid,
|
||||
origin="pro",
|
||||
origin=row_origin,
|
||||
id_map=id_map,
|
||||
item_catalog=catalog,
|
||||
list_meta=meta,
|
||||
@@ -309,11 +319,7 @@ def fetch_player_matches(
|
||||
continue
|
||||
slim["hero_id"] = hid
|
||||
slim["hero_key"] = id_to_key.get(hid)
|
||||
lt = meta.get("lobby_type")
|
||||
try:
|
||||
slim["lobby_type"] = int(lt) if lt is not None else None
|
||||
except (TypeError, ValueError):
|
||||
slim["lobby_type"] = None
|
||||
slim["lobby_type"] = lt_i
|
||||
rows.append(slim)
|
||||
return rows
|
||||
|
||||
@@ -390,16 +396,17 @@ def write_out(
|
||||
"attribution": "https://www.opendota.com",
|
||||
"fetched_at": datetime.now(timezone.utc).isoformat(),
|
||||
"player_source": player_source,
|
||||
"limit_per_pro": limit,
|
||||
"limit_per_lobby": limit,
|
||||
"limit_pros": limit_pros,
|
||||
"lobby_types": list(lobby_types),
|
||||
"pro_count": len(by_pro),
|
||||
"match_count": match_count,
|
||||
"hero_count": len(by_hero),
|
||||
"note_zh": (
|
||||
"OpenDota 明星/职业选手近期联赛/锦标赛对局;"
|
||||
"OpenDota 明星选手近期联赛/锦标赛对局(可选含天梯 lobby_type=7);"
|
||||
"默认名单见 web/data/pro_player_watchlist.json;"
|
||||
"lobby_type 1=训练/practice、2=tournament;"
|
||||
"每种 lobby 各保留最近 limit 场,避免联赛挤掉天梯;"
|
||||
"lobby_type 1=训练/practice、2=tournament、7=ranked;"
|
||||
"含终局出装、加点与联赛名(若有)。"
|
||||
),
|
||||
},
|
||||
@@ -408,10 +415,7 @@ def write_out(
|
||||
"by_pro": by_pro,
|
||||
"by_hero": by_hero,
|
||||
}
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(
|
||||
json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8"
|
||||
)
|
||||
write_json_atomic(path, payload)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
|
||||
Reference in New Issue
Block a user