Skip to content

Commit 18fe787

Browse files
Merge pull request #319 from RemainingDelta/312-Feature
312-Feature add monthly tournament reports, auto-detect Matcherino ID on start, and archive reports to dedicated channel
2 parents ed7f8fc + d47690c commit 18fe787

5 files changed

Lines changed: 664 additions & 22 deletions

File tree

features/config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
TOURNEY_SUPPORT_CHANNEL_ID = 1442037795987259464
2121
PRE_TOURNEY_SUPPORT_CHANNEL_ID = 1448917516071207133
2222
TOURNEY_ADMIN_CHANNEL_ID = 724835692395626516
23+
TOURNEY_REPORT_CHANNEL_ID = 1516162989374570689
24+
TOURNEY_SCHEDULE_CHANNEL_ID = 754927753643688046
2325
SPANISH_CHANNEL_ID = 1052348820513636463
2426

2527
TOURNEY_ADMIN_ROLE_ID = 1160989152381251756
@@ -200,6 +202,8 @@
200202
TOURNEY_SUPPORT_CHANNEL_ID = 1448916985713791000
201203
PRE_TOURNEY_SUPPORT_CHANNEL_ID = 1448917121743716485
202204
TOURNEY_ADMIN_CHANNEL_ID = 1452338842798526514
205+
TOURNEY_REPORT_CHANNEL_ID = 1516169206553509919
206+
TOURNEY_SCHEDULE_CHANNEL_ID = 1516186562478735400
203207
SPANISH_CHANNEL_ID = 1477148473710084127
204208

205209
TOURNEY_ADMIN_ROLE_ID = 1442028161889079469

features/tourney/tourney_commands.py

Lines changed: 127 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@
6060
HALL_OF_FAME_CHANNEL_ID,
6161
BOT_VERSION,
6262
TOURNEY_ADMIN_ROLE_ID,
63+
TOURNEY_REPORT_CHANNEL_ID,
64+
TOURNEY_SCHEDULE_CHANNEL_ID,
6365
)
6466
from .tourney_utils import (
6567
close_ticket_via_command,
@@ -1340,6 +1342,61 @@ async def start_tourney_command(ctx: commands.Context, region: str = None):
13401342
else:
13411343
await reset_tourney_session_start_time(existing_session["_id"])
13421344

1345+
# Auto-detect Matcherino ID from #tourney-schedule (±1 day of today)
1346+
auto_matcherino_id = None
1347+
auto_detect_error = None
1348+
schedule_channel = ctx.bot.get_channel(TOURNEY_SCHEDULE_CHANNEL_ID)
1349+
if not schedule_channel:
1350+
auto_detect_error = "⚠️ Auto-detect: `TOURNEY_SCHEDULE_CHANNEL_ID` not found — check `config.py`."
1351+
else:
1352+
today = datetime.datetime.now(datetime.timezone.utc).date()
1353+
msgs_checked = 0
1354+
closest_date_seen = None
1355+
try:
1356+
async for msg in schedule_channel.history(limit=100):
1357+
content = msg.content or ""
1358+
date_match = re.search(
1359+
r"•\s*\**\s*Date:\**\s*(.+)", content, re.IGNORECASE
1360+
)
1361+
if not date_match:
1362+
continue
1363+
msgs_checked += 1
1364+
date_str = date_match.group(1).strip()
1365+
try:
1366+
parsed_date = datetime.datetime.strptime(
1367+
date_str, "%B %d, %Y"
1368+
).date()
1369+
except ValueError:
1370+
auto_detect_error = f"⚠️ Auto-detect: Found a date but couldn't parse it: `{date_str}` — expected format `June 19, 2026`."
1371+
continue
1372+
closest_date_seen = parsed_date
1373+
if abs((parsed_date - today).days) <= 1:
1374+
url_match = re.search(
1375+
r"matcherino\.com/supercell/tournaments/(\d+)", content
1376+
)
1377+
if url_match:
1378+
auto_matcherino_id = url_match.group(1)
1379+
break
1380+
else:
1381+
auto_detect_error = f"⚠️ Auto-detect: Found the schedule post for `{date_str}` but no Matcherino URL in the message."
1382+
break
1383+
1384+
if not auto_matcherino_id and not auto_detect_error:
1385+
if msgs_checked == 0:
1386+
auto_detect_error = f"⚠️ Auto-detect: No messages with a `• Date:` field found in <#{TOURNEY_SCHEDULE_CHANNEL_ID}>."
1387+
else:
1388+
auto_detect_error = (
1389+
f"⚠️ Auto-detect: No schedule post within ±1 day of today ({today.strftime('%B %d, %Y')}). "
1390+
f"Closest date found: `{closest_date_seen.strftime('%B %d, %Y') if closest_date_seen else 'none'}`."
1391+
)
1392+
except Exception as e:
1393+
auto_detect_error = f"⚠️ Auto-detect error: `{e}`"
1394+
1395+
if auto_matcherino_id:
1396+
active_session = await get_active_tourney_session()
1397+
if active_session:
1398+
await update_matcherino_id(active_session["_id"], auto_matcherino_id)
1399+
13431400
await lock_command(ctx)
13441401

13451402
# --- SA REGION LOGIC ---
@@ -1479,8 +1536,16 @@ async def start_tourney_command(ctx: commands.Context, region: str = None):
14791536
except Exception as e:
14801537
print(f"Failed to delete pre-tourney ticket {ch.name}: {e}")
14811538

1539+
if auto_matcherino_id:
1540+
matcherino_notice = f"🔗 Matcherino ID auto-set to `{auto_matcherino_id}` from the schedule. If wrong, use `/set-matcherino` to fix it."
1541+
else:
1542+
matcherino_notice = (
1543+
auto_detect_error
1544+
or "⚠️ Could not auto-detect Matcherino ID. Set it manually with `/set-matcherino`."
1545+
)
1546+
14821547
await ctx.send(
1483-
f"✅ Tourney Started! Channels updated and {deleted_count} pre-tourney tickets deleted.\n⚠️ Don't forget to set the new Matcherino ID with `/set-matcherino` and enable ML data collection if needed."
1548+
f"✅ Tourney Started! Channels updated and {deleted_count} pre-tourney tickets deleted.\n{matcherino_notice}"
14841549
)
14851550

14861551
# Grant Tourney Admin the Timeout Members permission for the duration of the tourney.
@@ -1529,8 +1594,6 @@ async def _rename_admin_role():
15291594
"hype_message_id": None,
15301595
},
15311596
}
1532-
await dashboard_cog.start_dashboard()
1533-
15341597
# Apply 60s slow mode to general channel during tourney.
15351598
general_channel = guild.get_channel(GENERAL_CHANNEL_ID)
15361599
if isinstance(general_channel, discord.TextChannel):
@@ -1542,6 +1605,11 @@ async def _rename_admin_role():
15421605
except Exception as e:
15431606
print(f"Failed to set slow mode on general channel: {e}")
15441607

