lib/rest-gw2/client.rb in rest-gw2-0.4.0 vs lib/rest-gw2/client.rb in rest-gw2-0.5.0
- old
+ new
@@ -1,7 +1,10 @@
+# frozen_string_literal: true
require 'rest-core'
+require 'rest-gw2/client/item_detail'
+require 'set'
module RestGW2
Client = RC::Builder.client do
use RC::DefaultSite , 'https://api.guildwars2.com/'
use RC::DefaultHeaders, {'Accept' => 'application/json'}
@@ -53,18 +56,29 @@
end.new(error, code, url)
end
end
Client.include(Module.new{
+ def me opts={}
+ get('v2/account', {}, opts)
+ end
+
# https://wiki.guildwars2.com/wiki/API:2/account
# https://wiki.guildwars2.com/wiki/API:2/worlds
- # https://wiki.guildwars2.com/wiki/API:1/guild_details
+ # https://wiki.guildwars2.com/wiki/API:2/guild/:id
def account_with_detail opts={}
- me = get('v2/account', {}, opts)
- worlds = get('v2/worlds', :ids => me['world'])
- guilds = guilds_detail(me['guilds'])
- me.merge('world' => world_detail(worlds.first), 'guilds' => guilds)
+ m = me(opts)
+ worlds = get('v2/worlds', :ids => m['world'])
+ guilds = guilds_detail(m['guilds'])
+ # m['guild_leader'] would be nil if there's no guild permission
+ guild_leader = (m['guild_leader'] || []).map do |gid|
+ guilds.find{ |g| g['id'] == gid }
+ end
+ me.merge(
+ 'world' => world_detail(worlds.first),
+ 'guilds' => guilds,
+ 'guild_leader' => guild_leader)
end
# https://wiki.guildwars2.com/wiki/API:2/guild/:id/stash
def stash_with_detail gid, opts={}
stash = get("v2/guild/#{gid}/stash")
@@ -84,10 +98,15 @@
i.merge('id' => i['item_id'])
end
end
end
+ # https://wiki.guildwars2.com/wiki/API:2/guild/:id/members
+ def guild_members gid, opts={}
+ get("v2/guild/#{gid}/members", {}, opts)
+ end
+
# https://wiki.guildwars2.com/wiki/API:2/characters
def get_character name, opts={}
get("v2/characters/#{RC::Middleware.escape(name)}", {}, opts)
end
@@ -95,16 +114,22 @@
def characters_with_detail opts={}
chars = get('v2/characters', {}, opts).map do |name|
get_character(name, opts)
end
- guilds = chars.map do |c|
- get_guild(c['guild']) if c['guild']
- end
+ guild_ids = chars.map{ |c| c['guild'] }.compact.uniq
+ guild_promises = guilds_detail(guild_ids)
- chars.zip(guilds).map do |(c, g)|
- c['guild'] = g
+ title_ids = chars.map{ |c| c['title'] }.compact
+ titles = get('v2/titles', :ids => title_ids.join(',')).
+ group_by{ |t| t['id'] }
+
+ guilds = guild_promises.group_by{ |g| g['id'] }
+
+ chars.map do |c|
+ c['guild'] = guilds.dig(c['guild'], 0)
+ c['title'] = titles.dig(c['title'], 0, 'name')
c
end.sort_by{ |c| -c['age'] }
end
def bags_with_detail bags, opts={}
@@ -113,87 +138,201 @@
detail.shift(bags.size).map do |b|
b && b.merge('inventory' => detail.shift(b['size']))
end
end
+ # https://wiki.guildwars2.com/wiki/API:2/currencies
+ # https://wiki.guildwars2.com/wiki/API:2/account/wallet
+ def wallet_with_detail opts={}
+ wallet = get('v2/account/wallet', {}, opts)
+ ids = wallet.map{ |w| w['id'] }.join(',')
+ currencies = get('v2/currencies', :ids => ids).group_by{ |w| w['id'] }
+ wallet.map do |currency|
+ currency.merge(currencies[currency['id']].first)
+ end.sort_by{ |c| c['order'] }
+ end
+
+ # https://wiki.guildwars2.com/wiki/API:2/account/skins
+ def skins_with_detail opts={}
+ unlocks_with_detail(:all_skins, 'v2/account/skins', opts)
+ end
+
+ # https://wiki.guildwars2.com/wiki/API:2/account/outfits
+ def outfits_with_detail opts={}
+ unlocks_with_detail(:all_outfits, 'v2/account/outfits', opts)
+ end
+
+ # https://wiki.guildwars2.com/wiki/API:2/account/mailcarriers
+ def mailcarriers_with_detail opts={}
+ unlocks_with_detail(:all_mailcarriers, 'v2/account/mailcarriers', opts)
+ end
+
+ # https://wiki.guildwars2.com/wiki/API:2/account/gliders
+ def gliders_with_detail opts={}
+ unlocks_with_detail(:all_gliders, 'v2/account/gliders', opts)
+ end
+
+ # https://wiki.guildwars2.com/wiki/API:2/skins
+ def all_skins
+ all_unlocks('v2/skins')
+ end
+
+ # https://wiki.guildwars2.com/wiki/API:2/outfits
+ def all_outfits
+ all_unlocks('v2/outfits')
+ end
+
+ # https://wiki.guildwars2.com/wiki/API:2/mailcarriers
+ def all_mailcarriers
+ all_unlocks('v2/mailcarriers')
+ end
+
+ # https://wiki.guildwars2.com/wiki/API:2/gliders
+ def all_gliders
+ all_unlocks('v2/gliders')
+ end
+
+ # https://wiki.guildwars2.com/wiki/API:2/finishers
+ def all_fininshers
+ all_unlocks('v2/finishers')
+ end
+
+ # https://wiki.guildwars2.com/wiki/API:2/cats
+ def all_cats
+ all_unlocks('v2/cats')
+ end
+
+ # https://wiki.guildwars2.com/wiki/API:2/titles
+ def all_titles
+ all_unlocks('v2/titles')
+ end
+
# https://wiki.guildwars2.com/wiki/API:2/colors
# https://wiki.guildwars2.com/wiki/API:2/account/dyes
def dyes_with_detail opts={}
mine = get('v2/account/dyes', opts)
+
get('v2/colors').each_slice(100).map do |slice|
- slice.join(',')
- end.map do |ids|
- with_item_detail('v2/colors', :ids => ids) do |colors|
+ with_item_detail('v2/colors', :ids => slice.join(',')) do |colors|
colors.map{ |c| c.merge('id' => c['item'], 'color_id' => c['id']) }
end
end.flatten.map do |color|
- color['count'] = if mine.include?(color['color_id'])
- 1
- else
- 0
- end
+ color['count'] =
+ if mine.include?(color['color_id'])
+ 1
+ else
+ 0
+ end
color
end.sort_by{ |c| c['categories'] }
end
- # https://wiki.guildwars2.com/wiki/API:2/account/skins
- def skins_with_detail opts={}
- mine = get('v2/account/skins', {}, opts)
- all_skins.flatten.map do |skin|
- skin['count'] = if mine.include?(skin['id'])
- 1
- else
- 0
- end
- skin['nolink'] = true
- skin
- end.sort_by{ |s| s['name'] || '' }
- end
-
- # https://wiki.guildwars2.com/wiki/API:2/skins
- def all_skins
- get('v2/skins').each_slice(100).map do |slice|
- get('v2/skins', :ids => slice.join(','))
- end
- end
-
# https://wiki.guildwars2.com/wiki/API:2/minis
# https://wiki.guildwars2.com/wiki/API:2/account/minis
def minis_with_detail opts={}
mine = get('v2/account/minis', {}, opts)
+
get('v2/minis').each_slice(100).map do |slice|
- slice.join(',')
- end.map do |ids|
- with_item_detail('v2/minis', :ids => ids) do |minis|
+ with_item_detail('v2/minis', :ids => slice.join(',')) do |minis|
minis.map{ |m| m.merge('id' => m['item_id'], 'mini_id' => m['id']) }
end
end.flatten.map do |mini|
- mini['count'] = if mine.include?(mini['mini_id'])
- 1
- else
- 0
- end
+ mini['count'] =
+ if mine.include?(mini['mini_id'])
+ 1
+ else
+ 0
+ end
+ mini['nolink'] = true
mini
end.sort_by{ |m| m['order'] }
end
- # https://wiki.guildwars2.com/wiki/API:2/account/wallet
- # https://wiki.guildwars2.com/wiki/API:2/currencies
- def wallet_with_detail opts={}
- wallet = get('v2/account/wallet', {}, opts)
- ids = wallet.map{ |w| w['id'] }.join(',')
- currencies = get('v2/currencies', :ids => ids).group_by{ |w| w['id'] }
- wallet.map do |currency|
- currency.merge(currencies[currency['id']].first)
- end.sort_by{ |c| c['order'] }
+ # https://wiki.guildwars2.com/wiki/API:2/account/finishers
+ def finishers_with_detail opts={}
+ mine_promise = get('v2/account/finishers', {}, opts)
+
+ all = all_fininshers
+ mine = mine_promise.group_by{ |u| u['id'] }
+
+ all.flatten.map do |finisher|
+ finisher['count'] =
+ if mine.dig(finisher['id'], 0, 'permanent')
+ Float::INFINITY
+ else
+ mine.dig(finisher['id'], 0, 'quantity') || 0
+ end
+ finisher['nolink'] = true
+ finisher['description'] = finisher['unlock_details']
+ finisher
+ end.sort_by{ |m| m['order'] }
end
- def with_item_detail path, query={}, opts={}, &block
- block ||= :itself.to_proc
- expand_item_detail(block.call(get(path, query, opts)), opts)
+ # https://wiki.guildwars2.com/wiki/API:2/account/home/cats
+ def cats_with_detail opts={}
+ mine_promise = get('v2/account/home/cats', opts)
+
+ all = all_cats
+ mine = Set.new(mine_promise.map{ |cat| cat['id'] })
+
+ all.flatten.map do |cat|
+ cat['count'] =
+ if mine.member?(cat['id'])
+ 1
+ else
+ 0
+ end
+ cat['name'] = cat['hint']
+ cat
+ end.sort_by{ |c| c['name'] }
end
+ # https://wiki.guildwars2.com/wiki/API:2/nodes
+ # https://wiki.guildwars2.com/wiki/API:2/account/home/nodes
+ def nodes_with_detail opts={}
+ all = get('v2/nodes')
+ mine = Set.new(get('v2/account/home/nodes', opts))
+
+ all.map do |name|
+ count =
+ if mine.member?(name)
+ 1
+ else
+ 0
+ end
+ {'name' => name, 'count' => count}
+ end.sort_by{ |n| n['name'] }
+ end
+
+ # https://wiki.guildwars2.com/wiki/API:2/account/titles
+ def titles_with_detail opts={}
+ all = all_titles
+ mine = get('v2/account/titles')
+
+ all.flatten.map do |title|
+ title['count'] =
+ if mine.member?(title['id'])
+ 1
+ else
+ 0
+ end
+ title
+ end.sort_by{ |t| t['name'] }
+ end
+
+ # https://wiki.guildwars2.com/wiki/API:2/commerce/delivery
+ def delivery_with_detail query={}, opts={}
+ items = with_item_detail('v2/commerce/delivery',
+ {:page_size => 200}.merge(query), opts) do |delivery|
+ ['price' => delivery['coins']] + delivery['items']
+ end
+
+ compact_items(items) do |last, current|
+ last['id'] == current['id']
+ end
+ end
+
# https://wiki.guildwars2.com/wiki/API:2/commerce/transactions
def transactions_with_detail path, query={}, opts={}
with_item_detail("v2/commerce/transactions/#{path}",
{:page_size => 200}.merge(query), opts) do |trans|
trans.map do |t|
@@ -201,67 +340,31 @@
end
end
end
def transactions_with_detail_compact path, query={}, opts={}
- transactions_with_detail(path, query, opts).inject([]) do |ret, trans|
- last = ret.last
- if last && last['item_id'] == trans['item_id'] &&
- last['price'] == trans['price']
- last['count'] += trans['count']
- else
- ret << trans
- end
- ret
+ items = transactions_with_detail(path, query, opts)
+
+ compact_items(items) do |last, current|
+ last['id'] == current['id'] && last['price'] == current['price']
end
end
- # https://wiki.guildwars2.com/wiki/API:2/items
- # https://wiki.guildwars2.com/wiki/API:2/commerce/prices
+ def with_item_detail path, query={}, opts={}, &block
+ block ||= :itself.to_proc
+ expand_item_detail(block.call(get(path, query, opts)), opts)
+ end
+
def expand_item_detail items, opts={}
- skins = all_skins
- detail = item_detail_group_by_id(items, opts)
- upgrades = extract_items_in_slots(items, opts, 'upgrades', 'infusions')
+ detail = ItemDetail.new(self, items, opts)
+ detail.populate
- skins_detail = skins.flatten.group_by{ |s| s['id'] }
- items.map do |i|
- next i unless data = i && detail[i['id']]
- s = i['skin']
- u = i['upgrades']
- f = i['infusions']
- i.merge(data).merge(
- 'count' => i['count'] || 1,
- 'skin' => s && skins_detail[s].first,
- 'upgrades' => u && u.flat_map(&upgrades.method(:[])),
- 'infusions' => f && f.flat_map(&upgrades.method(:[])))
- end
+ items.map(&detail.method(:fill))
end
private
- def item_detail_group_by_id items, opts={}
- items.map{ |i| i && i['id'] }.compact.each_slice(100).map do |slice|
- q = {:ids => slice.join(',')}
- [get('v2/items', q),
- get('v2/commerce/prices', q, {:error_detector => false}.merge(opts))]
- end.flat_map(&:itself).map(&:to_a).flatten.group_by{ |i| i['id'] }.
- inject({}){ |r, (id, v)| r[id] = v.inject(&:merge); r }
- # this is probably a dirty way to workaround converting hashes to arrays
- end
- def extract_items_in_slots items, opts, *slots
- upgrades = items.flat_map do |i|
- if i
- i.values_at(*slots).flatten.compact.map do |id|
- {'id' => id}
- end
- else
- []
- end
- end
- item_detail_group_by_id(upgrades, opts)
- end
-
# https://wiki.guildwars2.com/wiki/API:2/worlds
def world_detail world
region = case r = world['id'] / 1000
when 1
'North America'
@@ -283,15 +386,51 @@
"Unknown (#{r})"
end
"#{world['name']} (#{world['population']}) / #{region} (#{lang})"
end
- # https://wiki.guildwars2.com/wiki/API:1/guild_details
def guilds_detail guilds
guilds.map(&method(:get_guild))
end
+ # https://wiki.guildwars2.com/wiki/API:2/guild/:id
def get_guild gid
- get('v1/guild_details', :guild_id => gid)
+ get("v2/guild/#{gid}")
+ end
+
+ # Returns Array[Promise[Detail]]
+ def all_unlocks path
+ get(path).each_slice(100).map do |slice|
+ get(path, :ids => slice.join(','))
+ end
+ end
+
+ def unlocks_with_detail kind, path, opts
+ all = public_send(kind)
+ mine = Set.new(get(path, {}, opts))
+ all.flatten.map do |unlock|
+ unlock['count'] =
+ if mine.member?(unlock['id'])
+ 1
+ else
+ 0
+ end
+ unlock['nolink'] = true
+ unlock
+ end.sort_by{ |u| u['order'] || u['name'] || '' }
+ end
+
+ def compact_items items
+ items.inject([]) do |result, item|
+ last = result.last
+
+ if last && yield(last, item)
+ last['count'] += item['count']
+ else
+ result << item
+ end
+
+ result
+ end
end
})
end