feat(bot.py, dota.py, utils.py): 增加查询某人战绩的命令

增加查询某人战绩的命令

Signed-off-by: Ching <loooching@gmail.com>
This commit is contained in:
Ching 2023-09-18 16:55:24 +08:00
parent 233fa91b5b
commit cd1fc45044
3 changed files with 115 additions and 14 deletions

View File

@ -40,6 +40,18 @@ async def send_message(channel):
logger.info(f"sending match {match_['match_id']}, {data}") logger.info(f"sending match {match_['match_id']}, {data}")
await channel.send(content=data['content'], embeds=[discord.Embed.from_dict(embed) for embed in data['embeds']]) await channel.send(content=data['content'], embeds=[discord.Embed.from_dict(embed) for embed in data['embeds']])
@bot.command(description="获取最近战绩", name='recent_matches') # this decorator makes a slash command
async def get_friends_recent_matches(ctx, name, match_count=5): # a slash command will be created with the name "ping"
logger.info(f"get_friends_recent_matches {name} {match_count}")
friends = dota.Friend.filter(name=name)
match_count = int(match_count)
if friends.count() == 0:
await ctx.respond(content=f'找不到 {name} 的信息')
return
data = dota.Friend.serialize_recent_matches_for_discord(friends, match_count)
await ctx.respond(content=data['content'], embeds=[discord.Embed.from_dict(embed) for embed in data['embeds']])
@tasks.loop(minutes=1) @tasks.loop(minutes=1)
async def heartbeat(): async def heartbeat():
utils.heartbeat() utils.heartbeat()

81
dota.py
View File

@ -75,13 +75,77 @@ class Friend(BaseModel):
steam_id = peewee.IntegerField(primary_key=True) steam_id = peewee.IntegerField(primary_key=True)
name = peewee.CharField() name = peewee.CharField()
def get_recent_matches(self): def get_recent_matches(self, limit=1):
try: try:
return player_client.get_players_by_account_id_select_matches(self.steam_id, limit=1) return player_client.get_players_by_account_id_select_matches(self.steam_id, limit=limit)
except: except:
logger.error('fail to get player %s recent matches' % self.steam_id) logger.error('fail to get player %s recent matches' % self.steam_id)
return [] return []
def serialize_recent_matches(self, limit=1):
matches = self.get_recent_matches(limit=limit)
data = []
for match_ in matches:
data.append({
'match_id': match_.match_id,
'win': match_.radiant_win == (match_.player_slot < 128),
'is_radiant': match_.player_slot < 128,
'kills': match_.kills,
'deaths': match_.deaths,
'assists': match_.assists,
'party_size': match_.party_size,
'start_time': match_.start_time,
'duration': match_.duration,
'average_rank': utils.get_ranking(match_.average_rank),
'hero_id': match_.hero_id,
})
return data
@classmethod
def serialize_recent_matches_for_discord(cls, friends, limit=5):
# {
# "content": "## 水哥的战报\n",
# "embeds": [
# {
# "description": "3黑 00:34:23",
# "fields": [],
# "title": "2 杀 5 死 3 助 ",
# "color": 6732650,
# "url": "https://www.opendota.com/matches/7335993790",
# "timestamp": "2023-09-12T16:00:00.000Z"
# }
# ],
# }
matches = []
if limit > 10:
limit = 10
for friend in friends:
matches.extend(friend.serialize_recent_matches(limit=limit))
# sort matches by start_time from latest to oldest
matches.sort(key=lambda x: x['start_time'], reverse=True)
name = friends[0].name
data = {
'content': f'## {name}的战报',
'embeds': [],
}
for match_ in matches[:limit]:
duration = '%d:%02d:%02d' % utils.convert_seconds_to_hms(match_['duration'])
if match_['party_size'] > 1:
summary = f"{match_['party_size']}{duration}"
else:
summary = f"单排 {duration}"
start_time = datetime.datetime.fromtimestamp(match_['start_time']).strftime('%Y-%m-%dT%H:%M:%S.000+08:00')
hero_name = Hero.get(hero_id=match_['hero_id']).localized_name
data['embeds'].append({
'title': f"{hero_name} {match_['kills']}{match_['deaths']}{match_['assists']}",
'description': summary + '\n' + match_['average_rank'],
'color': 6732650 if match_['win'] else 16724787, # 66bb6a or FF3333
'fields': [],
'timestamp': start_time,
'url': f"https://www.opendota.com/matches/{match_['match_id']}",
})
return data
def get_friends_recent_matches(): def get_friends_recent_matches():
matches = [] matches = []
@ -98,17 +162,6 @@ def get_friends_recent_matches():
matches.append(match_obj.serialize_match()) matches.append(match_obj.serialize_match())
return matches return matches
def shorten_digits(num):
# if num like 12345, return 1.2w
# if num like 1234, return 1.2k
# if num < 1000, return num
# if result ends with 0, remove it
if num >= 10000:
return '%.1fw' % (num / 10000)
elif num >= 1000:
return '%.1fk' % (num / 1000)
else:
return str(num)
def serialize_match_for_discord(match_): def serialize_match_for_discord(match_):
# { # {
@ -171,7 +224,7 @@ def serialize_match_for_discord(match_):
dire_highest_damage_idx = 0 dire_highest_damage_idx = 0
for player in match_['players']: for player in match_['players']:
desc = f"{player['nickname'] or player['personaname']}Lv.**{player['level']}** {player['hero']} **{player['kills']}** 杀 **{player['deaths']}** 死 **{player['assists']}** 助 **{shorten_digits(player['total_gold'])}** 经济 **{shorten_digits(player['hero_damage'])}** 伤害 " desc = f"{player['nickname'] or player['personaname']}Lv.**{player['level']}** {player['hero']} **{player['kills']}** 杀 **{player['deaths']}** 死 **{player['assists']}** 助 **{utils.shorten_digits(player['total_gold'])}** 经济 **{utils.shorten_digits(player['hero_damage'])}** 伤害 "
if player['is_radiant']: if player['is_radiant']:
radiant.append(desc) radiant.append(desc)

View File

@ -30,3 +30,39 @@ def heartbeat():
except: except:
logger.error('fail to heartbeat, resp status: %s' % resp.status_code) logger.error('fail to heartbeat, resp status: %s' % resp.status_code)
pass pass
def get_ranking(ranking_int):
# (10-15: Herald, 20-25: Guardian, 30-35: Crusader, 40-45: Archon, 50-55: Legend, 60-65: Ancient, 70-75: Divine, 80-85: Immortal).
stars = ranking_int % 10
if ranking_int < 20:
return '先锋 %s' % stars
elif ranking_int < 30:
return '卫士 %s' % stars
elif ranking_int < 40:
return '中军 %s' % stars
elif ranking_int < 50:
return '统帅 %s' % stars
elif ranking_int < 60:
return '传奇 %s' % stars
elif ranking_int < 70:
return '万古流芳 %s' % stars
elif ranking_int < 80:
return '超凡入圣 %s' % stars
elif ranking_int < 90:
return '不朽 %s' % stars
else:
return 'Unknown %s' % stars
def shorten_digits(num):
# if num like 12345, return 1.2w
# if num like 1234, return 1.2k
# if num < 1000, return num
# if result ends with 0, remove it
if num >= 10000:
return '%.1fw' % (num / 10000)
elif num >= 1000:
return '%.1fk' % (num / 1000)
else:
return str(num)