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

Discord.js v13 EMBED_FIELD_VALUE错误修复及代码修改求助

解决Discord机器人movieinfo命令的RangeError [EMBED_FIELD_VALUE]问题

错误原因

该错误是因为Discord的MessageEmbed要求所有字段值必须是非空字符串,你的代码中存在以下问题:

  • 部分数字类型字段直接传入addField,虽Discord.js会尝试自动转换,但存在潜在风险;
  • 仅通过falsy值判断字段是否存在,会漏掉值为0的合法场景(比如评分0分);
  • 未处理空字符串类型的字段,直接传入会触发校验错误。

修复后的完整代码

const fetch = require('node-fetch');

module.exports = {
  name: 'movieinfo',
  description: 'Affiche des informations sur un film, une série, un anime ou un épisode.',
  category: '🎥 Films et séries',
  usage: '<titre du film, de la série, de l\'anime ou de l\'épisode>',

  async execute(message, args) {
    try {
      const apiKey = 'API KEY';
      const query = args.join(' ');
      const response = await fetch(`https://api.themoviedb.org/3/search/multi?api_key=${apiKey}&language=fr-FR&query=${encodeURIComponent(query)}`);
      const data = await response.json();
      const results = data.results;

      if (!results || results.length === 0) {
        message.channel.send(`Désolé, je n'ai pas trouvé d'informations pour "${query}".`);
        return;
      }

      const mediaTypes = results.map(result => result.media_type);
      const uniqueMediaTypes = [...new Set(mediaTypes)];
      const mediaType = await askMediaType(message, uniqueMediaTypes, query);

      if (!mediaType) return;

      const filteredResults = results.filter(result => result.media_type === mediaType);
      const result = filteredResults[0];

      if (!result) {
        message.channel.send(`Désolé, je n'ai pas trouvé de ${mediaType.toLowerCase()} pour "${query}".`);
        return;
      }

      let title, releaseDate, overview, posterUrl, startDate, endDate, year, rating, voteCount, contentScore, numberOfSeasons, numberOfEpisodes;

      if (mediaType === 'movie') {
        title = result.title;
        releaseDate = result.release_date;
        overview = result.overview || "Aucun synopsis disponible";
        posterUrl = result.poster_path;
        year = releaseDate ? new Date(releaseDate).getFullYear() : null;
        rating = result.vote_average;
        voteCount = result.vote_count;
        contentScore = result.popularity;
      } else if (mediaType === 'tv' || mediaType === 'anime') {
        title = result.name;
        releaseDate = result.first_air_date;
        overview = result.overview || "Aucun synopsis disponible";
        posterUrl = result.poster_path;
        startDate = result.first_air_date;
        endDate = result.last_air_date;
        year = startDate ? new Date(startDate).getFullYear() : null;
        rating = result.vote_average;
        voteCount = result.vote_count;
        contentScore = result.popularity;
        numberOfSeasons = result.number_of_seasons;
        numberOfEpisodes = result.number_of_episodes;
      } else if (mediaType === 'person') {
        title = result.name;
        releaseDate = null;
        overview = result.biography || "Aucune biographie disponible";
        posterUrl = result.profile_path;
      } else {
        message.channel.send(`Désolé, je ne suis pas en mesure de fournir des informations pour "${query}".`);
        return;
      }

      const releaseYear = releaseDate ? ` (${new Date(releaseDate).getFullYear()})` : '';
      const posterEmbed = posterUrl ? new Discord.MessageEmbed().setImage(`https://image.tmdb.org/t/p/original${posterUrl}`) : null;

      const infoEmbed = new Discord.MessageEmbed()
        .setTitle(`${title}${releaseYear}`)
        .setColor('#f8ecfc');

      if (mediaType === 'movie' || mediaType === 'tv' || mediaType === 'anime') {
        if (year !== null && year !== undefined) {
          infoEmbed.addField('Année', year.toString(), true);
        }

        if (rating !== null && rating !== undefined) {
          infoEmbed.addField('Note des utilisateurs', `${rating}/10`, true);
        }

        if (contentScore !== null && contentScore !== undefined) {
          infoEmbed.addField('Score de contenu', `${contentScore.toFixed(1)}/100`, true);
        }

        if (mediaType === 'tv' || mediaType === 'anime') {
          if (numberOfSeasons !== null && numberOfSeasons !== undefined) {
            infoEmbed.addField('Nombre de saisons', numberOfSeasons.toString(), true);
          }

          if (numberOfEpisodes !== null && numberOfEpisodes !== undefined) {
            infoEmbed.addField('Nombre d\'épisodes', numberOfEpisodes.toString(), true);
          }

          if (startDate) {
            const endDateString = endDate ? ` - ${new Date(endDate).toLocaleDateString('fr-FR')}` : '';
            infoEmbed.addField('Dates de diffusion', `${new Date(startDate).toLocaleDateString('fr-FR')}${endDateString}`, true);
          }

          infoEmbed.addField('Synopsis', overview);
        }
      }

      if (mediaType === 'person') {
        infoEmbed.addField('Biographie', overview);
      }

      message.channel.send(`Je vous ai trouvé plusieurs ${mediaType.toLowerCase()} correspondant à "${query}" :\n${filteredResults.map(result => result.title || result.name || 'Intitulé inconnu').join(', ')}`).then(() => {
        const embeds = [infoEmbed, posterEmbed].filter(embed => {
          if (!embed) return false;
          if (embed === infoEmbed) {
            return embed.title || embed.fields.length > 0;
          }
          return true;
        });
        message.channel.send({ embeds });
      });
    } catch (error) {
      console.error(error);
      message.channel.send('Une erreur vient de se produire.');
    }
  },
};

async function askMediaType(message, mediaTypes, query) {
  const mediaTypeString = mediaTypes.map((mediaType, index) => `${index + 1}. ${mediaType.toLowerCase()}`).join('\n');

  const mediaTypeMessage = await message.channel.send(`J'ai trouvé plusieurs types de médias pour "${query}". Veuillez choisir un type de média en tapant le numéro correspondant :\n${mediaTypeString}`);

  const filter = m => m.author.id === message.author.id && /^\d+$/.test(m.content);

  try {
    const collected = await message.channel.awaitMessages({ filter, max: 1, time: 15000, errors: ['time'] });
    const choice = parseInt(collected.first().content);

    if (choice < 1 || choice > mediaTypes.length) {
      message.channel.send(`Désolé, "${choice}" n'est pas un choix valide.`);
      return askMediaType(message, mediaTypes, query);
    }

    return mediaTypes[choice - 1];
  } catch (err) {
    message.channel.send(`Temps écoulé, veuillez réessayer la commande.`);
    return null;
  }
}

关键修改点

  1. 空字段默认值:给overview设置默认文本,避免空字符串传入Embed;
  2. 严格存在性校验:将if (year)改为if (year !== null && year !== undefined),确保0值合法字段能正常显示;
  3. 数字转字符串:年份、季数等数字字段通过toString()转换为字符串,符合MessageEmbed要求;
  4. Embed过滤优化:修改发送前的过滤逻辑,避免对数字字段调用trim()导致的错误;
  5. 超时异常处理:在askMediaType中添加catch块,处理用户超时未输入的情况,防止机器人崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 21:32:06