add lastYear_or_1000games
This commit is contained in:
parent
7232a8d304
commit
3226d4c162
3 changed files with 92 additions and 1 deletions
|
|
@ -21,6 +21,7 @@ from formatters import StatsFormatter
|
||||||
from i18n import t
|
from i18n import t
|
||||||
from admin_bot import get_admin_bot, init_admin_bot
|
from admin_bot import get_admin_bot, init_admin_bot
|
||||||
from message_counters import MessageCounters
|
from message_counters import MessageCounters
|
||||||
|
import time
|
||||||
|
|
||||||
# Configure logging
|
# Configure logging
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
|
|
@ -624,6 +625,32 @@ class LichessBot:
|
||||||
"""Week command"""
|
"""Week command"""
|
||||||
await self.get_stats(update, context, "week")
|
await self.get_stats(update, context, "week")
|
||||||
|
|
||||||
|
async def last_year_or_1000games(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
|
"""Get last year stats or last 1000 rated games, whichever limits first"""
|
||||||
|
user_id = update.effective_user.id
|
||||||
|
active_gamer = self.db.get_user_active_gamer(user_id)
|
||||||
|
lang = self.get_user_language_from_update(update)
|
||||||
|
if not active_gamer:
|
||||||
|
await update.message.reply_text(
|
||||||
|
t('no_active_gamer', lang)
|
||||||
|
)
|
||||||
|
return
|
||||||
|
username = active_gamer['username']
|
||||||
|
now_ms = int(time.time() * 1000)
|
||||||
|
year_ms = 365 * 24 * 3600 * 1000
|
||||||
|
since_ms = now_ms - year_ms
|
||||||
|
try:
|
||||||
|
data = await self.lichess_api.get_games_period(username, since_ms, now_ms, rated_only=True)
|
||||||
|
if not data:
|
||||||
|
await update.message.reply_text(t('no_data', lang))
|
||||||
|
return
|
||||||
|
text = StatsFormatter.format_last_year_or_1000(data, username, lang)
|
||||||
|
await update.message.reply_text(text)
|
||||||
|
self.counters.increment('last_year_1000')
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"/lastYear_or_1000games error: {e}")
|
||||||
|
await update.message.reply_text(f"Error: {e}")
|
||||||
|
|
||||||
async def setperiod(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
async def setperiod(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
"""Set period command"""
|
"""Set period command"""
|
||||||
user_id = update.effective_user.id
|
user_id = update.effective_user.id
|
||||||
|
|
@ -906,6 +933,7 @@ class LichessBot:
|
||||||
application.add_handler(CommandHandler("today", self.today))
|
application.add_handler(CommandHandler("today", self.today))
|
||||||
application.add_handler(CommandHandler("yesterday", self.yesterday))
|
application.add_handler(CommandHandler("yesterday", self.yesterday))
|
||||||
application.add_handler(CommandHandler("week", self.week))
|
application.add_handler(CommandHandler("week", self.week))
|
||||||
|
application.add_handler(CommandHandler("lastYear_or_1000games", self.last_year_or_1000games))
|
||||||
application.add_handler(CommandHandler("setperiod", self.setperiod))
|
application.add_handler(CommandHandler("setperiod", self.setperiod))
|
||||||
application.add_handler(CommandHandler("lang", self.check_language))
|
application.add_handler(CommandHandler("lang", self.check_language))
|
||||||
application.add_handler(CommandHandler("resetlang", self.reset_language))
|
application.add_handler(CommandHandler("resetlang", self.reset_language))
|
||||||
|
|
|
||||||
|
|
@ -169,3 +169,64 @@ class StatsFormatter:
|
||||||
result += t('no_activity', lang)
|
result += t('no_activity', lang)
|
||||||
|
|
||||||
return result.rstrip()
|
return result.rstrip()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def format_last_year_or_1000(data: Dict[str, Any], username: str, lang: str = 'en') -> str:
|
||||||
|
"""
|
||||||
|
Format response for last year or last 1000 games.
|
||||||
|
Expects GamesOfPeriodResponse-like payload.
|
||||||
|
"""
|
||||||
|
if not data:
|
||||||
|
return "📭 No data"
|
||||||
|
games_count = data.get('games_count', 0)
|
||||||
|
period_start = data.get('period_start')
|
||||||
|
period_end = data.get('period_end')
|
||||||
|
stats = (data.get('data') or {})
|
||||||
|
# Title and subheader
|
||||||
|
if games_count >= 1000:
|
||||||
|
header = f"📈 {username}: last 1000 rated games"
|
||||||
|
# Use period_start as earliest known bound (server does not expose earliest game timestamp)
|
||||||
|
if isinstance(period_start, int):
|
||||||
|
earliest = datetime.fromtimestamp(period_start).strftime("%d.%m.%Y")
|
||||||
|
header += f"\nНачало этих 1000 партий: {earliest}"
|
||||||
|
else:
|
||||||
|
header = f"📈 {username}: last year (rated), games: {games_count}"
|
||||||
|
if isinstance(period_start, int) and isinstance(period_end, int):
|
||||||
|
start_str = datetime.fromtimestamp(period_start).strftime("%d.%m.%Y")
|
||||||
|
end_str = datetime.fromtimestamp(period_end).strftime("%d.%m.%Y")
|
||||||
|
header += f"\nПериод: {start_str}–{end_str}"
|
||||||
|
# Body per mode
|
||||||
|
lines = []
|
||||||
|
for mode in ["bullet", "blitz", "rapid", "classical", "correspondence"]:
|
||||||
|
mode_stats = stats.get(mode)
|
||||||
|
if not mode_stats:
|
||||||
|
continue
|
||||||
|
games_played = mode_stats.get('games_played', 0)
|
||||||
|
if games_played == 0:
|
||||||
|
continue
|
||||||
|
emoji = StatsFormatter._get_game_type_emoji(mode)
|
||||||
|
wins = mode_stats.get('wins', 0)
|
||||||
|
losses = mode_stats.get('losses', 0)
|
||||||
|
draws = mode_stats.get('draws', 0)
|
||||||
|
rating_change = mode_stats.get('rating_change', 0)
|
||||||
|
rating_change_str = StatsFormatter._format_rating_change(rating_change)
|
||||||
|
rating = mode_stats.get('rating')
|
||||||
|
rating_str = rating if rating is not None else "—"
|
||||||
|
lines.append(
|
||||||
|
f"{emoji} {mode.title()}: {games_played} Δ {rating_change_str} R {rating_str} (+{wins} -{losses} ={draws})"
|
||||||
|
)
|
||||||
|
# Total
|
||||||
|
total = stats.get('total') or {}
|
||||||
|
total_line = ""
|
||||||
|
if total:
|
||||||
|
tg = total.get('games_played', 0)
|
||||||
|
tw = total.get('wins', 0)
|
||||||
|
tl = total.get('losses', 0)
|
||||||
|
td = total.get('draws', 0)
|
||||||
|
trc = total.get('rating_change', 0)
|
||||||
|
trc_str = StatsFormatter._format_rating_change(trc)
|
||||||
|
tr = total.get('rating')
|
||||||
|
tr_str = tr if tr is not None else "—"
|
||||||
|
total_line = f"\nИтого: {tg} Δ {trc_str} R {tr_str} (+{tw} -{tl} ={td})"
|
||||||
|
body = "\n".join(lines) + total_line
|
||||||
|
return f"{header}\n{body}".rstrip()
|
||||||
|
|
|
||||||
|
|
@ -77,11 +77,13 @@ class LichessAPI:
|
||||||
logger.error(f"Error getting week stats: {e}")
|
logger.error(f"Error getting week stats: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def get_games_period(self, username: str, since: int, until: int) -> Optional[Dict[str, Any]]:
|
async def get_games_period(self, username: str, since: int, until: int, rated_only: Optional[bool] = None) -> Optional[Dict[str, Any]]:
|
||||||
"""Get games for a specific period"""
|
"""Get games for a specific period"""
|
||||||
try:
|
try:
|
||||||
url = f"{self.stats_base_url}/games/{username}/period"
|
url = f"{self.stats_base_url}/games/{username}/period"
|
||||||
params = {"since": since, "until": until}
|
params = {"since": since, "until": until}
|
||||||
|
if rated_only is not None:
|
||||||
|
params["rated_only"] = "true" if rated_only else "false"
|
||||||
logger.info(f"🔍 LichessAPI.get_games_period: URL={url}, params={params}")
|
logger.info(f"🔍 LichessAPI.get_games_period: URL={url}, params={params}")
|
||||||
|
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue