discord_bot.py 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import asyncio
  2. import aiohttp
  3. import os
  4. import threading
  5. from configparser import ConfigParser
  6. import discord
  7. import zwift_offline
  8. class DiscordBot(discord.Client):
  9. def __init__(self, intents, channel, welcome_msg, help_msg, announce):
  10. discord.Client.__init__(self, intents=intents)
  11. self.channel_id = channel
  12. self.welcome_msg = welcome_msg
  13. self.help_msg = help_msg
  14. self.announce = announce
  15. async def on_ready(self):
  16. self.channel = self.get_channel(self.channel_id)
  17. async def on_member_join(self, member):
  18. if self.welcome_msg:
  19. await self.channel.send('%s\n%s' % (member.mention, self.welcome_msg))
  20. async def on_message(self, message):
  21. if message.author.id == self.user.id:
  22. return
  23. if message.content == '!online':
  24. await message.channel.send('%s riders online' % len(zwift_offline.online))
  25. elif message.content == '!help' and self.help_msg:
  26. await message.channel.send(self.help_msg)
  27. elif message.content == '!ping':
  28. await message.channel.send('pong')
  29. elif message.channel == self.channel and not message.author.bot and not message.content.startswith('!'):
  30. zwift_offline.send_message(message.content, message.author.name)
  31. class DiscordThread(threading.Thread):
  32. def __init__(self, config_file):
  33. threading.Thread.__init__(self)
  34. if not os.path.isfile(config_file):
  35. raise Exception("DiscordThread invoked without a configuration file")
  36. self.CONFIG = ConfigParser()
  37. SECTION = 'discord'
  38. self.CONFIG.read(config_file)
  39. self.token = self.CONFIG.get(SECTION, 'token')
  40. self.webhook = self.CONFIG.get(SECTION, 'webhook')
  41. self.channel = self.CONFIG.getint(SECTION, 'channel')
  42. self.welcome_msg = self.CONFIG.get(SECTION, 'welcome_message', fallback='')
  43. self.help_msg = self.CONFIG.get(SECTION, 'help_message', fallback='')
  44. self.announce = self.CONFIG.getboolean(SECTION, 'announce_players', fallback=False)
  45. self.intents = discord.Intents.default()
  46. self.intents.members = True
  47. self.intents.message_content = True
  48. self.loop = asyncio.get_event_loop()
  49. self.start()
  50. async def starter(self):
  51. self.discord_bot = DiscordBot(self.intents, self.channel, self.welcome_msg, self.help_msg, self.announce)
  52. await self.discord_bot.start(self.token)
  53. def run(self):
  54. try:
  55. self.loop.run_until_complete(self.starter())
  56. except Exception as exc:
  57. print('DiscordThread exception: %s' % repr(exc))
  58. async def webhook_send(self, message, sender):
  59. async with aiohttp.ClientSession() as session:
  60. await discord.Webhook.from_url(self.webhook, session=session).send(message, username=sender)
  61. def send_message(self, message, sender_id=None):
  62. if sender_id is not None:
  63. profile = zwift_offline.get_partial_profile(sender_id)
  64. sender = profile.first_name + ' ' + profile.last_name
  65. else:
  66. sender = 'Server'
  67. asyncio.run_coroutine_threadsafe(self.webhook_send(message, sender), self.loop)
  68. def change_presence(self, n):
  69. if n > 0:
  70. activity = discord.Game(name=f"{n} rider{'s'[:n>1]} online")
  71. else:
  72. activity = None
  73. asyncio.run_coroutine_threadsafe(self.discord_bot.change_presence(activity=activity), self.loop)