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