discorb 0.5.5 → 0.7.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.
data/lib/discorb/color.rb CHANGED
@@ -130,35 +130,65 @@ module Discorb
130
130
  #
131
131
  # Create a color from a Discord's color.
132
132
  # Currently these colors are supported:
133
- # - teal (0x1abc9c)
134
- # - dark_teal (0x11806a)
135
- # - green (0x2ecc71)
136
- # - dark_green (0x1f8b4c)
137
- # - blue (0x3498db)
138
- # - dark_blue (0x206694)
139
- # - purple (0x9b59b6)
140
- # - dark_purple (0x71368a)
141
- # - magenta (0xe91e63)
142
- # - dark_magenta (0xad1457)
143
- # - gold (0xf1c40f)
144
- # - dark_gold (0xc27c0e)
145
- # - orange (0xe67e22)
146
- # - dark_orange (0xa84300)
147
- # - red (0xe74c3c)
148
- # - dark_red (0x992d22)
149
- # - lighter_grey (0x95a5a6)
150
- # - lighter_gray (0x95a5a6)
151
- # - dark_grey (0x607d8b)
152
- # - dark_gray (0x607d8b)
153
- # - light_grey (0x979c9f)
154
- # - light_gray (0x979c9f)
155
- # - darker_grey (0x546e7a)
156
- # - darker_gray (0x546e7a)
157
- # - og_blurple (0x7289da)
158
- # - blurple (0x5865f2)
159
- # - greyple (0x99aab5)
160
- # - dark_theme (0x36393f)
161
- # - fuchsia (0xeb459e)
133
+ # | Color Name | Hexadecimal |
134
+ # |------------|------------|
135
+ # | `:teal` | `#1abc9c` |
136
+ # | `:dark_teal` | `#11806a` |
137
+ # | `:green` | `#2ecc71` |
138
+ # | `:dark_green` | `#1f8b4c` |
139
+ # | `:blue` | `#3498db` |
140
+ # | `:dark_blue` | `#206694` |
141
+ # | `:purple` | `#9b59b6` |
142
+ # | `:dark_purple` | `#71368a` |
143
+ # | `:magenta` | `#e91e63` |
144
+ # | `:dark_magenta` | `#ad1457` |
145
+ # | `:gold` | `#f1c40f` |
146
+ # | `:dark_gold` | `#c27c0e` |
147
+ # | `:orange` | `#e67e22` |
148
+ # | `:dark_orange` | `#a84300` |
149
+ # | `:red` | `#e74c3c` |
150
+ # | `:dark_red` | `#992d22` |
151
+ # | `:lighter_grey` | `#95a5a6` |
152
+ # | `:lighter_gray` | `#95a5a6` |
153
+ # | `:dark_grey` | `#607d8b` |
154
+ # | `:dark_gray` | `#607d8b` |
155
+ # | `:light_grey` | `#979c9f` |
156
+ # | `:light_gray` | `#979c9f` |
157
+ # | `:darker_grey` | `#546e7a` |
158
+ # | `:darker_gray` | `#546e7a` |
159
+ # | `:og_blurple` | `#7289da` |
160
+ # | `:blurple` | `#5865f2` |
161
+ # | `:greyple` | `#99aab5` |
162
+ # | `:dark_theme` | `#36393f` |
163
+ # | `:fuchsia` | `#eb459e` |
164
+ # | `:dark_teal` | `#11806a` |
165
+ # | `:green` | `#2ecc71` |
166
+ # | `:dark_green` | `#1f8b4c` |
167
+ # | `:blue` | `#3498db` |
168
+ # | `:dark_blue` | `#206694` |
169
+ # | `:purple` | `#9b59b6` |
170
+ # | `:dark_purple` | `#71368a` |
171
+ # | `:magenta` | `#e91e63` |
172
+ # | `:dark_magenta` | `#ad1457` |
173
+ # | `:gold` | `#f1c40f` |
174
+ # | `:dark_gold` | `#c27c0e` |
175
+ # | `:orange` | `#e67e22` |
176
+ # | `:dark_orange` | `#a84300` |
177
+ # | `:red` | `#e74c3c` |
178
+ # | `:dark_red` | `#992d22` |
179
+ # | `:lighter_grey` | `#95a5a6` |
180
+ # | `:lighter_gray` | `#95a5a6` |
181
+ # | `:dark_grey` | `#607d8b` |
182
+ # | `:dark_gray` | `#607d8b` |
183
+ # | `:light_grey` | `#979c9f` |
184
+ # | `:light_gray` | `#979c9f` |
185
+ # | `:darker_grey` | `#546e7a` |
186
+ # | `:darker_gray` | `#546e7a` |
187
+ # | `:og_blurple` | `#7289da` |
188
+ # | `:blurple` | `#5865f2` |
189
+ # | `:greyple` | `#99aab5` |
190
+ # | `:dark_theme` | `#36393f` |
191
+ # | `:fuchsia` | `#eb459e` |
162
192
  #
