Discord4J

Discord4J

高性能反应式 Java Discord 机器人开发框架

Discord4J 是一个基于反应式编程的 Java Discord 机器人开发框架。它支持官方 API,提供模块化架构,适用于不同规模的机器人项目。该框架遵循反应式流协议,具有高效性能和自动速率限制等特性。Discord4J 兼容 Kotlin 协程,并有活跃的社区支持。

Discord4JJavaDiscordAPI反应式编程Github开源项目

Discord4J

<a href="https://discord4j.com"><img align="right" src="https://yellow-cdn.veclightyear.com/ab5030c0/37b0218c-2b14-4f0d-b611-ab4e91cb23f1.svg?sanitize=true" width=27%></a>

支持服务器邀请 Maven Central Javadocs GitHub 工作流状态(分支)

Discord4J 是一个快速、强大、无偏见、响应式的库,可以使用官方 Discord Bot API 在 Java、Kotlin 和其他 JVM 语言中快速轻松地开发 Discord 机器人。

🏃 快速示例

在这个 v3.2 版本的示例中,每当用户发送 !ping 消息时,机器人将立即回复 Pong!

确保在 开发者门户 中启用了机器人的 消息内容 意图。

public class ExampleBot { public static void main(String[] args) { String token = args[0]; DiscordClient client = DiscordClient.create(token); GatewayDiscordClient gateway = client.login().block(); gateway.on(MessageCreateEvent.class).subscribe(event -> { Message message = event.getMessage(); if ("!ping".equals(message.getContent())) { MessageChannel channel = message.getChannel().block(); channel.createMessage("Pong!").block(); } }); gateway.onDisconnect().block(); } }

完整的项目示例,请查看我们的示例项目仓库 这里

🔗 快速链接

💎 优势

  • 🚀 响应式 - Discord4J 遵循 reactive-streams 协议,确保 Discord 机器人无论规模大小都能平稳高效地运行。

  • 📜 官方 - 自动限速、自动重连策略和一致的命名约定是 Discord4J 提供的众多功能之一,确保您的 Discord 机器人符合 Discord 的规范,并在与我们的库交互时提供最少的意外。

  • 🛠️ 模块化 - Discord4J 将自身分解为模块,允许高级用户在较低级别与我们的 API 交互,以构建最小且快速的运行时,甚至添加自己的抽象。

  • ⚔️ 强大 - Discord4J 可用于开发任何规模的机器人。我们提供了许多工具来开发大规模机器人,包括 自定义分布式框架堆外缓存,以及与 Reactor 的交互,允许与 Spring 和 Micronaut 等框架完全集成。

  • 🏫 社区 - 我们以包容性的社区为荣,并愿意在遇到挑战时提供帮助;或者如果您只是想聊天!我们提供从 Discord4J 特定问题、一般编程和 Web 开发帮助,甚至 Reactor 特定问题的帮助。请务必访问我们的 Discord 服务器

📦 安装

Gradle

repositories { mavenCentral() } dependencies { implementation 'com.discord4j:discord4j-core:3.2.5' }

Gradle Kotlin DSL

repositories { mavenCentral() } dependencies { implementation("com.discord4j:discord4j-core:3.2.5") }

Maven

<dependencies> <dependency> <groupId>com.discord4j</groupId> <artifactId>discord4j-core</artifactId> <version>3.2.5</version> </dependency> </dependencies>

SBT

libraryDependencies ++= Seq( "com.discord4j" % "discord4j-core" % "3.2.5" )

🔀 Discord4J 版本

Discord4J 3.2.x 包括更简单且更强大的 API 来构建请求、新的实体缓存和依赖项升级带来的性能改进。查看我们的 迁移指南 了解更多详情。

Discord4J支持状态网关/API意图交互
v3.3.x开发中v9强制,非特权默认完全支持
v3.2.x当前v8强制,非特权默认完全支持
v3.1.x仅维护v6可选,无意图默认仅维护

有关兼容性的更多详情,请参阅 我们的文档

🎉 赞助商

我们要特别感谢所有赞助商为我们提供资金,使我们能够继续开发和托管仓库资源以及推动社区项目。特别要感谢以下这些杰出的个人:

⛰️ 大型机器人

以下是一些使用Discord4J的真实大型机器人示例:

  • Groovy - 曾是Discord上第二大机器人,在2021年8月关闭前为超过400万个服务器提供音乐服务。
  • ZeroTwo - 一个动漫多功能机器人,被100多万个服务器使用。
  • DisCal - 将Google日历无缝且全面地集成到Discord中;服务超过2.1万个服务器。
  • Shadbot - 一个可配置的多功能机器人,具有音乐、赌博小游戏、视频游戏统计等功能;在2021年8月关闭前服务近1.2万个服务器。

你是否拥有使用Discord4J的大型机器人?请在我们的Discord中询问管理员或提交拉取请求,将你的机器人添加到列表中!

⚛️ 响应式

Discord4J使用Project Reactor作为我们异步框架的基础。Reactor提供了一个简单而强大的API,使用户能够减少资源并提高性能。

public class ExampleBot { public static void main(String[] args) { String token = args[0]; DiscordClient client = DiscordClient.create(token); client.login().flatMapMany(gateway -> gateway.on(MessageCreateEvent.class)) .map(MessageCreateEvent::getMessage) .filter(message -> "!ping".equals(message.getContent())) .flatMap(Message::getChannel) .flatMap(channel -> channel.createMessage("Pong!")) .blockLast(); } }

Discord4J还提供了几种方法来帮助更好地组合响应式链,例如GatewayDiscordClient#withGateway和带有错误处理重载的EventDispatcher#on

public class ExampleBot { public static void main(String[] args) { String token = args[0]; DiscordClient client = DiscordClient.create(token); client.withGateway(gateway -> { Publisher<?> pingPong = gateway.on(MessageCreateEvent.class, event -> Mono.just(event.getMessage()) .filter(message -> "!ping".equals(message.getContent())) .flatMap(Message::getChannel) .flatMap(channel -> channel.createMessage("Pong!"))); Publisher<?> onDisconnect = gateway.onDisconnect() .doOnTerminate(() -> System.out.println("已断开连接!")); return Mono.when(pingPong, onDisconnect); }).block(); } }

🧵 Kotlin

通过使用Reactor,Discord4J在与kotlinx-coroutines-reactor库配对时与Kotlin协程有原生集成。

val token = args[0] val client = DiscordClient.create(token) client.withGateway { mono { it.on(MessageCreateEvent::class.java) .asFlow() .collect { val message = it.message if (message.content == "!ping") { val channel = message.channel.awaitSingle() channel.createMessage("Pong!").awaitSingle() } } } } .block()

🐛 常见错误

在未启用消息内容意图的情况下调用Message#getContent

从2022年9月1日起,Discord要求机器人启用"MESSAGE_CONTENT"意图才能访问消息内容。 要启用该意图,请前往Discord开发者门户并选择你的机器人。然后,转到"Bot"选项卡并启用"Message Content"意图。 然后,在创建DiscordClient时将该意图添加到你的机器人中:

GatewayDiscordClient client = DiscordClient.create(token) .gateway() .setEnabledIntents(IntentSet.nonPrivileged().and(IntentSet.of(Intent.MESSAGE_CONTENT))) .login() .block();

📚 示例

📑 消息嵌入

<img align="right" src="https://yellow-cdn.veclightyear.com/ab5030c0/b987c66a-d126-4a7f-8706-90869ddffa6e.png" height=420px>
// IMAGE_URL = https://cdn.betterttv.net/emote/55028cd2135896936880fdd7/3x // ANY_URL = https://www.youtube.com/watch?v=5zwY50-necw MessageChannel channel = ... EmbedCreateSpec.Builder builder = EmbedCreateSpec.builder(); builder.author("setAuthor", ANY_URL, IMAGE_URL); builder.image(IMAGE_URL); builder.title("setTitle/setUrl"); builder.url(ANY_URL); builder.description("setDescription\n" + "大D:是setImage\n" + "小D:是setThumbnail\n" + "<-- setColor"); builder.addField("addField", "inline = true", true); builder.addField("addFIeld", "inline = true", true); builder.addField("addFile", "inline = false", false); builder.thumbnail(IMAGE_URL); builder.footer("setFooter --> setTimestamp", IMAGE_URL); builder.timestamp(Instant.now()); channel.createMessage(builder.build()).block();

