implemented //icon with button confirmation system
This commit is contained in:
		
							parent
							
								
									30bf87b106
								
							
						
					
					
						commit
						69a01a0608
					
				
					 2 changed files with 70 additions and 8 deletions
				
			
		| 
						 | 
					@ -6,15 +6,48 @@ const DiscordTypes = require("discord-api-types/v10")
 | 
				
			||||||
const {discord, sync, db} = require("../passthrough")
 | 
					const {discord, sync, db} = require("../passthrough")
 | 
				
			||||||
/** @type {import("../matrix/api")}) */
 | 
					/** @type {import("../matrix/api")}) */
 | 
				
			||||||
const api = sync.require("../matrix/api")
 | 
					const api = sync.require("../matrix/api")
 | 
				
			||||||
 | 
					/** @type {import("../matrix/file")} */
 | 
				
			||||||
 | 
					const file = sync.require("../matrix/file")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const prefix = "/"
 | 
					const PREFIX = "//"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let buttons = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @param {string} channelID where to add the button
 | 
				
			||||||
 | 
					 * @param {string} messageID where to add the button
 | 
				
			||||||
 | 
					 * @param {string} emoji emoji to add as a button
 | 
				
			||||||
 | 
					 * @param {string} userID only listen for responses from this user
 | 
				
			||||||
 | 
					 * @returns {Promise<import("discord-api-types/v10").GatewayMessageReactionAddDispatchData>}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					async function addButton(channelID, messageID, emoji, userID) {
 | 
				
			||||||
 | 
						await discord.snow.channel.createReaction(channelID, messageID, emoji)
 | 
				
			||||||
 | 
						return new Promise(resolve => {
 | 
				
			||||||
 | 
							buttons.push({channelID, messageID, userID, resolve, created: Date.now()})
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Clear out old buttons every so often to free memory
 | 
				
			||||||
 | 
					setInterval(() => {
 | 
				
			||||||
 | 
						const now = Date.now()
 | 
				
			||||||
 | 
						buttons = buttons.filter(b => now - b.created < 2*60*60*1000)
 | 
				
			||||||
 | 
					}, 10*60*1000)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @param {import("discord-api-types/v10").GatewayMessageReactionAddDispatchData} data */
 | 
				
			||||||
 | 
					function onReactionAdd(data) {
 | 
				
			||||||
 | 
						const button = buttons.find(b => b.channelID === data.channel_id && b.messageID === data.message_id && b.userID === data.user_id)
 | 
				
			||||||
 | 
						if (button) {
 | 
				
			||||||
 | 
							buttons = buttons.filter(b => b !== button) // remove button data so it can't be clicked again
 | 
				
			||||||
 | 
							button.resolve(data)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @callback CommandExecute
 | 
					 * @callback CommandExecute
 | 
				
			||||||
 * @param {DiscordTypes.GatewayMessageCreateDispatchData} message
 | 
					 * @param {DiscordTypes.GatewayMessageCreateDispatchData} message
 | 
				
			||||||
 * @param {DiscordTypes.APIGuildTextChannel} channel
 | 
					 * @param {DiscordTypes.APIGuildTextChannel} channel
 | 
				
			||||||
 * @param {DiscordTypes.APIGuild} guild
 | 
					 * @param {DiscordTypes.APIGuild} guild
 | 
				
			||||||
 * @param {any} [ctx]
 | 
					 * @param {Partial<DiscordTypes.RESTPostAPIChannelMessageJSONBody>} [ctx]
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -42,24 +75,51 @@ const commands = [{
 | 
				
			||||||
	aliases: ["icon", "avatar", "roomicon", "roomavatar", "channelicon", "channelavatar"],
 | 
						aliases: ["icon", "avatar", "roomicon", "roomavatar", "channelicon", "channelavatar"],
 | 
				
			||||||
	execute: replyctx(
 | 
						execute: replyctx(
 | 
				
			||||||
		async (message, channel, guild, ctx) => {
 | 
							async (message, channel, guild, ctx) => {
 | 
				
			||||||
 | 
								// Guard
 | 
				
			||||||
			const roomID = db.prepare("SELECT room_id FROM channel_room WHERE channel_id = ?").pluck().get(channel.id)
 | 
								const roomID = db.prepare("SELECT room_id FROM channel_room WHERE channel_id = ?").pluck().get(channel.id)
 | 
				
			||||||
			if (!roomID) return discord.snow.channel.createMessage(channel.id, {
 | 
								if (!roomID) return discord.snow.channel.createMessage(channel.id, {
 | 
				
			||||||
				...ctx,
 | 
									...ctx,
 | 
				
			||||||
				content: "This channel isn't bridged to the other side."
 | 
									content: "This channel isn't bridged to the other side."
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Current avatar
 | 
				
			||||||
			const avatarEvent = await api.getStateEvent(roomID, "m.room.avatar", "")
 | 
								const avatarEvent = await api.getStateEvent(roomID, "m.room.avatar", "")
 | 
				
			||||||
			const avatarURL = avatarEvent?.url
 | 
								const avatarURLParts = avatarEvent?.url.match(/^mxc:\/\/([^/]+)\/(\w+)$/)
 | 
				
			||||||
			return discord.snow.channel.createMessage(channel.id, {
 | 
								let currentAvatarMessage =
 | 
				
			||||||
 | 
									( avatarURLParts ? `Current room-specific avatar: https://matrix.cadence.moe/_matrix/media/r0/download/${avatarURLParts[1]}/${avatarURLParts[2]}`
 | 
				
			||||||
 | 
									: "No avatar. Now's your time to strike. Use `//icon` again with a link or upload to set the room-specific avatar.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Next potential avatar
 | 
				
			||||||
 | 
								const nextAvatarURL = message.attachments.find(a => a.content_type?.startsWith("image/"))?.url || message.content.match(/https?:\/\/[^ ]+\.[^ ]+\.(?:png|jpg|jpeg|webp)\b/)?.[0]
 | 
				
			||||||
 | 
								let nextAvatarMessage =
 | 
				
			||||||
 | 
									( nextAvatarURL ? `\nYou want to set it to: ${nextAvatarURL}\nHit ✅ to make it happen.`
 | 
				
			||||||
 | 
									: "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								const sent = await discord.snow.channel.createMessage(channel.id, {
 | 
				
			||||||
				...ctx,
 | 
									...ctx,
 | 
				
			||||||
				content: `Current room avatar: ${avatarURL}`
 | 
									content: currentAvatarMessage + nextAvatarMessage
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (nextAvatarURL) {
 | 
				
			||||||
 | 
									addButton(channel.id, sent.id, "✅", message.author.id).then(async data => {
 | 
				
			||||||
 | 
										const mxcUrl = await file.uploadDiscordFileToMxc(nextAvatarURL)
 | 
				
			||||||
 | 
										await api.sendState(roomID, "m.room.avatar", "", {
 | 
				
			||||||
 | 
											url: mxcUrl
 | 
				
			||||||
 | 
										})
 | 
				
			||||||
 | 
										db.prepare("UPDATE channel_room SET custom_avatar = ? WHERE channel_id = ?").run(mxcUrl, channel.id)
 | 
				
			||||||
 | 
										await discord.snow.channel.createMessage(channel.id, {
 | 
				
			||||||
 | 
											...ctx,
 | 
				
			||||||
 | 
											content: "Your creation is unleashed. Any complaints will be redirected to Grelbo."
 | 
				
			||||||
 | 
										})
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
}, {
 | 
					}, {
 | 
				
			||||||
	aliases: ["invite"],
 | 
						aliases: ["invite"],
 | 
				
			||||||
	execute: replyctx(
 | 
						execute: replyctx(
 | 
				
			||||||
		async (message, channel, guild, ctx) => {
 | 
							async (message, channel, guild, ctx) => {
 | 
				
			||||||
			discord.snow.channel.createMessage(channel.id, {
 | 
								return discord.snow.channel.createMessage(channel.id, {
 | 
				
			||||||
				...ctx,
 | 
									...ctx,
 | 
				
			||||||
				content: "This command isn't implemented yet."
 | 
									content: "This command isn't implemented yet."
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
| 
						 | 
					@ -69,8 +129,8 @@ const commands = [{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** @type {CommandExecute} */
 | 
					/** @type {CommandExecute} */
 | 
				
			||||||
async function execute(message, channel, guild) {
 | 
					async function execute(message, channel, guild) {
 | 
				
			||||||
	if (!message.content.startsWith(prefix)) return
 | 
						if (!message.content.startsWith(PREFIX)) return
 | 
				
			||||||
	const words = message.content.split(" ")
 | 
						const words = message.content.slice(PREFIX.length).split(" ")
 | 
				
			||||||
	const commandName = words[0]
 | 
						const commandName = words[0]
 | 
				
			||||||
	const command = commands.find(c => c.aliases.includes(commandName))
 | 
						const command = commands.find(c => c.aliases.includes(commandName))
 | 
				
			||||||
	if (!command) return
 | 
						if (!command) return
 | 
				
			||||||
| 
						 | 
					@ -79,3 +139,4 @@ async function execute(message, channel, guild) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports.execute = execute
 | 
					module.exports.execute = execute
 | 
				
			||||||
 | 
					module.exports.onReactionAdd = onReactionAdd
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -197,6 +197,7 @@ module.exports = {
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	async onReactionAdd(client, data) {
 | 
						async onReactionAdd(client, data) {
 | 
				
			||||||
		if (data.user_id === client.user.id) return // m2d reactions are added by the discord bot user - do not reflect them back to matrix.
 | 
							if (data.user_id === client.user.id) return // m2d reactions are added by the discord bot user - do not reflect them back to matrix.
 | 
				
			||||||
 | 
							discordCommandHandler.onReactionAdd(data)
 | 
				
			||||||
		if (data.emoji.id !== null) return // TODO: image emoji reactions
 | 
							if (data.emoji.id !== null) return // TODO: image emoji reactions
 | 
				
			||||||
		await addReaction.addReaction(data)
 | 
							await addReaction.addReaction(data)
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue