Reapply bug fixes to branch

This commit is contained in:
Cal Corum 2025-09-20 11:02:05 -05:00
parent 2b4b84e193
commit 4e71c33344
2 changed files with 148 additions and 88 deletions

View File

@ -294,13 +294,39 @@ class SBaTransaction:
return True
return False
def get_gms(self, bot, team=None):
async def get_gms(self, bot, team=None):
if team is None:
return [bot.get_user(x) for x in self.gms]
gms = []
for gm_id in self.gms:
try:
user = await bot.fetch_user(gm_id)
if user:
gms.append(user)
except discord.NotFound:
logger.warning(f'User {gm_id} not found')
except Exception as e:
logger.error(f'Error fetching user {gm_id}: {e}')
return gms
else:
these_gms = [bot.get_user(self.teams[team]['team']['gmid'])]
these_gms = []
try:
user = await bot.fetch_user(self.teams[team]['team']['gmid'])
if user:
these_gms.append(user)
except discord.NotFound:
logger.warning(f'User {self.teams[team]["team"]["gmid"]} not found')
except Exception as e:
logger.error(f'Error fetching user {self.teams[team]["team"]["gmid"]}: {e}')
if self.teams[team]['team']['gmid2']:
these_gms.append(bot.get_user(self.teams[team]['team']['gmid2']))
try:
user = await bot.fetch_user(self.teams[team]['team']['gmid2'])
if user:
these_gms.append(user)
except discord.NotFound:
logger.warning(f'User {self.teams[team]["team"]["gmid2"]} not found')
except Exception as e:
logger.error(f'Error fetching user {self.teams[team]["team"]["gmid2"]}: {e}')
return these_gms
async def send(self, content=None, embed=None):
@ -414,11 +440,11 @@ class SBaTransaction:
# If player is leaving this team, remove from roster and subtract WARa
if x['oldteam'] == this_team:
team_roster.remove(x['player'])
team_roster = [p for p in team_roster if p['id'] != x['player']['id']]
wara -= x['player']['wara']
# If player is leaving MiL team, remove from roster and subtract WARa
elif x['oldteam']['abbrev'] == f'{this_team["abbrev"]}MiL':
mil_roster.remove(x['player'])
mil_roster = [p for p in mil_roster if p['id'] != x['player']['id']]
mil_wara -= x['player']['wara']
logger.info(f'updating rosters')
@ -440,7 +466,7 @@ class SBaTransaction:
if self.players[x]['player']['team'] == this_team:
logger.info(f'major league player')
# logger.info(f'team roster: {team_roster}')
team_roster.remove(self.players[x]['player'])
team_roster = [p for p in team_roster if p['id'] != self.players[x]['player']['id']]
# 06-13: COMMENTED OUT TO RESOLVE MID-WEEK IL REPLACEMENT BEING SENT BACK DOWN
# if self.effective_week != self.current.week:
wara -= self.players[x]['player']['wara']
@ -448,7 +474,7 @@ class SBaTransaction:
# If player is leaving MiL team next week, remove from roster and subtract WARa
if self.players[x]['player']['team']['abbrev'] == f'{this_team["abbrev"]}MiL':
logger.info(f'minor league player')
mil_roster.remove(self.players[x]['player'])
mil_roster = [p for p in mil_roster if p['id'] != self.players[x]['player']['id']]
# logger.info(f'mil roster: {mil_roster}')
if self.effective_week != self.current.week:
mil_wara -= self.players[x]['player']['wara']
@ -547,6 +573,7 @@ class Transactions(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.trade_season = False
self.weekly_warning_sent = False
self.weekly_loop.start()
@ -560,54 +587,64 @@ class Transactions(commands.Cog):
@tasks.loop(minutes=1)
async def weekly_loop(self):
logger.info(f'Inside weekly_loop')
if OFFSEASON_FLAG:
logger.info(f'Exiting weekly_loop; OFFSEASON_FLAG: {OFFSEASON_FLAG}')
return
try:
logger.info(f'Inside weekly_loop')
if OFFSEASON_FLAG:
logger.info(f'Exiting weekly_loop; OFFSEASON_FLAG: {OFFSEASON_FLAG}')
return
current = await get_current()
now = datetime.datetime.now()
logger.info(f'Datetime: {now} / weekday: {now.weekday()} / current: {current}')
current = await get_current()
now = datetime.datetime.now()
logger.info(f'Datetime: {now} / weekday: {now.weekday()} / current: {current}')
# Begin Freeze
# if now.weekday() == 0 and now.hour == 5 and not current.freeze: # Spring/Summer
if now.weekday() == 0 and now.hour == 0 and not current.freeze: # Fall/Winter
logger.info(f'weekly_loop - setting the freeze')
current.week += 1
await db_patch('current', object_id=current.id, params=[('week', current.week), ('freeze', True)])
await self.run_transactions(current)
# Begin Freeze
# if now.weekday() == 0 and now.hour == 5 and not current.freeze: # Spring/Summer
if now.weekday() == 0 and now.hour == 0 and not current.freeze: # Fall/Winter
logger.info(f'weekly_loop - setting the freeze')
current.week += 1
await db_patch('current', object_id=current.id, params=[('week', current.week), ('freeze', True)])
await self.run_transactions(current)
logger.debug(f'Building freeze string')
week_num = f'Week {current.week}'
stars = f'{"":*<32}'
freeze_message = f'```\n' \
f'{stars}\n'\
f'{week_num: >9} Freeze Period Begins\n' \
f'{stars}\n```'
logger.debug(f'Freeze string:\n\n{freeze_message}')
await send_to_channel(self.bot, 'transaction-log', freeze_message)
logger.debug(f'Building freeze string')
week_num = f'Week {current.week}'
stars = f'{"":*<32}'
freeze_message = f'```\n' \
f'{stars}\n'\
f'{week_num: >9} Freeze Period Begins\n' \
f'{stars}\n```'
logger.debug(f'Freeze string:\n\n{freeze_message}')
await send_to_channel(self.bot, 'transaction-log', freeze_message)
if current.week > 0 and current.week <= 18:
await self.post_weekly_info(current)
if current.week > 0 and current.week <= 18:
await self.post_weekly_info(current)
# End Freeze
# elif now.weekday() == 5 and now.hour == 5 and current.freeze: # Spring/Summer
elif now.weekday() == 5 and now.hour == 0 and current.freeze: # Fall/Winter
logger.info(f'weekly_loop - running the un-freeze')
await db_patch('current', object_id=current.id, params=[('freeze', False)])
# End Freeze
# elif now.weekday() == 5 and now.hour == 5 and current.freeze: # Spring/Summer
elif now.weekday() == 5 and now.hour == 0 and current.freeze: # Fall/Winter
logger.info(f'weekly_loop - running the un-freeze')
await db_patch('current', object_id=current.id, params=[('freeze', False)])
week_num = f'Week {current.week}'
stars = f'{"":*<30}'
freeze_message = f'```\n' \
f'{stars}\n'\
f'{week_num: >9} Freeze Period Ends\n' \
f'{stars}\n```'
await self.process_freeze_moves(current)
await send_to_channel(self.bot, 'transaction-log', freeze_message)
self.trade_season = False
week_num = f'Week {current.week}'
stars = f'{"":*<30}'
freeze_message = f'```\n' \
f'{stars}\n'\
f'{week_num: >9} Freeze Period Ends\n' \
f'{stars}\n```'
await self.process_freeze_moves(current)
await send_to_channel(self.bot, 'transaction-log', freeze_message)
self.trade_season = False
else:
logger.info(f'weekly_loop - No freeze actions being taken')
else:
logger.info(f'weekly_loop - No freeze actions being taken')
except Exception as e:
logger.error(f'Unhandled exception in weekly_loop: {e}')
error_message = f"⚠️ **Weekly Freeze Task Failed**\n```\nError: {str(e)}\nTime: {datetime.datetime.now()}\nTask: weekly_loop in transactions.py\n```"
try:
if not self.weekly_warning_sent:
await send_owner_notification(error_message)
self.weekly_warning_sent = True
except Exception as e:
logger.error(f'Failed to send error message :( {e}')
@weekly_loop.before_loop
async def before_notif_check(self):
@ -1008,7 +1045,7 @@ class Transactions(commands.Cog):
while True:
prompt = 'Are you adding a team to this deal? (Yes/No)'
this_q = Question(self.bot, trade.channel, prompt, 'yesno', 30)
resp = await this_q.ask(trade.get_gms(self.bot))
resp = await this_q.ask(await trade.get_gms(self.bot))
if resp is None:
await trade.send('RIP this move. Maybe next time.')
@ -1019,7 +1056,7 @@ class Transactions(commands.Cog):
else:
this_q.prompt = 'Please enter the team\'s abbreviation.'
this_q.qtype = 'text'
resp = await this_q.ask(trade.get_gms(self.bot))
resp = await this_q.ask(await trade.get_gms(self.bot))
if not resp:
await trade.send('RIP this move. Maybe next time.')
@ -1040,7 +1077,7 @@ class Transactions(commands.Cog):
while True:
prompt = f'Are you trading a player between teams?'
this_q = Question(self.bot, trade.channel, prompt, 'yesno', 300)
resp = await this_q.ask(trade.get_gms(self.bot))
resp = await this_q.ask(await trade.get_gms(self.bot))
if resp is None:
await trade.send('RIP this move. Maybe next time.')
@ -1051,7 +1088,7 @@ class Transactions(commands.Cog):
else:
this_q.prompt = 'Which player is being traded?'
this_q.qtype = 'text'
resp = await this_q.ask(trade.get_gms(self.bot))
resp = await this_q.ask(await trade.get_gms(self.bot))
if not resp:
pass
@ -1077,7 +1114,7 @@ class Transactions(commands.Cog):
await trade.send(f'Ope. {player["name"]} is already one the move next week.')
else:
this_q.prompt = 'Where are they going? Please enter the destination team\'s abbreviation.'
resp = await this_q.ask(trade.get_gms(self.bot))
resp = await this_q.ask(await trade.get_gms(self.bot))
if resp is None:
await trade.send('RIP this move. Maybe next time.')
@ -1103,7 +1140,7 @@ class Transactions(commands.Cog):
# while True and current.pick_trade_end >= current.week >= current.pick_trade_start:
# prompt = f'Are you trading any draft picks?'
# this_q = Question(self.bot, trade.channel, prompt, 'yesno', 300)
# resp = await this_q.ask(trade.get_gms(self.bot))
# resp = await this_q.ask(await trade.get_gms(self.bot))
# effective_season = current.season if OFFSEASON_FLAG else current.season + 1
# team_season = current.season
#
@ -1117,7 +1154,7 @@ class Transactions(commands.Cog):
# # Get first pick
# this_q.prompt = 'Enter the pick\'s original owner and round number like this: TIT 17'
# this_q.qtype = 'text'
# resp = await this_q.ask(trade.get_gms(self.bot))
# resp = await this_q.ask(await trade.get_gms(self.bot))
#
# if not resp:
# await trade.send('RIP this move. Maybe next time.')
@ -1138,7 +1175,7 @@ class Transactions(commands.Cog):
# f'round number, please.')
# else:
# this_q.prompt = 'Now enter the return pick\'s original owner and round number like this: TIT 17'
# resp = await this_q.ask(trade.get_gms(self.bot))
# resp = await this_q.ask(await trade.get_gms(self.bot))
#
# if not resp:
# await trade.send('RIP this move. Maybe next time.')
@ -1188,7 +1225,7 @@ class Transactions(commands.Cog):
while True:
this_q.prompt = f'{trade.teams[team]["role"].mention}\nAre you making an FA drop?'
this_q.qtype = 'yesno'
resp = await this_q.ask(trade.get_gms(self.bot, team))
resp = await this_q.ask(await trade.get_gms(self.bot, team))
if resp is None:
await trade.send('RIP this move. Maybe next time.')
@ -1199,7 +1236,7 @@ class Transactions(commands.Cog):
else:
this_q.prompt = 'Who are you dropping?'
this_q.qtype = 'text'
resp = await this_q.ask(trade.get_gms(self.bot, team))
resp = await this_q.ask(await trade.get_gms(self.bot, team))
if resp is None:
await trade.send('RIP this move. Maybe next time.')
@ -1271,7 +1308,7 @@ class Transactions(commands.Cog):
for team in trade.teams:
this_q.prompt = f'{trade.teams[team]["role"].mention}\nDo you accept this trade?'
this_q.qtype = 'yesno'
resp = await this_q.ask(trade.get_gms(self.bot, team))
resp = await this_q.ask(await trade.get_gms(self.bot, team))
if not resp:
await trade.send('RIP this move. Maybe next time.')
@ -1348,7 +1385,7 @@ class Transactions(commands.Cog):
# while True:
# prompt = 'Are you adding a team to this deal? (Yes/No)'
# this_q = Question(self.bot, trade.channel, prompt, 'yesno', 30)
# resp = await this_q.ask(trade.get_gms(self.bot))
# resp = await this_q.ask(await trade.get_gms(self.bot))
#
# if resp is None:
# await trade.send('RIP this move. Maybe next time.')
@ -1359,7 +1396,7 @@ class Transactions(commands.Cog):
# else:
# this_q.prompt = 'Please enter the team\'s abbreviation.'
# this_q.qtype = 'text'
# resp = await this_q.ask(trade.get_gms(self.bot))
# resp = await this_q.ask(await trade.get_gms(self.bot))
#
# if not resp:
# await trade.send('RIP this move. Maybe next time.')
@ -1381,7 +1418,7 @@ class Transactions(commands.Cog):
# while True:
# prompt = f'Are you trading any draft picks?'
# this_q = Question(self.bot, trade.channel, prompt, 'yesno', 300)
# resp = await this_q.ask(trade.get_gms(self.bot))
# resp = await this_q.ask(await trade.get_gms(self.bot))
# effective_season = current.season if OFFSEASON_FLAG else current.season + 1
# team_season = current.season
#
@ -1395,7 +1432,7 @@ class Transactions(commands.Cog):
# # Get first pick
# this_q.prompt = 'Enter the overall pick number being traded.'
# this_q.qtype = 'int'
# resp = await this_q.ask(trade.get_gms(self.bot))
# resp = await this_q.ask(await trade.get_gms(self.bot))
#
# if not resp:
# await trade.send('RIP this move. Maybe next time.')
@ -1411,7 +1448,7 @@ class Transactions(commands.Cog):
# await trade.send(f'Frick, I couldn\'t find pick #{resp}.')
# else:
# this_q.prompt = 'Now enter the return pick\'s overall pick number.'
# resp = await this_q.ask(trade.get_gms(self.bot))
# resp = await this_q.ask(await trade.get_gms(self.bot))
#
# if not resp:
# await trade.send('RIP this move. Maybe next time.')
@ -1485,7 +1522,7 @@ class Transactions(commands.Cog):
# for team in trade.teams:
# this_q.prompt = f'{trade.teams[team]["role"].mention}\nDo you accept this trade?'
# this_q.qtype = 'yesno'
# resp = await this_q.ask(trade.get_gms(self.bot, team))
# resp = await this_q.ask(await trade.get_gms(self.bot, team))
#
# if not resp:
# await trade.send('RIP this move. Maybe next time.')
@ -1558,7 +1595,7 @@ class Transactions(commands.Cog):
while True and not OFFSEASON_FLAG:
prompt = f'Are you adding someone to the Minor League roster?'
this_q = Question(self.bot, dropadd.channel, prompt, 'yesno', 300)
resp = await this_q.ask(dropadd.get_gms(self.bot))
resp = await this_q.ask(await dropadd.get_gms(self.bot))
if resp is None:
await dropadd.send('RIP this move. Maybe next time.')
@ -1569,7 +1606,7 @@ class Transactions(commands.Cog):
else:
this_q.prompt = 'Who are you sending to the MiL?'
this_q.qtype = 'text'
resp = await this_q.ask(dropadd.get_gms(self.bot))
resp = await this_q.ask(await dropadd.get_gms(self.bot))
if resp is None:
await dropadd.send('RIP this move. Maybe next time.')
@ -1611,7 +1648,7 @@ class Transactions(commands.Cog):
while True and not OFFSEASON_FLAG:
prompt = f'Are you adding any players to the Major League roster?'
this_q = Question(self.bot, dropadd.channel, prompt, 'yesno', 300)
resp = await this_q.ask(dropadd.get_gms(self.bot))
resp = await this_q.ask(await dropadd.get_gms(self.bot))
if resp is None:
await dropadd.send('RIP this move. Maybe next time.')
@ -1622,7 +1659,7 @@ class Transactions(commands.Cog):
else:
this_q.prompt = 'Who are you adding?'
this_q.qtype = 'text'
resp = await this_q.ask(dropadd.get_gms(self.bot))
resp = await this_q.ask(await dropadd.get_gms(self.bot))
if resp is None:
await dropadd.send('RIP this move. Maybe next time.')
@ -1671,7 +1708,7 @@ class Transactions(commands.Cog):
while True:
prompt = f'Are you dropping anyone to FA?'
this_q = Question(self.bot, dropadd.channel, prompt, 'yesno', 300)
resp = await this_q.ask(dropadd.get_gms(self.bot))
resp = await this_q.ask(await dropadd.get_gms(self.bot))
if resp is None:
await dropadd.send('RIP this move. Maybe next time.')
@ -1682,7 +1719,7 @@ class Transactions(commands.Cog):
else:
this_q.prompt = 'Who are you dropping to FA?'
this_q.qtype = 'text'
resp = await this_q.ask(dropadd.get_gms(self.bot))
resp = await this_q.ask(await dropadd.get_gms(self.bot))
if resp is None:
await dropadd.send('RIP this move. Maybe next time.')
@ -1762,7 +1799,7 @@ class Transactions(commands.Cog):
for team in dropadd.teams:
this_q.prompt = f'{dropadd.teams[team]["role"].mention}\nWould you like me to run this move?'
this_q.qtype = 'yesno'
resp = await this_q.ask(dropadd.get_gms(self.bot, team))
resp = await this_q.ask(await dropadd.get_gms(self.bot, team))
if not resp:
await dropadd.send('RIP this move. Maybe next time.')
@ -1844,7 +1881,7 @@ class Transactions(commands.Cog):
while True:
prompt = f'Are you sending someone to the IL?'
this_q = Question(self.bot, dropadd.channel, prompt, 'yesno', 300)
resp = await this_q.ask(dropadd.get_gms(self.bot))
resp = await this_q.ask(await dropadd.get_gms(self.bot))
if resp is None:
await dropadd.send('RIP this move. Maybe next time.')
@ -1855,7 +1892,7 @@ class Transactions(commands.Cog):
else:
this_q.prompt = 'Who are you sending to the IL?'
this_q.qtype = 'text'
resp = await this_q.ask(dropadd.get_gms(self.bot))
resp = await this_q.ask(await dropadd.get_gms(self.bot))
if resp is None:
await dropadd.send('RIP this move. Maybe next time.')
@ -1887,7 +1924,7 @@ class Transactions(commands.Cog):
while True and not OFFSEASON_FLAG:
prompt = f'Are you adding someone to the Major League team?'
this_q = Question(self.bot, dropadd.channel, prompt, 'yesno', 300)
resp = await this_q.ask(dropadd.get_gms(self.bot))
resp = await this_q.ask(await dropadd.get_gms(self.bot))
if resp is None:
await dropadd.send('RIP this move. Maybe next time.')
@ -1898,7 +1935,7 @@ class Transactions(commands.Cog):
else:
this_q.prompt = 'Who are you adding?'
this_q.qtype = 'text'
resp = await this_q.ask(dropadd.get_gms(self.bot))
resp = await this_q.ask(await dropadd.get_gms(self.bot))
if resp is None:
await dropadd.send('RIP this move. Maybe next time.')
@ -1929,7 +1966,7 @@ class Transactions(commands.Cog):
while True and not OFFSEASON_FLAG:
prompt = f'Are you adding someone to the Minor League team?'
this_q = Question(self.bot, dropadd.channel, prompt, 'yesno', 300)
resp = await this_q.ask(dropadd.get_gms(self.bot))
resp = await this_q.ask(await dropadd.get_gms(self.bot))
if resp is None:
await dropadd.send('RIP this move. Maybe next time.')
@ -1940,7 +1977,7 @@ class Transactions(commands.Cog):
else:
this_q.prompt = 'Who are you sending to the MiL?'
this_q.qtype = 'text'
resp = await this_q.ask(dropadd.get_gms(self.bot))
resp = await this_q.ask(await dropadd.get_gms(self.bot))
if resp is None:
await dropadd.send('RIP this move. Maybe next time.')
@ -1975,7 +2012,7 @@ class Transactions(commands.Cog):
while True:
prompt = f'Are you dropping anyone to FA?'
this_q = Question(self.bot, dropadd.channel, prompt, 'yesno', 300)
resp = await this_q.ask(dropadd.get_gms(self.bot))
resp = await this_q.ask(await dropadd.get_gms(self.bot))
if resp is None:
await dropadd.send('RIP this move. Maybe next time.')
@ -1986,7 +2023,7 @@ class Transactions(commands.Cog):
else:
this_q.prompt = 'Who are you dropping to FA?'
this_q.qtype = 'text'
resp = await this_q.ask(dropadd.get_gms(self.bot))
resp = await this_q.ask(await dropadd.get_gms(self.bot))
if resp is None:
await dropadd.send('RIP this move. Maybe next time.')
@ -2055,7 +2092,7 @@ class Transactions(commands.Cog):
for team in dropadd.teams:
this_q.prompt = f'{dropadd.teams[team]["role"].mention}\nWould you like me to run this move?'
this_q.qtype = 'yesno'
resp = await this_q.ask(dropadd.get_gms(self.bot, team))
resp = await this_q.ask(await dropadd.get_gms(self.bot, team))
if not resp:
await dropadd.send('RIP this move. Maybe next time.')

View File

@ -14,6 +14,7 @@ import json
import discord
import requests
import aiohttp
from discord.ext import commands
from difflib import get_close_matches
@ -214,9 +215,12 @@ class Question:
def text(mes):
return mes.channel == self.channel and mes.author in responders
logger.info(f'Sending watched message')
await self.channel.send(content=self.prompt, embed=self.embed)
logger.info(f'message is sent')
try:
logger.info(f'waiting for a response')
resp = await self.bot.wait_for(
'message',
timeout=self.timeout,
@ -865,7 +869,7 @@ async def get_player_embed(player, current, ctx=None, season=None):
embed.add_field(name='P Injury', value=f'{player["pitcher_injury"]} (6-{13 - player["pitcher_injury"]})')
else:
embed.add_field(name='P Injury', value=f'{player["pitcher_injury"]} (---)')
if d_query['count'] > 0:
if d_query and d_query.get('count') > 0:
pick = d_query['picks'][0]
num = pick["overall"] % 16
if num == 0:
@ -896,7 +900,7 @@ async def get_player_embed(player, current, ctx=None, season=None):
b_query = await db_get('battingstats/totals', params=[
('season', player['season']), ('player_id', player['id']), ('s_type', 'regular')])
if b_query['count'] > 0:
if b_query and b_query.get('count') > 0:
b = b_query['stats'][0]
if b['ab'] > 0:
@ -927,7 +931,7 @@ async def get_player_embed(player, current, ctx=None, season=None):
p_query = await db_get('pitchingstats/totals', params=[
('season', player['season']), ('player_id', player['id']), ('s_type', 'regular')])
if p_query['count'] > 0:
if p_query and p_query.get('count') > 0:
p = p_query['stats'][0]
if p['ip'] > 0:
@ -967,7 +971,7 @@ async def get_player_embed(player, current, ctx=None, season=None):
batter_priority = True
b, p, batting_string, pitching_string = None, None, None, None
if b_query['count'] > 0:
if b_query and b_query.get('count') > 0:
b = b_query['stats'][0]
batting_string = f'```\n' \
f' AVG OBP SLG\n' \
@ -977,7 +981,7 @@ async def get_player_embed(player, current, ctx=None, season=None):
f' PA H RBI 2B 3B HR SB\n' \
f'{b["pa"]: >3} {b["hit"]: ^3} {b["rbi"]: ^3} {b["double"]: >2} {b["triple"]: >2} ' \
f'{b["hr"]: >2} {b["sb"]: >2}```\n'
if p_query['count'] > 0:
if p_query and p_query.get('count') > 0:
p = p_query['stats'][0]
if b is None or p["tbf"] > b["pa"]:
batter_priority = False
@ -1183,3 +1187,22 @@ def random_from_list(data_list: list):
def get_team_url(this_team):
return f'https://sba.manticorum.com/teams/{this_team["season"]}/{this_team["abbrev"]}'
async def send_owner_notification(message: str):
"""
Send a notification message to the bot owner via Discord webhook.
Args:
message (str): The message content to send
"""
logger = logging.getLogger('discord_app')
try:
async with aiohttp.ClientSession() as session:
webhook_url = "https://discord.com/api/webhooks/1408811717424840876/7RXG_D5IqovA3Jwa9YOobUjVcVMuLc6cQyezABcWuXaHo5Fvz1en10M7J43o3OJ3bzGW"
payload = {
"content": message
}
await session.post(webhook_url, json=payload)
except Exception as webhook_error:
logger.error(f'Failed to send owner notification: {webhook_error}')