🏷️ 通过角色名称查找成员

用户通常更喜欢使用名称而不是ID。这个例子将演示如何搜索所有具有特定名称角色的成员。

Guild guild = ... Set<Member> roleMembers = new HashSet<>(); for (Member member : guild.getMembers().toIterable()) { for (Role role : member.getRoles().toIterable()) { if ("Developers".equalsIgnoreCase(role.getName())) { roleMembers.add(member); break; } } } return roleMembers;

或者,使用Reactor:

Guild guild = ... return guild.getMembers() .filterWhen(member -> member.getRoles() .map(Role::getName) .any("Developers"::equalsIgnoreCase));

🎵 语音和音乐

Discord4J为语音连接提供全面支持,并能够向连接到同一频道的其他用户发送音频。Discord4J可以接受任何Opus音频源,LavaPlayer是从YouTube、SoundCloud和其他提供商下载和编码音频的首选解决方案。

[!警告]
原始的LavaPlayer不再维护。可以在这里找到一个新的维护版本。 如果你需要Java 8支持,可以使用Walkyst的LavaPlayer分支,但它也不再维护!

首先,你需要实例化和配置一个通常是全局的AudioPlayerManager

public static final AudioPlayerManager PLAYER_MANAGER; static { PLAYER_MANAGER = new DefaultAudioPlayerManager(); // 这是Discord4J可以利用的优化策略,以最小化内存分配 PLAYER_MANAGER.getConfiguration().setFrameBufferFactory(NonAllocatingAudioFrameBuffer::new); AudioSourceManagers.registerRemoteSources(PLAYER_MANAGER); AudioSourceManagers.registerLocalSource(PLAYER_MANAGER); } 接下来,我们需要允许Discord4JAudioPlayer读取到AudioProvider public class LavaPlayerAudioProvider extends AudioProvider { private final AudioPlayer player; private final MutableAudioFrame frame; public LavaPlayerAudioProvider(AudioPlayer player) { // 为Discord4J的AudioProvider分配一个ByteBuffer来存储Discord的音频数据 super(ByteBuffer.allocate(StandardAudioDataFormats.DISCORD_OPUS.maximumChunkSize())); // 设置LavaPlayer的AudioFrame使用与Discord4J相同的缓冲区 frame = new MutableAudioFrame(); frame.setBuffer(getBuffer()); this.player = player; } @Override public boolean provide() { // AudioPlayer将音频数据写入AudioFrame boolean didProvide = player.provide(frame); if (didProvide) { getBuffer().flip(); } return didProvide; } } 通常,音频播放器会有队列或内部播放列表,让用户能够在歌曲播放完毕或要求跳过时自动循环播放歌曲。我们可以通过创建AudioTrackScheduler来外部管理这个队列,并将其传递给代码的其他部分,以允许查看、排队或跳过音轨。 public class AudioTrackScheduler extends AudioEventAdapter { private final List<AudioTrack> queue; private final AudioPlayer player; public AudioTrackScheduler(AudioPlayer player) { // 队列可能被不同的线程修改,所以要保证内存安全 // 但这并不能消除目前存在的几个竞态条件 queue = Collections.synchronizedList(new LinkedList<>()); this.player = player; } public List<AudioTrack> getQueue() { return queue; } public boolean play(AudioTrack track) { return play(track, false); } public boolean play(AudioTrack track, boolean force) { boolean playing = player.startTrack(track, !force); if (!playing) { queue.add(track); } return playing; } public boolean skip() { return !queue.isEmpty() && play(queue.remove(0), true); } @Override public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) { // 如果音轨自然完成(FINISHED)或无法播放(LOAD_FAILED),则推进播放器 if (endReason.mayStartNext) { skip(); } } } 目前,Discord每个服务器只允许一个语音连接。在这个限制下,将我们目前处理的三个组件(AudioPlayerLavaPlayerAudioProviderAudioTrackScheduler)与特定的Guild关联起来是合乎逻辑的,它们自然由某个Snowflake唯一标识。从逻辑上讲,将这些对象组合成一个对象是有意义的,这样可以将它们放入Map中,在连接到语音频道或处理命令时更容易检索。 public class GuildAudioManager { private static final Map<Snowflake, GuildAudioManager> MANAGERS = new ConcurrentHashMap<>(); public static GuildAudioManager of(Snowflake id) { return MANAGERS.computeIfAbsent(id, ignored -> new GuildAudioManager()); } private final AudioPlayer player; private final AudioTrackScheduler scheduler; private final LavaPlayerAudioProvider provider; private GuildAudioManager() { player = PLAYER_MANAGER.createPlayer(); scheduler = new AudioTrackScheduler(player); provider = new LavaPlayerAudioProvider(player); player.addListener(scheduler); } // getter方法 } 最后,我们需要连接到语音频道。连接后,你会得到一个VoiceConnection对象,之后可以通过调用VoiceConnection#disconnect来断开与语音频道的连接。 VoiceChannel channel = ... AudioProvider provider = GuildAudioManager.of(channel.getGuildId()).getProvider(); VoiceConnection connection = channel.join(spec -> spec.setProvider(provider)).block(); // 在AudioLoadResultHandler中,将AudioTrack实例添加到AudioTrackScheduler(并向用户发送通知) PLAYER_MANAGER.loadItem("https://www.youtube.com/watch?v=dQw4w9WgXcQ", new AudioLoadResultHandler() { /* 重写方法 */ }) ### ❌ 自动断开语音频道连接 通常,在所有人都离开语音频道后,机器人应该自动断开连接,因为用户经常忘记手动断开机器人。下面的示例展示了如何使用反应式方法而不是命令式方法来优雅地解决这个问题。 VoiceChannel channel = ... Mono<Void> onDisconnect = channel.join(spec -> { /* TODO 初始化 */ }) .flatMap(connection -> { // 机器人本身有一个VoiceState;1个VoiceState表示机器人独自一人 Publisher<Boolean> voiceStateCounter = channel.getVoiceStates() .count() .map(count -> 1L == count); // 10秒后,检查机器人是否独自一人。这在机器人独自加入, // 但连接后没有其他人加入的情况下很有用 Mono<Void> onDelay = Mono.delay(Duration.ofSeconds(10L)) .filterWhen(ignored -> voiceStateCounter) .switchIfEmpty(Mono.never()) .then(); // 当人们加入和离开`channel`时,检查机器人是否独自一人。 // 注意,第一个过滤器并非严格必要,但它可以防止许多不必要的缓存调用 Mono<Void> onEvent = channel.getClient().getEventDispatcher().on(VoiceStateUpdateEvent.class) .filter(event -> event.getOld().flatMap(VoiceState::getChannelId).map(channel.getId()::equals).orElse(false)) .filterWhen(ignored -> voiceStateCounter) .next() .then(); // 如果onDelay或onEvent完成,则断开机器人连接! return Mono.first(onDelay, onEvent).then(connection.disconnect()); });

编辑推荐精选

Qwen2.5-VL

Qwen2.5-VL

一款强大的视觉语言模型,支持图像和视频输入

Qwen2.5-VL 是一款强大的视觉语言模型,支持图像和视频输入,可用于多种场景,如商品特点总结、图像文字识别等。项目提供了 OpenAI API 服务、Web UI 示例等部署方式,还包含了视觉处理工具,有助于开发者快速集成和使用,提升工作效率。

HunyuanVideo

HunyuanVideo

HunyuanVideo 是一个可基于文本生成高质量图像和视频的项目。

HunyuanVideo 是一个专注于文本到图像及视频生成的项目。它具备强大的视频生成能力,支持多种分辨率和视频长度选择,能根据用户输入的文本生成逼真的图像和视频。使用先进的技术架构和算法,可灵活调整生成参数,满足不同场景的需求,是文本生成图像视频领域的优质工具。

WebUI for Browser Use

WebUI for Browser Use

一个基于 Gradio 构建的 WebUI,支持与浏览器智能体进行便捷交互。

WebUI for Browser Use 是一个强大的项目,它集成了多种大型语言模型,支持自定义浏览器使用,具备持久化浏览器会话等功能。用户可以通过简洁友好的界面轻松控制浏览器智能体完成各类任务,无论是数据提取、网页导航还是表单填写等操作都能高效实现,有利于提高工作效率和获取信息的便捷性。该项目适合开发者、研究人员以及需要自动化浏览器操作的人群使用,在 SEO 优化方面,其关键词涵盖浏览器使用、WebUI、大型语言模型集成等,有助于提高网页在搜索引擎中的曝光度。

xiaozhi-esp32

xiaozhi-esp32

基于 ESP32 的小智 AI 开发项目,支持多种网络连接与协议,实现语音交互等功能。

xiaozhi-esp32 是一个极具创新性的基于 ESP32 的开发项目,专注于人工智能语音交互领域。项目涵盖了丰富的功能,如网络连接、OTA 升级、设备激活等,同时支持多种语言。无论是开发爱好者还是专业开发者,都能借助该项目快速搭建起高效的 AI 语音交互系统,为智能设备开发提供强大助力。

olmocr

olmocr

一个用于 OCR 的项目,支持多种模型和服务器进行 PDF 到 Markdown 的转换,并提供测试和报告功能。

olmocr 是一个专注于光学字符识别(OCR)的 Python 项目,由 Allen Institute for Artificial Intelligence 开发。它支持多种模型和服务器,如 vllm、sglang、OpenAI 等,可将 PDF 文件的页面转换为 Markdown 格式。项目还提供了测试框架和 HTML 报告生成功能,方便用户对 OCR 结果进行评估和分析。适用于科研、文档处理等领域,有助于提高工作效率和准确性。

飞书多维表格

飞书多维表格

飞书多维表格 ×DeepSeek R1 满血版

飞书多维表格联合 DeepSeek R1 模型,提供 AI 自动化解决方案,支持批量写作、数据分析、跨模态处理等功能,适用于电商、短视频、影视创作等场景,提升企业生产力与创作效率。关键词:飞书多维表格、DeepSeek R1、AI 自动化、批量处理、企业协同工具。

CSM

CSM

高质量语音生成模型

CSM 是一个开源的语音生成项目,它提供了一个基于 Llama-3.2-1B 和 CSM-1B 的语音生成模型。该项目支持多语言,可生成多种声音,适用于研究和教育场景。通过使用 CSM,用户可以方便地进行语音合成,同时项目还提供了水印功能,确保生成音频的可追溯性和透明度。

agents-course

agents-course

Hugging Face 的 AI 智能体课程,涵盖多种智能体框架及相关知识

本项目是 Hugging Face 推出的 AI 智能体课程,深入介绍了 AI 智能体的相关概念,如大语言模型、工具使用等。课程包含多个单元,详细讲解了不同的智能体框架,如 smolagents 和 LlamaIndex,提供了丰富的学习资源和实践案例。适合对 AI 智能体感兴趣的开发者和学习者,有助于提升他们在该领域的知识和技能。

RagaAI-Catalyst

RagaAI-Catalyst

用于 AI 项目管理和 API 交互的工具集,助力 AI 项目高效开发与管理。

RagaAI-Catalyst 是一款专注于 AI 领域的强大工具集,为开发者提供了便捷的项目管理、API 交互、令牌管理等功能。支持多 API 密钥上传,能快速创建、列出和管理 AI 项目,还可获取项目用例和指标信息。适用于各类 AI 开发场景,提升开发效率,推动 AI 项目顺利开展。

smolagents

smolagents

一个包含多种工具和文档处理功能,适用于 LLM 使用的项目。

smolagents 是一个功能丰富的项目,提供了如文件格式转换、网页内容读取、语义搜索等多种工具,支持将常见文件类型或网页转换为 Markdown,方便进行文档处理和信息提取,能满足不同场景下的需求,提升工作效率和数据处理能力。

下拉加载更多