import os import requests import gradio as gr import pandas as pd BASE_URL = "https://sportsbook-nash.draftkings.com/sites/US-VA-SB/api/sportscontent/controldata/league/leagueSubcategory/v1/markets" LEAGUE_ID = "42133" SUBCATEGORY_ID = "18010" # OT adjustment factor (1 goal vs ~1.5 goals) ADJUSTMENT_FACTOR = 0.67 DEBUG = True def log(msg): if DEBUG: print(msg) # ========================= # Odds Conversion # ========================= def american_to_prob(odds): odds = float(odds) if odds > 0: return 100 / (odds + 100) else: return abs(odds) / (abs(odds) + 100) def prob_to_decimal(p): if p <= 0: return None return round(1 / p, 3) def extract_decimal_adjusted(odds): try: if odds is None: return None if isinstance(odds, dict): odds = odds.get("american") or odds.get("value") or odds.get("price") odds = str(odds).strip().replace("−", "-") # already decimal if "." in odds and not odds.startswith("+") and not odds.startswith("-"): base_dec = float(odds) p = 1 / base_dec else: p = american_to_prob(float(odds)) # apply OT adjustment p_adj = p * ADJUSTMENT_FACTOR return prob_to_decimal(p_adj) except: return None # ========================= # Copy Format (TSV) # ========================= def df_to_tsv(df): if df is None or df.empty: return "" return "\n".join( f"{row['Player']}\t{row['Decimal Odds']}" for _, row in df.iterrows() ) # ========================= # Fetch Data # ========================= def fetch_data(): headers = { "accept": "*/*", "content-type": "application/json; charset=utf-8", "origin": "https://sportsbook.draftkings.com", "referer": "https://sportsbook.draftkings.com/", "user-agent": "Mozilla/5.0", } params = { "isBatchable": "false", "templateVars": f"{LEAGUE_ID},{SUBCATEGORY_ID}", "eventsQuery": f"$filter=leagueId eq '{LEAGUE_ID}' AND clientMetadata/Subcategories/any(s: s/Id eq '{SUBCATEGORY_ID}')", "marketsQuery": f"$filter=clientMetadata/subCategoryId eq '{SUBCATEGORY_ID}'", "include": "Events", "entity": "events", } r = requests.get(BASE_URL, headers=headers, params=params, timeout=20) r.raise_for_status() data = r.json() log(f"Events: {len(data.get('events', []))}") log(f"Selections: {len(data.get('selections', []))}") return data # ========================= # Extract Games # ========================= def extract_games(data): games = [] for e in data.get("events", []): event_id = e.get("id") name = e.get("name") if event_id and name: games.append((name, str(event_id))) return games # ========================= # Match Markets # ========================= def get_market_ids(data, event_id): market_ids = [] for m in data.get("markets", []): mid = m.get("id") if str(m.get("eventId")) == str(event_id): market_ids.append(str(mid)) if "eventIds" in m and str(event_id) in [str(x) for x in m["eventIds"]]: market_ids.append(str(mid)) return set(market_ids) # ========================= # Extract Players # ========================= def extract_players(data, event_id): selections = data.get("selections", []) market_ids = get_market_ids(data, event_id) rows = [] for s in selections: market_id = s.get("marketId") if str(market_id) not in market_ids: continue player = None if s.get("participants"): player = s["participants"][0].get("name") if not player: player = s.get("label") or s.get("outcomeName") odds = s.get("displayOdds") or s.get("oddsAmerican") or s.get("price") dec = extract_decimal_adjusted(odds) if player and dec is not None: rows.append((player, dec)) df = pd.DataFrame(rows, columns=["Player", "Decimal Odds"]) return df.drop_duplicates().sort_values("Player").reset_index(drop=True) # ========================= # Initialize # ========================= def initialize_app(): data = fetch_data() games = extract_games(data) if not games: return {}, gr.Dropdown(choices=[], value=None) game_map = {name: eid for name, eid in games} return game_map, gr.Dropdown( choices=list(game_map.keys()), value=list(game_map.keys())[0] ) # ========================= # Run # ========================= def run_selected_game(game_map, selected_game): if not selected_game: return pd.DataFrame(), "" data = fetch_data() event_id = game_map[selected_game] df = extract_players(data, event_id) return df, df_to_tsv(df) # ========================= # UI # ========================= with gr.Blocks(title="DK NHL OT Adjusted Points") as demo: gr.Markdown("# DK NHL OT Adjusted Points") game_map_state = gr.State({}) with gr.Row(): game_dropdown = gr.Dropdown(label="Select Game", scale=5) run_btn = gr.Button("Run", variant="primary") refresh_btn = gr.Button("Refresh") output_df = gr.Dataframe( headers=["Player", "Decimal Odds"], datatype=["str", "number"], interactive=False, label="Adjusted Player Table" ) copy_box = gr.Textbox( label="Copy (paste into Excel/Sheets)", lines=12, interactive=False ) demo.load( initialize_app, inputs=[], outputs=[game_map_state, game_dropdown] ) run_btn.click( run_selected_game, inputs=[game_map_state, game_dropdown], outputs=[output_df, copy_box] ) refresh_btn.click( initialize_app, inputs=[], outputs=[game_map_state, game_dropdown] ) # ========================= # Launch # ========================= if __name__ == "__main__": demo.queue().launch( server_name="0.0.0.0", server_port=int(os.getenv("PORT", 7860)) )