querying.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. from logging import Logger
  2. import random
  3. import asyncio
  4. from aiohttp import MultipartWriter
  5. from bs4 import BeautifulSoup
  6. from rollbot import as_command, RollbotFailure, Attachment
  7. from rollbot.injection import Request, Args, Arg, Config
  8. @as_command
  9. async def inspire(req: Request, logger: Logger):
  10. """
  11. Using the command !inspire will request an inspiration image from http://inspirobot.me/
  12. """
  13. try:
  14. async with req.get("http://inspirobot.me/api?generate=true") as res:
  15. return await res.text()
  16. except:
  17. logger.exception("Failed !inspire")
  18. RollbotFailure.SERVICE_DOWN.raise_exc(detail="Could not reach inspirobot")
  19. @as_command
  20. async def shield(req: Request, blazon: Args, logger: Logger):
  21. boundary = f"----RollbotBoundary{''.join(str(random.randint(0, 9)) for _ in range(10))}"
  22. headers = {
  23. "Content-Type": f"multipart/form-data; boundary={boundary}",
  24. "Cache-Control": "no-cache",
  25. }
  26. with MultipartWriter(boundary=boundary) as form:
  27. form.append(blazon).set_content_disposition("form-data", name="blazon")
  28. form.append("1").set_content_disposition("form-data", name="asfile")
  29. form.append("wappenwiki").set_content_disposition("form-data", name="palette")
  30. form.append("flat").set_content_disposition("form-data", name="effect")
  31. form.append("500").set_content_disposition("form-data", name="size")
  32. try:
  33. async with req.post(
  34. "https://drawshield.net/include/drawshield.php",
  35. headers=headers,
  36. data=form,
  37. ) as res:
  38. res.raise_for_status()
  39. return Attachment("image", await res.read())
  40. except:
  41. logger.exception("Failed !shield")
  42. RollbotFailure.SERVICE_DOWN.raise_exc(detail="Could not reach DrawShield")
  43. @as_command
  44. async def scp(
  45. number: Arg(0, convert=int, fail_msg="Could not parse argument {} into integer"), req: Request
  46. ):
  47. page_url = f"http://www.scp-wiki.net/scp-{number:03d}"
  48. series_url = "http://www.scp-wiki.net/scp-series"
  49. series = (number // 1000) + 1
  50. if series != 1:
  51. series_url += "-" + str(series)
  52. async def get_obj_class():
  53. async with req.get(page_url) as page:
  54. page_html = BeautifulSoup(await page.text(), "html.parser")
  55. for p in page_html.find_all("p"):
  56. if "Object Class" in p.text:
  57. return p.text
  58. return "Error retrieving object class!"
  59. query = f"SCP-{number:03d}"
  60. async def get_title():
  61. async with req.get(series_url) as series:
  62. series_html = BeautifulSoup(await series.text(), "html.parser")
  63. for li in series_html.find_all("li"):
  64. if query in li.text:
  65. return li.text.split("-", 2)[-1].strip()
  66. return "Error retrieving title!"
  67. obj_class, title = await asyncio.gather(get_obj_class(), get_title())
  68. return f"Item # {number}\n{obj_class}\n{title}\n{page_url}"
  69. @as_command
  70. async def riddle(args: Args, req: Request, logger: Logger, sleep: Config("riddle.sleep")):
  71. if args.lower() != "me piss":
  72. RollbotFailure.INVALID_ARGUMENTS.raise_exc()
  73. rnum = None
  74. riddle = None
  75. for n in range(20):
  76. rnum = random.randint(2, 10050)
  77. async with req.get(f"https://www.riddles.com/{rnum}") as res:
  78. riddle_page = BeautifulSoup(await res.text(), "html.parser")
  79. riddle_panel = riddle_page.find("div", class_="panel-body")
  80. if riddle_panel is not None:
  81. parts = [p.text for p in riddle_panel.find_all("p")]
  82. if (
  83. len(parts) == 2
  84. and not parts[0].startswith("Riddle Status: User Rejected")
  85. and not parts[0].startswith("Riddle Status: User Moderated")
  86. ):
  87. riddle = parts[0]
  88. answer = parts[1]
  89. break
  90. logger.info(f"Failed to parse riddle #{rnum}, attempt #{n}")
  91. else:
  92. RollbotFailure.SERVICE_DOWN.raise_exc(detail="Failed to find a riddle fast enough")
  93. yield "\n\n".join(
  94. (
  95. f"Riddle #{rnum}",
  96. riddle,
  97. f"I'll post the response in about {sleep} seconds!",
  98. )
  99. )
  100. # TODO need to confirm this works without blocking in a proper task deploying system
  101. await asyncio.sleep(sleep)
  102. yield "\n\n".join(("Here's the riddle answer from before!", riddle, answer))
  103. @as_command
  104. async def selfie(req: Request, logger: Logger):
  105. try:
  106. async with req.get(
  107. "https://cdn.star.nesdis.noaa.gov/GOES16/ABI/SECTOR/ne/GEOCOLOR/latest.jpg"
  108. ) as res:
  109. res.raise_for_status()
  110. return Attachment("image", await res.read())
  111. except:
  112. logger.exception("Failed to call GOES16")
  113. RollbotFailure.SERVICE_DOWN.raise_exc(detail="Failed to call GOES16")
  114. @as_command
  115. async def cat(req: Request, logger: Logger):
  116. """
  117. The !cat command grabs a cat from https://thiscatdoesnotexist.com/
  118. """
  119. try:
  120. async with req.get(
  121. "https://thiscatdoesnotexist.com/", headers={"User-Agent": "Rollbot"}
  122. ) as res:
  123. res.raise_for_status()
  124. return Attachment("image", await res.read())
  125. except:
  126. logger.exception("Failed to call cat generator")
  127. RollbotFailure.SERVICE_DOWN.raise_exc(detail="Failed to call cat generator")
  128. @as_command
  129. async def horse(req: Request, logger: Logger):
  130. """
  131. The !horse command grabs a horse from https://thishorsedoesnotexist.com/
  132. """
  133. try:
  134. async with req.get(
  135. "https://thishorsedoesnotexist.com/", headers={"User-Agent": "Rollbot"}
  136. ) as res:
  137. res.raise_for_status()
  138. return Attachment("image", await res.read())
  139. except:
  140. logger.exception("Failed to call horse generator")
  141. RollbotFailure.SERVICE_DOWN.raise_exc(detail="Failed to call horse generator")
  142. @as_command
  143. async def npc(req: Request, logger: Logger):
  144. """
  145. The !horse command grabs a person from https://thispersondoesnotexist.com/
  146. """
  147. try:
  148. async with req.get(
  149. "https://thispersondoesnotexist.com/", headers={"User-Agent": "Rollbot"}
  150. ) as res:
  151. res.raise_for_status()
  152. return Attachment("image", await res.read())
  153. except:
  154. logger.exception("Failed to call person generator")
  155. RollbotFailure.SERVICE_DOWN.raise_exc(detail="Failed to call person generator")
  156. art_number = 0
  157. @as_command
  158. async def art(req: Request, logger: Logger):
  159. """
  160. The !art command uses the 9gans gallery at https://9gans.com/ which generates 9 images every hour.
  161. This command will cycle through those 9 images, so if you fire it 10 times in quick succession, the tenth
  162. piece of art might be the same as the first.
  163. """
  164. global art_number
  165. art_number += 1
  166. art_number %= 9
  167. try:
  168. async with req.get(
  169. f"https://storage.googleapis.com/9gans/mini/{art_number + 1}.jpg"
  170. ) as res:
  171. res.raise_for_status()
  172. return Attachment("image", await res.read())
  173. except:
  174. logger.exception("Failed to call art generator")
  175. RollbotFailure.SERVICE_DOWN.raise_exc(detail="Failed to call art generator")
  176. @as_command
  177. async def imagine(args: Args, api_key: Config("text2img.api_key"), req: Request, logger: Logger):
  178. """
  179. The !imagine command uses the text2img API at https://deepai.org/machine-learning-model/text2img
  180. """
  181. args = args.strip()
  182. if len(args) == 0:
  183. RollbotFailure.INVALID_ARGUMENTS.raise_exc(
  184. detail="The !imagine command needs text to imagine!"
  185. )
  186. try:
  187. async with req.post(
  188. "https://api.deepai.org/api/text2img", data={"text": args}, headers={"api-key": api_key}
  189. ) as res:
  190. res.raise_for_status()
  191. print(await res.text())
  192. js = await res.json()
  193. return js.get("output_url", None)
  194. except:
  195. logger.exception("Failed to call text2img service")
  196. RollbotFailure.SERVICE_DOWN.raise_exc(detail="Failed to call text2img service")