#!/usr/bin/python3 import os, time, telebot, asyncio, telebot.async_telebot, nest_asyncio, sys, logging, time from FortniteStatusNotifier import * from Formatter import * from FortniteClient import * from FortniteEvents import * from persistence import UserRepository, StatsRepository, PresenceRepository # Check token in environment variables if "TELEBOT_BOT_TOKEN" not in os.environ: raise AssertionError("Please configure TELEBOT_BOT_TOKEN as environment variables") class ClientInitObserver(ClientInit): async def on_event(self) -> None: # Accept pending friends for friend_request in fortniteClient.incoming_pending_friends: await fortniteClient.event_friend_request(friend_request) # Record user stats if len(statsRepository.getStats()) == 0: await record_user_stats() class FortniteStatusObserver(Observer): async def update(self, fortniteStatus) -> None: await send_message_to_all(formatFortniteStatus(fortniteStatus)) class FortnitePresenceObserver(PresenceObserver): async def update(self, display_name: str, playing: bool, party_size: int) -> None: if playing: last_presence = prensenceRepository.getLastUserPresence(display_name) diff = time.time() - last_presence if diff > 60 * 60: # 60 minutes await self.__notifyFriendPlaying(display_name, party_size) prensenceRepository.setLastUserPresence(display_name, time.time()) async def __notifyFriendPlaying(self, display_name: str, party_size: int): await send_message_to_all(formatFriendOnline(display_name, party_size)) class ExceptionHandler(telebot.ExceptionHandler): def handle(self, exception): logging.error('Exception happened: {}'.format(str(exception))) sys.exit('Exiting with telebot exception') return True bot = telebot.async_telebot.AsyncTeleBot( token=os.environ["TELEBOT_BOT_TOKEN"], exception_handler=ExceptionHandler()) userRepository = UserRepository() statsRepository = StatsRepository() prensenceRepository = PresenceRepository() fortniteStatusWrapper = FortniteStatusNotifier(FortniteStatusObserver()) fortniteClient = FortniteClient(FortnitePresenceObserver(), ClientInitObserver()) @bot.message_handler(commands = ['start']) async def startCommand(message: telebot.types.Message): if message.chat.type == 'private': alias = message.chat.username else: alias = message.chat.title userRepository.putUser(message.chat.id, alias) await reply(message, 'This chat successfully registered to receive Fortnite updates') @bot.message_handler(commands = ['status']) async def getStatus(message): await reply(message, formatFortniteStatus(fortniteStatus.getStatus())) @bot.message_handler(commands = ['friends']) async def getFriends(message): friends = await fortniteClient.get_friends() await reply(message, formatUsers(friends)) @bot.message_handler(commands = ['stats']) async def getStats(message): friends = await fortniteClient.get_friends() stats = [await friend.fetch_stats() for friend in friends] await reply(message, formatUserStatsList(stats)) @bot.message_handler(commands = ['todaystats']) async def getTodayStats(message): persisted_stats = statsRepository.getStats() friends = await fortniteClient.get_friends() current_stats = [await friend.fetch_stats() for friend in friends] await reply(message, formatUserStatsDifference(persisted_stats, current_stats)) @bot.message_handler(commands = ['recordstats']) async def recordStats(message): await record_user_stats() @bot.message_handler(commands = ['online']) async def mockOnline(message): await FortnitePresenceObserver().update('snoopdesigns', True, 1) @bot.message_handler(commands = ['offline']) async def mockOffline(message): await FortnitePresenceObserver().update('snoopdesigns', False, 1) @bot.message_handler(commands = ['find']) async def findUser(message): arg = message.text.split() if len(arg) > 1: search_user_display_name = arg[1] user: User = await fortniteClient.find_user(search_user_display_name) if user is not None: await reply(message, formatUser(user)) else: await reply(message, 'User {} not found'.format(search_user_display_name)) else: await reply(message, 'Usage: /find username') @bot.message_handler(commands = ['add']) async def addUser(message): arg = message.text.split() if len(arg) > 1: user_id = arg[1] await fortniteClient.add_friend(user_id) await reply(message, 'Send friend request successfully') else: await reply(message, 'Usage: /add username') async def send_message_to_all(message_text: str): for user in userRepository.getAllUsers(): try: await bot.send_message( user[0], message_text, parse_mode='MarkdownV2' ) except Exception as error: if 'bot was kicked from the group chat' in str(error): userRepository.removeChat(user[0]) async def reply(message, message_text): await bot.reply_to( message, message_text, parse_mode='MarkdownV2') async def record_user_stats(): print('Recording user stats') friends = await fortniteClient.get_friends() for friend in friends: await statsRepository.putStats(friend) async def run_tgbot(): await bot.polling() async def run_fortniteStatusWrapper(): await fortniteStatusWrapper.run() async def run_fortniteClient(): fortniteClient.run() async def run_record_stats(): while True: t = time.localtime() if t.tm_hour == 5: # only at 05:00 await record_user_stats() await asyncio.sleep(60 * 60) # 1 hour async def run_all(): await asyncio.gather(run_tgbot(), run_fortniteStatusWrapper(), run_fortniteClient(), run_record_stats()) if __name__ == '__main__': nest_asyncio.apply() loop = asyncio.get_event_loop() loop.run_until_complete(run_all()) loop.close()