discordrb 3.7.2 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2229818c42fe455f937dceb0463ddb7489cd79058d6d617f0483ad8c287309ac
4
- data.tar.gz: a0e966d6f85306b413cd8d7aad14f7746517fe4f241621c7ee84c0ac676e66f1
3
+ metadata.gz: 15353f4dac7b2532ca9fe369b46689c312b0df92951ff32c372abc38b0cc5ebc
4
+ data.tar.gz: e6c1ade2c4f550d4fff676ad8b0fcc88463af023343bc2d0af45b3e8f87d5c4a
5
5
  SHA512:
6
- metadata.gz: c535560deb7c130f75292caa6dd31cbfeefcf553ac2b584de7e6346a1e6d84a09252990a4a46e21162e4fc6600eb31402abaea8985ecdfc317b700b819aa72b8
7
- data.tar.gz: 2ba9ec20ad47028f5137fe025f443e6dd6b64d36ed85a996de499372179897ce75cf8c446c3eb7d5a6181d645dc948285606ef133a55e5d33ea7ad667d963848
6
+ metadata.gz: 9a9628272b84421103bbc2505d1af71d3f2b0012231d6d37f22897b00b832122200092a4022a8d3218608aa30ee593f0345a8c9c18104f69349dc0fb4aa5ba1b
7
+ data.tar.gz: 41b15bd52e42175ec8ebe9a3f21c264c236549609df6032e0ec73a172e692f1827710ab025e6b277d40d2b1bb78a4be6cf38aaebc19cc880629c1abb1df86484
data/CHANGELOG.md CHANGED
@@ -5,6 +5,34 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [3.8.0] - 2026-02-04
9
+
10
+ [3.8.0]: https://github.com/shardlab/discordrb/releases/tag/v3.8.0
11
+ [View diff for this release.](https://github.com/shardlab/discordrb/compare/v3.7.2..v3.8.0)
12
+
13
+
14
+ ### Summary
15
+
16
+ ## What's Changed
17
+ * Fix wrong wording in `#voice_state_update` documentation by @gitnickolson in https://github.com/shardlab/discordrb/pull/411
18
+ * feat: integration events by @Droid00000 in https://github.com/shardlab/discordrb/pull/418
19
+ * feat: optimize Bot#emoji by @Droid00000 in https://github.com/shardlab/discordrb/pull/417
20
+ * feat: replied user in allowed mentions by @Droid00000 in https://github.com/shardlab/discordrb/pull/415
21
+ * feat: emoji serialization helper by @Droid00000 in https://github.com/shardlab/discordrb/pull/405
22
+ * feat: delegate more interaction methods by @Droid00000 in https://github.com/shardlab/discordrb/pull/414
23
+ * fix: Secret -> Secrets by @Droid00000 in https://github.com/shardlab/discordrb/pull/392
24
+ * feat: followed channels by @Droid00000 in https://github.com/shardlab/discordrb/pull/328
25
+ * fix: errors on :THREAD_LIST_SYNC by @Droid00000 in https://github.com/shardlab/discordrb/pull/320
26
+ * style: message initializer by @Droid00000 in https://github.com/shardlab/discordrb/pull/382
27
+ * bump: copyright version by @Droid00000 in https://github.com/shardlab/discordrb/pull/424
28
+ * feat: new components by @Droid00000 in https://github.com/shardlab/discordrb/pull/297
29
+
30
+ ## New Contributors
31
+ * @gitnickolson made their first contribution in https://github.com/shardlab/discordrb/pull/411
32
+
33
+ **Full Changelog**: https://github.com/shardlab/discordrb/compare/v3.7.2...v3.8.0
34
+
35
+
8
36
  ## [3.7.2] 2025-12-24
9
37
 
10
38
  [View diff for this release](https://github.com/shardlab/discordrb/compare/v3.7.1...v3.7.2)
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015-2023 meew0
3
+ Copyright (c) 2015-2026 meew0
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![Gem](https://img.shields.io/gem/v/discordrb.svg)](https://rubygems.org/gems/discordrb)
4
4
  [![Gem](https://img.shields.io/gem/dt/discordrb.svg)](https://rubygems.org/gems/discordrb)
5
5
  [![CircleCI](https://circleci.com/gh/shardlab/discordrb.svg?style=svg)](https://circleci.com/gh/shardlab/discordrb)
6
- [![Inline docs](https://inch-ci.org/github/shardlab/discordrb.svg?branch=main)](https://drb.shardlab.dev/v3.6.0/)
6
+ [![Inline docs](https://inch-ci.org/github/shardlab/discordrb.svg?branch=main)](https://drb.shardlab.dev/v3.8.0/)
7
7
  [![Join Discord](https://img.shields.io/badge/discord-join-7289DA.svg)](https://discord.gg/cyK3Hjm)
8
8
 
9
9
  An implementation of the [Discord](https://discord.com/) API using Ruby.
@@ -19,7 +19,7 @@ An implementation of the [Discord](https://discord.com/) API using Ruby.
19
19
  - [Development](https://github.com/shardlab/discordrb#development), [Contributing](https://github.com/shardlab/discordrb#contributing)
20
20
  - [License](https://github.com/shardlab/discordrb#license)
21
21
 
22
- See also: [Documentation](https://drb.shardlab.dev/v3.6.0/), [Tutorials](https://github.com/shardlab/discordrb/wiki)
22
+ See also: [Documentation](https://drb.shardlab.dev/v3.8.0/), [Tutorials](https://github.com/shardlab/discordrb/wiki)
23
23
 
24
24
  ## Introduction
25
25
 
@@ -131,7 +131,7 @@ If you've made an open source project on GitHub that uses discordrb, consider ad
131
131
 
132
132
  Also included is a webhooks client, which can be used as a separate gem `discordrb-webhooks`. This special client can be used to form requests to Discord webhook URLs in a high-level manner.
133
133
 
134
- - [`discordrb-webhooks` documentation](https://drb.shardlab.dev/v3.6.0/Discordrb/Webhooks.html)
134
+ - [`discordrb-webhooks` documentation](https://drb.shardlab.dev/v3.8.0/Discordrb/Webhooks.html)
135
135
  - [More information about webhooks](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks)
136
136
  - [Embed visualizer tool](https://leovoel.github.io/embed-visualizer/) - Includes a discordrb code generator for forming embeds
137
137
 
data/discordrb.gemspec CHANGED
@@ -38,7 +38,7 @@ Gem::Specification.new do |spec|
38
38
 
39
39
  spec.required_ruby_version = '>= 3.2'
40
40
 
41
- spec.add_development_dependency 'bundler', '>= 1.10', '< 3'
41
+ spec.add_development_dependency 'bundler', '>= 1.10', '< 5'
42
42
  spec.add_development_dependency 'rake', '~> 13.0'
43
43
  spec.add_development_dependency 'redcarpet', '~> 3.5' # YARD markdown formatting
44
44
  spec.add_development_dependency 'rspec', '~> 3.0'
@@ -14,14 +14,20 @@ module Discordrb
14
14
  # @return [Array<String, Integer>, nil]
15
15
  attr_accessor :roles
16
16
 
17
+ # @return [true, false, nil]
18
+ attr_accessor :replied_user
19
+ alias_method :replied_user?, :replied_user
20
+
17
21
  # @param parse [Array<"users", "roles", "everyone">] Mention types that can be inferred from the message.
18
22
  # `users` and `roles` allow for all mentions of the respective type to ping. `everyone` allows usage of `@everyone` and `@here`
19
23
  # @param users [Array<User, String, Integer>] Users or user IDs that can be pinged. Cannot be used in conjunction with `"users"` in `parse`
20
24
  # @param roles [Array<Role, String, Integer>] Roles or role IDs that can be pinged. Cannot be used in conjunction with `"roles"` in `parse`
21
- def initialize(parse: nil, users: nil, roles: nil)
25
+ # @param replied_user [true, false, nil] For replies, whether to mention the author of the message being replied to. Defaults to no mention
26
+ def initialize(parse: nil, users: nil, roles: nil, replied_user: nil)
22
27
  @parse = parse
23
28
  @users = users
24
29
  @roles = roles
30
+ @replied_user = replied_user
25
31
  end
26
32
 
27
33
  # @!visibility private
@@ -29,7 +35,8 @@ module Discordrb
29
35
  {
30
36
  parse: @parse,
31
37
  users: @users&.map { |user| user.is_a?(IDObject) ? user.id : user },
32
- roles: @roles&.map { |role| role.is_a?(IDObject) ? role.id : role }
38
+ roles: @roles&.map { |role| role.is_a?(IDObject) ? role.id : role },
39
+ replied_user: @replied_user
33
40
  }.compact
34
41
  end
35
42
  end
@@ -464,6 +464,21 @@ module Discordrb::API::Channel
464
464
  )
465
465
  end
466
466
 
467
+ # Follow an annoucement channel.
468
+ # https://discord.com/developers/docs/resources/channel#follow-announcement-channel
469
+ def follow_channel(token, channel_id, webhook_channel_id, reason = nil)
470
+ Discordrb::API.request(
471
+ :channels_cid_followers,
472
+ channel_id,
473
+ :post,
474
+ "#{Discordrb::API.api_base}/channels/#{channel_id}/followers",
475
+ { webhook_channel_id: webhook_channel_id }.to_json,
476
+ Authorization: token,
477
+ content_type: :json,
478
+ 'X-Audit-Log-Reason': reason
479
+ )
480
+ end
481
+
467
482
  # Start a thread based off a channel message.
468
483
  # https://discord.com/developers/docs/resources/channel#start-thread-with-message
469
484
  def start_thread_with_message(token, channel_id, message_id, name, auto_archive_duration)
@@ -51,8 +51,8 @@ module Discordrb::API::Interaction
51
51
 
52
52
  # Edit the original response to an interaction.
53
53
  # https://discord.com/developers/docs/interactions/slash-commands#edit-original-interaction-response
54
- def edit_original_interaction_response(interaction_token, application_id, content = nil, embeds = nil, allowed_mentions = nil, components = nil, attachments = nil)
55
- Discordrb::API::Webhook.token_edit_message(interaction_token, application_id, '@original', content, embeds, allowed_mentions, components, attachments)
54
+ def edit_original_interaction_response(interaction_token, application_id, content = nil, embeds = nil, allowed_mentions = nil, components = nil, attachments = nil, flags = nil)
55
+ Discordrb::API::Webhook.token_edit_message(interaction_token, application_id, '@original', content, embeds, allowed_mentions, components, attachments, flags)
56
56
  end
57
57
 
58
58
  # Delete the original response to an interaction.
@@ -120,8 +120,8 @@ module Discordrb::API::Webhook
120
120
 
121
121
  # Edit a webhook message via webhook token
122
122
  # https://discord.com/developers/docs/resources/webhook#edit-webhook-message
123
- def token_edit_message(webhook_token, webhook_id, message_id, content = nil, embeds = nil, allowed_mentions = nil, components = nil, attachments = nil)
124
- body = { content: content, embeds: embeds, allowed_mentions: allowed_mentions, components: components }
123
+ def token_edit_message(webhook_token, webhook_id, message_id, content = nil, embeds = nil, allowed_mentions = nil, components = nil, attachments = nil, flags = nil)
124
+ body = { content: content, embeds: embeds, allowed_mentions: allowed_mentions, components: components, flags: flags }
125
125
 
126
126
  body = if attachments
127
127
  files = [*0...attachments.size].zip(attachments).to_h
data/lib/discordrb/bot.rb CHANGED
@@ -20,6 +20,7 @@ require 'discordrb/events/webhooks'
20
20
  require 'discordrb/events/invites'
21
21
  require 'discordrb/events/interactions'
22
22
  require 'discordrb/events/threads'
23
+ require 'discordrb/events/integrations'
23
24
 
24
25
  require 'discordrb/api'
25
26
  require 'discordrb/api/channel'
@@ -199,12 +200,18 @@ module Discordrb
199
200
  # The list of emoji the bot can use.
200
201
  # @return [Array<Emoji>] the emoji available.
201
202
  def emoji(id = nil)
202
- emoji_hash = servers.values.map(&:emoji).reduce(&:merge)
203
- if id
204
- id = id.resolve_id
205
- emoji_hash[id]
203
+ if (id = id&.resolve_id)
204
+ @servers.each_value do |server|
205
+ emoji = server.emojis[id]
206
+ return emoji if emoji
207
+ end
206
208
  else
207
- emoji_hash.values
209
+ hash = {}
210
+ @servers.each_value do |server|
211
+ hash.merge!(server.emojis)
212
+ end
213
+
214
+ hash
208
215
  end
209
216
  end
210
217
 
@@ -939,6 +946,11 @@ module Discordrb
939
946
  API::Application.delete_application_emoji(@token, profile.id, emoji_id.resolve_id)
940
947
  end
941
948
 
949
+ # @!visibility private
950
+ def inspect
951
+ "<Bot client_id=#{@client_id.inspect} redact_token=#{@redact_token.inspect}>"
952
+ end
953
+
942
954
  private
943
955
 
944
956
  # Throws a useful exception if there's currently no gateway connection.
@@ -1579,6 +1591,15 @@ module Discordrb
1579
1591
 
1580
1592
  event = ServerRoleDeleteEvent.new(data, self)
1581
1593
  raise_event(event)
1594
+ when :INTEGRATION_CREATE
1595
+ event = IntegrationCreateEvent.new(data, self)
1596
+ raise_event(event)
1597
+ when :INTEGRATION_UPDATE
1598
+ event = IntegrationUpdateEvent.new(data, self)
1599
+ raise_event(event)
1600
+ when :INTEGRATION_DELETE
1601
+ event = IntegrationDeleteEvent.new(data, self)
1602
+ raise_event(event)
1582
1603
  when :GUILD_CREATE
1583
1604
  create_guild(data)
1584
1605
 
@@ -1718,8 +1739,25 @@ module Discordrb
1718
1739
 
1719
1740
  # raise ThreadDeleteEvent
1720
1741
  when :THREAD_LIST_SYNC
1721
- data['members'].map { |member| ensure_thread_member(member) }
1722
- data['threads'].map { |channel| ensure_channel(channel, data['guild_id']) }
1742
+ server_id = data['guild_id'].to_i
1743
+ server = @servers[server_id]
1744
+
1745
+ # The `channel_ids` field has two meanings:
1746
+ #
1747
+ # 1. If the field is not present, the thread list is being synced for the whole server.
1748
+ #
1749
+ # 2. We are syncing the threads for a specific channel. This can happen when gaining access
1750
+ # to a channel.
1751
+ if (ids = data['channel_ids']&.map(&:to_i))
1752
+ @channels.delete_if { |_, channel| channel.thread? && ids.any?(channel.parent&.id) }
1753
+ server&.clear_threads(ids)
1754
+ else
1755
+ @channels.delete_if { |_, channel| channel.server.id == server_id && channel.thread? }
1756
+ server&.clear_threads
1757
+ end
1758
+
1759
+ data['members'].each { |member| ensure_thread_member(member) }
1760
+ data['threads'].each { |channel| ensure_channel(channel) }
1723
1761
 
1724
1762
  # raise ThreadListSyncEvent?
1725
1763
  when :THREAD_MEMBER_UPDATE
@@ -14,6 +14,7 @@ require 'discordrb/events/await'
14
14
  require 'discordrb/events/bans'
15
15
  require 'discordrb/events/reactions'
16
16
  require 'discordrb/events/interactions'
17
+ require 'discordrb/events/integrations'
17
18
 
18
19
  require 'discordrb/await'
19
20
 
@@ -290,7 +291,7 @@ module Discordrb
290
291
  # This **event** is raised when a user's voice state changes. This includes when a user joins, leaves, or
291
292
  # moves between voice channels, as well as their mute and deaf status for themselves and on the server.
292
293
  # @param attributes [Hash] The event's attributes.
293
- # @option attributes [String, Integer, User] :from Matches the user that sent the message.
294
+ # @option attributes [String, Integer, User] :from Matches the user that raised the event.
294
295
  # @option attributes [String, Integer, Channel] :channel Matches the voice channel the user has joined.
295
296
  # @option attributes [String, Integer, Channel] :old_channel Matches the voice channel the user was in previously.
296
297
  # @option attributes [true, false] :mute Matches whether or not the user is muted server-wide.
@@ -696,6 +697,42 @@ module Discordrb
696
697
  register_event(ApplicationCommandPermissionsUpdateEvent, attributes, block)
697
698
  end
698
699
 
700
+ # This **event** is raised whenever an integration is added to a server.
701
+ # @param attributes [Hash] The event's attributes.
702
+ # @option attributes [String, Integer, Integration] :id An integration to match against.
703
+ # @option attributes [String, Integer, Server] :server A server to match against.
704
+ # @option attributes [String, Integer, Application] :application An application to match against.
705
+ # @yield The block is executed when the event is raised.
706
+ # @yieldparam event [IntegrationCreateEvent] The event that was raised.
707
+ # @return [IntegrationCreateEventHandler] The event handler that was registered.
708
+ def integration_create(attributes = {}, &block)
709
+ register_event(IntegrationCreateEvent, attributes, block)
710
+ end
711
+
712
+ # This **event** is raised whenever an integration is updated in a server.
713
+ # @param attributes [Hash] The event's attributes.
714
+ # @option attributes [String, Integer, Integration] :id An integration to match against.
715
+ # @option attributes [String, Integer, Server] :server A server to match against.
716
+ # @option attributes [String, Integer, Application] :application An application to match against.
717
+ # @yield The block is executed when the event is raised.
718
+ # @yieldparam event [IntegrationUpdateEvent] The event that was raised.
719
+ # @return [IntegrationUpdateEventHandler] The event handler that was registered.
720
+ def integration_update(attributes = {}, &block)
721
+ register_event(IntegrationUpdateEvent, attributes, block)
722
+ end
723
+
724
+ # This **event** is raised whenever an integration is removed from a server.
725
+ # @param attributes [Hash] The event's attributes.
726
+ # @option attributes [String, Integer, Integration] :id An integration to match against.
727
+ # @option attributes [String, Integer, Server] :server A server to match against.
728
+ # @option attributes [String, Integer, Application] :application An application to match against.
729
+ # @yield The block is executed when the event is raised.
730
+ # @yieldparam event [IntegrationDeleteEvent] The event that was raised.
731
+ # @return [IntegrationDeleteEventHandler] The event handler that was registered.
732
+ def integration_delete(attributes = {}, &block)
733
+ register_event(IntegrationDeleteEvent, attributes, block)
734
+ end
735
+
699
736
  # This **event** is raised for every dispatch received over the gateway, whether supported by discordrb or not.
700
737
  # @param attributes [Hash] The event's attributes.
701
738
  # @option attributes [String, Symbol, Regexp] :type Matches the event type of the dispatch.
@@ -83,7 +83,7 @@ module Discordrb
83
83
  @created_at = Time.at(data['created_at'].to_i)
84
84
 
85
85
  @timestamps = Timestamps.new(data['timestamps']) if data['timestamps']
86
- @secrets = Secret.new(data['secrets']) if data['secrets']
86
+ @secrets = Secrets.new(data['secrets']) if data['secrets']
87
87
  @assets = Assets.new(data['assets'], @application_id) if data['assets']
88
88
  @party = Party.new(data['party']) if data['party']
89
89
  @emoji = Emoji.new(data['emoji'], bot, nil) if data['emoji']
@@ -157,7 +157,7 @@ module Discordrb
157
157
  def channel
158
158
  return nil unless @channel_id
159
159
 
160
- @channel ||= @bot.channel(@channel_id, @server, bot, self)
160
+ @channel ||= @bot.channel(@channel_id)
161
161
  end
162
162
 
163
163
  # @!visibility private
@@ -478,7 +478,7 @@ module Discordrb
478
478
  # @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
479
479
  # @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
480
480
  # @param components [View, Array<Hash>] Interaction components to associate with this message.
481
- # @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2) and SUPPRESS_NOTIFICATIONS (1 << 12) can be set.
481
+ # @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2), SUPPRESS_NOTIFICATIONS (1 << 12), and IS_COMPONENTS_V2 (1 << 15) can be set.
482
482
  # @return [Message] the message that was sent.
483
483
  def send_message(content, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, flags = 0)
484
484
  @bot.send_message(@id, content, tts, embed, attachments, allowed_mentions, message_reference, components, flags)
@@ -495,7 +495,7 @@ module Discordrb
495
495
  # @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
496
496
  # @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
497
497
  # @param components [View, Array<Hash>] Interaction components to associate with this message.
498
- # @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2) and SUPPRESS_NOTIFICATIONS (1 << 12) can be set.
498
+ # @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2), SUPPRESS_NOTIFICATIONS (1 << 12), and IS_COMPONENTS_V2 (1 << 15) can be set.
499
499
  def send_temporary_message(content, timeout, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, flags = 0)
500
500
  @bot.send_temporary_message(@id, content, timeout, tts, embed, attachments, allowed_mentions, message_reference, components, flags)
501
501
  end
@@ -513,7 +513,7 @@ module Discordrb
513
513
  # @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
514
514
  # @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
515
515
  # @param components [View, Array<Hash>] Interaction components to associate with this message.
516
- # @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2) and SUPPRESS_NOTIFICATIONS (1 << 12) can be set.
516
+ # @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2), SUPPRESS_NOTIFICATIONS (1 << 12), and IS_COMPONENTS_V2 (1 << 15) can be set.
517
517
  # @yield [embed] Yields the embed to allow for easy building inside a block.
518
518
  # @yieldparam embed [Discordrb::Webhooks::Embed] The embed from the parameters, or a new one.
519
519
  # @return [Message] The resulting message.
@@ -963,6 +963,16 @@ module Discordrb
963
963
  invites.map { |invite_data| Invite.new(invite_data, @bot) }
964
964
  end
965
965
 
966
+ # Follow the announcement (news) channel to send crossposted messages to a target channel.
967
+ # @param target [Channel, Integer, String] The target channel to send crossposted messages to.
968
+ # @param reason [String, nil] The audit log reason shown for the created webhook in the target channel.
969
+ # @return [Integer] the ID of the created webhook in the target channel.
970
+ def follow(target, reason: nil)
971
+ raise 'Cannot follow a non-announcement channel' unless news?
972
+
973
+ JSON.parse(API::Channel.follow_channel(@bot.token, @id, target.resolve_id, reason))['webhook_id'].to_i
974
+ end
975
+
966
976
  # Returns the last message or forum post created in this channel.
967
977
  # @return [Message, Channel, nil] the last message sent in this channel,
968
978
  # the most recent forum post if this is a forum or media channel, or `nil`.