使用新生成的图像自动更新/编辑嵌入消息 - Discord.js
Posted
技术标签:
【中文标题】使用新生成的图像自动更新/编辑嵌入消息 - Discord.js【英文标题】:Auto-update/ edit an embedded message with a newly generated image - Discord.js 【发布时间】:2021-05-22 20:25:49 【问题描述】:我有一个响应!stock
命令的机器人。
当用户键入!stock
时,用户消息将被删除,并以图片作为附件将嵌入内容发送到频道。
此图像是通过 Puppeteer 唯一生成的(使用我根据从数据库中检索到的一些 Mongo 数据构建的 html 字符串)。
这是我的代码:
const config = require('../config');
const
doesGivenUserHaveGivenRole,
generateStockImage
= require('../utils');
module.exports =
name: 'stock',
description: 'Use to post the latest stock levels',
guildOnly: true,
async execute(message, args)
// don't allow arguments
if (args && args.length > 0) return;
// ignore if we're not an admin
if (!doesGivenUserHaveGivenRole(message, message.author.id, config.ADMIN_ROLE_ID)) return;
// delete the author's message
message.delete();
// generate a new HTML string & return an embed to send to the channel
const generatedStockImage = await generateStockImage();
// send that message
message.channel.send(generatedStockImage).then(message =>
// then every minute
setInterval(async () =>
// get the image again
const generatedEdit = await generateStockImage();
// edit the original message with the new image (simple, right?)
message.edit(generatedEdit);
, 60000);
);
;
generateStockImage
函数如下所示:
const generateStockImage = async () =>
// check if the image already exists
if (fs.existsSync('./image.png'))
// if it does
fs.unlink('./image.png', (err) =>
if (err)
console.error(err)
return;
// remove it, as we want to generate a new one for sure
console.log('removed');
);
// get my data from MongoDB
const stock = await getStock();
console.log(stock[0].stock);
let html = `<!DOCTYPE html><html><head><style>bodybackground-color: black; color: white;width: 870px;height: 225px;tablefont-family: arial, sans-serif; border-collapse: collapse;td, thborder: 1px solid #dddddd; padding: 4px; text-align: center;.denominationtext-align: centre; font-size: 14px;margin: 0px 0px 10px 0px;.amountfont-size: 35px;.containerdisplay: flex;.tablemargin: 0px 5px 0px 0px; width: 100%;.greencolor: #2ecc71;.yellowcolor: #f1c40f;.redcolor: #c45563;.iconwidth:20px;height:20px;padding-right:3px</style></head><body><div class="container"> `;
stock.forEach(code =>
let colour;
if (code.stock >= 100)
colour = 'green';
if (code.stock <= 50)
colour = 'yellow';
if (code.stock === 0)
colour = 'red';
html += `<!-- some html code I generate dynamically based on stock (above) $code.something -->`;
);
// close my html
html += `</div></body></html>`;
// create a new puppeteer browser
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport(
width: 880,
height: 235,
deviceScaleFactor: 1,
);
await page.setContent(html);
await page.screenshot( path: './image.png' ); // take a screenshot of the page we generated
await browser.close();
// wait for 8 seconds (to make sure the image is written to file first)
await sleep(8000);
const buffer = fs.readFileSync('./image.png');
const attachment = new Discord.MessageAttachment(buffer, 'image.png');
const embedToReturn =
embed:
color: '#4287f5',
title: 'Current Stock',
files: [attachment],
image:
url: 'attachment://image.png'
,
timestamp: new Date(),
footer:
text: 'My Bot Name',
icon_url: 'https://i.imgur.com/myBotLogo.png',
console.log(embedToReturn);
return embedToReturn; // return the new embed value
我的代码根据数据库数据成功生成了一张新图片,并保存到项目根目录。
根据我从 MongoDB 收到的数据,我可以打开文件并查看它实际上是一个新生成的图像。
此图像在第一次运行命令时成功发布,但不会在后续“编辑”时更新。
我面临的问题是生成的图像没有在我的嵌入中更新。
当message.edit
事件被触发时,它似乎没有使用generatedEdit
。
图像保持完全相同,即使嵌入有新的时间戳和消息本身的 (edited)
文本。
它每分钟都会成功地“编辑”消息,但只是没有显示最新生成的图像(即使该图像位于我的项目根目录中,并且我可以看到它已经更新)。
我感觉是以下行导致了问题:const attachment = new Discord.MessageAttachment(buffer, 'image.png');
这与不和谐缓存有关吗?我做错了什么?
【问题讨论】:
您在编辑邮件之前是否尝试过console.log
generatedEdit
,以确保您要发送的图片是正确的?
@Levi_OP 是的,还检查了缓冲区以确保图像不同,还检查了输出文件
我认为它必须与缓存有关。您可以尝试在每次附加图像时重命名图像,以免不和谐可能不依赖缓存。
你的意思是你试图用不同的图片编辑邮件吗?
@Bqre 是的。这是正确的。 60 秒后,创建一个新图像,将其放入现有的嵌入中
【参考方案1】:
仅通过查看您的代码,我找不到任何逻辑错误,它应该按预期工作。
正如您所提到的,有一种可能性是,Discord 正在缓存图像数据,基于提供的相同文件名。
一些建议:
尝试为您发送到 Discord 服务器的每个图像文件指定一个唯一的名称。
const generateStockImage = async () =>
const imageName = `image-$Date.now().png`
// note: old cleanup part removed since now each image name is unique.
// you could for example remove all images except the current "imageName" one
// get my data from MongoDB
const stock = await getStock();
console.log(stock[0].stock);
let html = `<!DOCTYPE html><html><head><style>bodybackground-color: black; color: white;width: 870px;height: 225px;tablefont-family: arial, sans-serif; border-collapse: collapse;td, thborder: 1px solid #dddddd; padding: 4px; text-align: center;.denominationtext-align: centre; font-size: 14px;margin: 0px 0px 10px 0px;.amountfont-size: 35px;.containerdisplay: flex;.tablemargin: 0px 5px 0px 0px; width: 100%;.greencolor: #2ecc71;.yellowcolor: #f1c40f;.redcolor: #c45563;.iconwidth:20px;height:20px;padding-right:3px</style></head><body><div class="container"> `;
stock.forEach(code =>
let colour;
if (code.stock >= 100)
colour = 'green';
if (code.stock <= 50)
colour = 'yellow';
if (code.stock === 0)
colour = 'red';
html += `<!-- some html code I generate dynamically based on stock (above) $code.something -->`;
);
// close my html
html += `</div></body></html>`;
// create a new puppeteer browser
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport(
width: 880,
height: 235,
deviceScaleFactor: 1,
);
await page.setContent(html);
await page.screenshot( path: `./$imageName` ); // take a screenshot of the page we generated
await browser.close();
// wait for 8 seconds (to make sure the image is written to file first)
await sleep(8000);
const buffer = fs.readFileSync(`./$imageName`);
const attachment = new Discord.MessageAttachment(buffer, imageName);
const embedToReturn =
embed:
color: '#4287f5',
title: 'Current Stock',
files: [attachment],
image:
url: `attachment://$imageName`
,
timestamp: new Date(),
footer:
text: 'My Bot Name',
icon_url: 'https://i.imgur.com/myBotLogo.png',
console.log(embedToReturn);
return embedToReturn; // return the new embed value
这部分也需要考虑:
// send that message
message.channel.send(generatedStockImage).then(message =>
// then every minute
setInterval(async () =>
// get the image again
const generatedEdit = await generateStockImage();
// edit the original message with the new image (simple, right?)
message.edit(generatedEdit);
, 60000);
);
请注意,在 setInterval()
中,您引用了 message
变量,但如果您的意图是在回调中引用外部上下文 message
或内部上下文 message
变量,则会产生歧义。
为了使您的意图明确并防止由于意外行为而可能出现的错误,我建议不要隐藏回调中的变量。 提示: 甚至还有一个 ESlint 规则,值得考虑:no-shadow
// send that message
message.channel.send(generatedStockImage).then(sentMessage =>
// then every minute
setInterval(async () =>
// get the image again
const generatedEdit = await generateStockImage();
// edit the original message with the new image (simple, right?)
sentMessage.edit(generatedEdit);
, 60000);
);
如果引用我刚刚重命名的sentVariable
对你不起作用,那么你可以直接省略它,只保留原来的引用:
// send that message
message.channel.send(generatedStockImage).then(() => // or, if want to still see it around, append with _: (_message) =>
// then every minute
setInterval(async () =>
// get the image again
const generatedEdit = await generateStockImage();
// edit the original message with the new image (simple, right?)
message.edit(generatedEdit);
, 60000);
);
【讨论】:
以上是关于使用新生成的图像自动更新/编辑嵌入消息 - Discord.js的主要内容,如果未能解决你的问题,请参考以下文章
编辑带有图像附件的嵌入消息在聊天中加倍 - Discord JDA
Discord.js 使用来自其他消息的附件来更新嵌入中的图像