1608+
# Start dashboard last so it's the final message in #tourney-admin,
1609+
# preventing an immediate delete+repost flash on the first 5-minute tick.
1610+
if dashboard_cog:
1611+
await dashboard_cog.start_dashboard()
1612+
15451613
@bot.command(name="endtourney")
15461614
async def end_tourney_command(ctx: commands.Context):
15471615
"""
@@ -1588,13 +1656,6 @@ async def end_tourney_command(ctx: commands.Context):
15881656
except Exception as e:
15891657
print(f"!endtourney announcement sync error: {e}")
15901658

1591-
# Do a final progress dashboard refresh before stopping so it shows Tournament Over.
1592-
if dashboard_cog:
1593-
try:
1594-
await dashboard_cog.update_progress_dashboard()
1595-
except Exception as e:
1596-
print(f"!endtourney final progress update error: {e}")
1597-
15981659
winner_was_posted = (
15991660
dashboard_cog is not None
16001661
and dashboard_cog._winner_announcement_state.get("winner") is not None
@@ -1684,16 +1745,55 @@ async def _retry_winner_post():
16841745
icon = f"**{i + 1}.**" # e.g. "4.", "5.", "6."
16851746

16861747
staff_msg += (
1687-
f"{icon} **{s['username']}**: {s['tickets_closed']} tickets\n"
1748+
f"{icon} <@{s['user_id']}>: {s['tickets_closed']} tickets\n"
16881749
)
16891750

16901751
if not staff_msg:
16911752
staff_msg = "No tickets closed."
16921753

1693-
# 3. Send Embed
1694-
stat_embed = discord.Embed(
1695-
title="📊 Tournament Report", color=discord.Color.gold()
1696-
)
1754+
# 3. Look up tournament name (Matcherino API) and canonical date (#tourney-schedule)
1755+
tourney_date_str = None
1756+
tourney_name = None
1757+
matcherino_id = session.get("matcherino_id")
1758+
if matcherino_id:
1759+
try:
1760+
payout_data = fetch_payout_report(str(matcherino_id))
1761+
if "error" not in payout_data:
1762+
tourney_name = payout_data.get("tourney_name")
1763+
except Exception as e:
1764+
print(f"⚠️ Could not fetch tourney name from Matcherino: {e}")
1765+
1766+
ann_channel = ctx.bot.get_channel(TOURNEY_SCHEDULE_CHANNEL_ID)
1767+
if ann_channel:
1768+
try:
1769+
async for msg in ann_channel.history(limit=500):
1770+
if str(matcherino_id) in (msg.content or ""):
1771+
m = re.search(
1772+
r"•\s*\**\s*Date:\**\s*(.+)",
1773+
msg.content,
1774+
re.IGNORECASE,
1775+
)
1776+
if m:
1777+
tourney_date_str = m.group(1).strip()
1778+
break
1779+
except Exception as e:
1780+
print(f"⚠️ Could not look up tourney date from schedule: {e}")
1781+
1782+
# 4. Build Embed
1783+
if tourney_name and matcherino_id:
1784+
matcherino_url = (
1785+
f"https://matcherino.com/supercell/tournaments/{matcherino_id}"
1786+
)
1787+
stat_embed = discord.Embed(
1788+
title=f"📊 Tournament Report ({tourney_name})",
1789+
url=matcherino_url,
1790+
color=discord.Color.gold(),
1791+
)
1792+
else:
1793+
stat_embed = discord.Embed(
1794+
title="📊 Tournament Report",
1795+
color=discord.Color.gold(),
1796+
)
16971797
stat_embed.add_field(
16981798
name="⏱️ Duration", value=f"`{hours}h {minutes}m`", inline=True
16991799
)
@@ -1715,15 +1815,20 @@ async def _retry_winner_post():
17151815
stat_embed.add_field(
17161816
name="🏆 Top Tourney Admins", value=staff_msg, inline=False
17171817
)
1818+
if tourney_date_str:
1819+
stat_embed.add_field(
1820+
name="📅 Tournament Date", value=tourney_date_str, inline=False
1821+
)
1822+
if matcherino_id:
1823+
stat_embed.set_footer(text=f"Matcherino ID: {matcherino_id}")
17181824

1719-
report_msg = await ctx.send(embed=stat_embed)
1720-
1721-
try:
1722-
await report_msg.pin()
1723-
except Exception as e:
1724-
print(f"⚠️ Could not pin report: {e}")
1825+
# 5. Send to command channel (no pin) and archive to #tourney-reports
1826+
await ctx.send(embed=stat_embed)
1827+
report_channel = ctx.bot.get_channel(TOURNEY_REPORT_CHANNEL_ID)
1828+
if report_channel:
1829+
await report_channel.send(embed=stat_embed)
17251830

1726-
# 4. Close Session in DB
1831+
# 6. Close Session in DB
17271832
await end_tourney_session(session["_id"])
17281833
await set_tourney_collect_data(session["_id"], False)
17291834
clear_bracket_teams_cache()

0 commit comments

Comments
 (0)