05/23 Add Pick 5, Millionair Balls, etc

This commit is contained in:
2026-05-23 17:04:40 -04:00
parent b5e03fbf10
commit c792d9878e
10 changed files with 302 additions and 50 deletions
+103 -1
View File
@@ -12,6 +12,7 @@ import logging
import threading
import requests
from datetime import datetime
from db.models import get_game_by_name, insert_draw, insert_fetch_log
@@ -26,6 +27,10 @@ MEGAMILLIONS_TX_URL = (
"Mega_Millions/Winning_Numbers/download.html"
)
VA_CASH5_URL = "https://www.valottery.com/api/v1/downloadall?gameId=1030"
VA_MILLIONAIREFORLIFE_URL = "https://www.valottery.com/api/v1/downloadall?gameId=1075"
VA_BANKAMILLION_URL = "https://www.valottery.com/api/v1/downloadall?gameId=1070"
_fetch_lock = threading.Lock()
@@ -231,6 +236,96 @@ def fetch_megamillions_tx():
return _error_result(source, added, skipped, f"Network error: {e}")
# ── Virginia Lottery (shared parser) ─────────────────────────────────────────
def _parse_va_date(raw: str) -> str | None:
"""'5/22/2026' or '05/22/2026''2026-05-22'."""
parts = raw.strip().split("/")
if len(parts) != 3:
return None
try:
return f"{parts[2]}-{parts[0].zfill(2)}-{parts[1].zfill(2)}"
except (IndexError, ValueError):
return None
def _fetch_va_lottery(game_name: str, source: str, url: str) -> dict:
"""
Fetch VA Lottery draw data from the valottery.com download API.
Format per line: 'M/D/YYYY; N1,N2,...[; Label: bonus]'
First line may be a 'Results for ...' header — skipped automatically.
"""
game = get_game_by_name(game_name)
if not game:
return _error_result(source, 0, 0, f"{game_name} game not found in DB")
game_id = game["id"]
added = skipped = 0
try:
resp = requests.get(url, timeout=30)
resp.raise_for_status()
for line in resp.text.splitlines():
line = line.strip()
if not line or line.lower().startswith("results for"):
continue
parts = [p.strip() for p in line.split(";")]
if len(parts) < 2:
continue
draw_date = _parse_va_date(parts[0])
if draw_date is None:
continue
try:
numbers = [int(n.strip()) for n in parts[1].split(",") if n.strip()]
except ValueError as e:
logger.warning("[FETCH] VA %s parse error %r: %s", source, line, e)
continue
bonus = None
if len(parts) >= 3:
colon = parts[2].rfind(":")
if colon >= 0:
try:
bonus = int(parts[2][colon + 1:].strip())
except ValueError:
pass
result = insert_draw(game_id, draw_date, numbers, bonus=bonus, source=source)
if result == "inserted":
added += 1
else:
skipped += 1
logger.info("[FETCH] %s done — added=%d skipped=%d", source, added, skipped)
insert_fetch_log(source, added, skipped, "success")
return {"source": source, "added": added, "skipped": skipped,
"status": "success", "message": None}
except requests.RequestException as e:
logger.error("[FETCH] %s error: %s", source, e)
return _error_result(source, added, skipped, f"Network error: {e}")
def fetch_cash5_va():
"""Fetch Cash 5 draws from VA Lottery download API."""
return _fetch_va_lottery("Cash 5", "cash5_va", VA_CASH5_URL)
def fetch_millionaireforlife_va():
"""Fetch Millionaire for Life draws from VA Lottery download API."""
return _fetch_va_lottery("Millionaire for Life", "millionaireforlife_va",
VA_MILLIONAIREFORLIFE_URL)
def fetch_bankamillion_va():
"""Fetch Bank a Million draws from VA Lottery download API."""
return _fetch_va_lottery("Bank a Million", "bankamillion_va", VA_BANKAMILLION_URL)
# ── fetch_all ─────────────────────────────────────────────────────────────────
def fetch_all():
@@ -241,7 +336,14 @@ def fetch_all():
"""
logger.info("[FETCH] fetch_all() starting")
results = []
for fn in (fetch_powerball_ny, fetch_megamillions_ny, fetch_megamillions_tx):
for fn in (
fetch_powerball_ny,
fetch_megamillions_ny,
fetch_megamillions_tx,
fetch_cash5_va,
fetch_millionaireforlife_va,
fetch_bankamillion_va,
):
try:
results.append(fn())
except Exception as e: