添加赔率

This commit is contained in:
hajimi
2026-07-11 11:19:43 +08:00
parent c9ac46faa7
commit 3a5d571e53
29 changed files with 3006 additions and 542 deletions
+134 -52
View File
@@ -15,6 +15,14 @@ import pymysql
import requests
import urllib3
from titan_odds import (
DEFAULT_TITAN_COMPANY_ID,
DEFAULT_TITAN_COMPANY_NAME,
DEFAULT_TITAN_CUP_URLS,
DEFAULT_TITAN_EURO_COMPANY_ID,
TitanOddsClient,
)
DEFAULT_BASE_URLS = [
"https://205.201.0.120/",
@@ -70,6 +78,13 @@ def _safe_int(value: Any, default: int = 0) -> int:
return default
def _safe_float(value: Any, default: float = 0.0) -> float:
try:
return float(str(value).strip())
except (TypeError, ValueError):
return default
def _text(raw: Dict[str, str], key: str) -> str:
return str(raw.get(key) or "").strip()
@@ -538,62 +553,129 @@ def _build_result(
def run(db_config: Dict[str, Any], env: Optional[Dict[str, str]] = None) -> Dict[str, Any]:
env = env if env is not None else os.environ
username = (env.get("ODDS_USERNAME") or env.get("HG_ODDS_USERNAME") or "").strip()
password = (env.get("ODDS_PASSWORD") or env.get("HG_ODDS_PASSWORD") or "").strip()
if not username or not password:
return _build_result(
success=False,
candidate_count=0,
saved_count=0,
errors=["ODDS_USERNAME/ODDS_PASSWORD 未配置"],
)
base_urls = [_normalize_base_url(url) for url in _split_env_list(env.get("ODDS_BASE_URLS", ""), DEFAULT_BASE_URLS)]
sport_types = [item.upper() for item in _split_env_list(env.get("ODDS_SPORT_TYPES", ""), DEFAULT_SPORT_TYPES)]
show_types = [item.lower() for item in _split_env_list(env.get("ODDS_SHOW_TYPES", ""), DEFAULT_SHOW_TYPES)]
timeout = _safe_int(env.get("ODDS_TIMEOUT"), 20)
verify_tls = _bool_env(env.get("ODDS_VERIFY_TLS"), default=False)
langx = (env.get("ODDS_LANGX") or "zh-cn").strip()
odds_type = (env.get("ODDS_TYPE") or "H").strip().upper()
request_delay = float(env.get("ODDS_REQUEST_DELAY_SECONDS") or REQUEST_DELAY_SECONDS)
client: Optional[HgOddsClient] = None
login_errors: List[str] = []
for base_url in base_urls:
try:
candidate = HgOddsClient(
base_url=base_url,
username=username,
password=password,
timeout=timeout,
verify_tls=verify_tls,
langx=langx,
odds_type=odds_type,
)
candidate.login()
client = candidate
break
except Exception as exc: # noqa: BLE001
login_errors.append(f"{base_url}: {exc}")
if client is None:
return _build_result(success=False, candidate_count=0, saved_count=0, errors=login_errors)
items: List[Dict[str, Any]] = []
fetch_errors: List[str] = []
source_urls: List[str] = []
successful_sources = 0
skipped_count = 0
for sport_type in sport_types:
for show_type in show_types:
username = (env.get("ODDS_USERNAME") or env.get("HG_ODDS_USERNAME") or "").strip()
password = (env.get("ODDS_PASSWORD") or env.get("HG_ODDS_PASSWORD") or "").strip()
if username and password:
base_urls = [
_normalize_base_url(url)
for url in _split_env_list(env.get("ODDS_BASE_URLS", ""), DEFAULT_BASE_URLS)
]
sport_types = [
item.upper()
for item in _split_env_list(env.get("ODDS_SPORT_TYPES", ""), DEFAULT_SPORT_TYPES)
]
show_types = [
item.lower()
for item in _split_env_list(env.get("ODDS_SHOW_TYPES", ""), DEFAULT_SHOW_TYPES)
]
timeout = _safe_int(env.get("ODDS_TIMEOUT"), 20)
verify_tls = _bool_env(env.get("ODDS_VERIFY_TLS"), default=False)
langx = (env.get("ODDS_LANGX") or "zh-cn").strip()
odds_type = (env.get("ODDS_TYPE") or "H").strip().upper()
request_delay = _safe_float(
env.get("ODDS_REQUEST_DELAY_SECONDS"),
REQUEST_DELAY_SECONDS,
)
client: Optional[HgOddsClient] = None
login_errors: List[str] = []
for base_url in base_urls:
try:
items.extend(client.fetch_game_list(sport_type, show_type))
except OddsGameListUnavailable:
skipped_count += 1
candidate = HgOddsClient(
base_url=base_url,
username=username,
password=password,
timeout=timeout,
verify_tls=verify_tls,
langx=langx,
odds_type=odds_type,
)
candidate.login()
client = candidate
break
except Exception as exc: # noqa: BLE001
fetch_errors.append(f"{sport_type}/{show_type}: {exc}")
if request_delay > 0:
time.sleep(request_delay)
login_errors.append(f"hg {base_url}: {exc}")
if client is None:
fetch_errors.extend(login_errors)
else:
successful_sources += 1
source_urls.append(client.base_url)
for sport_type in sport_types:
for show_type in show_types:
try:
items.extend(client.fetch_game_list(sport_type, show_type))
except OddsGameListUnavailable:
skipped_count += 1
except Exception as exc: # noqa: BLE001
fetch_errors.append(f"hg {sport_type}/{show_type}: {exc}")
if request_delay > 0:
time.sleep(request_delay)
titan_enabled = _bool_env(env.get("TITAN_ODDS_ENABLED"), default=True)
if titan_enabled:
titan_urls = [
str(url).strip()
for url in _split_env_list(
env.get("TITAN_ODDS_URLS", ""),
DEFAULT_TITAN_CUP_URLS,
)
]
titan_client = TitanOddsClient(
timeout=_safe_int(env.get("TITAN_ODDS_TIMEOUT"), 20),
verify_tls=_bool_env(env.get("TITAN_ODDS_VERIFY_TLS"), default=True),
company_id=_safe_int(
env.get("TITAN_ODDS_COMPANY_ID"),
DEFAULT_TITAN_COMPANY_ID,
),
euro_company_id=_safe_int(
env.get("TITAN_ODDS_EURO_COMPANY_ID"),
DEFAULT_TITAN_EURO_COMPANY_ID,
),
company_name=(
env.get("TITAN_ODDS_COMPANY_NAME")
or DEFAULT_TITAN_COMPANY_NAME
).strip(),
show_type=(env.get("TITAN_ODDS_SHOW_TYPE") or "early").strip().lower(),
request_delay=_safe_float(
env.get("TITAN_ODDS_REQUEST_DELAY_SECONDS"),
0.2,
),
)
for titan_url in titan_urls:
try:
items.extend(titan_client.fetch_cup(titan_url))
successful_sources += 1
source_urls.append(titan_url)
except Exception as exc: # noqa: BLE001
fetch_errors.append(f"titan007 {titan_url}: {exc}")
titan_request_delay = _safe_float(
env.get("TITAN_ODDS_REQUEST_DELAY_SECONDS"),
0.2,
)
if titan_request_delay > 0:
time.sleep(titan_request_delay)
if successful_sources == 0:
if not username or not password:
fetch_errors.append("ODDS_USERNAME/ODDS_PASSWORD 未配置")
return _build_result(
success=False,
candidate_count=len(items),
saved_count=0,
source_url=",".join(dict.fromkeys(source_urls)),
skipped_count=skipped_count,
errors=fetch_errors or ["没有可用的赔率来源"],
)
repo = None
source_url = ",".join(dict.fromkeys(source_urls))
try:
repo = MatchOddsRepository(db_config)
repo.ensure_table()
@@ -603,7 +685,7 @@ def run(db_config: Dict[str, Any], env: Optional[Dict[str, str]] = None) -> Dict
success=False,
candidate_count=len(items),
saved_count=0,
source_url=client.base_url,
source_url=source_url,
skipped_count=skipped_count,
errors=fetch_errors + [f"database: {exc}"],
)
@@ -612,10 +694,10 @@ def run(db_config: Dict[str, Any], env: Optional[Dict[str, str]] = None) -> Dict
repo.close()
return _build_result(
success=len(fetch_errors) == 0,
success=True,
candidate_count=len(items),
saved_count=saved_count,
source_url=client.base_url,
source_url=source_url,
skipped_count=skipped_count,
errors=fetch_errors,
)