163
193
  # @param [Symbol] color A Discord color name.
164
194
  #
@@ -4,7 +4,7 @@ module Discorb
4
4
  # @return [String] The API base URL.
5
5
  API_BASE_URL = "https://discord.com/api/v9"
6
6
  # @return [String] The version of discorb.
7
- VERSION = "0.5.5"
7
+ VERSION = "0.7.0"
8
8
  # @return [String] The user agent for the bot.
9
9
  USER_AGENT = "DiscordBot (https://github.com/discorb-lib/discorb #{VERSION}) Ruby/#{RUBY_VERSION}"
10
10
 
data/lib/discorb/embed.rb CHANGED
@@ -93,18 +93,18 @@ module Discorb
93
93
  # @return [Hash] Converted embed.
94
94
  #
95
95
  def to_hash
96
- {
97
- title: @title,
98
- description: @description,
99
- url: @url,
100
- timestamp: @timestamp&.iso8601,
101
- color: @color&.to_i,
102
- footer: @footer&.to_hash,
103
- image: @image&.to_hash,
104
- thumbnail: @thumbnail&.to_hash,
105
- author: @author&.to_hash,
106
- fields: @fields&.map { |f| f.to_hash },
107
- }
96
+ ret = { type: "rich" }
97
+ ret[:title] = @title if @title
98
+ ret[:description] = @description if @description
99
+ ret[:url] = @url if @url
100
+ ret[:timestamp] = @timestamp&.iso8601 if @timestamp
101
+ ret[:color] = @color&.to_i if @color
102
+ ret[:footer] = @footer&.to_hash if @footer
103
+ ret[:image] = @image&.to_hash if @image
104
+ ret[:thumbnail] = @thumbnail&.to_hash if @thumbnail
105
+ ret[:author] = @author&.to_hash if @author
106
+ ret[:fields] = @fields&.map { |f| f.to_hash } if @fields.any?
107
+ ret
108
108
  end
109
109
 
110
110
  #
data/lib/discorb/emoji.rb CHANGED
@@ -6,6 +6,13 @@ module Discorb
6
6
  # Represents a Discord emoji.
7
7
  # @abstract
8
8
  class Emoji
9
+ def eql?(other)
10
+ other.is_a?(self.class) && other.to_uri == to_uri
11
+ end
12
+
13
+ def ==(other)
14
+ eql?(other)
15
+ end
9
16
  end
10
17
 
11
18
  # Represents a custom emoji in discord.
@@ -79,7 +86,7 @@ module Discorb
79
86
  # @param [Array<Discorb::Role>] roles The new roles that can use this emoji.
80
87
  # @param [String] reason The reason for editing the emoji.
81
88
  #
82
- # @return [self] The edited emoji.
89
+ # @return [Async::Task<self>] The edited emoji.
83
90
  #
84
91
  def edit(name: :unset, roles: :unset, reason: nil)
85
92
  Async do
@@ -100,7 +107,7 @@ module Discorb
100
107
  #
101
108
  # @param [String] reason The reason for deleting the emoji.
102
109
  #
103
- # @return [self] The deleted emoji.
110
+ # @return [Async::Task<self>] The deleted emoji.
104
111
  #
105
112
  def delete!(reason: nil)
106
113
  Async do
data/lib/discorb/error.rb CHANGED
@@ -67,6 +67,12 @@ module Discorb
67
67
  end
68
68
  end
69
69
 
70
+ #
71
+ # Represents a 401 error.
72
+ #
73
+ class UnauthorizedError < HTTPError
74
+ end
75
+
70
76
  #
71
77
  # Represents a 403 error.
72
78
  #
@@ -88,7 +94,7 @@ module Discorb
88
94
  @client.close!
89
95
  DiscorbError.instance_method(:initialize).bind(self).call(<<~MESSAGE)
90
96
  The client is banned from CloudFlare.
91
- Hint: Try to increase the number of requests per second, e.g. Use sleep in between requests.
97
+ Hint: Try to decrease the number of requests per second, e.g. Use sleep in between requests.
92
98
  MESSAGE
