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)
6466from .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