pokeplot 0.2.0beta
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +4 -0
- data/LICENSE.txt +621 -0
- data/README.md +99 -0
- data/Rakefile +9 -0
- data/bin/pokeplot +223 -0
- data/lib/pokeplot/api.rb +109 -0
- data/lib/pokeplot/database.rb +22 -0
- data/lib/pokeplot/helpers/array.rb +5 -0
- data/lib/pokeplot/helpers/cell_ids.rb +14 -0
- data/lib/pokeplot/helpers/math.rb +20 -0
- data/lib/pokeplot/helpers/time.rb +15 -0
- data/lib/pokeplot/miner.rb +241 -0
- data/lib/pokeplot/pushbullet.rb +41 -0
- data/lib/pokeplot/socket.rb +65 -0
- data/lib/pokeplot/version.rb +3 -0
- data/lib/pokeplot/web/canvasjs.min.js +555 -0
- data/lib/pokeplot/web/index.html +158 -0
- data/lib/pokeplot/web.rb +26 -0
- data/lib/pokeplot.rb +7 -0
- data/spec/api_spec.rb +148 -0
- data/spec/database_spec.rb +33 -0
- data/spec/miner_spec.rb +110 -0
- data/spec/pushbullet_spec.rb +31 -0
- data/spec/socket_spec.rb +45 -0
- data/spec/spec_helper.rb +115 -0
- data/spec/web_spec.rb +18 -0
- metadata +240 -0
@@ -0,0 +1,241 @@
|
|
1
|
+
require 'pokeplot/helpers/math'
|
2
|
+
require 'pokeplot/helpers/array'
|
3
|
+
require 'pokeplot/api'
|
4
|
+
module Pokeplot
|
5
|
+
class Miner
|
6
|
+
|
7
|
+
include Database
|
8
|
+
|
9
|
+
attr_accessor :miner, :db
|
10
|
+
|
11
|
+
def initialize(accounts, lat, lng, range = 20, interval = 600, pokemon = true, forts = true, threaded = false, encryption = '', log = true, apilog = true)
|
12
|
+
@apis = []
|
13
|
+
@accounts = accounts
|
14
|
+
@lat = lat
|
15
|
+
@lng = lng
|
16
|
+
@db = Database.mongo
|
17
|
+
@range = range
|
18
|
+
@interval = interval
|
19
|
+
@pokemon = pokemon
|
20
|
+
@forts = forts
|
21
|
+
@threaded = threaded
|
22
|
+
@encryption = encryption
|
23
|
+
@logging = log
|
24
|
+
@apilog = apilog
|
25
|
+
@miner = nil
|
26
|
+
@coords = []
|
27
|
+
|
28
|
+
get_all_coords
|
29
|
+
end
|
30
|
+
|
31
|
+
def start
|
32
|
+
if !@miner.is_a?(Thread)
|
33
|
+
@miner = Thread.new {
|
34
|
+
puts "[+] Starting miner on new thread" if @logging
|
35
|
+
|
36
|
+
puts "[+] #{@coords.count} coords to scan using #{@accounts.count} accounts" if @logging
|
37
|
+
puts "[+] Logging in all accounts" if @logging
|
38
|
+
|
39
|
+
if @threaded
|
40
|
+
@threads = []
|
41
|
+
@accounts.each_with_index do |account, index|
|
42
|
+
@threads << Thread.new do
|
43
|
+
api = API.new(@lat, @lng, @encryption, @apilog)
|
44
|
+
api.login(account['username'], account['password'], account['provider'])
|
45
|
+
sleep(1)
|
46
|
+
|
47
|
+
loop do
|
48
|
+
current_time = Time.now.to_i
|
49
|
+
|
50
|
+
groups = @coords.in_groups(@accounts.count)
|
51
|
+
|
52
|
+
groups[index].each do |coord|
|
53
|
+
api.set_location(coord[:lat], coord[:lng])
|
54
|
+
response = api.map_heartbeat
|
55
|
+
parse_map_objects(response)
|
56
|
+
sleep(10)
|
57
|
+
end
|
58
|
+
scan_time = Time.now.to_i - current_time
|
59
|
+
puts "[+] Scan finnished for account #{account['username']} in #{scan_time} seconds" if @logging
|
60
|
+
sleep_time = @interval - scan_time
|
61
|
+
sleep_time = [sleep_time, 0].max
|
62
|
+
puts "[+] Thread sleeping for #{sleep_time} seconds..." if @logging
|
63
|
+
sleep(sleep_time)
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
else #NOT THEADED
|
70
|
+
|
71
|
+
@accounts.each do |account|
|
72
|
+
api = API.new(@lat, @lng, @encryption, @apilog)
|
73
|
+
api.login(account['username'], account['password'], account['provider'])
|
74
|
+
@apis.push(api)
|
75
|
+
sleep(2)
|
76
|
+
end
|
77
|
+
|
78
|
+
loop do
|
79
|
+
current_time = Time.now.to_i
|
80
|
+
|
81
|
+
groups = @coords.in_groups(@apis.count)
|
82
|
+
diff = groups.first.count - groups.last.count
|
83
|
+
groups.last.push(*([0] * diff)) if diff > 0
|
84
|
+
|
85
|
+
groups = groups.transpose
|
86
|
+
groups.each_with_index do |group, n|
|
87
|
+
puts "[+] Starting group #{n + 1} of #{groups.count}" if @logging
|
88
|
+
group_time = Time.now.to_i
|
89
|
+
group.each_with_index do |coord, index|
|
90
|
+
if coord.is_a?(Hash)
|
91
|
+
api = @apis[index]
|
92
|
+
api.set_location(coord[:lat], coord[:lng])
|
93
|
+
response = api.map_heartbeat
|
94
|
+
parse_map_objects(response)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
group_time = Time.now.to_i - group_time
|
98
|
+
puts "[+] Group finnished in #{group_time} seconds" if @logging
|
99
|
+
end
|
100
|
+
|
101
|
+
scan_time = Time.now.to_i - current_time
|
102
|
+
puts "[+] Scan Time: #{scan_time} s'" if @logging
|
103
|
+
sleep_time = @interval - scan_time
|
104
|
+
sleep_time = [sleep_time, 0].max
|
105
|
+
puts "[+] Sleeping for #{sleep_time} seconds..." if @logging
|
106
|
+
sleep(sleep_time)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
}
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def stop
|
114
|
+
Thread.kill(@miner) if @miner.is_a?(Thread)
|
115
|
+
if @threads.is_a?(Array)
|
116
|
+
@threads.each {|t| Thread.kill(t) if t.is_a?(Thread) }
|
117
|
+
end
|
118
|
+
@miner = nil
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
def get_all_coords
|
124
|
+
origin = {:lat => @lat, :lng => @lng}
|
125
|
+
@coords = [origin]
|
126
|
+
|
127
|
+
float_lat = @lat
|
128
|
+
float_lng = @lng
|
129
|
+
|
130
|
+
latrad = Helpers::Math.deg_to_rad(float_lat)
|
131
|
+
|
132
|
+
hex_r = 70.0 #range of detection for pokemon = 100m || changed to 70
|
133
|
+
hex_m = 3.0**(0.5)/2.0*hex_r
|
134
|
+
|
135
|
+
(1...(@range+1)).to_a.each do |a|
|
136
|
+
(0...(a*6)).to_a.each do |i|
|
137
|
+
x_un=1.5*hex_r/Helpers::Math.get_earth_radius(float_lat)/Math.cos(latrad)*180/Math::PI
|
138
|
+
y_un=1.0*hex_m/Helpers::Math.get_earth_radius(float_lat)*180/Math::PI
|
139
|
+
if i < a
|
140
|
+
lat = float_lat+y_un*(-2*a+i)
|
141
|
+
lng = float_lng+x_un*i
|
142
|
+
elsif i < 2*a
|
143
|
+
lat = float_lat+y_un*(-3*a+2*i)
|
144
|
+
lng = float_lng+x_un*a
|
145
|
+
elsif i < 3*a
|
146
|
+
lat = float_lat+y_un*(-a+i)
|
147
|
+
lng = float_lng+x_un*(3*a-i)
|
148
|
+
elsif i < 4*a
|
149
|
+
lat = float_lat+y_un*(5*a-i)
|
150
|
+
lng = float_lng+x_un*(3*a-i)
|
151
|
+
elsif i < 5*a
|
152
|
+
lat = float_lat+y_un*(9*a-2*i)
|
153
|
+
lng = float_lng+x_un*-a
|
154
|
+
else
|
155
|
+
lat = float_lat+y_un*(4*a-i)
|
156
|
+
lng = float_lng+x_un*(-6*a+i)
|
157
|
+
end
|
158
|
+
@coords << {:lat => lat, :lng => lng}
|
159
|
+
end
|
160
|
+
end
|
161
|
+
@coords
|
162
|
+
end
|
163
|
+
|
164
|
+
def parse_map_objects(response)
|
165
|
+
if response[:GET_MAP_OBJECTS][:status] == :SUCCESS
|
166
|
+
response[:GET_MAP_OBJECTS][:map_cells].each do |cell|
|
167
|
+
|
168
|
+
cell[:wild_pokemons].each do |pokemon|
|
169
|
+
if pokemon[:time_till_hidden_ms] < 0
|
170
|
+
puts "[+] Saving possible long spawn: #{pokemon[:spawn_point_id]}" if @logging
|
171
|
+
longspawn(cell, pokemon)
|
172
|
+
else
|
173
|
+
if new_encounter?(pokemon[:encounter_id].to_s, pokemon[:spawn_point_id], pokemon[:latitude].to_s, pokemon[:longitude].to_s) && @pokemon
|
174
|
+
@db[:encounters].insert_one({
|
175
|
+
cell_id: cell[:s2_cell_id].to_s,
|
176
|
+
current_timestamp_ms: cell[:current_timestamp_ms].to_s,
|
177
|
+
encounter_id: pokemon[:encounter_id].to_s,
|
178
|
+
latitude: pokemon[:latitude].to_s,
|
179
|
+
longitude: pokemon[:longitude].to_s,
|
180
|
+
spawn_point_id: pokemon[:spawn_point_id],
|
181
|
+
pokemon: pokemon[:pokemon_data][:pokemon_id].to_s,
|
182
|
+
time_till_hidden_ms: pokemon[:time_till_hidden_ms].to_s
|
183
|
+
})
|
184
|
+
puts "[+] Found a \e[36m#{pokemon[:pokemon_data][:pokemon_id]}\e[0m" if @logging
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
cell[:forts].each do |fort|
|
190
|
+
if new_fort?(fort[:id].to_s) && @forts
|
191
|
+
@db[:forts].insert_one({
|
192
|
+
cell_id: cell[:s2_cell_id].to_s,
|
193
|
+
current_timestamp_ms: cell[:current_timestamp_ms].to_s,
|
194
|
+
fort_id: fort[:id],
|
195
|
+
enabled: fort[:enabled].to_s,
|
196
|
+
latitude: fort[:latitude].to_s,
|
197
|
+
longitude: fort[:longitude].to_s,
|
198
|
+
type: fort[:type].to_s
|
199
|
+
})
|
200
|
+
puts "[+] Found a fort: #{fort[:type]}" if @logging
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
end
|
205
|
+
else
|
206
|
+
puts "[-] UNSUCCESSFUL RESPONSE STATUS #{response[:GET_MAP_OBJECTS][:status]}" if @logging
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def new_encounter?(encounter_id, spawn_point_id, lat, lng)
|
211
|
+
if @db[:encounters].find({encounter_id: encounter_id, spawn_point_id: spawn_point_id, latitude: lat, longitude: lng}).count == 0
|
212
|
+
true
|
213
|
+
else
|
214
|
+
false
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def new_fort?(fort_id)
|
219
|
+
if @db[:forts].find({fort_id: fort_id}).count == 0
|
220
|
+
true
|
221
|
+
else
|
222
|
+
false
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def longspawn(cell, pokemon)
|
227
|
+
@db[:longspawn].insert_one({
|
228
|
+
cell_id: cell[:s2_cell_id].to_s,
|
229
|
+
current_timestamp_ms: cell[:current_timestamp_ms].to_s,
|
230
|
+
encounter_id: pokemon[:encounter_id].to_s,
|
231
|
+
latitude: pokemon[:latitude].to_s,
|
232
|
+
longitude: pokemon[:longitude].to_s,
|
233
|
+
spawn_point_id: pokemon[:spawn_point_id],
|
234
|
+
pokemon: pokemon[:pokemon_data][:pokemon_id].to_s,
|
235
|
+
time_till_hidden_ms: pokemon[:time_till_hidden_ms].to_s
|
236
|
+
})
|
237
|
+
puts "[+] Found a \e[36m#{pokemon[:pokemon_data][:pokemon_id]}\e[0m (Long spawn)" if @logging
|
238
|
+
end
|
239
|
+
|
240
|
+
end
|
241
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'washbullet'
|
2
|
+
require 'pokeplot/helpers/time'
|
3
|
+
|
4
|
+
module Pokeplot
|
5
|
+
class Pushbullet
|
6
|
+
|
7
|
+
def initialize(api_key, pokemon = [])
|
8
|
+
@pokemon = pokemon
|
9
|
+
@client = Washbullet::Client.new(api_key)
|
10
|
+
end
|
11
|
+
|
12
|
+
def started(event)
|
13
|
+
if event.command.has_key?('insert')
|
14
|
+
if event.command.fetch('insert') == 'encounters'
|
15
|
+
if @pokemon.include?(event.command.fetch('documents')[0][:pokemon])
|
16
|
+
text = "Found a #{event.command.fetch('documents')[0][:pokemon]}! "
|
17
|
+
time = Helpers::Time.to_s(Time.now.to_i - ((event.command.fetch('documents')[0][:current_timestamp_ms].to_i / 1000) -(event.command.fetch('documents')[0][:time_till_hidden_ms].to_i / 1000)))
|
18
|
+
text += "It expires in #{time}. "
|
19
|
+
text += "Google maps: http://www.google.com/maps/place/#{event.command.fetch('documents')[0][:latitude]},#{event.command.fetch('documents')[0][:longitude]}"
|
20
|
+
|
21
|
+
|
22
|
+
@client.devices.each do |device|
|
23
|
+
@client.push_note(
|
24
|
+
receiver: :device,
|
25
|
+
identifier: device.body['iden'],
|
26
|
+
params: {
|
27
|
+
title: 'Pokeplot',
|
28
|
+
body: text
|
29
|
+
}
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def failed(_); end
|
38
|
+
def succeeded(_); end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'em-websocket'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Pokeplot
|
5
|
+
class Socket
|
6
|
+
include Database
|
7
|
+
|
8
|
+
def initialize(host = "0.0.0.0", port = 9090, log = false)
|
9
|
+
@clients = []
|
10
|
+
Thread.new do
|
11
|
+
EM.run do
|
12
|
+
|
13
|
+
db = Database.mongo
|
14
|
+
EM::WebSocket.run(:host => host, :port => port) do |ws|
|
15
|
+
ws.onopen do |handshake|
|
16
|
+
puts "[+] WebSocket connection open" if @log
|
17
|
+
pokemon = {:type => "count", :data => {}}
|
18
|
+
spawns = {:type => "spawn_points", :data => {}}
|
19
|
+
|
20
|
+
db[:encounters].find().each do |bson|
|
21
|
+
#get initial pokemon
|
22
|
+
if pokemon[:data].has_key?(bson[:pokemon])
|
23
|
+
pokemon[:data][bson[:pokemon]] += 1
|
24
|
+
else
|
25
|
+
pokemon[:data][bson[:pokemon]] = 1
|
26
|
+
end
|
27
|
+
|
28
|
+
#get spawn points
|
29
|
+
if spawns[:data].has_key?(bson[:spawn_point_id])
|
30
|
+
spawns[:data][bson[:spawn_point_id]] += 1
|
31
|
+
else
|
32
|
+
spawns[:data][bson[:spawn_point_id]] = 1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
ws.send(pokemon.to_json)
|
37
|
+
ws.send(spawns.to_json)
|
38
|
+
@clients << ws
|
39
|
+
end
|
40
|
+
|
41
|
+
ws.onclose { @clients.delete(ws) }
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
#Mongo
|
50
|
+
def started(event)
|
51
|
+
if event.command.has_key?('insert')
|
52
|
+
if event.command.fetch('insert') == 'encounters'
|
53
|
+
@clients.each do |c|
|
54
|
+
c.send({:type => "pokemon", :data => event.command.fetch('documents')[0]}.to_json)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def failed(_); end
|
61
|
+
def succeeded(_); end
|
62
|
+
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|