Skip to content

Commit c6e7ba0

Browse files
committed
feat: get images from past messages
1 parent f32b2c9 commit c6e7ba0

File tree

4 files changed

+80
-14
lines changed

4 files changed

+80
-14
lines changed

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ DISCORD_APP_ID=
22
DISCORD_PUBLIC_KEY=
33
DISCORD_BOT_TOKEN=
44
COMMANDS_DEBUG=false
5+
LOOKBACK_LIMIT=25
56
WEEBSH_KEY=
67
IMGSRV_CACHE_TIMEOUT=3600000
78
IMGSRV_INTERVAL=60000

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
"description": "Slash commands for PhotoBox",
55
"main": "dist/index.js",
66
"scripts": {
7-
"start": "npx shx NODE_ENV=production cd dist && node index.js",
8-
"build": "npx shx rm -rf dist && tsc",
7+
"start": "NODE_ENV=production cd dist && node index.js",
8+
"build": "npx rimraf dist && tsc",
99
"dev": "devScript",
1010
"dev:ts": "cd src && ts-node index.ts",
1111
"lint": "npx eslint --ext .ts ./src",

src/imgsrv/abstracts.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,32 +34,32 @@ export abstract class GenerationCommand extends SlashCommand {
3434
});
3535
}
3636

37-
async generate(ctx: CommandContext, payload: ImgSrvPayload) {
38-
if (!this.endpoint) return 'No endpoint was defined for this command.';
37+
async generate(ctx: CommandContext, payload: ImgSrvPayload, endpoint = this.endpoint) {
38+
if (!endpoint) return 'No endpoint was defined for this command.';
3939

4040
await ctx.defer(false);
4141
try {
4242
logger.info(oneLine`
43-
Generating '${this.endpoint}' for
43+
Generating '${endpoint}' for
4444
${ctx.user.username}#${ctx.user.discriminator} (${ctx.user.id})
4545
`);
4646
const before = Date.now();
47-
const image = await generate(this.endpoint, payload);
47+
const image = await generate(endpoint, payload);
4848
const after = Date.now();
4949
const diff = after - before;
5050
logger.info(oneLine`
51-
'${this.endpoint}' for
51+
'${endpoint}' for
5252
${ctx.user.username}#${ctx.user.discriminator} (${ctx.user.id})
5353
took ${prettyMilliseconds(diff)}
5454
`);
5555
return {
56-
file: { file: image.buffer, name: `${this.endpoint}.${image.extension}` },
56+
file: { file: image.buffer, name: `${endpoint}.${image.extension}` },
5757
content: `Took ${prettyMilliseconds(after - before)} to render.`
5858
};
5959
} catch (err) {
6060
logger.error(
6161
oneLine`
62-
'${this.endpoint}' for
62+
'${endpoint}' for
6363
${ctx.user.username}#${ctx.user.discriminator} (${ctx.user.id})
6464
errored
6565
`,
@@ -88,7 +88,7 @@ export abstract class ImageCommand extends GenerationCommand {
8888
{
8989
name: 'avatar',
9090
type: CommandOptionType.USER,
91-
description: 'Use the avatar of the given user, defaults to your avatar.'
91+
description: 'Use the avatar of the given user, defaults to the last posted image.'
9292
}
9393
]
9494
});
@@ -98,7 +98,7 @@ export abstract class ImageCommand extends GenerationCommand {
9898
const user = ctx.users.first() || ctx.user;
9999
const media = ctx.options.media as string;
100100

101-
const result = await find(user, media);
101+
const result = await find(user, media, ctx, ctx.users.size === 1);
102102
const payload: ImagePayload = { image: result.url };
103103

104104
return this.generate(ctx, payload);

src/media/index.ts

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import emojilib from 'emojilib';
22
import path from 'path';
33
import Extractor from './extractor';
44
import { iterateFolder } from '../util';
5-
import { User } from 'slash-create';
5+
import { User, CommandContext, MessageData } from 'slash-create';
66

77
export const CUSTOM_EMOJI_REGEX = /<(a?):([0-9a-zA-Z-_]+):(\d+)>/;
88
export const URL_REGEX = /https?:\/\/[^\s<|]+[^<.,:;"')\]\s>|*_~`]/i;
@@ -67,12 +67,65 @@ export function clearCache() {
6767
for (const extractor of extractors) extractor.clearCache();
6868
}
6969

70-
export async function find(user: User, media?: string): Promise<FindMediaResult> {
70+
export async function fetchMessages(ctx: CommandContext): Promise<MessageData[]> {
71+
try {
72+
return ctx.creator.requestHandler.request(
73+
'get',
74+
`/channels/${ctx.channelID}/messages?limit=${process.env.LOOKBACK_LIMIT || 25}`
75+
);
76+
} catch (e) {
77+
return null;
78+
}
79+
}
80+
81+
export async function findFromMessage(message: MessageData): Promise<FindMediaResult | null> {
82+
// Attachment
83+
if (message.attachments.length)
84+
return {
85+
url: message.attachments[0].url,
86+
from: 'attachment',
87+
past: true
88+
};
89+
90+
// Embed
91+
if (message.embeds.length) {
92+
const targetURL = message.embeds
93+
.filter((embed) => (embed.image && embed.image.url) || (embed.thumbnail && embed.thumbnail.url))
94+
.map((embed) => (embed.image ? embed.image.url : embed.thumbnail!.url))[0];
95+
if (targetURL)
96+
return {
97+
url: targetURL,
98+
from: 'embed',
99+
past: true
100+
};
101+
}
102+
103+
// URL detection
104+
if (URL_REGEX.test(message.content)) {
105+
const targetURL = message.content.match(URL_REGEX)![1];
106+
const convertedURL = targetURL ? (await parseURL(targetURL)) || targetURL : targetURL;
107+
if (targetURL)
108+
return {
109+
url: convertedURL,
110+
from: 'url',
111+
past: true
112+
};
113+
}
114+
115+
return null;
116+
}
117+
118+
export async function find(
119+
user: User,
120+
media?: string,
121+
ctx?: CommandContext,
122+
preferUser = false
123+
): Promise<FindMediaResult> {
71124
if (media) {
72125
// URL detection
73126
if (URL_REGEX.test(media)) {
74127
const targetURL = media.match(URL_REGEX)![1];
75-
const convertedURL = targetURL ? (await this.parseURL(targetURL)) || targetURL : targetURL;
128+
const convertedURL = targetURL ? (await parseURL(targetURL)) || targetURL : targetURL;
76129
if (targetURL)
77130
return {
78131
url: convertedURL,
@@ -88,6 +141,7 @@ export async function find(user: User, media?: string): Promise<FindMediaResult>
88141
from: 'customEmoji'
89142
};
90143
}
144+
91145
// Emoji (Longer length emojis get priority)
92146
const emojiMatches = Object.keys(emojilib)
93147
.filter((emoji) => media.startsWith(emoji))
@@ -100,6 +154,17 @@ export async function find(user: User, media?: string): Promise<FindMediaResult>
100154
};
101155
}
102156

157+
if (ctx && !preferUser) {
158+
const messages = await fetchMessages(ctx);
159+
if (messages) {
160+
for (const message of messages) {
161+
// TODO filter other message types
162+
const messageResult = await findFromMessage(message);
163+
if (messageResult) return messageResult;
164+
}
165+
}
166+
}
167+
103168
// User's Avatar
104169
return {
105170
url: user.dynamicAvatarURL(user.avatar?.startsWith('a_') ? 'gif' : 'png', 1024),

0 commit comments

Comments
 (0)