Cuu.
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.

93 lines
3.0 KiB

  1. /* eslint-disable import/prefer-default-export */
  2. /* eslint-disable @typescript-eslint/no-unsafe-call */
  3. /* eslint-disable @typescript-eslint/no-unsafe-assignment */
  4. /* eslint-disable @typescript-eslint/no-unsafe-member-access */
  5. /* eslint-disable @typescript-eslint/no-unsafe-return */
  6. import { readFile } from 'fs/promises';
  7. import { GuildEmoji, Message } from 'discord.js';
  8. import * as sources from '../utils/sources';
  9. import * as database from '../utils/database';
  10. type ImageReply = {
  11. tags: (string | string[])[],
  12. emojiName?: string[],
  13. content?: string,
  14. }
  15. export const listenForImagesAndReply = async (message: Message): Promise<void> => {
  16. const promises = Array
  17. .from(message.attachments.values())
  18. .filter((a) => a.url.endsWith('.jpg') || a.url.endsWith('.jpeg') || a.url.endsWith('.png'))
  19. .map(async (a) => sources.reverseSearch(a.url));
  20. const reverseSearchData = await Promise.all(promises);
  21. const imageInfoPromises = reverseSearchData.map(async (d) => {
  22. const [booruResult] = d.results;
  23. if (!booruResult) {
  24. return null;
  25. }
  26. return sources.fetchImage(booruResult.data.gelbooru_id.toString());
  27. });
  28. const imageInfos = await Promise.all(imageInfoPromises);
  29. const tags = imageInfos.filter((i) => Boolean(i)).map((info) => info.tags.split(' ')).flat();
  30. const repliesBuffer = await readFile('.image-replies.json');
  31. const repliesString = repliesBuffer.toString('utf-8');
  32. const replies = JSON.parse(repliesString) as ImageReply[];
  33. const theReply = replies.reduce<ImageReply | null>(
  34. (chosenReply, reply) => {
  35. if (chosenReply === null && reply.tags.some((t) => {
  36. if (Array.isArray(t)) {
  37. return t.every((tt) => tags.includes(tt));
  38. }
  39. return tags.includes(t);
  40. })) {
  41. return reply;
  42. }
  43. return chosenReply;
  44. },
  45. null,
  46. );
  47. console.log(`${message.id}: ${tags.join(' ')}`);
  48. if (theReply) {
  49. const { emojiName: emojiNames = [], content: replyContent = '' } = theReply;
  50. console.log([...emojiNames.map((em) => `+:${em}:`), replyContent].join(' '));
  51. if (emojiNames.length > 0) {
  52. const emojis = emojiNames
  53. .map((emName) => (
  54. message.guild?.emojis.cache.find((em) => em.name === emName)
  55. ))
  56. .filter((em) => Boolean(em)) as GuildEmoji[];
  57. await Promise.all(emojis.map((em) => message.react(em)));
  58. }
  59. if (theReply.content) {
  60. await message.reply(theReply.content);
  61. }
  62. }
  63. };
  64. export const replyRandomImage = async (message: Message, topic: string): Promise<void> => {
  65. const data = await sources.fetchBooru(topic);
  66. await message.channel.send({
  67. embeds: [
  68. {
  69. title: 'CuuBot',
  70. image: {
  71. url: data.post[0].file_url as string,
  72. },
  73. },
  74. ],
  75. });
  76. };
  77. export const queueImage = async (message: Message): Promise<void> => {
  78. const promises = Array
  79. .from(message.attachments.values())
  80. .map(async (attachment) => database.save(message.author.id, { url: attachment.url }));
  81. await Promise.all(promises);
  82. await message.react('✅');
  83. };