From 8f5331bcf96028b9c8818a720bcc6bc2f6c8cbdd Mon Sep 17 00:00:00 2001 From: MikuroXina Date: Sun, 26 Nov 2023 15:17:35 +0900 Subject: [PATCH] Split into pin_message.ts --- src/commands.ts | 155 +----------------------------------- src/commands/pin_message.ts | 153 +++++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+), 154 deletions(-) create mode 100644 src/commands/pin_message.ts diff --git a/src/commands.ts b/src/commands.ts index 7b7d014..4f7e9fc 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -1,11 +1,10 @@ +import { pinMessage, WebhookOptions } from "./commands/pin_message.ts"; import { ApplicationCommandType, - ENDPOINT, Interaction, InteractionHandlers, InteractionResponseType, InteractionType, - PartialMessage, } from "./types.ts"; const errorResponse = (reason: string) => ({ @@ -15,158 +14,6 @@ const errorResponse = (reason: string) => ({ }, }); -const editSentResponse = ( - { applicationId, interactionToken }: { - applicationId: string; - interactionToken: string; - }, -) => -(content: string) => - fetch( - [ - ENDPOINT, - "webhooks", - applicationId, - interactionToken, - "messages", - "@original", - ].join("/"), - { - method: "PATCH", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ content }), - }, - ); - -export interface WebhookOptions { - applicationId: string; - webhookId: string; - webhookToken: string; -} - -const USER_AGENT = - "pindome-chan Bot (https://github.com/approvers/pindome-chan)"; - -const sendWebhook = ( - message: FormData, - { webhookId, webhookToken }: WebhookOptions, -): Promise => - fetch( - [ENDPOINT, "webhooks", webhookId, webhookToken].join("/"), - { - headers: { - "User-Agent": USER_AGENT, - }, - method: "POST", - body: message, - }, - ); - -const cutContent = (content: string): string => { - const spoilerMarks = []; - const spoilerSpans: [number, number][] = []; - const chars = [...content]; - let isInCodeBlock = false; - for (let i = 0; i < chars.length - 1; ++i) { - if (chars[i] === "|" && chars[i + 1] === "|" && !isInCodeBlock) { - const start = spoilerMarks.pop(); - if (start !== undefined) { - spoilerSpans.push([start, i + 2]); - } else { - spoilerMarks.push(i); - } - ++i; - } - if ( - chars[i] === "`" && chars[i + 1] === "`" && chars[i + 2] === "`" && - chars[i + 3] === "\n" - ) { - isInCodeBlock = !isInCodeBlock; - if (isInCodeBlock) { - spoilerMarks.pop(); - } - i += 3; - } - } - - const PREVIEW_LENGTH = 20; - const isCuttingSpoiler = spoilerSpans.some(([start, end]) => - start <= PREVIEW_LENGTH && PREVIEW_LENGTH < end - ); - - let cut = ""; - cut += content.substring(0, PREVIEW_LENGTH); - if (isCuttingSpoiler) { - cut += "||"; - } - if (PREVIEW_LENGTH <= content.length) { - cut += "..."; - } - return cut; -}; - -async function pinMessage( - message: PartialMessage, - interaction: Interaction, - options: WebhookOptions, -) { - const editSent = editSentResponse({ - applicationId: options.applicationId, - interactionToken: interaction.token, - }); - - const form = new FormData(); - form.append( - "payload_json", - JSON.stringify({ - ...message, - content: `${message.content}\nby ${message.author.username}`.trim(), - allowed_mentions: { - parse: [], - }, - message_reference: { - message_id: message.id, - }, - attachments: message.attachments.map((attachment, index) => ({ - id: index, - filename: attachment.filename, - })), - }), - ); - for (let index = 0; index < message.attachments.length; ++index) { - const attachment = message.attachments[index]; - const res = await fetch(attachment.url); - const blob = await res.blob(); - - const UPLOAD_SIZE_LIMIT = 8 * 1024 * 1024; - if (UPLOAD_SIZE_LIMIT < blob.size) { - await editSent( - "アップロード上限を超えているから、ピン留めできないみたいです…", - ); - return; - } - form.append(`files[${index}]`, blob, attachment.filename); - } - - let previewContent = ""; - if (message.content.length !== 0) { - previewContent += cutContent(message.content); - } - - const res = await sendWebhook(form, options); - - if (!res || !res.ok) { - console.error(await res?.text()); - const followupRes = await editSent("ピン留めに失敗しちゃった……"); - console.log(await followupRes.text()); - return; - } - const followupRes = await editSent(`ピン留めできたよ!\n${previewContent}`); - console.log(await followupRes.text()); -} - export const makeCommands = (options: WebhookOptions): InteractionHandlers => [ [ { diff --git a/src/commands/pin_message.ts b/src/commands/pin_message.ts new file mode 100644 index 0000000..7e90780 --- /dev/null +++ b/src/commands/pin_message.ts @@ -0,0 +1,153 @@ +import { ENDPOINT, Interaction, PartialMessage } from "../types.ts"; + +const editSentResponse = ( + { applicationId, interactionToken }: { + applicationId: string; + interactionToken: string; + }, +) => +(content: string) => + fetch( + [ + ENDPOINT, + "webhooks", + applicationId, + interactionToken, + "messages", + "@original", + ].join("/"), + { + method: "PATCH", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ content }), + }, + ); + +const USER_AGENT = + "pindome-chan Bot (https://github.com/approvers/pindome-chan)"; + +export interface WebhookOptions { + applicationId: string; + webhookId: string; + webhookToken: string; +} + +const sendWebhook = ( + message: FormData, + { webhookId, webhookToken }: WebhookOptions, +): Promise => + fetch( + [ENDPOINT, "webhooks", webhookId, webhookToken].join("/"), + { + headers: { + "User-Agent": USER_AGENT, + }, + method: "POST", + body: message, + }, + ); + +const cutContent = (content: string): string => { + const spoilerMarks = []; + const spoilerSpans: [number, number][] = []; + const chars = [...content]; + let isInCodeBlock = false; + for (let i = 0; i < chars.length - 1; ++i) { + if (chars[i] === "|" && chars[i + 1] === "|" && !isInCodeBlock) { + const start = spoilerMarks.pop(); + if (start !== undefined) { + spoilerSpans.push([start, i + 2]); + } else { + spoilerMarks.push(i); + } + ++i; + } + if ( + chars[i] === "`" && chars[i + 1] === "`" && chars[i + 2] === "`" && + chars[i + 3] === "\n" + ) { + isInCodeBlock = !isInCodeBlock; + if (isInCodeBlock) { + spoilerMarks.pop(); + } + i += 3; + } + } + + const PREVIEW_LENGTH = 20; + const isCuttingSpoiler = spoilerSpans.some(([start, end]) => + start <= PREVIEW_LENGTH && PREVIEW_LENGTH < end + ); + + let cut = ""; + cut += content.substring(0, PREVIEW_LENGTH); + if (isCuttingSpoiler) { + cut += "||"; + } + if (PREVIEW_LENGTH <= content.length) { + cut += "..."; + } + return cut; +}; + +export async function pinMessage( + message: PartialMessage, + interaction: Interaction, + options: WebhookOptions, +) { + const editSent = editSentResponse({ + applicationId: options.applicationId, + interactionToken: interaction.token, + }); + + const form = new FormData(); + form.append( + "payload_json", + JSON.stringify({ + ...message, + content: `${message.content}\nby ${message.author.username}`.trim(), + allowed_mentions: { + parse: [], + }, + message_reference: { + message_id: message.id, + }, + attachments: message.attachments.map((attachment, index) => ({ + id: index, + filename: attachment.filename, + })), + }), + ); + for (let index = 0; index < message.attachments.length; ++index) { + const attachment = message.attachments[index]; + const res = await fetch(attachment.url); + const blob = await res.blob(); + + const UPLOAD_SIZE_LIMIT = 8 * 1024 * 1024; + if (UPLOAD_SIZE_LIMIT < blob.size) { + await editSent( + "アップロード上限を超えているから、ピン留めできないみたいです…", + ); + return; + } + form.append(`files[${index}]`, blob, attachment.filename); + } + + let previewContent = ""; + if (message.content.length !== 0) { + previewContent += cutContent(message.content); + } + + const res = await sendWebhook(form, options); + + if (!res || !res.ok) { + console.error(await res?.text()); + const followupRes = await editSent("ピン留めに失敗しちゃった……"); + console.log(await followupRes.text()); + return; + } + const followupRes = await editSent(`ピン留めできたよ!\n${previewContent}`); + console.log(await followupRes.text()); +}