diff --git a/src/events/handle-message.ts b/src/events/handle-message.ts index 0cd03b5..96119ab 100644 --- a/src/events/handle-message.ts +++ b/src/events/handle-message.ts @@ -1,7 +1,7 @@ -import { AllowedMentionsTypes, Message as DiscordMessage, GuildBasedChannel, GuildTextBasedChannel, OmitPartialGroupDMChannel, PartialMessage, ReadonlyCollection } from 'discord.js'; +import { AllowedMentionsTypes, Message as DiscordMessage, GuildBasedChannel, GuildTextBasedChannel, OmitPartialGroupDMChannel, PartialMessage, ReadonlyCollection, spoiler } from 'discord.js'; import { config } from '../config'; import { E621Post } from '../types'; -import { getE621Post, getE621PostByMd5, getPostUrl, hasBlacklistedTags } from '../utils/e621-utils'; +import { getE621Post, getE621PostByMd5, getPostUrl, PostAction, spoilerOrBlacklist } from '../utils/e621-utils'; import { Database } from '../shared/Database'; import { logDeletion, logEdit } from '../utils/message-logger'; import { isEdited } from '../utils/message-utils'; @@ -205,7 +205,7 @@ async function blacklistIfNecessary(message: Message, posts: E621Post[]): Promis const isStaffChannel = await channelIsInStaffCategory(channel); for (const post of posts) { - if (hasBlacklistedTags(post)) { + if (spoilerOrBlacklist(post).action == PostAction.Blacklist) { blacklistedIds.push(post.id); } } @@ -256,8 +256,9 @@ async function postIdHandler(message: Message, matchedGroups: RegExpExecArray[]) const sfw = await channelIsSafe(message.channel as GuildBasedChannel); const content = posts.map((post) => { + const shouldSpoiler = spoilerOrBlacklist(post); if (sfw && post.rating != 's') return ` [NSFW] <${getPostUrl(post)}>`; - return getPostUrl(post); + return shouldSpoiler.action == PostAction.Spoiler ? `${spoiler(getPostUrl(post))} (${shouldSpoiler.tag})` : getPostUrl(post); }).join('\n'); if (content.trim().length > 0) return content.trim(); diff --git a/src/shared/RedisClient.ts b/src/shared/RedisClient.ts index c89f77e..c9ecdbc 100644 --- a/src/shared/RedisClient.ts +++ b/src/shared/RedisClient.ts @@ -2,7 +2,7 @@ import { createClient } from '@redis/client'; import { Database } from './Database'; import { config } from '../config'; import { APIEmbedField, Client, EmbedAuthorOptions, EmbedBuilder, SendableChannels, TextBasedChannel } from 'discord.js'; -import { blipIDRegex, commentIDRegex, forumTopicIDRegex, humanizeCapitalization, poolIDRegex, postIDRegex, shouldAlert, recordIDRegex, searchLinkRegex, setIDRegex, takedownIDRegex, ticketIDRegex, userIDRegex, wikiLinkRegex, getE621Post, hasBlacklistedTags } from '../utils'; +import { blipIDRegex, commentIDRegex, forumTopicIDRegex, humanizeCapitalization, poolIDRegex, postIDRegex, shouldAlert, recordIDRegex, searchLinkRegex, setIDRegex, takedownIDRegex, ticketIDRegex, userIDRegex, wikiLinkRegex, getE621Post, spoilerOrBlacklist, PostAction } from '../utils'; import { BanUpdate, Ticket, TicketPhrase, TicketUpdate } from '../types'; // TODO: Condense this and the message event handler regex array. @@ -32,7 +32,7 @@ const linkReplacers = [ tester: async (postId: string, before: string, after: string) => { const post = await getE621Post(postId); if (!post) return { allowed: true, before, after }; - const allowed = !hasBlacklistedTags(post); + const allowed = spoilerOrBlacklist(post).action != PostAction.Blacklist; return { allowed, before, after }; }, diff --git a/src/utils/e621-utils.ts b/src/utils/e621-utils.ts index 9779149..a3f17dc 100644 --- a/src/utils/e621-utils.ts +++ b/src/utils/e621-utils.ts @@ -6,6 +6,9 @@ import { Database } from '../shared/Database'; const BLACKLISTED_TAGS: string[] = []; const BLACKLISTED_NONSAFE_TAGS: string[] = ['young']; +const SPOILERED_TAGS: string[] = ['gore', 'scat', 'watersports']; +const SPOILERED_NONSAFE_TAGS: string[] = []; + const USER_AGENT = 'E621DiscordBot'; async function request(path: string, query?: { [name: string]: string }): Promise { @@ -41,13 +44,26 @@ export async function getE621PostByMd5(md5: string): Promise { return (await request('/posts', { md5 }))?.post as E621Post ?? null; } -export function hasBlacklistedTags(post: E621Post): boolean { - for (const tags of Object.values(post.tags)) { - if (tags.some(t => BLACKLISTED_TAGS.includes(t))) return true; - if (post.rating != 's' && tags.some(t => BLACKLISTED_NONSAFE_TAGS.includes(t))) return true; +export const enum PostAction { + NoAction = 0, + Spoiler = 1, + Blacklist = 2 +} + +export function spoilerOrBlacklist(post: E621Post): { action: PostAction, tag: string } { + const tags = Object.values(post.tags).flat(); + + for (const tag of tags) { + if (BLACKLISTED_TAGS.includes(tag)) return { action: PostAction.Blacklist, tag }; + if (post.rating != 's' && BLACKLISTED_NONSAFE_TAGS.includes(tag)) return { action: PostAction.Blacklist, tag }; } - return false; + for (const tag of tags) { + if (SPOILERED_TAGS.includes(tag)) return { action: PostAction.Spoiler, tag }; + if (post.rating != 's' && SPOILERED_NONSAFE_TAGS.includes(tag)) return { action: PostAction.Spoiler, tag }; + } + + return { action: PostAction.NoAction, tag: '' }; } export function getPostUrl(post: E621Post): string {