diff --git a/backend/src/plugins/Tags/TagsPlugin.ts b/backend/src/plugins/Tags/TagsPlugin.ts index f3a488e2..18d65540 100644 --- a/backend/src/plugins/Tags/TagsPlugin.ts +++ b/backend/src/plugins/Tags/TagsPlugin.ts @@ -12,6 +12,9 @@ import { TagDeleteCmd } from "./commands/TagDeleteCmd"; import { TagEvalCmd } from "./commands/TagEvalCmd"; import { TagListCmd } from "./commands/TagListCmd"; import { TagSourceCmd } from "./commands/TagSourceCmd"; +import moment from "moment-timezone"; +import humanizeDuration from "humanize-duration"; +import { convertDelayStringToMS } from "../../utils"; const defaultOptions: PluginOptions = { config: { @@ -67,6 +70,114 @@ export const TagsPlugin = zeppelinPlugin()("tags", { state.onMessageDeleteFn = msg => onMessageDelete(pluginData, msg); state.savedMessages.events.on("delete", state.onMessageDeleteFn); + + state.tagFunctions = { + parseDateTime(str) { + if (typeof str === "number") { + return str; // Unix timestamp + } + + if (typeof str !== "string") { + return Date.now(); + } + + return moment(str, "YYYY-MM-DD HH:mm:ss").valueOf(); + }, + + countdown(toDate) { + const target = moment(this.parseDateTime(toDate)); + + const now = moment(); + if (!target.isValid()) return ""; + + const diff = target.diff(now); + const result = humanizeDuration(diff, { largest: 2, round: true }); + return diff >= 0 ? result : `${result} ago`; + }, + + now() { + return Date.now(); + }, + + timeAdd(...args) { + let reference; + let delay; + + if (args.length >= 2) { + // (time, delay) + reference = this.parseDateTime(args[0]); + delay = args[1]; + } else { + // (delay), implicit "now" as time + reference = Date.now(); + delay = args[0]; + } + + const delayMS = convertDelayStringToMS(delay); + return moment(reference) + .add(delayMS) + .valueOf(); + }, + + timeSub(...args) { + let reference; + let delay; + + if (args.length >= 2) { + // (time, delay) + reference = this.parseDateTime(args[0]); + delay = args[1]; + } else { + // (delay), implicit "now" as time + reference = Date.now(); + delay = args[0]; + } + + const delayMS = convertDelayStringToMS(delay); + return moment(reference) + .subtract(delayMS) + .valueOf(); + }, + + timeAgo(delay) { + return this.timeSub(delay); + }, + + formatTime(time, format) { + const parsed = this.parseDateTime(time); + return moment(parsed).format(format); + }, + + discordDateFormat(time) { + const parsed = time ? this.parseDateTime(time) : Date.now(); + + return moment(parsed).format("YYYY-MM-DD"); + }, + + mention: input => { + if (typeof input !== "string") { + return ""; + } + + if (input.match(/^<(@#)(!&)\d+>$/)) { + return input; + } + + if (pluginData.guild.members.has(input) || pluginData.client.users.has(input)) { + return `<@!${input}>`; + } + + if (pluginData.guild.channels.has(input) || pluginData.client.channelGuildMap[input]) { + return `<#${input}>`; + } + + return ""; + }, + }; + + for (const [name, fn] of Object.entries(state.tagFunctions)) { + state.tagFunctions[name] = (fn as any).bind(state.tagFunctions); + } }, onUnload(pluginData) {