mij-discord 1.0.6 → 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a986d989e1c82e40f9c1c5346b3496a402491f3e
4
- data.tar.gz: 8db9cd45703269a7c40e03beccc2c4dcf272b0d3
3
+ metadata.gz: aca2803ee72c1ab5229d6767b809ee5a3a1aa605
4
+ data.tar.gz: 037b4495e988f6c7c70e83801920fda475b9a262
5
5
  SHA512:
6
- metadata.gz: 31147c15e9b63573c41bba6b700b9be15002be8b7262ca42c2fc50a7fc0ed7486ca08e6833a98ee53f58a4cbbdc151d05b6a43ee0da399698f291b7925100e9c
7
- data.tar.gz: e5d0c9e7383b825b8bb513177361cb9dbd56650fd8f3563ca18c878ac3a9269f816f2b3d84e43c5d18b97ac15b41f43316e5831d69f920cf828781cb5c31686a
6
+ metadata.gz: 2ff78a29820234b6ff79a848ccb0fb9b77019d645ec18bb6040a3566923f3e775462f01224a8df803ac07d31f29d55d4f7eb50c7de3ae5e464eac19b05c7fb0d
7
+ data.tar.gz: 641bcc97f7a0039e655eb7ad4800a1dfcf0d62c9a5ff9333243204dc2eb9fbec24e897a4b54b40bf0288bece09cff9f740bc3a5308ade781647adb8b908fd0ac
@@ -1,14 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MijDiscord
4
- class Bot
5
- class AuthInfo
6
- attr_reader :token
4
+ class Bot
5
+ class AuthInfo
6
+ attr_reader :token
7
7
 
8
8
  attr_reader :type
9
9
 
10
- def initialize(token, type)
11
- @token, @type = token, type
10
+ attr_reader :name
11
+
12
+ def initialize(token, type, name)
13
+ @type, @name = type, name
14
+
15
+ @token = case type
16
+ when :bot then "Bot #{token}"
17
+ when :user then "#{token}"
18
+ else raise ArgumentError, 'Invalid token type'
19
+ end
20
+ end
21
+
22
+ def bot?
23
+ @type == :bot
24
+ end
25
+
26
+ def user?
27
+ @type == :user
12
28
  end
13
29
 
14
30
  alias_method :to_s, :token
@@ -60,8 +76,6 @@ module MijDiscord
60
76
 
61
77
  UNAVAILABLE_SERVER_TIMEOUT = 10
62
78
 
63
- USER_STATUS = [:online, :idle, :dnd, :invisible, :offline].freeze
64
-
65
79
  attr_reader :name
66
80
 
67
81
  attr_reader :client_id
@@ -78,15 +92,8 @@ module MijDiscord
78
92
 
79
93
  def initialize(client_id:, token:, type: :bot, name: nil,
80
94
  shard_id: nil, num_shards: nil, ignore_bots: false, ignore_self: true)
81
- @client_id, @name = client_id.to_id, name || ''
82
-
83
- token = case type
84
- when :bot then "Bot #{token}"
85
- when :user then "#{token}"
86
- else raise ArgumentError, 'Invalid bot type'
87
- end
88
-
89
- @auth = AuthInfo.new(token, type)
95
+ @client_id = client_id.to_id
96
+ @auth = AuthInfo.new(token, type, name)
90
97
 
91
98
  @cache = MijDiscord::Cache::BotCache.new(self)
92
99
 
@@ -296,26 +303,26 @@ module MijDiscord
296
303
  @ignore_self && user.to_id == @client_id || @ignored_ids.include?(user.to_id)
297
304
  end
298
305
 
299
- def change_status(status: nil, game: nil, url: nil)
306
+ def update_presence(status: nil, game: nil)
300
307
  gateway_check
301
308
 
302
- status = status.nil? ? @profile.status : USER_STATUS.find(status)
303
- raise ArgumentError, "Status '#{status}' is not valid" unless status
304
-
305
- game_obj = case game
306
- when false
307
- nil
308
- when nil
309
- {'name' => @profile.game, 'url' => @profile.stream_url, 'type' => @profile.stream_type}
310
- else
311
- {'name' => game, 'url' => url, 'type' => url ? 1 : 0}
309
+ status = case status
310
+ when nil then @profile.status
311
+ when :online, :idle, :dnd, :online then status
312
+ else raise ArgumentError, 'Invalid status'
312
313
  end
313
314
 
314
- game_obj&.reject! {|_,v| v.nil? }
315
- game_obj = nil if game_obj&.empty?
316
-
317
- @gateway.send_status_update(status, nil, game_obj, false)
318
- @profile.update_presence('status' => status, 'game' => game_obj)
315
+ game = case game
316
+ when nil then @profile.game
317
+ when false then nil
318
+ when String, Hash
319
+ MijDiscord::Data::Game.construct(game)
320
+ when MijDiscord::Data::Game then game
321
+ else raise ArgumentError, 'Invalid game'
322
+ end&.to_hash
323
+
324
+ @gateway.send_status_update(status, nil, game, false)
325
+ @profile.update_presence('status' => status, 'game' => game)
319
326
  nil
320
327
  end
321
328
 
@@ -372,6 +379,7 @@ module MijDiscord
372
379
  when :GUILD_MEMBERS_CHUNK
373
380
  server = @cache.get_server(data['guild_id'])
374
381
  server.update_members_chunk(data['members'])
382
+ puts "Chunk(#{server.id}+#{data['members'].length})"
375
383
 
376
384
  when :GUILD_CREATE
377
385
  server = @cache.put_server(data)
@@ -386,6 +394,10 @@ module MijDiscord
386
394
 
387
395
  trigger_event(:create_server, self, server)
388
396
 
397
+ when :GUILD_SYNC
398
+ server = @cache.get_server(data['id'])
399
+ server.update_synced_data(data)
400
+
389
401
  when :GUILD_UPDATE
390
402
  server = @cache.put_server(data, update: true)
391
403
  trigger_event(:update_server, self, server)
@@ -424,17 +436,17 @@ module MijDiscord
424
436
 
425
437
  when :GUILD_MEMBER_ADD
426
438
  server = @cache.get_server(data['guild_id'])
427
- member = server.cache.put_member(data)
439
+ member = server.update_member(data, :add)
428
440
  trigger_event(:create_member, self, member, server)
429
441
 
430
442
  when :GUILD_MEMBER_UPDATE
431
443
  server = @cache.get_server(data['guild_id'])
432
- member = server.cache.put_member(data, update: true)
444
+ member = server.update_member(data, :update)
433
445
  trigger_event(:update_member, self, member, server)
434
446
 
435
447
  when :GUILD_MEMBER_REMOVE
436
448
  server = @cache.get_server(data['guild_id'])
437
- member = server.cache.remove_member(data['user']['id'])
449
+ member = server.update_member(data, :remove)
438
450
  trigger_event(:delete_member, self, member, server)
439
451
 
440
452
  when :GUILD_ROLE_CREATE
@@ -573,6 +585,11 @@ module MijDiscord
573
585
  @gateway.notify_ready
574
586
 
575
587
  trigger_event(:ready, self)
588
+
589
+ if @auth.user?
590
+ guilds = @cache.list_servers.map(&:id)
591
+ @gateway.send_request_guild_sync(guilds)
592
+ end
576
593
  end
577
594
 
578
595
  def trigger_event(name, *args)
@@ -81,7 +81,10 @@ module MijDiscord::Cache
81
81
  return nil if local
82
82
 
83
83
  begin
84
- response = MijDiscord::Core::API::User.resolve(@bot.auth, id)
84
+ response = case @bot.auth.type
85
+ when :bot then MijDiscord::Core::API::User.resolve(@bot.auth, id)
86
+ when :user then MijDiscord::Core::API::User.resolve2(@bot.auth, id)
87
+ end
85
88
  rescue RestClient::ResourceNotFound
86
89
  return nil
87
90
  end
@@ -6,12 +6,10 @@ module MijDiscord::Core::API
6
6
  CDN_URL = 'https://cdn.discordapp.com'
7
7
 
8
8
  class << self
9
- attr_accessor :bot_name
10
-
11
9
  def user_agent(auth)
12
10
  case auth&.type
13
11
  when :bot
14
- bot_name = @bot_name || 'generic'
12
+ bot_name = auth.name || 'generic'
15
13
  ua_base = "DiscordBot (https://github.com/Mijyuoon/mij-discord, v#{MijDiscord::VERSION})"
16
14
  "#{ua_base} mij-discord/#{MijDiscord::VERSION} #{bot_name}"
17
15
 
@@ -14,7 +14,19 @@ module MijDiscord::Core::API::User
14
14
  )
15
15
  end
16
16
 
17
- # Get profile data
17
+ # Get profile data (for userbots only)
18
+ # Not officially documented, reverse engineered from tracking Discord's network activity
19
+ def resolve2(auth, user_id)
20
+ MijDiscord::Core::API.request(
21
+ :users_uid,
22
+ nil,
23
+ :get,
24
+ "#{MijDiscord::Core::API::APIBASE_URL}/users/#{user_id}/profile",
25
+ Authorization: auth
26
+ )
27
+ end
28
+
29
+ # Get current user data
18
30
  # https://discordapp.com/developers/docs/resources/user#get-current-user
19
31
  def profile(auth)
20
32
  MijDiscord::Core::API.request(
@@ -60,6 +60,10 @@ module MijDiscord::Core
60
60
  # **Received**: Returned after a heartbeat was sent to the server. This allows clients to identify and deal with
61
61
  # zombie connections that don't dispatch any events anymore.
62
62
  HEARTBEAT_ACK = 11
63
+
64
+ # **Sent**: [Undocumented] This opcode makes the gateway to send current state of a server. This includes a list
65
+ # of members and their presences, which mirror the format of GUILD_CREATE event.
66
+ GUILD_SYNC = 12
63
67
  end
64
68
 
65
69
  # @!visibility private
@@ -238,7 +242,7 @@ module MijDiscord::Core
238
242
  send_packet(Opcodes::RESUME, data)
239
243
  end
240
244
 
241
- def send_request_members(server_id, query, limit)
245
+ def send_request_members(server_id, query = '', limit = 0)
242
246
  data = {
243
247
  guild_id: server_id,
244
248
  query: query,
@@ -248,6 +252,10 @@ module MijDiscord::Core
248
252
  send_packet(Opcodes::REQUEST_MEMBERS, data)
249
253
  end
250
254
 
255
+ def send_request_guild_sync(guilds)
256
+ send_packet(Opcodes::GUILD_SYNC, guilds)
257
+ end
258
+
251
259
  def send_packet(opcode, packet)
252
260
  data = {
253
261
  op: opcode,
@@ -66,7 +66,7 @@ module MijDiscord::Data
66
66
 
67
67
  @id = data['id'].to_i
68
68
  @large = data['large']
69
- @members_init = data['member_count']
69
+ @member_count = data['member_count']
70
70
  @members_chunked = 0
71
71
 
72
72
  @cache = MijDiscord::Cache::ServerCache.new(self, @bot)
@@ -75,15 +75,7 @@ module MijDiscord::Data
75
75
 
76
76
  data['roles']&.each {|ro| @cache.put_role(ro) }
77
77
 
78
- data['members']&.each {|mb| @cache.put_member(mb) }
79
-
80
- data['presences']&.each do |pr|
81
- next unless pr['user']
82
-
83
- user_id = pr['user']['id'].to_i
84
- user = @cache.get_member(user_id, local: true)
85
- user.update_presence(pr) if user
86
- end
78
+ update_synced_data(data)
87
79
 
88
80
  @voice_states = {}
89
81
  data['voice_states']&.each {|vs| update_voice_state(vs) }
@@ -146,7 +138,33 @@ module MijDiscord::Data
146
138
  @members_chunked += data.length
147
139
  data.each {|mb| @cache.put_member(mb) }
148
140
 
149
- @members_chunked = nil if @members_chunked == @members_init
141
+ @members_chunked = nil if @members_chunked == @member_count
142
+ end
143
+
144
+ def update_synced_data(data)
145
+ data['members']&.each {|mb| @cache.put_member(mb, update: true) }
146
+
147
+ data['presences']&.each do |pr|
148
+ next unless pr['user']
149
+
150
+ user_id = pr['user']['id'].to_i
151
+ user = @cache.get_member(user_id, local: true)
152
+ user.update_presence(pr) if user
153
+ end
154
+ end
155
+
156
+ def update_member(data, mode)
157
+ case mode
158
+ when :add
159
+ @member_count += 1
160
+ @cache.put_member(data)
161
+ when :remove
162
+ @member_count -= 1
163
+ key = data['user']['id']
164
+ @cache.remove_member(key)
165
+ when :update
166
+ @cache.put_member(data, update: true)
167
+ end
150
168
  end
151
169
 
152
170
  def channels
@@ -1,6 +1,112 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MijDiscord::Data
4
+ class Game
5
+ PLAYING_TYPE = [
6
+ :playing,
7
+ :streaming,
8
+ :listening,
9
+ :watching,
10
+ ].freeze
11
+
12
+ attr_reader :name
13
+
14
+ attr_reader :url
15
+
16
+ attr_reader :details
17
+
18
+ attr_reader :state
19
+
20
+ attr_reader :start_time
21
+
22
+ attr_reader :end_time
23
+
24
+ attr_reader :application
25
+
26
+ attr_reader :large_image
27
+
28
+ attr_reader :large_text
29
+
30
+ attr_reader :small_image
31
+
32
+ attr_reader :small_text
33
+
34
+ def type
35
+ PLAYING_TYPE[@type]
36
+ end
37
+
38
+ def initialize(data)
39
+ @type = data['type']
40
+ @name = data['name']
41
+ @url = data['url']
42
+ @details = data['details']
43
+ @state = data['state']
44
+
45
+ if (start_time = data.dig('timestamps', 'start'))
46
+ @start_time = Time.at(start_time).utc
47
+ end
48
+ if (end_time = data.dig('timestamps', 'end'))
49
+ @end_time = Time.at(end_time).utc
50
+ end
51
+
52
+ if (assets = data['assets'])
53
+ @large_image = assets['large_image']
54
+ @large_text = assets['large_text']
55
+ @small_image = assets['small_image']
56
+ @small_text = assets['small_text']
57
+ end
58
+ end
59
+
60
+ def to_hash
61
+ self.class.construct({
62
+ start_time: @start_time,
63
+ end_time: @end_time,
64
+
65
+ large_image: @large_image,
66
+ large_text: @large_text,
67
+ small_image: @small_image,
68
+ small_text: @small_text,
69
+
70
+ type: @type,
71
+ name: @name,
72
+ url: @url,
73
+ details: @details,
74
+ state: @state,
75
+ })
76
+ end
77
+
78
+ def self.construct(data)
79
+ data = {name: data} if data.is_a?(String)
80
+
81
+ times = {
82
+ start: data[:start_time]&.to_i,
83
+ end: data[:end_time]&.to_i,
84
+ }.delete_if {|_,v| v.nil? }
85
+
86
+ assets = {
87
+ large_image: data[:large_image],
88
+ large_text: data[:large_text],
89
+ small_image: data[:small_image],
90
+ small_text: data[:small_text],
91
+ }.delete_if {|_,v| v.nil? }
92
+
93
+ type = PLAYING_TYPE.index(data[:type])
94
+
95
+ game = {
96
+ type: type || 0,
97
+ name: data[:name],
98
+ url: data[:url],
99
+ details: data[:details],
100
+ state: data[:state],
101
+
102
+ timestamps: times.empty? ? nil : times,
103
+ assets: assets.empty? ? nil : assets,
104
+ }.delete_if {|_,v| v.nil? }
105
+
106
+ game
107
+ end
108
+ end
109
+
4
110
  class User
5
111
  include IDObject
6
112
 
@@ -21,18 +127,19 @@ module MijDiscord::Data
21
127
 
22
128
  attr_reader :game
23
129
 
24
- attr_reader :stream_url
25
-
26
- attr_reader :stream_type
130
+ attr_reader :extra
27
131
 
28
132
  def initialize(data, bot)
29
133
  @bot = bot
30
134
 
135
+ # Kludge for User::resolve2 API call
136
+ data = data['user'] if data['user'].is_a?(Hash)
137
+
31
138
  @id = data['id'].to_i
32
139
  @bot_account = !!data['bot']
33
140
  update_data(data)
34
141
 
35
- @status = :offline
142
+ @status, @game = :offline, nil
36
143
 
37
144
  @roles = {}
38
145
  end
@@ -47,11 +154,9 @@ module MijDiscord::Data
47
154
  @status = presence['status'].to_sym
48
155
 
49
156
  if (game = presence['game'])
50
- @game = game['name']
51
- @stream_url = game['url']
52
- @stream_type = game['type']
157
+ @game = Game.new(game)
53
158
  else
54
- @game = @stream_url = @stream_type = nil
159
+ @game = nil
55
160
  end
56
161
  end
57
162
 
@@ -126,6 +231,8 @@ module MijDiscord::Data
126
231
  return MijDiscord::Core::API::User.default_avatar(@discriminator) unless @avatar_id
127
232
  MijDiscord::Core::API::User.avatar_url(@id, @avatar_id, format)
128
233
  end
234
+
235
+ alias_method :avatar, :avatar_url
129
236
  end
130
237
 
131
238
  class Profile < User
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MijDiscord
4
- VERSION = '1.0.6'
4
+ VERSION = '1.0.7'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mij-discord
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.6
4
+ version: 1.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mijyuoon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-11-22 00:00:00.000000000 Z
11
+ date: 2017-12-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client