common.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. import datetime
  2. import logging
  3. import os
  4. import time
  5. import traceback
  6. from voussoirkit import vlogging
  7. VERSION = '2020.09.06.0'
  8. try:
  9. import praw
  10. except ImportError:
  11. praw = None
  12. if praw is None or praw.__version__.startswith('3.'):
  13. import praw4
  14. praw = praw4
  15. try:
  16. import bot
  17. except ImportError:
  18. bot = None
  19. if bot is None or bot.praw != praw:
  20. try:
  21. import bot4
  22. bot = bot4
  23. except ImportError:
  24. message = '\n'.join([
  25. 'Could not find your PRAW4 bot file as either `bot.py` or `bot4.py`.',
  26. 'Please see the README.md file for instructions on how to prepare it.'
  27. ])
  28. raise ImportError(message)
  29. log = vlogging.get_logger(__name__)
  30. r = bot.anonymous()
  31. def assert_file_exists(filepath):
  32. if not os.path.exists(filepath):
  33. raise FileNotFoundError(filepath)
  34. def b36(i):
  35. if isinstance(i, int):
  36. return base36encode(i)
  37. return base36decode(i)
  38. def base36decode(number):
  39. return int(number, 36)
  40. def base36encode(number, alphabet='0123456789abcdefghijklmnopqrstuvwxyz'):
  41. """Converts an integer to a base36 string."""
  42. if not isinstance(number, (int)):
  43. raise TypeError('number must be an integer')
  44. base36 = ''
  45. sign = ''
  46. if number < 0:
  47. sign = '-'
  48. number = -number
  49. if 0 <= number < len(alphabet):
  50. return sign + alphabet[number]
  51. while number != 0:
  52. number, i = divmod(number, len(alphabet))
  53. base36 = alphabet[i] + base36
  54. return sign + base36
  55. def fetchgenerator(cursor):
  56. while True:
  57. item = cursor.fetchone()
  58. if item is None:
  59. break
  60. yield item
  61. def generator_chunker(generator, chunk_size):
  62. '''
  63. Given an item generator, yield lists of length chunk_size, except maybe
  64. the last one.
  65. '''
  66. chunk = []
  67. for item in generator:
  68. chunk.append(item)
  69. if len(chunk) == chunk_size:
  70. yield chunk
  71. chunk = []
  72. if len(chunk) != 0:
  73. yield chunk
  74. def get_now(stamp=True):
  75. now = datetime.datetime.now(datetime.timezone.utc)
  76. if stamp:
  77. return int(now.timestamp())
  78. return now
  79. def human(timestamp):
  80. x = datetime.datetime.utcfromtimestamp(timestamp)
  81. x = datetime.datetime.strftime(x, "%b %d %Y %H:%M:%S")
  82. return x
  83. def int_none(x):
  84. if x is None:
  85. return None
  86. return int(x)
  87. def is_xor(*args):
  88. '''
  89. Return True if and only if one arg is truthy.
  90. '''
  91. return [bool(a) for a in args].count(True) == 1
  92. def login():
  93. global r
  94. log.debug('Logging in to reddit.')
  95. r = bot.login(r)
  96. def nofailrequest(function):
  97. '''
  98. Creates a function that will retry until it succeeds.
  99. This function accepts 1 parameter, a function, and returns a modified
  100. version of that function that will try-catch, sleep, and loop until it
  101. finally returns.
  102. '''
  103. def a(*args, **kwargs):
  104. while True:
  105. try:
  106. result = function(*args, **kwargs)
  107. return result
  108. except KeyboardInterrupt:
  109. raise
  110. except Exception:
  111. traceback.print_exc()
  112. print('Retrying in 2...')
  113. time.sleep(2)
  114. return a
  115. def split_any(text, delimiters):
  116. delimiters = list(delimiters)
  117. (splitter, replacers) = (delimiters[0], delimiters[1:])
  118. for replacer in replacers:
  119. text = text.replace(replacer, splitter)
  120. return text.split(splitter)
  121. def subreddit_for_submission(submission_id):
  122. submission_id = t3_prefix(submission_id)[3:]
  123. submission = r.submission(submission_id)
  124. return submission.subreddit
  125. def t3_prefix(submission_id):
  126. if not submission_id.startswith('t3_'):
  127. submission_id = 't3_' + submission_id
  128. return submission_id