You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Node.js环境下Discord Bot新增功能后再次触发System: Unexpected end of input错误求助

Fixing "System: Unexpected end of input" Error in Your Discord Bot

Hey there! Let's dig into fixing that "System: Unexpected end of input" error you're hitting with your Discord bot. I've gone through your code and found several key issues that are causing this problem (and some other bugs that would pop up later). Let's break them down and fix the code step by step.

Key Issues Identified

  • Critical variable order issue: You tried to call client.login() before defining the client variable itself. JavaScript reads code top-to-bottom, so this would throw a reference error immediately.
  • Unscoped code block: There's an if(message.content === "embed") block floating outside any event listener. This is invalid because message doesn't exist in that scope, and it breaks the code structure, leading to the "unexpected end of input" error.
  • Duplicate message event listeners: You have multiple client.on("message") callbacks. This not only causes unnecessary overhead but can lead to conflicting logic and missed events.
  • Undefined variables: The .daily command uses a currency variable that's never defined, and the .purge command references args which is only defined in a separate, unused message listener.
  • Incomplete logic: The .smoothie command creates an embed but never sends it, and the .cpstest command starts handling topUsers but doesn't finish that section.

Corrected Full Code

const express = require('express');
const app = express();
const Database = require("@replit/database");
const db = new Database();
const Discord = require("discord.js");
const client = new Discord.Client();

// Define currency for economy commands
const currency = " coins";

// Express server setup
app.get("/", (req, res) => {
  res.send("hello world");
});

app.listen(3000, () => {
  console.log("Project is ready!");
});

// Client ready event
client.on("ready", () => {
  client.user.setPresence({ 
    activity: { name: "being a discord bot" }, 
    status: "online" 
  });
  console.log(`Logged in as ${client.user.tag}!`);
});

// Guild member welcome event
client.on("guildMemberAdd", member => {
  if(member.guild.id === "850466744581488640"){
    const welcomeChannel = client.channels.cache.get("850486786433745017");
    if(welcomeChannel) welcomeChannel.send(`Welcome ${member}!`);
  }
});

// Snipe collection setup
client.snipe = new Discord.Collection();
client.on("messageDelete", deletedMsg => {
  client.snipe.set(deletedMsg.channel.id, deletedMsg);
});