93
99
  end
94
100
  end
data/lib/discorb/event.rb CHANGED
@@ -11,17 +11,17 @@ module Discorb
11
11
  attr_reader :block
12
12
  # @return [Symbol] the event id.
13
13
  attr_reader :id
14
- # @return [Hash] the event discriminator.
15
- attr_reader :discriminator
14
+ # @return [Hash] the event metadata.
15
+ attr_reader :metadata
16
16
  # @return [Boolean] whether the event is once or not.
17
17
  attr_reader :once
18
18
  alias once? once
19
19
 
20
- def initialize(block, id, discriminator)
20
+ def initialize(block, id, metadata)
21
21
  @block = block
22
22
  @id = id
23
- @once = discriminator.fetch(:once, false)
24
- @discriminator = discriminator
23
+ @once = metadata.fetch(:once, false)
24
+ @metadata = metadata
25
25
  @rescue = nil
26
26
  end
27
27
 
@@ -2,6 +2,7 @@
2
2
  require "optparse"
3
3
  require "json"
4
4
  require "discorb/utils/colored_puts"
5
+ require "io/console"
5
6
 
6
7
  ARGV.delete_at 0
7
8
  # @!visibility private
@@ -20,6 +21,7 @@ options = {
20
21
  log_file: nil,
21
22
  log_color: nil,
22
23
  setup: nil,
24
+ token: false,
23
25
  }
24
26
  opt.on("-d", "--deamon", "Run as a daemon.") { |v| options[:daemon] = v }
25
27
  opt.on("-l", "--log-level LEVEL", "Log level.") do |v|
@@ -33,6 +35,7 @@ end
33
35
  opt.on("-f", "--log-file FILE", "File to write log to.") { |v| options[:log_file] = v }
34
36
  opt.on("-c", "--[no-]log-color", "Whether to colorize log output.") { |v| options[:log_color] = v }
35
37
  opt.on("-s", "--setup", "Whether to setup application commands.") { |v| options[:setup] = v }
38
+ opt.on("-t", "--token [ENV]", "The name of the environment variable to use for token, or just `-t` or `--token` for intractive prompt.") { |v| options[:token] = v }
36
39
  opt.parse!(ARGV)
37
40
 
38
41
  script = ARGV[0]
@@ -42,6 +45,15 @@ script ||= "main.rb"
42
45
  ENV["DISCORB_CLI_FLAG"] = "run"
43
46
  ENV["DISCORB_CLI_OPTIONS"] = JSON.generate(options)
44
47
 
48
+ if options[:token]
49
+ ENV["DISCORB_CLI_TOKEN"] = ENV[options[:token]]
50
+ raise "#{options[:token]} is not set." if ENV["DISCORB_CLI_TOKEN"].nil?
51
+ elsif options[:token].nil? || options[:token] == "-"
52
+ print "\e[90mPlease enter your token: \e[m"
53
+ ENV["DISCORB_CLI_TOKEN"] = $stdin.noecho(&:gets).chomp
54
+ puts ""
55
+ end
56
+
45
57
  begin
46
58
  load script
47
59
  rescue LoadError
@@ -4,19 +4,32 @@ require "discorb/utils/colored_puts"
4
4
 
5
5
  ARGV.delete_at 0
6
6
 
7
+ options = {
8
+ guilds: nil,
9
+ }
10
+
7
11
  opt = OptionParser.new <<~BANNER
8
12
  This command will setup application commands.
9
13
 
10
- Usage: discorb setup [script]
14
+ Usage: discorb setup [options] [script]
11
15
 
12
16
  script The script to setup.
13
17
  BANNER
18
+ opt.on("-g", "--guild ID", Array, "The guild ID to setup, use comma for setup commands in multiple guilds, or `global` for setup global commands.") { |v| options[:guilds] = v }
14
19
  opt.parse!(ARGV)
15
20
 
16
21
  script = ARGV[0]
17
22
  script ||= "main.rb"
18
23
  ENV["DISCORB_CLI_FLAG"] = "setup"
19
24
 
25
+ if options[:guilds] == ["global"]
26
+ ENV["DISCORB_SETUP_GUILDS"] = "global"
27
+ elsif options[:guilds]
28
+ ENV["DISCORB_SETUP_GUILDS"] = options[:guilds].join(",")
29
+ else
30
+ ENV["DISCORB_SETUP_GUILDS"] = nil
31
+ end
32
+
20
33
  begin
21
34
  load script
22
35
  rescue LoadError
