botbotbotbot / sportbet.py
coollsd's picture
Update sportbet.py
d478ceb verified
raw
history blame
13.4 kB
import discord
from discord import app_commands
import aiohttp
import asyncio
from datetime import datetime, timezone, timedelta
from cash import user_cash # Ensure you have a 'cash.py' module managing user_cash as a dictionary
user_bets = {}
API_KEY = "jE7yBJVRNAwdDesMgTzTXUUSx1It41Fq"
async def fetch_nhl_scores():
today = datetime.now().strftime('%Y%m%d')
url = f"https://api.foxsports.com/bifrost/v1/nhl/scoreboard/segment/{today}?apikey={API_KEY}"
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.json()
async def fetch_nfl_scores():
current_year = datetime.now().year
for week in range(1, 18): # NFL regular season has 17 weeks
url = f"https://api.foxsports.com/bifrost/v1/nfl/scoreboard/segment/{current_year}-{week}-1?apikey={API_KEY}"
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
data = await response.json()
if data['sectionList'][0]['events'][0]['eventStatus'] == 2:
return data
return None # If no current week is found
class SportSelect(discord.ui.Select):
def __init__(self):
options = [
discord.SelectOption(label="NHL", description="Bet on NHL games"),
discord.SelectOption(label="NFL", description="Bet on NFL games")
]
super().__init__(placeholder="Select a sport to bet on", min_values=1, max_values=1, options=options)
async def callback(self, interaction: discord.Interaction):
selected_sport = self.values[0]
await interaction.response.edit_message(content=f"Selected Sport: {selected_sport}. Fetching games...", view=None)
await asyncio.sleep(1) # Brief pause for better UX
if selected_sport == "NHL":
scores = await fetch_nhl_scores()
events = scores.get('sectionList', [])[0].get('events', [])
upcoming_games = [game for game in events if game.get('eventStatus') == 2]
if not upcoming_games:
await interaction.followup.send("No NHL games available for betting today.", ephemeral=False)
return
view = GameSelect(upcoming_games, "NHL")
await interaction.followup.send("Select a game to bet on:", view=view, ephemeral=False)
elif selected_sport == "NFL":
scores = await fetch_nfl_scores()
if not scores:
await interaction.followup.send("No NFL games available for betting this week.", ephemeral=False)
return
events = scores.get('sectionList', [])[0].get('events', [])
upcoming_games = [game for game in events if game.get('eventStatus') == 2]
if not upcoming_games:
await interaction.followup.send("No NFL games available for betting this week.", ephemeral=False)
return
view = GameSelect(upcoming_games, "NFL")
await interaction.followup.send("Select a game to bet on:", view=view, ephemeral=False)
class GameSelect(discord.ui.View):
def __init__(self, games, league):
super().__init__()
self.league = league
options = [
discord.SelectOption(
label=f"{game['lowerTeam']['longName']} vs {game['upperTeam']['longName']}",
value=game['id'],
description=f"Start time: <t:{int(datetime.fromisoformat(game['eventTime'].replace('Z', '+00:00')).timestamp())}:F>"
) for game in games
]
self.games = {game['id']: game for game in games}
self.add_item(GameOptionSelect(options, self.league, self.games))
class GameOptionSelect(discord.ui.Select):
def __init__(self, options, league, games):
super().__init__(placeholder="Select a game", min_values=1, max_values=1, options=options)
self.league = league
self.games = games
async def callback(self, interaction: discord.Interaction):
selected_game_id = self.values[0]
game_data = self.games.get(selected_game_id)
if not game_data:
await interaction.response.send_message("Selected game data not found.", ephemeral=False)
return
await interaction.response.edit_message(content="Select a team to bet on:", view=None)
await asyncio.sleep(1) # Brief pause for better UX
view = TeamSelect(game_data, self.league)
await interaction.followup.send("Select a team to bet on:", view=view, ephemeral=False)
class TeamSelect(discord.ui.View):
def __init__(self, game, league):
super().__init__()
self.league = league
away_team = game['lowerTeam']
home_team = game['upperTeam']
options = [
discord.SelectOption(label=away_team['longName'], value=away_team['name']),
discord.SelectOption(label=home_team['longName'], value=home_team['name'])
]
self.game = game
self.add_item(TeamOptionSelect(options, league, game))
class TeamOptionSelect(discord.ui.Select):
def __init__(self, options, league, game):
super().__init__(placeholder="Select a team to bet on", min_values=1, max_values=1, options=options)
self.league = league
self.game = game
async def callback(self, interaction: discord.Interaction):
selected_team = self.values[0]
await interaction.response.send_modal(BetModal(selected_team, interaction.user.id, self.game, self.league))
class BetModal(discord.ui.Modal, title="Place Your Bet"):
bet_amount = discord.ui.TextInput(label="Bet Amount", placeholder="Enter bet amount", required=True)
def __init__(self, team, user_id, game_data, league):
super().__init__()
self.team = team
self.user_id = user_id
self.game_data = game_data
self.league = league
async def on_submit(self, interaction: discord.Interaction):
try:
bet_amount = int(self.bet_amount.value)
if bet_amount <= 0:
raise ValueError("Bet amount must be greater than 0.")
if bet_amount > user_cash.get(self.user_id, 0):
raise ValueError("Insufficient balance. Please check your balance and try again.")
user_cash[self.user_id] -= bet_amount
await interaction.response.send_message(f"Bet placed on **{self.team}** for **${bet_amount}**.", ephemeral=False)
user = await interaction.client.fetch_user(self.user_id)
embed = discord.Embed(title="Bet Placed", color=0x787878)
embed.add_field(name="League", value=self.league, inline=False)
embed.add_field(name="Team", value=self.team, inline=False)
embed.add_field(name="Amount", value=f"${bet_amount}", inline=False)
game_description = f"{self.game_data['lowerTeam']['longName']} vs {self.game_data['upperTeam']['longName']}"
start_time = self.game_data['eventTime']
embed.add_field(name="Game", value=game_description, inline=False)
embed.add_field(name="Start Time", value=f"<t:{int(datetime.fromisoformat(start_time.replace('Z', '+00:00')).timestamp())}:F>", inline=False)
await user.send(embed=embed)
if self.user_id not in user_bets:
user_bets[self.user_id] = []
# Initialize previous scores to None to track changes only when they occur.
user_bets[self.user_id].append({
"league": self.league,
"team": self.team,
"amount": bet_amount,
"game_data": self.game_data,
"previous_scores": {
"away": None,
"home": None,
}
})
asyncio.create_task(self.monitor_game(interaction))
except ValueError as e:
await interaction.response.send_message(str(e), ephemeral=False)
async def monitor_game(self, interaction):
previous_scores={
"away": None,
"home": None,
}
while True:
scores_response=await fetch_nhl_scores() if self.league =="NHL" else fetch_nfl_scores()
event_list_key='events' if 'events' in scores_response.get('sectionList', [{}])[0] else 'games'
current_game=None
for section in scores_response.get('sectionList', []):
for event in section.get(event_list_key , []):
if event['id']==self.game_data['id']:
current_game=event
break
if not current_game:
await asyncio.sleep(60)
continue
current_scores={
"away": current_game['lowerTeam'].get('score'),
"home": current_game['upperTeam'].get('score'),
}
score_changed=False
for key in ["away","home"]:
current_score=current_scores[key]
previous_score=previous_scores[key]
# Only notify when the score changes from a non-None state.
if previous_score is not None and current_score!=previous_score:
score_changed=True
previous_scores=current_scores.copy()
if score_changed:
away_score=current_scores["away"] or 'N/A'
home_score=current_scores["home"] or 'N/A'
message=f"Score update: {away_score} - {home_score}"
user=await interaction.client.fetch_user(self.user_id)
await user.send(message)
event_status=current_game.get('eventStatus')
if event_status==3:
break
await asyncio.sleep(60)
class SportBetView(discord.ui.View):
def __init__(self):
super().__init__()
self.add_item(SportSelect())
@discord.ui.button(label="View Bets", style=discord.ButtonStyle.secondary)
async def view_bets(self ,interaction:discord.Interaction ,button :discord.ui.Button ):
await show_current_bets(interaction)
async def show_current_bets(interaction:discord.Interaction ):
user_id=interaction.user.id
if user_id not in user_bets or not user_bets[user_id]:
await interaction.response.send_message("You have no active bets." ,ephemeral=False )
return
embed=discord.Embed(title ="Your Current Bets" ,color=0x787878 )
for i ,bet in enumerate(user_bets[user_id] ,1 ):
league=bet ['league']
team=bet ['team']
amount=bet ['amount']
game=bet ['game_data']
away_score='N/A' if 'score' not in game ['lowerTeam'] else str(game ['lowerTeam']['score'])
home_score='N/A' if 'score' not in game ['upperTeam'] else str(game ['upperTeam']['score'])
status='Final' if 'score' in game ['upperTeam'] else f"Starts <t:{int(datetime.fromisoformat(game ['eventTime'].replace('Z','+00:00')).timestamp())}:R>"
embed.add_field(
name=f"Bet {i}: {league}" ,
value=(f"**Team:** {team}\n"
f"**Amount:** ${amount}\n"
f"**Game:** {game ['lowerTeam']['longName']} vs {game ['upperTeam']['longName']}\n"
f"**Status:** {status}\n"
f"**Current Score:** {away_score} - {home_score}\n"
f"**Start Time:** <t:{int(datetime.fromisoformat(game ['eventTime'].replace('Z','+00:00')).timestamp())}:F>"),
inline=False )
view=discord.ui.View()
cancel_select=discord.ui.Select(
placeholder ="Select a bet to cancel",
min_values=1 ,
max_values=1 ,
options=[
discord.SelectOption(label=f"Bet {i}" ,value=str(i-1)) for i in range(1 ,len(user_bets[user_id])+1 )
]
)
view.add_item(cancel_select)
async def cancel_callback(interaction_cancel :discord.Interaction ):
if interaction_cancel.user.id !=user_id :
await interaction_cancel.response.send_message("You cannot cancel other users' bets." ,ephemeral=False )
return
bet_index=int(cancel_select.values[0])
cancelled_bet=user_bets[user_id][bet_index]
start_time=datetime.fromisoformat(cancelled_bet ['game_data']['eventTime'].replace('Z','+00:00'))
if datetime.now(timezone.utc)>=start_time :
await interaction_cancel.response.send_message("You cannot cancel your bet as the game has already started." ,ephemeral=False )
return
user_cash[user_id]+=cancelled_bet ['amount']
user_bets[user_id].pop(bet_index)
await interaction_cancel.response.send_message(f"Bet cancelled. **${cancelled_bet ['amount']}** has been refunded." ,ephemeral=False )
if not user_bets[user_id]:
del user_bets[user_id]
cancel_select.callback=cancel_callback
await interaction.response.send_message(embed=embed ,view=view ,ephemeral=False )
@app_commands.command(name ="sportbet" ,description ="Bet on sports games")
async def sportbet(interaction :discord.Interaction ):
view=SportBetView()
await interaction.response.send_message("Select a sport to bet on:" ,view=view ,ephemeral=False )