Add !message/!messageinfo command

This commit is contained in:
Dragory 2020-08-06 00:46:47 +03:00
parent 60aff76ebe
commit e8ff297368
No known key found for this signature in database
GPG key ID: 5F387BA66DF8AAC1
9 changed files with 210 additions and 0 deletions

4
assets/icons/LICENSE Normal file
View file

@ -0,0 +1,4 @@
# TWEMOJI
Copyright 2020 Twitter, Inc and other contributors
Code licensed under the MIT License: http://opensource.org/licenses/MIT
Graphics licensed under CC-BY 4.0: https://creativecommons.org/licenses/by/4.0/

1
assets/icons/memo.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#CCD6DD" d="M31 32c0 2.209-1.791 4-4 4H5c-2.209 0-4-1.791-4-4V4c0-2.209 1.791-4 4-4h22c2.209 0 4 1.791 4 4v28z"/><path fill="#99AAB5" d="M27 24c0 .553-.447 1-1 1H6c-.552 0-1-.447-1-1 0-.553.448-1 1-1h20c.553 0 1 .447 1 1zm-16 4c0 .553-.448 1-1 1H6c-.552 0-1-.447-1-1 0-.553.448-1 1-1h4c.552 0 1 .447 1 1zM27 8c0 .552-.447 1-1 1H6c-.552 0-1-.448-1-1s.448-1 1-1h20c.553 0 1 .448 1 1zm0 4c0 .553-.447 1-1 1H6c-.552 0-1-.447-1-1 0-.553.448-1 1-1h20c.553 0 1 .447 1 1zm0 4c0 .553-.447 1-1 1H6c-.552 0-1-.447-1-1 0-.553.448-1 1-1h20c.553 0 1 .447 1 1zm0 4c0 .553-.447 1-1 1H6c-.552 0-1-.447-1-1 0-.553.448-1 1-1h20c.553 0 1 .447 1 1z"/><path fill="#66757F" d="M31 6.272c-.827-.535-1.837-.579-2.521-.023l-.792.646-1.484 1.211-.1.08-2.376 1.938-11.878 9.686c-.437.357-.793 1.219-1.173 2.074-.378.85-.969 2.852-1.443 4.391-.148.25-1.065 1.846-.551 2.453.52.615 2.326.01 2.568-.076 1.626-.174 3.731-.373 4.648-.58.924-.211 1.854-.395 2.291-.752.008-.006.01-.018.017-.023l11.858-9.666.792-.646.144-.118V6.272z"/><path fill="#D99E82" d="M18.145 22.526s-1.274-1.881-2.117-2.553c-.672-.843-2.549-2.116-2.549-2.116-.448-.446-1.191-.48-1.629-.043-.437.438-.793 1.366-1.173 2.291-.472 1.146-1.276 4.154-1.768 5.752-.083.272.517-.45.503-.21-.01.187.027.394.074.581l-.146.159.208.067c.025.082.05.154.068.21l.159-.146c.187.047.394.084.58.074.24-.014-.483.587-.21.503 1.598-.493 4.607-1.296 5.752-1.768.924-.381 1.854-.736 2.291-1.174.439-.435.406-1.178-.043-1.627z"/><path fill="#EA596E" d="M25.312 4.351c-.876.875-.876 2.293 0 3.168l3.167 3.168c.876.874 2.294.874 3.168 0l3.169-3.168c.874-.875.874-2.293 0-3.168l-3.169-3.168c-.874-.875-2.292-.875-3.168 0l-3.167 3.168z"/><path fill="#FFCC4D" d="M11.849 17.815l3.17 3.17 3.165 3.166 11.881-11.879-6.337-6.336-11.879 11.879z"/><path fill="#292F33" d="M11.298 26.742s-2.06 1.133-2.616.576c-.557-.558.581-2.611.581-2.611s1.951.036 2.035 2.035z"/><path fill="#CCD6DD" d="M23.728 5.935l3.96-3.96 6.336 6.337-3.96 3.96z"/><path fill="#99AAB5" d="M26.103 3.558l.792-.792 6.336 6.335-.792.792zM24.52 5.142l.791-.791 6.336 6.335-.792.792z"/></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
assets/icons/message.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

33
assets/icons/message.svg Normal file
View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 36 36" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(0.878157,0,0,0.878157,4.48099,4.50364)">
<g transform="matrix(0.853831,0,0,0.853831,0.146169,0)">
<path d="M31,32C31,34.209 29.209,36 27,36L5,36C2.791,36 1,34.209 1,32L1,4C1,1.791 2.791,0 5,0L27,0C29.209,0 31,1.791 31,4L31,32Z" style="fill:rgb(204,214,221);fill-rule:nonzero;"/>
</g>
<g transform="matrix(0.853831,0,0,0.853831,0.146169,0)">
<path d="M27,24C27,24.553 26.553,25 26,25L6,25C5.448,25 5,24.553 5,24C5,23.447 5.448,23 6,23L26,23C26.553,23 27,23.447 27,24ZM11,28C11,28.553 10.552,29 10,29L6,29C5.448,29 5,28.553 5,28C5,27.447 5.448,27 6,27L10,27C10.552,27 11,27.447 11,28ZM27,8C27,8.552 26.553,9 26,9L6,9C5.448,9 5,8.552 5,8C5,7.448 5.448,7 6,7L26,7C26.553,7 27,7.448 27,8ZM27,12C27,12.553 26.553,13 26,13L6,13C5.448,13 5,12.553 5,12C5,11.447 5.448,11 6,11L26,11C26.553,11 27,11.447 27,12ZM27,16C27,16.553 26.553,17 26,17L6,17C5.448,17 5,16.553 5,16C5,15.447 5.448,15 6,15L26,15C26.553,15 27,15.447 27,16ZM27,20C27,20.553 26.553,21 26,21L6,21C5.448,21 5,20.553 5,20C5,19.447 5.448,19 6,19L26,19C26.553,19 27,19.447 27,20Z" style="fill:rgb(153,170,181);fill-rule:nonzero;"/>
</g>
<g transform="matrix(0.853831,0,0,0.853831,0.146169,0)">
<path d="M31,6.272C30.173,5.737 29.163,5.693 28.479,6.249L27.687,6.895L26.203,8.106L26.103,8.186L23.727,10.124L11.849,19.81C11.412,20.167 11.056,21.029 10.676,21.884C10.298,22.734 9.707,24.736 9.233,26.275C9.085,26.525 8.168,28.121 8.682,28.728C9.202,29.343 11.008,28.738 11.25,28.652C12.876,28.478 14.981,28.279 15.898,28.072C16.822,27.861 17.752,27.677 18.189,27.32C18.197,27.314 18.199,27.302 18.206,27.297L30.064,17.631L30.856,16.985L31,16.867L31,6.272Z" style="fill:rgb(102,117,127);fill-rule:nonzero;"/>
</g>
<g transform="matrix(0.853831,0,0,0.853831,0.146169,0)">
<path d="M18.145,22.526C18.145,22.526 16.871,20.645 16.028,19.973C15.356,19.13 13.479,17.857 13.479,17.857C13.031,17.411 12.288,17.377 11.85,17.814C11.413,18.252 11.057,19.18 10.677,20.105C10.205,21.251 9.401,24.259 8.909,25.857C8.826,26.129 9.426,25.407 9.412,25.647C9.402,25.834 9.439,26.041 9.486,26.228L9.34,26.387L9.548,26.454C9.573,26.536 9.598,26.608 9.616,26.664L9.775,26.518C9.962,26.565 10.169,26.602 10.355,26.592C10.595,26.578 9.872,27.179 10.145,27.095C11.743,26.602 14.752,25.799 15.897,25.327C16.821,24.946 17.751,24.591 18.188,24.153C18.627,23.718 18.594,22.975 18.145,22.526Z" style="fill:rgb(217,158,130);fill-rule:nonzero;"/>
</g>
<g transform="matrix(0.853831,0,0,0.853831,0.146169,0)">
<path d="M25.312,4.351C24.436,5.226 24.436,6.644 25.312,7.519L28.479,10.687C29.355,11.561 30.773,11.561 31.647,10.687L34.816,7.519C35.69,6.644 35.69,5.226 34.816,4.351L31.647,1.183C30.773,0.308 29.355,0.308 28.479,1.183L25.312,4.351Z" style="fill:rgb(234,89,110);fill-rule:nonzero;"/>
</g>
<g transform="matrix(0.853831,0,0,0.853831,0.146169,0)">
<path d="M11.849,17.815L15.019,20.985L18.184,24.151L30.065,12.272L23.728,5.936L11.849,17.815Z" style="fill:rgb(255,204,77);fill-rule:nonzero;"/>
</g>
<g transform="matrix(0.853831,0,0,0.853831,0.146169,0)">
<path d="M11.298,26.742C11.298,26.742 9.238,27.875 8.682,27.318C8.125,26.76 9.263,24.707 9.263,24.707C9.263,24.707 11.214,24.743 11.298,26.742Z" style="fill:rgb(41,47,51);fill-rule:nonzero;"/>
</g>
<g transform="matrix(0.853831,0,0,0.853831,0.146169,0)">
<path d="M23.728,5.935L27.688,1.975L34.024,8.312L30.064,12.272L23.728,5.935Z" style="fill:rgb(204,214,221);fill-rule:nonzero;"/>
</g>
<g transform="matrix(0.853831,0,0,0.853831,0.146169,0)">
<path d="M26.103,3.558L26.895,2.766L33.231,9.101L32.439,9.893L26.103,3.558ZM24.52,5.142L25.311,4.351L31.647,10.686L30.855,11.478L24.52,5.142Z" style="fill:rgb(153,170,181);fill-rule:nonzero;"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

View file

@ -29,6 +29,7 @@ import { CleanCmd } from "./commands/CleanCmd";
import { Message } from "eris";
import { InviteInfoCmd } from "./commands/InviteInfoCmd";
import { ChannelInfoCmd } from "./commands/ChannelInfoCmd";
import { MessageInfoCmd } from "./commands/MessageInfoCmd";
const defaultOptions: PluginOptions<UtilityPluginType> = {
config: {
@ -40,6 +41,7 @@ const defaultOptions: PluginOptions<UtilityPluginType> = {
can_server: false,
can_invite: false,
can_channel: false,
can_message: false,
can_reload_guild: false,
can_nickname: false,
can_ping: false,
@ -65,6 +67,7 @@ const defaultOptions: PluginOptions<UtilityPluginType> = {
can_server: true,
can_invite: true,
can_channel: true,
can_message: true,
can_nickname: true,
can_vcmove: true,
can_help: true,
@ -116,6 +119,7 @@ export const UtilityPlugin = zeppelinPlugin<UtilityPluginType>()("utility", {
CleanCmd,
InviteInfoCmd,
ChannelInfoCmd,
MessageInfoCmd,
],
onLoad(pluginData) {

View file

@ -0,0 +1,31 @@
import { utilityCmd } from "../types";
import { commandTypeHelpers as ct } from "../../../commandTypes";
import { sendErrorMessage } from "../../../pluginUtils";
import { getMessageInfoEmbed } from "../functions/getMessageInfoEmbed";
import { canReadChannel } from "../../../utils/canReadChannel";
export const MessageInfoCmd = utilityCmd({
trigger: ["message", "messageinfo"],
description: "Show information about a message",
usage: "!message 534722016549404673-534722219696455701",
permission: "can_message",
signature: {
message: ct.messageTarget(),
},
async run({ message, args, pluginData }) {
if (!canReadChannel(args.message.channel, message.author.id)) {
sendErrorMessage(pluginData, message.channel, "Unknown message");
return;
}
const embed = await getMessageInfoEmbed(pluginData, args.message.channel.id, args.message.messageId);
if (!embed) {
sendErrorMessage(pluginData, message.channel, "Unknown message");
return;
}
message.channel.createMessage({ embed });
},
});

View file

@ -0,0 +1,129 @@
import { PluginData } from "knub";
import { UtilityPluginType } from "../types";
import { Constants, EmbedOptions } from "eris";
import moment from "moment-timezone";
import humanizeDuration from "humanize-duration";
import { chunkMessageLines, preEmbedPadding, trimEmptyLines, trimLines } from "../../../utils";
import { getDefaultPrefix } from "knub/dist/commands/commandUtils";
const MESSAGE_ICON = "https://cdn.discordapp.com/attachments/740650744830623756/740685652152025088/message.png";
export async function getMessageInfoEmbed(
pluginData: PluginData<UtilityPluginType>,
channelId: string,
messageId: string,
): Promise<EmbedOptions | null> {
const message = await pluginData.client.getMessage(channelId, messageId).catch(() => null);
if (!message) {
return null;
}
const embed: EmbedOptions = {
fields: [],
};
embed.author = {
name: `Message: ${message.id}`,
icon_url: MESSAGE_ICON,
};
const createdAt = moment(message.createdAt, "x");
const messageAge = humanizeDuration(Date.now() - message.createdAt, {
largest: 2,
round: true,
});
const editedAt = message.editedTimestamp && moment(message.editedTimestamp, "x");
const editAge =
message.editedTimestamp &&
humanizeDuration(Date.now() - message.editedTimestamp, {
largest: 2,
round: true,
});
const type =
{
[Constants.MessageTypes.DEFAULT]: "Regular message",
[Constants.MessageTypes.CHANNEL_PINNED_MESSAGE]: "System message",
[Constants.MessageTypes.GUILD_MEMBER_JOIN]: "System message",
[Constants.MessageTypes.USER_PREMIUM_GUILD_SUBSCRIPTION]: "System message",
[Constants.MessageTypes.USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1]: "System message",
[Constants.MessageTypes.USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2]: "System message",
[Constants.MessageTypes.USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3]: "System message",
[Constants.MessageTypes.CHANNEL_FOLLOW_ADD]: "System message",
[Constants.MessageTypes.GUILD_DISCOVERY_DISQUALIFIED]: "System message",
[Constants.MessageTypes.GUILD_DISCOVERY_REQUALIFIED]: "System message",
}[message.type] || "Unknown";
embed.fields.push({
name: preEmbedPadding + "Message information",
value: trimEmptyLines(
trimLines(`
ID: \`${message.id}\`
Channel: <#${message.channel.id}>
Channel ID: \`${message.channel.id}\`
Created: **${messageAge} ago** (\`${createdAt.format("MMM D, YYYY [at] H:mm [UTC]")}\`)
${editedAt ? `Edited at: **${editAge} ago** (\`${editedAt.format("MMM D, YYYY [at] H:mm [UTC]")}\`)` : ""}
Type: **${type}**
Link: [**Go to message **](https://discord.com/channels/${pluginData.guild.id}/${message.channel.id}/${
message.id
})
`),
),
});
const authorCreatedAt = moment(message.author.createdAt);
const authorAccountAge = humanizeDuration(Date.now() - message.author.createdAt, {
largest: 2,
round: true,
});
const authorJoinedAt = message.member && moment(message.member.joinedAt);
const authorServerAge =
message.member &&
humanizeDuration(Date.now() - message.member.joinedAt, {
largest: 2,
round: true,
});
embed.fields.push({
name: preEmbedPadding + "Author information",
value: trimLines(`
Name: **${message.author.username}#${message.author.discriminator}**
ID: \`${message.author.id}\`
Created: **${authorAccountAge} ago** (\`${authorCreatedAt.format("MMM D, YYYY [at] H:mm [UTC]")}\`)
${
authorJoinedAt
? `Joined: **${authorServerAge} ago** (\`${authorJoinedAt.format("MMM D, YYYY [at] H:mm [UTC]")}\`)`
: ""
}
Mention: <@!${message.author.id}>
`),
});
const textContent = message.content || "<no text content>";
const chunked = chunkMessageLines(textContent, 1014);
for (const [i, chunk] of chunked.entries()) {
embed.fields.push({
name: i === 0 ? preEmbedPadding + "Text content" : "[...]",
value: chunk,
});
}
if (message.attachments.length) {
embed.fields.push({
name: preEmbedPadding + "Attachments",
value: message.attachments[0].url,
});
}
if (message.embeds.length) {
const prefix = pluginData.guildConfig.prefix || getDefaultPrefix(pluginData.client);
embed.fields.push({
name: preEmbedPadding + "Embeds",
value: `Message contains an embed, use \`${prefix}source\` to see the embed source`,
});
}
return embed;
}

View file

@ -15,6 +15,7 @@ export const ConfigSchema = t.type({
can_server: t.boolean,
can_invite: t.boolean,
can_channel: t.boolean,
can_message: t.boolean,
can_reload_guild: t.boolean,
can_nickname: t.boolean,
can_ping: t.boolean,

View file

@ -492,6 +492,13 @@ export function trimLines(str: string) {
.trim();
}
export function trimEmptyLines(str: string) {
return str
.split("\n")
.filter(l => l.trim() !== "")
.join("\n");
}
export function asSingleLine(str: string) {
return trimLines(str).replace(/\n/g, " ");
}