#M i d g a 3
#meta developer: @midga3_modules
# scope: heroku_min 2.0.0
import srcomapi, srcomapi.datatypes as dt
import logging
from .. import loader, utils
from herokutl.tl.types import Message
__verison__ = (1, 1, 0)
logger = logging.getLogger(__name__)
@loader.tds
class speedruncom(loader.Module):
strings = {
"name": "Speedruns",
"searching": "🔍Searching...",
"game": "👾 Game: {}\n🎮 Number of runs: {}. \n 🏆Top runs: \n{}",
"not_found": "❌Not found, sry",
"new_notify": "You got a new notification: {}",
"token": "Token of sppedrun.com",
}
async def client_ready(self):
self.asset_channel = self._db.get("heroku.forums", "channel_id", 0)
self._notif_topic = await utils.asset_forum_topic(
self._client,
self._db,
self.asset_channel,
"speedrun.com",
description="Here will be notifications from speedrun.com.\nRequries token(change in cfg)",
icon_emoji_id=5345892905103932200,
)
def __init__(self):
self.config = loader.ModuleConfig(
loader.ConfigValue(
"token",
None,
lambda: self.strings("token"),
),
loader.ConfigValue(
"show_all_15",
False,
"Show all 15 runs on one page",
validator=loader.validators.Boolean(),
),
)
self.api = srcomapi.SpeedrunCom(self.config['token']); self.api.debug = 1
utils.register_placeholder("notifications", self.ph, "Number of notifications on speedrun.com")
async def ph(self):
return len(self._db.get("speedrun", "unread_ids", default=[]))
@loader.loop(interval=60, autostart=True)
async def poller(self):
if self.config['token'] is None:
return
else:
self.api = srcomapi.SpeedrunCom(self.config['token']); self.api.debug = 1
data = self.api.get("notifications")
unread = [n for n in data if n.get('status') == 'unread']
unread_ids = [n.get('id') for n in unread if n.get('id')]
saved_ids = self._db.get("speedrun", "unread_ids", default=[])
new_ids = [uid for uid in unread_ids if uid not in saved_ids]
self._db.set("speedrun", "unread_ids", unread_ids)
new_notifications = [n for n in unread if n.get('id') in new_ids]
for notification in new_notifications:
uri = None
if 'item' in notification and notification['item'].get('uri'):
uri = notification['item']['uri']
keyboard = None
if uri:
keyboard = {
"inline_keyboard": [
[{"text": "🔗 Link", "url": uri}]
]
}
await self.inline.bot.send_message(
int(f"-100{self.asset_channel}"),
self.strings['new_notify'].format(notification.get('text')),
disable_webpage_preview=True,
message_thread_id=self._notif_topic.id,
reply_markup=keyboard
)
def _game_nav(self, pages, index):
if len(pages) <= 1:
return None
buttons = []
if index > 0:
buttons.append({"text": "◀️", "callback": self._game_page, "args": (pages, index - 1)})
buttons.append({"text": f"{index + 1}/{len(pages)}", "callback": self._game_page, "args": (pages, index)})
if index < len(pages) - 1:
buttons.append({"text": "▶️", "callback": self._game_page, "args": (pages, index + 1)})
return [buttons]
async def _game_page(self, call, pages, index):
await call.edit(pages[index], reply_markup=self._game_nav(pages, index))
@loader.command()
async def game(self, message: Message):
args = utils.get_args_raw(message)
game = self.api.search(srcomapi.datatypes.Game, {"name": f"{args}"})[0]
await message.edit(self.strings['searching'])
try:
new_game_name = game.name
runs_data = self.api.get(f"runs?game={game.id}")
runs = runs_data['data'] if isinstance(runs_data, dict) and 'data' in runs_data else runs_data
top_fifteen = runs[:15] if runs else []
except Exception as e:
logger.error(f"Error: {e}")
await message.edit(self.strings['not_found'])
return
if not top_fifteen:
await message.edit(self.strings['not_found'])
return
pages = []
step = 15 if self.config["show_all_15"] else 5
for page_start in range(0, len(top_fifteen), step):
chunk = top_fifteen[page_start:page_start + step]
lines = []
for index, run in enumerate(chunk, start=page_start + 1):
if not run:
continue
player_id = run['players'][0]['id'] if 'players' in run and run['players'] else "Unknown"
player_name = self.api.get_user(str(player_id)).name
run_time = run['times']['realtime_t'] if 'times' in run else 0
video_url = run['videos']['links'][0]['uri'] if 'videos' in run and 'links' in run['videos'] and run['videos']['links'] else None
if video_url:
player_link = f'{player_name}'
else:
player_link = player_name
lines.append(f"{index}. {player_link} - {run_time}s")
runs_text = "
" + "\n".join(lines) + "
"
pages.append(self.strings['game'].format(new_game_name, len(runs), runs_text))
await self.inline.form(
message=message,
text=pages[0],
reply_markup=self._game_nav(pages, 0)
)