mij-discord 1.0.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 +7 -0
- data/.gitignore +10 -0
- data/.travis.yml +5 -0
- data/Gemfile +6 -0
- data/LICENSE +21 -0
- data/README.md +35 -0
- data/Rakefile +10 -0
- data/bin/console +7 -0
- data/bin/setup +6 -0
- data/lib/mij-discord.rb +56 -0
- data/lib/mij-discord/bot.rb +579 -0
- data/lib/mij-discord/cache.rb +298 -0
- data/lib/mij-discord/core/api.rb +228 -0
- data/lib/mij-discord/core/api/channel.rb +416 -0
- data/lib/mij-discord/core/api/invite.rb +43 -0
- data/lib/mij-discord/core/api/server.rb +465 -0
- data/lib/mij-discord/core/api/user.rb +144 -0
- data/lib/mij-discord/core/errors.rb +106 -0
- data/lib/mij-discord/core/gateway.rb +505 -0
- data/lib/mij-discord/data.rb +65 -0
- data/lib/mij-discord/data/application.rb +38 -0
- data/lib/mij-discord/data/channel.rb +404 -0
- data/lib/mij-discord/data/embed.rb +115 -0
- data/lib/mij-discord/data/emoji.rb +62 -0
- data/lib/mij-discord/data/invite.rb +87 -0
- data/lib/mij-discord/data/member.rb +174 -0
- data/lib/mij-discord/data/message.rb +206 -0
- data/lib/mij-discord/data/permissions.rb +121 -0
- data/lib/mij-discord/data/role.rb +99 -0
- data/lib/mij-discord/data/server.rb +359 -0
- data/lib/mij-discord/data/user.rb +173 -0
- data/lib/mij-discord/data/voice.rb +68 -0
- data/lib/mij-discord/events.rb +133 -0
- data/lib/mij-discord/events/basic.rb +80 -0
- data/lib/mij-discord/events/channel.rb +50 -0
- data/lib/mij-discord/events/member.rb +66 -0
- data/lib/mij-discord/events/message.rb +150 -0
- data/lib/mij-discord/events/server.rb +102 -0
- data/lib/mij-discord/logger.rb +20 -0
- data/lib/mij-discord/version.rb +5 -0
- data/mij-discord.gemspec +31 -0
- metadata +154 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MijDiscord::Data
|
4
|
+
DISCORD_EPOCH = 1_420_070_400_000
|
5
|
+
|
6
|
+
CHARACTER_LIMIT = 2000
|
7
|
+
|
8
|
+
module IDObject
|
9
|
+
attr_reader :id
|
10
|
+
alias_method :to_id, :id
|
11
|
+
|
12
|
+
def hash
|
13
|
+
@id.hash
|
14
|
+
end
|
15
|
+
|
16
|
+
def ==(other)
|
17
|
+
@id == (other.respond_to?(:to_id) ? other.to_id : other)
|
18
|
+
end
|
19
|
+
|
20
|
+
alias_method :eql?, :==
|
21
|
+
|
22
|
+
def creation_time
|
23
|
+
ms = (@id >> 22) + DISCORD_EPOCH
|
24
|
+
Time.at(ms / 1000.0).utc
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.synthesize(time)
|
28
|
+
ms = (time.to_f * 1000).to_i
|
29
|
+
(ms - DISCORD_EPOCH) << 22
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module PermissionObject
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
class ColorRGB
|
38
|
+
attr_reader :red
|
39
|
+
alias_method :r, :red
|
40
|
+
|
41
|
+
attr_reader :green
|
42
|
+
alias_method :g, :green
|
43
|
+
|
44
|
+
attr_reader :blue
|
45
|
+
alias_method :b, :blue
|
46
|
+
|
47
|
+
attr_reader :value
|
48
|
+
alias_method :to_i, :value
|
49
|
+
|
50
|
+
def initialize(color = nil)
|
51
|
+
self.value = color || 0xFFFFFF
|
52
|
+
end
|
53
|
+
|
54
|
+
def value=(color)
|
55
|
+
@value = color.is_a?(String) ? color.to_i(16) : color
|
56
|
+
@red = (@value >> 16) & 0xFF
|
57
|
+
@green = (@value >> 8) & 0xFF
|
58
|
+
@blue = (@value >> 0) & 0xFF
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_hex
|
62
|
+
'%06x' % @value
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MijDiscord::Data
|
4
|
+
class Application
|
5
|
+
include IDObject
|
6
|
+
|
7
|
+
attr_reader :name
|
8
|
+
|
9
|
+
attr_reader :description
|
10
|
+
|
11
|
+
attr_reader :rpc_origins
|
12
|
+
|
13
|
+
attr_reader :flags
|
14
|
+
|
15
|
+
attr_reader :owner
|
16
|
+
|
17
|
+
def initialize(data, bot)
|
18
|
+
@bot = bot
|
19
|
+
|
20
|
+
@id = data['id'].to_i
|
21
|
+
@name = data['name']
|
22
|
+
@description = data['description']
|
23
|
+
@icon_id = data['icon']
|
24
|
+
@rpc_origins = data['rpc_origins']
|
25
|
+
@flags = data['flags']
|
26
|
+
@owner = @bot.cache.put_user(data['owner'])
|
27
|
+
end
|
28
|
+
|
29
|
+
def icon_url(format = nil)
|
30
|
+
return nil if @icon_id.nil?
|
31
|
+
MijDiscord::Core::API.app_icon_url(@id, @icon_id, format)
|
32
|
+
end
|
33
|
+
|
34
|
+
def inspect
|
35
|
+
%(<Application id=#{@id} name="#{@name}">)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,404 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MijDiscord::Data
|
4
|
+
class Channel
|
5
|
+
TYPES = {
|
6
|
+
0 => :text,
|
7
|
+
1 => :pm,
|
8
|
+
2 => :voice,
|
9
|
+
3 => :group,
|
10
|
+
4 => :category,
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
include IDObject
|
14
|
+
|
15
|
+
attr_reader :bot
|
16
|
+
|
17
|
+
attr_reader :name
|
18
|
+
|
19
|
+
attr_reader :server
|
20
|
+
|
21
|
+
attr_reader :type
|
22
|
+
|
23
|
+
attr_reader :position
|
24
|
+
|
25
|
+
attr_reader :parent_id
|
26
|
+
|
27
|
+
attr_reader :permission_overwrites
|
28
|
+
alias_method :overwrites, :permission_overwrites
|
29
|
+
|
30
|
+
attr_reader :cache
|
31
|
+
|
32
|
+
def initialize(data, bot, server)
|
33
|
+
@bot = bot
|
34
|
+
@cache = MijDiscord::Cache::ChannelCache.new(self, @bot)
|
35
|
+
|
36
|
+
data = data[-1] if data.is_a?(Array)
|
37
|
+
|
38
|
+
@id = data['id'].to_i
|
39
|
+
update_data(data)
|
40
|
+
|
41
|
+
@server = server || @bot.server(data['guild_id']) unless private?
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.create(data, bot, server)
|
45
|
+
case TYPES[data['type']]
|
46
|
+
when :text, :pm, :group
|
47
|
+
TextChannel.new(data, bot, server)
|
48
|
+
when :voice
|
49
|
+
VoiceChannel.new(data, bot, server)
|
50
|
+
when :category
|
51
|
+
ChannelCategory.new(data, bot, server)
|
52
|
+
else
|
53
|
+
raise RuntimeError, 'Broken channel object!'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def update_data(data)
|
58
|
+
@name = data.fetch('name', @name) unless pm?
|
59
|
+
@type_id = data.fetch('type', @type_id || 0)
|
60
|
+
@type = TYPES[@type_id]
|
61
|
+
|
62
|
+
@position = data.fetch('position', @position)
|
63
|
+
@parent_id = data.fetch('parent_id', @parent_id).to_i
|
64
|
+
|
65
|
+
if (perms = data['permission_overwrites'])
|
66
|
+
@permission_overwrites = {}
|
67
|
+
|
68
|
+
perms.each do |elem|
|
69
|
+
id = elem['id'].to_i
|
70
|
+
@permission_overwrites[id] = Overwrite.from_hash(elem)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def mention
|
76
|
+
"<##{@id}>"
|
77
|
+
end
|
78
|
+
|
79
|
+
alias_method :to_s, :mention
|
80
|
+
|
81
|
+
def text?
|
82
|
+
@type == :text
|
83
|
+
end
|
84
|
+
|
85
|
+
def pm?
|
86
|
+
@type == :pm
|
87
|
+
end
|
88
|
+
|
89
|
+
alias_method :dm?, :pm?
|
90
|
+
|
91
|
+
def voice?
|
92
|
+
@type == :voice
|
93
|
+
end
|
94
|
+
|
95
|
+
def group?
|
96
|
+
@type == :group
|
97
|
+
end
|
98
|
+
|
99
|
+
def category?
|
100
|
+
@type == :category
|
101
|
+
end
|
102
|
+
|
103
|
+
def private?
|
104
|
+
pm? || group?
|
105
|
+
end
|
106
|
+
|
107
|
+
def default_channel?
|
108
|
+
@server.default_channel == self
|
109
|
+
end
|
110
|
+
|
111
|
+
alias_method :default?, :default_channel?
|
112
|
+
|
113
|
+
def parent
|
114
|
+
@parent_id ? @server.cache.get_channel(@parent_id) : nil
|
115
|
+
end
|
116
|
+
|
117
|
+
def member_overwrites
|
118
|
+
@permission_overwrites.values.select {|v| v.type == :member }
|
119
|
+
end
|
120
|
+
|
121
|
+
def role_overwrites
|
122
|
+
@permission_overwrites.values.select {|v| v.type == :role }
|
123
|
+
end
|
124
|
+
|
125
|
+
def set_name(name, reason = nil)
|
126
|
+
return if private?
|
127
|
+
|
128
|
+
set_options(reason, name: name)
|
129
|
+
end
|
130
|
+
|
131
|
+
alias_method :name=, :set_name
|
132
|
+
|
133
|
+
def set_position(position, reason = nil)
|
134
|
+
set_options(reason, position: position)
|
135
|
+
end
|
136
|
+
|
137
|
+
alias_method :position=, :set_position
|
138
|
+
|
139
|
+
def set_parent(parent, reason = nil)
|
140
|
+
set_options(reason, parent: parent)
|
141
|
+
end
|
142
|
+
|
143
|
+
def set_options(reason = nil, name: nil, topic: nil, nsfw: nil,
|
144
|
+
parent: nil, position: nil, bitrate: nil, user_limit: nil)
|
145
|
+
response = MijDiscord::Core::API::Channel.update(@bot.token, @id,
|
146
|
+
name, topic, nsfw,parent&.to_id, position, bitrate, user_limit, reason)
|
147
|
+
@server.cache.put_channel(JSON.parse(response), update: true)
|
148
|
+
end
|
149
|
+
|
150
|
+
def define_overwrite(object, reason = nil, allow: 0, deny: 0)
|
151
|
+
unless object.is_a?(Overwrite)
|
152
|
+
allow_bits = allow.respond_to?(:bits) ? allow.bits : allow
|
153
|
+
deny_bits = deny.respond_to?(:bits) ? deny.bits : deny
|
154
|
+
|
155
|
+
object = Overwrite.new(object, allow: allow_bits, deny: deny_bits)
|
156
|
+
end
|
157
|
+
|
158
|
+
MijDiscord::Core::API::Channel.update_permission(@bot.token, @id,
|
159
|
+
object.id, object.allow.bits, object.deny.bits, object.type, reason)
|
160
|
+
nil
|
161
|
+
end
|
162
|
+
|
163
|
+
def delete_overwrite(object, reason = nil)
|
164
|
+
raise ArgumentError, 'Invalid overwrite target' unless object.respond_to?(:to_id)
|
165
|
+
MijDiscord::Core::API::Channel.delete_permission(@bot.token, @id,
|
166
|
+
object.to_id, reason)
|
167
|
+
nil
|
168
|
+
end
|
169
|
+
|
170
|
+
def delete(reason = nil)
|
171
|
+
MijDiscord::Core::API::Channel.delete(@bot.token, @id, reason)
|
172
|
+
@server.cache.remove_channel(@id)
|
173
|
+
end
|
174
|
+
|
175
|
+
def inspect
|
176
|
+
%(<Channel id=#{@id} server=#{@server.id} name="#{@name}" type=#{@type}>)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
class TextChannel < Channel
|
181
|
+
attr_reader :topic
|
182
|
+
|
183
|
+
attr_reader :owner_id
|
184
|
+
|
185
|
+
attr_reader :nsfw
|
186
|
+
alias_method :nsfw?, :nsfw
|
187
|
+
|
188
|
+
attr_reader :recipients
|
189
|
+
|
190
|
+
def initialize(data, bot, server)
|
191
|
+
super(data, bot, server)
|
192
|
+
|
193
|
+
if private?
|
194
|
+
@recipients = []
|
195
|
+
if data['recipients']
|
196
|
+
data['recipients'].each do |rd|
|
197
|
+
user = @bot.cache.put_user(rd)
|
198
|
+
@recipients << Recipient.new(user, self, @bot)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
if pm?
|
203
|
+
@name = @recipients.first.username
|
204
|
+
else
|
205
|
+
@owner_id = data['owner_id'].to_i
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def update_data(data)
|
211
|
+
super(data)
|
212
|
+
|
213
|
+
@topic = data.fetch('topic', @topic)
|
214
|
+
@nsfw = data.fetch('nsfw', @nsfw)
|
215
|
+
end
|
216
|
+
|
217
|
+
def update_recipient(add: nil, remove: nil)
|
218
|
+
return unless group?
|
219
|
+
|
220
|
+
unless add.nil?
|
221
|
+
user = @bot.cache.put_user(add)
|
222
|
+
recipient = Recipient.new(user, self, @bot)
|
223
|
+
@recipients << recipient
|
224
|
+
return recipient
|
225
|
+
end
|
226
|
+
|
227
|
+
unless remove.nil?
|
228
|
+
id = remove['id'].to_i
|
229
|
+
recipient = @recipients.find {|x| x.id == id }
|
230
|
+
return @recipients.delete(recipient)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def owner
|
235
|
+
@owner_id ? @bot.cache.get_user(@owner_id) : nil
|
236
|
+
end
|
237
|
+
|
238
|
+
def set_topic(topic, reason = nil)
|
239
|
+
return unless text?
|
240
|
+
|
241
|
+
set_options(reason, topic: topic)
|
242
|
+
end
|
243
|
+
|
244
|
+
alias_method :topic=, :set_topic
|
245
|
+
|
246
|
+
def set_nsfw(nsfw, reason = nil)
|
247
|
+
return unless text?
|
248
|
+
|
249
|
+
set_options(reason, nsfw: nsfw)
|
250
|
+
end
|
251
|
+
|
252
|
+
alias_method :nsfw=, :set_nsfw
|
253
|
+
|
254
|
+
def send_message(text: '', embed: nil, tts: false)
|
255
|
+
raise MijDiscord::Core::Errors::MessageTooLong if text.length > 2000
|
256
|
+
|
257
|
+
response = MijDiscord::Core::API::Channel.create_message(@bot.token, @id,
|
258
|
+
text, tts, embed&.to_h)
|
259
|
+
@cache.put_message(JSON.parse(response))
|
260
|
+
end
|
261
|
+
|
262
|
+
def send_file(file, caption: '', tts: false)
|
263
|
+
raise MijDiscord::Core::Errors::MessageTooLong if caption.length > 2000
|
264
|
+
|
265
|
+
response = MijDiscord::Core::API::Channel.upload_file(@bot.token, @id, file, caption, tts)
|
266
|
+
@cache.put_message(JSON.parse(response))
|
267
|
+
end
|
268
|
+
|
269
|
+
def delete_message(message)
|
270
|
+
MijDiscord::Core::API::Channel.delete_message(@bot.token, @id, message.to_id)
|
271
|
+
@cache.remove_message(message)
|
272
|
+
end
|
273
|
+
|
274
|
+
def message(id)
|
275
|
+
@cache.get_message(id)
|
276
|
+
end
|
277
|
+
|
278
|
+
def message_history(amount, before: nil, after: nil, around: nil)
|
279
|
+
response = MijDiscord::Core::API::Channel.messages(@bot.token, @id,
|
280
|
+
amount, before&.to_id, after&.to_id, around&.to_id)
|
281
|
+
JSON.parse(response).map {|m| Message.new(m, @bot) }
|
282
|
+
end
|
283
|
+
|
284
|
+
alias_method :history, :message_history
|
285
|
+
|
286
|
+
def pinned_messages
|
287
|
+
response = MijDiscord::Core::API::Channel.pinned_messages(@bot.token, @id)
|
288
|
+
JSON.parse(response).map {|m| Message.new(m, @bot) }
|
289
|
+
end
|
290
|
+
|
291
|
+
alias_method :pinned, :pinned_messages
|
292
|
+
|
293
|
+
def delete_messages(messages)
|
294
|
+
two_weeks = Time.now - (14 * 86_400)
|
295
|
+
min_snowflake = IDObject.synthesize(two_weeks)
|
296
|
+
ids = messages.map(&:to_id).delete_if {|m| m < min_snowflake }
|
297
|
+
|
298
|
+
MijDiscord::Core::API::Channel.bulk_delete_messages(@bot.token, @id, ids)
|
299
|
+
ids.each {|m| @cache.remove_message(m) }
|
300
|
+
end
|
301
|
+
|
302
|
+
def invites
|
303
|
+
response = MijDiscord::Core::API::Channel.invites(@bot.token, @id)
|
304
|
+
JSON.parse(response).map {|x| Invite.new(x, @bot) }
|
305
|
+
end
|
306
|
+
|
307
|
+
def make_invite(reason = nil, max_age: 0, max_uses: 0, temporary: false, unique: false)
|
308
|
+
response = MijDiscord::Core::API::Channel.create_invite(@bot.token, @id,
|
309
|
+
max_age, max_uses, temporary, unique, reason)
|
310
|
+
Invite.new(JSON.parse(response), @bot)
|
311
|
+
end
|
312
|
+
|
313
|
+
alias_method :invite, :make_invite
|
314
|
+
|
315
|
+
def start_typing
|
316
|
+
MijDiscord::Core::API::Channel.start_typing(@bot.token, @id)
|
317
|
+
nil
|
318
|
+
end
|
319
|
+
|
320
|
+
def create_group(users)
|
321
|
+
raise 'Attempted to create group channel on a non-pm channel' unless pm?
|
322
|
+
|
323
|
+
ids = users.map(&:to_id)
|
324
|
+
response = MijDiscord::Core::API::Channel.create_group(@bot.token, @id, ids.shift)
|
325
|
+
channel = @bot.cache.put_channel(JSON.parse(response))
|
326
|
+
channel.add_group_users(ids)
|
327
|
+
|
328
|
+
channel
|
329
|
+
end
|
330
|
+
|
331
|
+
def add_group_users(users)
|
332
|
+
raise 'Attempted to add a user to a non-group channel' unless group?
|
333
|
+
|
334
|
+
users.each do |u|
|
335
|
+
MijDiscord::Core::API::Channel.add_group_user(@bot.token, @id, u.to_id)
|
336
|
+
end
|
337
|
+
nil
|
338
|
+
end
|
339
|
+
|
340
|
+
def remove_group_users(users)
|
341
|
+
raise 'Attempted to remove a user to a non-group channel' unless group?
|
342
|
+
|
343
|
+
users.each do |u|
|
344
|
+
MijDiscord::Core::API::Channel.remove_group_user(@bot.token, @id, u.to_id)
|
345
|
+
end
|
346
|
+
nil
|
347
|
+
end
|
348
|
+
|
349
|
+
def leave_group
|
350
|
+
raise 'Attempoted to leave a non-group channel' unless group?
|
351
|
+
|
352
|
+
MijDiscord::Core::API::Channel.leave_group(@bot.token, @id)
|
353
|
+
nil
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
class VoiceChannel < Channel
|
358
|
+
attr_reader :bitrate
|
359
|
+
|
360
|
+
attr_reader :user_limit
|
361
|
+
alias_method :limit, :user_limit
|
362
|
+
|
363
|
+
def initialize(data, bot, server)
|
364
|
+
super(data, bot, server)
|
365
|
+
|
366
|
+
|
367
|
+
end
|
368
|
+
|
369
|
+
def update_data(data)
|
370
|
+
super(data)
|
371
|
+
|
372
|
+
@bitrate = data.fetch('bitrate', @bitrate)
|
373
|
+
@user_limit = data.fetch('user_limit', @user_limit)
|
374
|
+
end
|
375
|
+
|
376
|
+
def set_bitrate(rate, reason = nil)
|
377
|
+
set_options(reason, bitrate: rate)
|
378
|
+
end
|
379
|
+
|
380
|
+
alias_method :bitrate=, :set_bitrate
|
381
|
+
|
382
|
+
def set_user_limit(limit, reason = nil)
|
383
|
+
set_options(reason, user_limit: limit)
|
384
|
+
end
|
385
|
+
|
386
|
+
alias_method :user_limit=, :set_user_limit
|
387
|
+
alias_method :set_limit, :set_user_limit
|
388
|
+
alias_method :limit=, :set_user_limit
|
389
|
+
end
|
390
|
+
|
391
|
+
class ChannelCategory < Channel
|
392
|
+
def initialize(data, bot, server)
|
393
|
+
super(data, bot, server)
|
394
|
+
end
|
395
|
+
|
396
|
+
def update_data(data)
|
397
|
+
super(data)
|
398
|
+
end
|
399
|
+
|
400
|
+
def channels
|
401
|
+
@server.channels.select! {|x| x.parent_id == @id }
|
402
|
+
end
|
403
|
+
end
|
404
|
+
end
|