// Merged all message command logic into one listener
client.on("message", async message => {
  // Ignore bot messages
  if(message.author.bot) return;

  // Define args for all commands that need them
  const args = message.content.split(" ").slice(1);

  // Ping command
  if(message.content === "ping") {
    message.channel.send("pong");
  }

  // Mute command
  if(message.content.startsWith(".mute")){
    if(!message.member.hasPermission("KICK_MEMBERS")) return message.channel.send("You don't have permission to mute.");
    const role = message.guild.roles.cache.find(role => role.name === "muted");
    const member = message.mentions.members.first();
    let reason = message.content.split(" ").slice(2).join(" ");
    if(!reason) reason = "No reason specified";
    if(!role) return message.channel.send("This server doesn't have a muted role.");
    if(!member) return message.channel.send("You didn't mention a member.");
    if(member.roles.cache.has(role.id)) return message.channel.send("That user is already muted.");
    
    member.roles.add(role)
      .then(() => {
        message.channel.send(`Successfully muted ${member} with reason: ${reason}`);
      })
      .catch(() => {
        message.channel.send("Oops, something went wrong.");
      });
  }

  // Nickname command
  if(message.content === ".nickname") {
    const nickname = ["smoothiepro", "smoothieisbest", "sub2smoothie", "SUBSKRAIB2SMOOTHIE"];
    message.channel.send(`${nickname[Math.floor(Math.random() * nickname.length)]} is your new name.`);
  }

  // Kill command
  if(message.content.startsWith(".kill")) {
    const victim = message.mentions.users.first();
    if(!victim) message.reply("Mention someone to kill");
    else{
      message.channel.send(`${victim} has died.`);
      // Fixed image URL (used direct image instead of Google search link)
      const image = new Discord.MessageAttachment("https://images.unsplash.com/photo-1501959181532-42a0a669554e?ixlib=rb-4.0.3&auto=format&fit=crop&w=1350&q=80");
      message.channel.send(image);
    }
  }

  // Kick command
  if(message.content.startsWith(".kick")) {
    if(message.member.hasPermission("KICK_MEMBERS")) {
      const member = message.mentions.members.first();
      if(!member) message.channel.send("Please mention someone");
      else {
        member.kick().then(mem => {
          message.channel.send(`Kicked ${mem.user.username}!`);
        }).catch(err => {
          message.channel.send(`Failed to kick: ${err.message}`);
        });
      }
    } else {
      message.reply("You don't have permission to do this.");
    }
  }

  // Cat image command
  if(message.content === ".catimage") {
    const image = new Discord.MessageAttachment("https://www.thesprucepets.com/thmb/gY_3zGT4Nasd_NM2QYu1iNj-6s8=/1080x721/filters:no_upscale():max_bytes(150000):strip_icc()/cutest-cats-on-the-internet-4-57eeab3c5f9b586c3549f9c2.jpeg");
    message.channel.send(image);
  }

  // Rickroll command
  if(message.content === ".rickroll") {
    const image = new Discord.MessageAttachment("https://media3.giphy.com/media/g7GKcSzwQfugw/200w.gif?cid=82a1493bx6tle1ut4bfnzw1zqgyjpw5vbw51c4j1fit3fbhu&rid=200w.gif&ct=g");
    message.channel.send(image);
    message.channel.send("You have Rick Rolled yourself. Try to be smarter next time.");
  }

  // Smoothie embed command
  if(message.content === ".smoothie") {
    const embed = new Discord.MessageEmbed()
      .setTitle("why did you do this")
      .setDescription("the man who abuses a discord bot")
      .setFooter("if you found this dm me your cool");
    message.channel.send(embed); // Added missing send call
  }

  // Ban command
  if(message.content.startsWith(".ban")) {
    if(message.member.hasPermission("BAN_MEMBERS")) {
      const member = message.mentions.members.first();
      if(!member) message.channel.send("Please mention someone");
      else {
        member.ban().then(mem => {
          message.channel.send(`Banned ${mem.user.username}!`);
        }).catch(err => {
          message.channel.send(`Failed to ban: ${err.message}`);
        });
      }
    } else {
      message.reply("You don't have permission to do this.");
    }
  }

  // Snipe command
  if(message.content.startsWith(".snipe")) {
    const channel = message.mentions.channels.first() || message.channel;
    const msg = client.snipe.get(channel.id);
    if(!msg) return message.channel.send("There is nothing to snipe.");
    const embed = new Discord.MessageEmbed()
      .setTitle(msg.author.tag)
      .setThumbnail(msg.author.displayAvatarURL({dynamic: true}))
      .setColor("RANDOM")
      .setDescription(msg.content);
    if(msg.attachments.first()) embed.setImage(msg.attachments.first().url);
    message.channel.send(embed);
  }

  // Purge command
  if(message.content.startsWith(".purge")) {
    if(!message.member.hasPermission("MANAGE_MESSAGES")) return message.channel.send("Missing Permission.");
    const amountToPurge = args[0];
    if(isNaN(amountToPurge) || amountToPurge < 1 || amountToPurge > 100) return message.channel.send("Must provide an integer between 1 and 100.");
    message.delete().catch(() => {});
    message.channel.bulkDelete(parseInt(amountToPurge))
      .then(deleted => {
        message.channel.send(`Deleted ${deleted.size} messages!`).then(v => v.delete({timeout: 5000}));
      })
      .catch(err => {
        message.channel.send(`Failed to purge messages: ${err.message}`);
      });
  }

  // Embed command
  if(message.content === "embed") {
    const embed = new Discord.MessageEmbed()
      .setTitle("Title")
      .setDescription("Description")
      .setColor("RANDOM")
      .setFooter("Footer");
    message.channel.send(embed);
  }

  // CPS Test command
  if(message.content.startsWith(".cpstest")) {
    const CPStest = new Discord.MessageEmbed()
      .setColor('#8f82ff')
      .setTitle('CPS Test')
      .setDescription(
        `Alright, ${message.author.username}. Ready to begin your CPS test? All you have to do is spam click this reaction above ^ as fast as you can, you have 10 seconds before the timer runs out. Good Luck!`,
      )
      .setFooter(
        'Note: This may be inaccurate depending on Discord API and Rate Limits.',
      );
    const sentMessage = await message.channel.send(CPStest);
    await sentMessage.react('🖱️');

    // Create a reaction collector
    const filter = (reaction, user) => reaction.emoji.name === '🖱️' && user.id === message.author.id;
    let clicks = 0; // Fixed initial click count (removed arbitrary multiplier)
    const timespan = 10;
    const collector = sentMessage.createReactionCollector(filter, { time: timespan * 1000 });

    collector.on('collect', () => {
      clicks++;
    });

    collector.on('end', () => {
      sentMessage.channel.send(
        `Collected ${clicks} total clicks.`,
      );
      const cps = (clicks / timespan).toFixed(2);
      sentMessage.channel.send(
        `Your CPS averaged ~${cps} clicks per second over ${timespan} seconds.`,
      );
      // Optional: Add topUsers logic here if you want to save high scores
    });
  }

  // Unmute command
  if(message.content.startsWith(".unmute")){
    if(!message.member.hasPermission("KICK_MEMBERS")) return message.channel.send("You don't have permission to unmute.");
    const role = message.guild.roles.cache.find(role => role.name === "muted");
    const member = message.mentions.members.first();
    let reason = message.content.split(" ").slice(2).join(" ");
    if(!reason) reason = "No reason specified";
    if(!role) return message.channel.send("This server doesn't have a muted role.");
    if(!member) return message.channel.send("You didn't mention a member.");
    if(!member.roles.cache.has(role.id)) return message.channel.send("That user is not muted.");
    
    member.roles.remove(role)
      .then(() => {
        message.channel.send(`Successfully unmuted ${member} with reason: ${reason}`);
      })
      .catch(() => {
        message.channel.send("Oops, something went wrong.");
      });
  }

  // Balance command
  if(message.content.toLowerCase().startsWith(".balance")) {
    let balance = await db.get(`wallet_${message.author.id}`);
    let bank = await db.get(`bank_${message.author.id}`);
    if (balance === null) balance = 0;
    if (bank === null) bank = 0;
    message.channel.send(`Your wallet: ${balance}${currency} and your bank: ${bank}${currency}`);
  }

  // Daily command
  if(message.content.toLowerCase().startsWith(".daily")) {
    const check = await db.get(`dailyCheck_${message.author.id}`);
    const timeout = 86400000; // 24 hours in ms
    if(check !== null && timeout - (Date.now() - check) > 0) {
      const ms = require("pretty_ms");
      const timeLeft = ms(timeout - (Date.now() - check));
      message.channel.send(`Woah wait there speedy! You have already claimed your daily prize and still need to wait ${timeLeft}`);
    } else { 
      const reward = 1000;
      let currentBalance = await db.get(`wallet_${message.author.id}`) || 0;
      await db.set(`wallet_${message.author.id}`, currentBalance + reward);
      await db.set(`dailyCheck_${message.author.id}`, Date.now());
      message.channel.send(`You have claimed ${reward.toLocaleString()}${currency}! Come back tomorrow for another reward!`);
    }
  }
});

// Login after all setup is done
client.login(process.env.token);

Key Fixes Explained

  1. Reordered initialization: We now load dependencies, create the client, set up all events, and then call client.login()—this ensures nothing runs before it's ready.
  2. Merged message listeners: All command logic lives in one message event callback, eliminating conflicts and making the code easier to debug.
  3. Fixed unscoped code: The embed command is now inside the message listener where message is valid.
  4. Defined missing variables: Added currency for economy commands, and declared args once at the top of the message listener for all commands to use.
  5. Completed incomplete logic: Added the send call for the .smoothie embed, fixed the .kill command's image URL (Google search links don't work as attachments), and cleaned up the CPS test's click counting.
  6. Added error handling: Added catch blocks for kick/ban/purge commands to handle permission issues or other errors gracefully.
  7. Fixed permission check: Changed .purge's permission to MANAGE_MESSAGES (the correct permission for deleting messages).

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

火山引擎 最新活动