You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord.js重复发送相同消息问题:对接YouTube API推送Discord频道故障

问题根因
  • 重复注册Discord消息事件监听器:你在new_vid函数的判断分支中每次执行都会给client新增一个message事件监听器,后续只要有任意消息触发该事件,所有累积的监听器都会同步执行发送逻辑,直接导致消息重复发送。且你已经拿到了可用的message对象,完全不需要额外监听消息事件来发消息。
  • 定时器重复启动风险:当用户多次发送!*start指令时,会同时启动多个定时拉取任务,并行拉取数据触发发送逻辑,也会导致重复推送。
  • YouTube API请求地址拼写错误:第一个拉取地址中playlistItemspart缺少分隔问号,正确应为playlistItems?part,会导致请求失败。
  • 全局变量污染风险:new_link、last_date、last_link、video_link等核心判断变量都使用全局声明,多轮循环、多次拉取时很容易出现变量覆盖,导致新旧内容判断逻辑失效。
修复方案
// 新增全局状态控制,避免重复启动定时器
let isRunning = false;
// 用对象存储不同频道的最新记录,避免全局变量串数据
let latestRecords = {
  "UUxVDmCmgQMTUTWMeRZUYliw": { lastDate: null, lastLink: null },
  "UUM_fQdoc0Jmd5mH3KLaDaXA": { lastDate: null, lastLink: null }
};
const playlistIds = ["UUxVDmCmgQMTUTWMeRZUYliw", "UUM_fQdoc0Jmd5mH3KLaDaXA"];

async function fetchAndCheck(notifyChannel, playlistId) {
    // 修正API地址拼写错误,动态传入playlistId
    const apiUrl = `https://youtube.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=2&playlistId=${playlistId}&key=${api_key}`;
    const res = await fetch(apiUrl);
    const fetched = await res.json();
    if (!fetched.items || !fetched.items.length) return;
    // 直接从接口返回值取所需字段,替代原全局操作避免污染
    const latestItem = fetched.items[0].snippet;
    const videoId = latestItem.resourceId.videoId;
    const newLink = `https://www.youtube.com/watch?v=${videoId}`;
    const channelName = latestItem.channelTitle;
    const publishDate = latestItem.publishedAt;
    const currentRecord = latestRecords[playlistId];
    // 只对比当前playlist的最新记录
    if (currentRecord.lastDate !== publishDate && currentRecord.lastLink !== newLink) {
        // 更新记录
        currentRecord.lastDate = publishDate;
        currentRecord.lastLink = newLink;
        // 直接用传入的频道对象发消息,不需要额外监听事件
        notifyChannel.send(`New video/live from ${channelName}`);
        notifyChannel.send(newLink);
    }
}

client.on("message", (message) => {
    if (message.content === "!*start" && !isRunning) {
        isRunning = true;
        // 直接拿到当前消息所在频道,不需要额外传channel
        const notifyChannel = message.channel;
        setInterval(async () => {
            for (const pid of playlistIds) {
                await fetchAndCheck(notifyChannel, pid);
            }
        }, 600000);
        message.reply("拉取通知任务已启动");
    }
});

内容的提问来源于stack exchange,提问作者Ant Tube

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 09:48:03