feat: Add daily rank tracking for Discord friends TUN-143
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Ching L 2025-03-07 11:22:40 +08:00
parent ed0a0c3f79
commit dfaa0720ee
2 changed files with 80 additions and 0 deletions

View File

@ -7,6 +7,8 @@ import utils
import sentry_sdk
import datetime
sentry_sdk.init(
dsn="https://272f1e4ecb3847ac8d24be796515e558@o4506942768021504.ingest.us.sentry.io/4506986058743808",
)
@ -127,10 +129,36 @@ async def activate_friend(ctx, steam_id):
async def heartbeat():
utils.heartbeat()
@tasks.loop(hours=24)
async def check_rank_changes(channel):
logger.info("Checking for rank changes")
try:
data = await dota.check_rank_changes_for_discord()
if data:
logger.info(f"Sending rank changes: {data}")
await channel.send(content=data['content'], embeds=[discord.Embed.from_dict(embed) for embed in data['embeds']])
except Exception as e:
logger.error(f"Error checking rank changes: {e}")
sentry_sdk.capture_exception(e)
@bot.event
async def on_ready():
channel = bot.get_channel(channel_id)
send_message.start(channel)
heartbeat.start()
# Start the rank check task and make it run at a specific time (e.g., noon)
check_rank_changes.start(channel)
# Calculate time until next noon
now = datetime.datetime.now()
target_time = now.replace(hour=21, minute=0, second=0, microsecond=0)
if now >= target_time:
target_time = target_time + datetime.timedelta(days=1)
# Adjust first run to happen at noon
seconds_until_target = (target_time - now).total_seconds()
check_rank_changes.change_interval(hours=24)
check_rank_changes.next_iteration = discord.utils.utcnow() + datetime.timedelta(seconds=seconds_until_target)
bot.run('MTE1MjE2NTc3NDMwNDIyMzI2Mg.GEi-17.VvuIkRy_cFD9XF6wtTagY95LKEbTxKaxy-FxGw') # 这里替换成你自己的 token

52
dota.py
View File

@ -90,6 +90,7 @@ class Friend(BaseModel):
steam_id = peewee.IntegerField(primary_key=True)
name = peewee.CharField()
active = peewee.BooleanField(default=True)
rank_tier = peewee.IntegerField(null=True)
def get_recent_matches(self, limit=1):
try:
@ -98,6 +99,20 @@ class Friend(BaseModel):
logger.error('fail to get player %s recent matches. error: %s' % (self.steam_id, e))
return []
def update_rank_tier(self):
"""Update player's rank tier from OpenDota API"""
try:
player_info = player_client.get_players_by_account_id(self.steam_id)
if player_info and hasattr(player_info, 'rank_tier') and player_info.rank_tier:
old_rank_tier = self.rank_tier
self.rank_tier = player_info.rank_tier
self.save()
return old_rank_tier != self.rank_tier, old_rank_tier
return False, None
except Exception as e:
logger.error(f'Failed to update rank tier for player {self.steam_id}. Error: {e}')
return False, None
def serialize_recent_matches(self, limit=1):
matches = self.get_recent_matches(limit=limit)
data = []
@ -369,3 +384,40 @@ async def serialize_match_for_discord(match_):
}
return data
async def check_rank_changes_for_discord():
"""Check for rank changes among all active friends and format for Discord"""
rank_changes = []
for friend in Friend.filter(active=True):
changed, old_rank_tier = friend.update_rank_tier()
if changed and friend.rank_tier is not None:
old_rank = utils.get_ranking(old_rank_tier) if old_rank_tier else "未校准"
new_rank = utils.get_ranking(friend.rank_tier)
rank_changes.append({
'name': friend.name,
'old_rank': old_rank,
'new_rank': new_rank,
'increased': friend.rank_tier > (old_rank_tier or 0)
})
if not rank_changes:
return None
data = {
'content': '## 天梯更新',
'embeds': []
}
for change in rank_changes:
direction = "⬆️ 上升" if change['increased'] else "⬇️ 下降"
color = 6732650 if change['increased'] else 16724787 # Green if increased, red if decreased
data['embeds'].append({
'title': f"{change['name']} 的天梯等级变化",
'description': f"{direction}{change['old_rank']}{change['new_rank']}",
'color': color
})
return data