@@ -8,7 +8,7 @@ module Discorb
8
8
  # @abstract
9
9
  #
10
10
  module Extension
11
- include Discorb::Command::Handler
11
+ include Discorb::ApplicationCommand::Handler
12
12
  undef setup_commands
13
13
 
14
14
  @events = {}
@@ -19,18 +19,18 @@ module Discorb
19
19
  #
20
20
  # @param [Symbol] event_name The name of the event.
21
21
  # @param [Symbol] id The id of the event. Used to delete the event.
22
- # @param [Hash] discriminator Other discriminators.
22
+ # @param [Hash] metadata Other metadata.
23
23
  # @param [Proc] block The block to execute when the event is triggered.
24
24
  #
25
25
  # @return [Discorb::Event] The event.
26
26
  #
27
- def event(event_name, id: nil, **discriminator, &block)
27
+ def event(event_name, id: nil, **metadata, &block)
28
28
  raise ArgumentError, "Event name must be a symbol" unless event_name.is_a?(Symbol)
29
29
  raise ArgumentError, "block must be a Proc" unless block.is_a?(Proc)
30
30
 
31
31
  @events[event_name] ||= []
32
- discriminator[:extension] = self.name
33
- @events[event_name] << Discorb::Event.new(block, id, discriminator)
32
+ metadata[:extension] = self.name
33
+ @events[event_name] << Discorb::Event.new(block, id, metadata)
34
34
  end
35
35
 
36
36
  #
@@ -38,18 +38,18 @@ module Discorb
38
38
  #
39
39
  # @param [Symbol] event_name The name of the event.
40
40
  # @param [Symbol] id The id of the event. Used to delete the event.
41
- # @param [Hash] discriminator Other discriminators.
41
+ # @param [Hash] metadata Other metadata.
42
42
  # @param [Proc] block The block to execute when the event is triggered.
43
43
  #
44
44
  # @return [Discorb::Event] The event.
45
45
  #
46
- def once_event(event_name, id: nil, **discriminator, &block)
47
- event(event_name, id: id, once: true, **discriminator, &block)
46
+ def once_event(event_name, id: nil, **metadata, &block)
47
+ event(event_name, id: id, once: true, **metadata, &block)
48
48
  end
49
49
 
50
50
  # @return [Hash{Symbol => Array<Discorb::Event>}] The events of the extension.
51
51
  attr_reader :events
52
- # @return [Array<Discorb::Command::Command] The commands of the extension.
52
+ # @return [Array<Discorb::ApplicationCommand::Command>] The commands of the extension.
53
53
  attr_reader :commands
54
54
  # @private
55
55
  attr_reader :bottom_commands
@@ -53,6 +53,12 @@ module Discorb
53
53
  attr_reader :member
54
54
  # @return [Discorb::UnicodeEmoji, Discorb::PartialEmoji] The emoji that was reacted with.
55
55
  attr_reader :emoji
56
+ # @macro client_cache
57
+ # @return [Discorb::Member, Discorb::User] The user or member who reacted.
58
+ attr_reader :fired_by
59
+
60
+ alias reactor fired_by
61
+ alias from fired_by
56
62
 
57
63
  # @!visibility private
58
64
  def initialize(client, data)
@@ -79,6 +85,8 @@ module Discorb
79
85
  end
80
86
  end
81
87
 
88
+ @fired_by = @member || @user || @client.users[data[:user_id]]
89
+
82
90
  @message = client.messages[data[:message_id]]
83
91
  @emoji = data[:emoji][:id].nil? ? UnicodeEmoji.new(data[:emoji][:name]) : PartialEmoji.new(data[:emoji])
84
92
  end
@@ -90,7 +98,7 @@ module Discorb
90
98
  #
91
99
  # @param [Boolean] force Whether to force fetching the message.
92
100
  #
93
- # @return [Discorb::Message] The message.
101
+ # @return [Async::Task<Discorb::Message>] The message.
94
102
  def fetch_message(force: false)
95
103
  Async do
96
104
  next @message if !force && @message
@@ -139,7 +147,7 @@ module Discorb
139
147
  #
140
148
  # @param [Boolean] force Whether to force fetching the message.
141
149
  #
142
- # @return [Discorb::Message] The message.
150
+ # @return [Async::Task<Discorb::Message>] The message.
143
151
  def fetch_message(force: false)
144
152
  Async do
145
153
  next @message if !force && @message
@@ -191,7 +199,7 @@ module Discorb
191
199
  #
192
200
  # @param [Boolean] force Whether to force fetching the message.
