cockatrice_feeder 0.0.2 → 0.0.7
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 +4 -4
- data/bin/gobble +0 -1
- data/lib/cockatrice_feeder.rb +219 -42
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8e43bbd10275d5150dd9d3e45c8d5b01df882c65
|
4
|
+
data.tar.gz: 18d5eae374e7e1ebe294f46fcdb7fcf3fa0c697f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d7f63f8025a330e9a62b6179cece671f0d7a91b0539fe9fa971ee3ef4e2bfee4dc4b3be0667800ce999662667825abc958d7fc5bc3165f6adf68f337f29b006
|
7
|
+
data.tar.gz: d7463259b547c30638eae233ea0174a31d7d79a64b9054ee05a50298248501399a11518f7330fa247d7df07e8c4be9f4812f986cf383af1ec355a73b6224702d
|
data/bin/gobble
CHANGED
data/lib/cockatrice_feeder.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module CockatriceFeeder
|
2
2
|
require 'httparty'
|
3
|
-
require 'awesome_print'
|
4
3
|
require 'nokogiri'
|
4
|
+
require 'fileutils'
|
5
5
|
|
6
6
|
@@app_dir = Dir.pwd+"/"
|
7
7
|
@@deck_dir = @@app_dir+"decks/"
|
@@ -11,6 +11,9 @@ module CockatriceFeeder
|
|
11
11
|
@@app_dir = (dir + (dir[-1] != "/" ? "/" : ""))
|
12
12
|
@@deck_dir = @@app_dir+"decks/"
|
13
13
|
@@meta_dir = @@app_dir+"meta/"
|
14
|
+
|
15
|
+
puts "decks will go here: #{@@deck_dir}"
|
16
|
+
puts "meta data will go here: #{@@meta_dir}"
|
14
17
|
end
|
15
18
|
|
16
19
|
def self.app_dir
|
@@ -19,6 +22,7 @@ module CockatriceFeeder
|
|
19
22
|
|
20
23
|
def self.set_deck_dir(dir)
|
21
24
|
@@deck_dir = (dir + (dir[-1] != "/" ? "/" : ""))
|
25
|
+
puts "decks will go here: #{@@deck_dir}"
|
22
26
|
end
|
23
27
|
|
24
28
|
def self.deck_dir
|
@@ -27,27 +31,30 @@ module CockatriceFeeder
|
|
27
31
|
|
28
32
|
def self.set_meta_dir(dir)
|
29
33
|
@@meta_dir = (dir + (dir[-1] != "/" ? "/" : ""))
|
34
|
+
puts "meta data will go here: #{@@meta_dir}"
|
30
35
|
end
|
31
36
|
|
32
37
|
def self.meta_dir
|
33
38
|
@@meta_dir
|
34
39
|
end
|
35
40
|
|
36
|
-
def self.setup
|
41
|
+
def self.setup(skip_meta = false)
|
37
42
|
unless File.directory?(@@meta_dir)
|
38
43
|
Dir.mkdir(@@meta_dir)
|
39
44
|
puts "Creating a folder at '#{@@meta_dir}' for storing meta data."
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
45
|
+
unless skip_meta
|
46
|
+
puts "Fetching meta data."
|
47
|
+
update_commanders()
|
48
|
+
update_banned()
|
49
|
+
update_commander_tiers()
|
50
|
+
end
|
44
51
|
end
|
45
52
|
|
46
53
|
unless File.directory?(@@deck_dir)
|
47
54
|
Dir.mkdir(@@deck_dir)
|
48
55
|
puts "Creating a folder at '#{@@deck_dir}' for generated decks."
|
49
56
|
|
50
|
-
folders = %w(edhrecavg mtgdecks tappedout deckstats)
|
57
|
+
folders = %w(edhrecavg mtgdecks tappedout deckstats archidekt)
|
51
58
|
|
52
59
|
folders.each do |folder|
|
53
60
|
unless File.directory?(@@deck_dir+folder)
|
@@ -61,7 +68,7 @@ module CockatriceFeeder
|
|
61
68
|
end
|
62
69
|
|
63
70
|
def self.update_commanders
|
64
|
-
puts "Downloading a list of all
|
71
|
+
puts "Downloading a list of all commanders from EDHREC."
|
65
72
|
commander_cids = %w(
|
66
73
|
w g r u b
|
67
74
|
wu ub br rg gw wb ur bg rw gu
|
@@ -139,18 +146,38 @@ module CockatriceFeeder
|
|
139
146
|
end
|
140
147
|
|
141
148
|
def self.commanders
|
149
|
+
unless File.exist?(@@meta_dir+"commanders.json")
|
150
|
+
update_commanders()
|
151
|
+
end
|
142
152
|
JSON.parse(File.read(@@meta_dir+"commanders.json"))
|
143
153
|
end
|
144
154
|
|
145
155
|
def self.banned
|
156
|
+
unless File.exist?(@@meta_dir+"banned.json")
|
157
|
+
update_banned()
|
158
|
+
end
|
146
159
|
JSON.parse(File.read(@@meta_dir+"banned.json"))
|
147
160
|
end
|
148
161
|
# names = banned.map{|c| c["name"]}.uniq.sort
|
149
162
|
|
150
|
-
def self.
|
163
|
+
def self.commander_tiers
|
164
|
+
unless File.exist?(@@meta_dir+"tiers.json")
|
165
|
+
update_commander_tiers()
|
166
|
+
end
|
151
167
|
JSON.parse(File.read(@@meta_dir+"tiers.json"))
|
152
168
|
end
|
153
169
|
|
170
|
+
def self.deck_obj(link = "", name = "", commanders = [], date = nil, price = nil)
|
171
|
+
{
|
172
|
+
link: link,
|
173
|
+
name: name,
|
174
|
+
commanders: commanders,
|
175
|
+
date: date,
|
176
|
+
price: price,
|
177
|
+
cardlist: []
|
178
|
+
}
|
179
|
+
end
|
180
|
+
|
154
181
|
def self.output_cod(deck, subfolder)
|
155
182
|
comments = [
|
156
183
|
deck[:name],
|
@@ -165,7 +192,7 @@ module CockatriceFeeder
|
|
165
192
|
deck[:name],
|
166
193
|
deck[:price],
|
167
194
|
subfolder
|
168
|
-
].compact.reject(&:empty?).uniq.join('_')
|
195
|
+
].compact.reject(&:empty?).uniq.join('_').gsub("/","")
|
169
196
|
|
170
197
|
builder = Nokogiri::XML::Builder.new do |xml|
|
171
198
|
xml.cockatrice_deck(:version => "1"){
|
@@ -210,14 +237,7 @@ module CockatriceFeeder
|
|
210
237
|
doc.css(".deck-wide-header a").each do |a|
|
211
238
|
link = a.attribute("href").value
|
212
239
|
if link.include?("/mtg-decks/")
|
213
|
-
decks <<
|
214
|
-
name: link.split("/").last,
|
215
|
-
commanders: [],
|
216
|
-
link: "https://tappedout.net"+link,
|
217
|
-
date: nil,
|
218
|
-
price: nil,
|
219
|
-
cardlist: []
|
220
|
-
}
|
240
|
+
decks << deck_obj("https://tappedout.net"+link, link.split("/").last)
|
221
241
|
end
|
222
242
|
end
|
223
243
|
end
|
@@ -262,14 +282,7 @@ module CockatriceFeeder
|
|
262
282
|
|
263
283
|
def self.edhrecavg_decklist
|
264
284
|
commanders.map{|c| c["link"]}.map do |c|
|
265
|
-
{
|
266
|
-
name: c,
|
267
|
-
commanders: [c],
|
268
|
-
link: "https://edhrec-json.s3.amazonaws.com/en/decks/#{c}.json",
|
269
|
-
price: nil,
|
270
|
-
date: nil,
|
271
|
-
cardlist: []
|
272
|
-
}
|
285
|
+
deck_obj("https://edhrec-json.s3.amazonaws.com/en/decks/#{c}.json", c, [c])
|
273
286
|
end
|
274
287
|
end
|
275
288
|
|
@@ -280,12 +293,142 @@ module CockatriceFeeder
|
|
280
293
|
output_cod(deck,"edhrecavg")
|
281
294
|
end
|
282
295
|
|
283
|
-
def self.deckstats_decklist
|
284
296
|
|
297
|
+
#order ["views,desc", "price,desc", "likes,desc", "updated,desc"]
|
298
|
+
#commander should be a name attribute from the commanders array of objects
|
299
|
+
def self.deckstats_decklist(commander = "", pages = (1..1), order_by = "likes,desc", price_min = "", price_max = "")
|
300
|
+
decklist = []
|
301
|
+
pages.each do |page|
|
302
|
+
url = [
|
303
|
+
"https://deckstats.net/decks/search/?lng=en",
|
304
|
+
"&search_title=",
|
305
|
+
"&search_format=10",
|
306
|
+
"&search_season=0",
|
307
|
+
"&search_cards_commander%5B%5D=#{URI.encode_www_form_component(commander)}",
|
308
|
+
"&search_cards_commander%5B%5D=",
|
309
|
+
"&search_price_min=#{price_min}",
|
310
|
+
"&search_price_max=#{price_max}",
|
311
|
+
"&search_colors%5B%5D=",
|
312
|
+
"&search_number_cards_main=100",
|
313
|
+
"&search_number_cards_sideboard=",
|
314
|
+
"&search_cards%5B%5D=",
|
315
|
+
"&search_tags=",
|
316
|
+
"&search_order=#{URI.encode_www_form_component(order_by)}",
|
317
|
+
"&utf8=%E2%9C%94",
|
318
|
+
"&page=#{page}"
|
319
|
+
].join("")
|
320
|
+
|
321
|
+
doc = Nokogiri::HTML(HTTParty.get(url).body)
|
322
|
+
|
323
|
+
doc.css(".deck_row").each do |dr|
|
324
|
+
link = dr.css("td")[1].css("a").first.attribute("href").value
|
325
|
+
decklist << deck_obj(link,link.split("/")[-2],[commander].reject(&:empty?))
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
decklist
|
330
|
+
end
|
331
|
+
|
332
|
+
def self.deckstats_deck(deck)
|
333
|
+
docstring = HTTParty.get(deck[:link]).body
|
334
|
+
|
335
|
+
doc = Nokogiri::HTML(docstring)
|
336
|
+
|
337
|
+
legal = (doc.css(".fa-exclamation-triangle").count == 0)
|
338
|
+
|
339
|
+
if legal
|
340
|
+
deck_data = JSON.parse(docstring.split("init_deck_data(").last.split(");deck_display();").first)
|
341
|
+
deck[:date] = DateTime.strptime(deck_data["updated"].to_s,'%s')
|
342
|
+
unless deck_data["highlight_cards"].nil?
|
343
|
+
deck[:commanders] = deck_data["highlight_cards"]
|
344
|
+
end
|
345
|
+
deck[:cardlist] = deck_data["sections"].map do |sec|
|
346
|
+
sec["cards"].map{|c| "#{c["amount"]} #{c["name"]}"}
|
347
|
+
end.flatten
|
348
|
+
|
349
|
+
deck[:price] = (
|
350
|
+
!doc.css(".deck_overview_price").first.nil? ?
|
351
|
+
doc.css(".deck_overview_price").first.content.gsub("$","").strip.split(".").first
|
352
|
+
: nil
|
353
|
+
)
|
354
|
+
|
355
|
+
output_cod(deck,'deckstats')
|
356
|
+
end
|
285
357
|
end
|
286
358
|
|
287
|
-
|
359
|
+
#colors = "White,Blue,Black,Red,Green,Colorless"
|
360
|
+
#orderBy = "-updatedAt", "-createdAt", "-points", "-viewCount"
|
361
|
+
def self.archidekt_decklist(
|
362
|
+
andcolors = nil, colors = nil, commander = nil, owner = nil, formats = 3, orderBy = "-createdAt", size: 100, pageSize: 50
|
363
|
+
)
|
364
|
+
|
365
|
+
url = [
|
366
|
+
"https://www.archidekt.com/api/decks/cards/?",
|
367
|
+
[
|
368
|
+
(andcolors.nil? ? nil : "true"),
|
369
|
+
(colors.nil? ? nil : "colors=#{URI.encode_www_form_component(colors)}"),
|
370
|
+
(commander.nil? ? nil : "commanders=#{URI.encode_www_form_component(commander)}"),
|
371
|
+
(owner.nil? ? nil : "owner=#{URI.encode_www_form_component(owner)}"),
|
372
|
+
"formats=#{formats}",
|
373
|
+
"orderBy=#{orderBy}",
|
374
|
+
"size=#{size}",
|
375
|
+
"pageSize=#{pageSize}"
|
376
|
+
].compact.join("&")
|
377
|
+
].join("")
|
378
|
+
|
379
|
+
puts url
|
380
|
+
|
381
|
+
decklist = []
|
382
|
+
data = JSON.parse(HTTParty.get(url).body)
|
383
|
+
|
384
|
+
data["results"].each do |r|
|
385
|
+
decklist << deck_obj("https://www.archidekt.com/decks/#{r["id"]}", r["name"])
|
386
|
+
end
|
288
387
|
|
388
|
+
decklist
|
389
|
+
end
|
390
|
+
|
391
|
+
# deck = CockatriceFeeder.deck_obj("https://www.archidekt.com/decks/992684#Rocking_that_equipment_Bro")
|
392
|
+
# CockatriceFeeder.archidekt_deck(deck)
|
393
|
+
def self.archidekt_deck(deck)
|
394
|
+
deck_id = deck[:link].split("/").last.split("#").first
|
395
|
+
|
396
|
+
api_url = "https://www.archidekt.com/api/decks/#{deck_id}/"
|
397
|
+
|
398
|
+
deck_data = JSON.parse(HTTParty.get(api_url).body)
|
399
|
+
|
400
|
+
included_categories = deck_data["categories"].select{|c| c["includedInDeck"]}.map{|c| c["name"] }
|
401
|
+
commander_categories = deck_data["categories"].select{|c| c["isPremier"]}.map{|c| c["name"] }
|
402
|
+
cardlist = []
|
403
|
+
tcg_price = 0.0
|
404
|
+
ck_price = 0.0
|
405
|
+
deck_data["cards"].each do |card|
|
406
|
+
cname = card["card"]["oracleCard"]["name"]
|
407
|
+
|
408
|
+
if card["card"]["oracleCard"]["layout"] != "split"
|
409
|
+
cname = cname.split(" // ").first
|
410
|
+
end
|
411
|
+
|
412
|
+
if (included_categories & card["categories"]).length > 0
|
413
|
+
cardlist << "#{card["quantity"]} #{cname}"
|
414
|
+
|
415
|
+
tcg_price += (card["card"]["prices"]["tcg"] * card["quantity"].to_f)
|
416
|
+
ck_price += (card["card"]["prices"]["ck"] * card["quantity"].to_f)
|
417
|
+
end
|
418
|
+
|
419
|
+
if (commander_categories & card["categories"]).length > 0
|
420
|
+
deck[:commanders] << cname
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
deck[:cardlist] = cardlist
|
425
|
+
deck[:price] = tcg_price.to_i.to_s
|
426
|
+
|
427
|
+
deck[:name] = deck_data["name"]
|
428
|
+
|
429
|
+
deck[:date] = deck_data["updatedAt"]
|
430
|
+
|
431
|
+
output_cod(deck,"archidekt")
|
289
432
|
end
|
290
433
|
|
291
434
|
def self.mtgdecks_decklist(pages = (1..1))
|
@@ -295,16 +438,14 @@ module CockatriceFeeder
|
|
295
438
|
doc = Nokogiri::HTML(HTTParty.get("https://mtgdecks.net/Commander/decklists/page:#{page}").body)
|
296
439
|
doc.css(".decks tr.previewable").each do |r|
|
297
440
|
if r.css("td")[0].css(".label-danger").length == 0
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
cardlist: []
|
307
|
-
}
|
441
|
+
link = "https://mtgdecks.net"+r.css("td")[1].css("a")[0].attribute("href").value
|
442
|
+
name = link.split("/").last
|
443
|
+
date = r.css("td")[6].css("strong")[0].content.
|
444
|
+
gsub("<span class=\"hidden-xs\">","").
|
445
|
+
gsub("</span>","").gsub(/\s+/, "")
|
446
|
+
price = r.css("td")[7].css("span.paper")[0].content.gsub("$","").gsub(/\s+/, "")
|
447
|
+
|
448
|
+
decks << deck_obj(link,name,nil,date,price)
|
308
449
|
end
|
309
450
|
end
|
310
451
|
end
|
@@ -313,7 +454,6 @@ module CockatriceFeeder
|
|
313
454
|
end
|
314
455
|
|
315
456
|
def self.mtgdecks_deck(deck)
|
316
|
-
puts deck[:link]
|
317
457
|
doc = Nokogiri::HTML(HTTParty.get(deck[:link]).body)
|
318
458
|
|
319
459
|
cardlist = []
|
@@ -334,8 +474,30 @@ module CockatriceFeeder
|
|
334
474
|
output_cod(deck,"mtgdecks")
|
335
475
|
end
|
336
476
|
|
477
|
+
def self.mtggoldfish_pricer(deck)
|
478
|
+
doc = Nokogiri::HTML(HTTParty.get("https://www.mtggoldfish.com/tools/deck_pricer#paper"))
|
479
|
+
csrf_token = nil
|
480
|
+
doc.css("meta").each do |m|
|
481
|
+
if !m.attribute("name").nil? && m.attribute("name").value == "csrf-token"
|
482
|
+
csrf_token = m.attribute("content").value
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
doc2 = Nokogiri::HTML(HTTParty.post("https://www.mtggoldfish.com/tools/deck_pricer#paper", {
|
487
|
+
body: {
|
488
|
+
utf8: "✓",
|
489
|
+
authenticity_token: csrf_token,
|
490
|
+
deck: deck[:cardlist].join("\n")
|
491
|
+
}
|
492
|
+
}))
|
493
|
+
|
494
|
+
deck[:price] = doc2.css(".deck-price-v2.paper").first.
|
495
|
+
content.strip.split(" ").last.split(".").first.gsub(",","")
|
496
|
+
end
|
497
|
+
|
337
498
|
def self.gobble
|
338
|
-
setup()
|
499
|
+
setup(skip_meta = true)
|
500
|
+
update_commanders()
|
339
501
|
|
340
502
|
total_decks = 0
|
341
503
|
|
@@ -360,10 +522,25 @@ module CockatriceFeeder
|
|
360
522
|
puts "#{decks.length} decks found."
|
361
523
|
decks.each {|d|
|
362
524
|
CockatriceFeeder.mtgdecks_deck(d)
|
363
|
-
|
525
|
+
if d[:cardlist].length > 0
|
526
|
+
total_decks += 1
|
527
|
+
end
|
528
|
+
}
|
529
|
+
|
530
|
+
puts "Fetching the first 5 pages of edh decks from deckstats ordered by likes"
|
531
|
+
decks = CockatriceFeeder.deckstats_decklist("", (1..5))
|
532
|
+
puts "#{decks.length} decks found."
|
533
|
+
decks.each {|d|
|
534
|
+
CockatriceFeeder.deckstats_deck(d)
|
535
|
+
if d[:cardlist].length > 0
|
536
|
+
total_decks += 1
|
537
|
+
end
|
364
538
|
}
|
365
539
|
|
366
|
-
puts "#{total_decks} decks created."
|
540
|
+
puts "#{total_decks} decks created at #{@@deck_dir}."
|
541
|
+
|
542
|
+
puts "cleaning up"
|
543
|
+
FileUtils.remove_dir(@@meta_dir)
|
367
544
|
puts "Scraw!"
|
368
545
|
end
|
369
546
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cockatrice_feeder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew Steinwachs
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-12-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -38,8 +38,8 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0.18'
|
41
|
-
description: A tool to scrape MTG decks from the internet along with some meta
|
42
|
-
and create Cockatrice compatible deck files.
|
41
|
+
description: A tool to scrape MTG EDH decks from the internet along with some meta
|
42
|
+
information and create Cockatrice compatible deck files.
|
43
43
|
email: matt.steinwachs@gmail.com
|
44
44
|
executables:
|
45
45
|
- gobble
|
@@ -71,5 +71,5 @@ rubyforge_project:
|
|
71
71
|
rubygems_version: 2.6.14
|
72
72
|
signing_key:
|
73
73
|
specification_version: 4
|
74
|
-
summary: Scrape and generate decks for cockatrice
|
74
|
+
summary: Scrape and generate MTG EDH decks for cockatrice
|
75
75
|
test_files: []
|