Experimental Discord bot written in Python
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

utils.py 2.0KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. """
  2. General utility functions.
  3. """
  4. import re
  5. from datetime import datetime, timedelta
  6. from discord import Guild
  7. from discord.ext.commands import Cog, Group
  8. def parse_timedelta(s: str) -> timedelta:
  9. """
  10. Parses a timespan. Format examples:
  11. "30m"
  12. "10s"
  13. "90d"
  14. "1h30m"
  15. "73d18h22m52s"
  16. """
  17. p = re.compile('^(?:[0-9]+[dhms])+$')
  18. if p.match(s) is None:
  19. raise ValueError("Illegal timespan value '{s}'.")
  20. p = re.compile('([0-9]+)([dhms])')
  21. days = 0
  22. hours = 0
  23. minutes = 0
  24. seconds = 0
  25. for m in p.finditer(s):
  26. scalar = int(m.group(1))
  27. unit = m.group(2)
  28. if unit == 'd':
  29. days = scalar
  30. elif unit == 'h':
  31. hours = scalar
  32. elif unit == 'm':
  33. minutes = scalar
  34. elif unit == 's':
  35. seconds = scalar
  36. return timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)
  37. def describe_timedelta(td: timedelta, max_components: int = 2) -> str:
  38. """
  39. Formats a human-readable description of a time span. E.g. "3 days 2 hours".
  40. """
  41. d = td.days
  42. h = td.seconds // 3600
  43. m = (td.seconds // 60) % 60
  44. s = td.seconds % 60
  45. components = []
  46. if d != 0:
  47. components.append('1 day' if d == 1 else f'{d} days')
  48. if h != 0:
  49. components.append('1 hour' if h == 1 else f'{h} hours')
  50. if m != 0:
  51. components.append('1 minute' if m == 1 else f'{m} minutes')
  52. if s != 0 or len(components) == 0:
  53. components.append('1 second' if s == 1 else f'{s} seconds')
  54. if len(components) > max_components:
  55. components = components[0:max_components]
  56. return ' '.join(components)
  57. def first_command_group(cog: Cog) -> Group:
  58. """
  59. Returns the first command Group found in a cog.
  60. """
  61. for member_name in dir(cog):
  62. member = getattr(cog, member_name)
  63. if isinstance(member, Group):
  64. return member
  65. return None
  66. def bot_log(guild: Guild, cog_class, message: str) -> None:
  67. """
  68. Logs a message to stdout with time, cog, and guild info.
  69. """
  70. now = datetime.now() # local
  71. s = f'[{now.strftime("%Y-%m-%dT%H:%M:%S")}|'
  72. s += f'{cog_class.__name__}|' if cog_class else '-|'
  73. s += f'{guild.name}] ' if guild else '-] '
  74. s += message
  75. print(s)