193
201
  #
194
- # @return [Discorb::Message] The message.
202
+ # @return [Async::Task<Discorb::Message>] The message.
195
203
  def fetch_message(force: false)
196
204
  Async do
197
205
  next @message if !force && @message
@@ -265,7 +273,7 @@ module Discorb
265
273
  # @macro async
266
274
  # @macro http
267
275
  #
268
- # @return [Discorb::Message] The message.
276
+ # @return [Async::Task<Discorb::Message>] The message.
269
277
  def fetch_message
270
278
  Async do
271
279
  channel.fetch_message(@id).wait
@@ -355,6 +363,9 @@ module Discorb
355
363
  class TypingStartEvent < GatewayEvent
356
364
  # @return [Discorb::Snowflake] The ID of the channel the user is typing in.
357
365
  attr_reader :user_id
366
+ # @macro client_cache
367
+ # @return [Discorb::Member] The member that is typing.
368
+ attr_reader :member
358
369
 
359
370
  # @!attribute [r] channel
360
371
  # @macro client_cache
@@ -365,6 +376,9 @@ module Discorb
365
376
  # @!attribute [r] user
366
377
  # @macro client_cache
367
378
  # @return [Discorb::User] The user that is typing.
379
+ # @!attribute [r] fired_by
380
+ # @macro client_cache
381
+ # @return [Discorb::Member, Discorb::User] The member or user that started typing.
368
382
 
369
383
  # @!visibility private
370
384
  def initialize(client, data)
@@ -388,6 +402,12 @@ module Discorb
388
402
  def guild
389
403
  @client.guilds[@guild_id]
390
404
  end
405
+
406
+ def fired_by
407
+ @member || user
408
+ end
409
+
410
+ alias from fired_by
391
411
  end
392
412
 
393
413
  #
@@ -513,7 +533,6 @@ module Discorb
513
533
  case payload[:op]
514
534
  when 10
515
535
  @heartbeat_interval = data[:heartbeat_interval]
516
- @tasks << handle_heartbeat(@heartbeat_interval)
517
536
  if @first
518
537
  payload = {
519
538
  token: @token,
@@ -523,6 +542,13 @@ module Discorb
523
542
  }
524
543
  payload[:presence] = @identify_presence if @identify_presence
525
544
  send_gateway(2, **payload)
545
+ Async do
546
+ sleep 2
547
+ next unless @uncached_guilds.nil?
548
+
549
+ raise ClientError, "Failed to connect to gateway.\nHint: This usually means that your intents are invalid."
550
+ exit 1
551
+ end
526
552
  else
527
553
  payload = {
528
554
  token: @token,
@@ -540,7 +566,7 @@ module Discorb
540
566
  connect_gateway(false)
541
567
  else
542
568
  @log.info "Connection is not resumable, reconnecting with opcode 2"
543
- task.sleep(2)
569
+ sleep(2)
544
570
  @connection.close
545
571
  connect_gateway(true)
546
572
  end
@@ -555,7 +581,7 @@ module Discorb
555
581
 
556
582
  def handle_heartbeat(interval)
557
583
  Async do |task|
558
- task.sleep((interval / 1000.0 - 1) * rand)
584
+ sleep((interval / 1000.0 - 1) * rand)
559
585
  loop do
560
586
  @heartbeat_before = Time.now.to_f
561
587
  @connection.write({ op: 1, d: @last_s }.to_json)
@@ -578,6 +604,12 @@ module Discorb
578
604
  @session_id = data[:session_id]
579
605
  @user = ClientUser.new(self, data[:user])
580
606
  @uncached_guilds = data[:guilds].map { |g| g[:id] }
607
+ if @uncached_guilds == [] or !@intents.guilds
608
+ @ready = true
609
+ dispatch(:ready)
610
+ @log.info("Successfully connected to Discord.")
611
+ end
612
+ @tasks << handle_heartbeat(@heartbeat_interval)
581
613
  when "GUILD_CREATE"
582
614
  if @uncached_guilds.include?(data[:id])
583
615
  Guild.new(self, data, true)
@@ -585,7 +617,7 @@ module Discorb
585
617
  if @uncached_guilds == []
586
618
  @ready = true
587
619
  dispatch(:ready)
588
- @log.info("Guilds were cached")
620
+ @log.info("Successfully connected to Discord, and cached all guilds.")
589
621
  end
590
622
  elsif @guilds.has?(data[:id])
591
623
  @guilds[data[:id]].send(:_set_data, data)