rcg.ts 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import { Message } from "discord.js";
  2. import got from "got";
  3. import { logger } from "src/logging";
  4. import { Command, ICommandData, Plugin } from "src/model/plugin";
  5. import { tryDo } from "@shared/common/async_utils";
  6. import Jimp from "jimp";
  7. const rcgRe = /<div class="rcg-panels">\s*<img src="([^"]*)" .*\/>\s*<img src="([^"]*)" .*\/>\s*<img src="([^"]*)" .*\/>\s*<\/div>/i;
  8. interface XkcdResponse {
  9. img: string;
  10. }
  11. @Plugin
  12. export class Rcg {
  13. async sendErrorMessage(msg: Message): Promise<void> {
  14. const xkcdResult = await tryDo(got.get<XkcdResponse>("https://xkcd.com/info.0.json", { responseType: "json" }));
  15. if(!xkcdResult.ok || !xkcdResult.result) {
  16. await msg.reply("sorry, I couldn't get any comics :(.");
  17. return;
  18. }
  19. await msg.reply("sorry, I couldn't get a random comic! Here is today's XKCD instead:", {
  20. files: [ xkcdResult.result.body.img ]
  21. });
  22. }
  23. @Command({
  24. type: "mention",
  25. pattern: "random comic",
  26. auth: false,
  27. documentation: {description: "Generates a comic just for you!", example: "random comic"}
  28. })
  29. async randomComic({ message }: ICommandData): Promise<void> {
  30. const result = await tryDo(got.get("http://explosm.net/rcg/view/?promo=false"));
  31. if (!result.ok) {
  32. logger.error("Failed to get RCG. Got error: %s", result.error);
  33. await this.sendErrorMessage(message);
  34. return;
  35. }
  36. const regexResult = rcgRe.exec(result.result.body);
  37. if(!regexResult || regexResult.length == 0) {
  38. logger.error("Could not find RCG from body. Got response body: %s", result.result.body);
  39. await this.sendErrorMessage(message);
  40. return;
  41. }
  42. const panelUrls = [regexResult[1], regexResult[2], regexResult[3]];
  43. const panels = [];
  44. let totalWidth = 0;
  45. let maxHeight = 0;
  46. for (const panelUrl of panelUrls) {
  47. const panelImgResult = await tryDo(Jimp.read(panelUrl));
  48. if (!panelImgResult.ok) {
  49. logger.error("Failed to download panel %s", panelUrl);
  50. await this.sendErrorMessage(message);
  51. return;
  52. }
  53. const img = panelImgResult.result;
  54. const [w, h] = [ img.getWidth(), img.getHeight() ];
  55. panels.push(img);
  56. totalWidth += w;
  57. if (h > maxHeight) {
  58. maxHeight = h;
  59. }
  60. }
  61. const PADDING = 5;
  62. let newImg = await Jimp.create(PADDING * 4 + totalWidth, PADDING * 2 + maxHeight, "white");
  63. let curX = PADDING;
  64. for (const panel of panels) {
  65. newImg = await newImg.blit(panel, curX, PADDING);
  66. curX += panel.getWidth() + PADDING;
  67. }
  68. newImg.quality(80);
  69. const buffer = await newImg.getBufferAsync(Jimp.MIME_JPEG);
  70. const messagePostResult = await tryDo(message.reply("I find this very funny:", {
  71. files: [ buffer ]
  72. }));
  73. if (!messagePostResult.ok) {
  74. logger.error("Failed to get RCG. Got error: %s", messagePostResult.error);
  75. await this.sendErrorMessage(message);
  76. }
  77. }
  78. }