steam-prices 0.1.3 → 0.1.5
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.
- data/README.md +9 -0
- data/lib/steam_prices/steam_game.rb +5 -3
- data/lib/steam_prices/steam_updater.rb +89 -14
- data/lib/steam_prices/version.rb +1 -1
- data/spec/steam_updater_spec.rb +94 -10
- metadata +5 -5
data/README.md
CHANGED
@@ -3,12 +3,14 @@ module SteamPrices
|
|
3
3
|
|
4
4
|
include Updater
|
5
5
|
|
6
|
-
attr_reader :app_id, :app_name, :store_link, :logo_link, :date_released, :
|
6
|
+
attr_reader :app_id, :app_name, :store_link, :logo_link, :date_released, :status, :category
|
7
|
+
attr_accessor :price
|
7
8
|
|
8
9
|
def initialize(app_name = nil, app_id = nil, store_link = nil, logo_link = nil, date_released = nil, price = nil)
|
9
10
|
@app_id = app_id.to_i
|
10
11
|
@app_name = app_name.to_s
|
11
|
-
@store_link = store_link
|
12
|
+
@store_link = store_link ||= "http://store.steampowered.com/app/12312312"
|
13
|
+
@category = (@store_link.match(/(.*store\.steampowered\.com\/app\/[\d]+\/)/) ? GAME : PACK)
|
12
14
|
@logo_link = logo_link
|
13
15
|
@date_released = date_released
|
14
16
|
raise ArgumentError, "Expected: Money()" if price.class.name != 'Money' && price != nil
|
@@ -17,7 +19,7 @@ module SteamPrices
|
|
17
19
|
|
18
20
|
def update(currency = nil)
|
19
21
|
return nil if !@app_name or @app_id == 0
|
20
|
-
self.class.update_one(@app_name, @app_id, currency)
|
22
|
+
self.class.update_one(@category, @app_name, @app_id, currency)
|
21
23
|
end
|
22
24
|
|
23
25
|
end
|
@@ -7,6 +7,16 @@ module SteamPrices
|
|
7
7
|
base.extend ClassMethods
|
8
8
|
end
|
9
9
|
|
10
|
+
|
11
|
+
EXCEPTIONS = {
|
12
|
+
#warhammer retribution
|
13
|
+
56400 => 56437,
|
14
|
+
#lost coast
|
15
|
+
340 => 0.00,
|
16
|
+
}
|
17
|
+
|
18
|
+
PACK = 996
|
19
|
+
GAME = 998
|
10
20
|
|
11
21
|
|
12
22
|
|
@@ -16,37 +26,74 @@ module SteamPrices
|
|
16
26
|
end
|
17
27
|
|
18
28
|
|
29
|
+
def status(price)
|
30
|
+
(price.empty? ? :not_found : :ok)
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_price(node)
|
34
|
+
# remove strikethrough prices
|
35
|
+
node.search('span').remove
|
36
|
+
price = node.text.gsub(/[\W_]/, '')
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
def update_one_game(name, app_id, currency = nil)
|
42
|
+
self.update_one(GAME, name, app_id, currency)
|
43
|
+
end
|
44
|
+
|
45
|
+
def update_one_pack(name, app_id, currency = nil)
|
46
|
+
self.update_one(PACK, name, app_id, currency)
|
47
|
+
end
|
48
|
+
|
19
49
|
# update a single one
|
20
|
-
def update_one(name, app_id, currency = nil)
|
50
|
+
def update_one(category, name, app_id, currency = nil)
|
21
51
|
prices = Hash.new
|
22
52
|
|
23
53
|
@countries = self.currency(currency) if !currency.nil?
|
24
54
|
|
25
55
|
@countries.each do |curr, country|
|
26
|
-
doc = Nokogiri::HTML(open(URI.encode("http://store.steampowered.com/search/results?sort_by=Name&sort_order=ASC&category1
|
27
|
-
|
56
|
+
doc = Nokogiri::HTML(open(URI.encode("http://store.steampowered.com/search/results?sort_by=Name&sort_order=ASC&category1=#{category}&cc=#{country}&v6=1&page=1&term=#{name}")))
|
57
|
+
node = doc.xpath('.//a[regex(., "/store\.steampowered\.com\/(app|sub)\/' + app_id.to_s + '/")]', Class.new {
|
28
58
|
def regex node_set, regex
|
29
59
|
node_set.find_all { |node| node['href'] =~ /#{regex}/ }
|
30
60
|
end
|
31
|
-
}.new).search('.search_price')
|
32
|
-
|
61
|
+
}.new).search('.search_price')
|
62
|
+
price = self.get_price(node)
|
63
|
+
status = (node.empty? ? :bad_request : self.status(price))
|
64
|
+
prices[curr] = { :price => (status == :ok ? Money.new(price.to_f, curr) : nil), :status => status }
|
33
65
|
end
|
34
66
|
prices
|
35
67
|
end
|
36
68
|
|
69
|
+
def update_everything(currency = nil, display = true)
|
70
|
+
#combine the two hashes
|
71
|
+
self.update_all_games(currency, display).merge!(self.update_all_packs(currency, display))
|
72
|
+
end
|
73
|
+
|
74
|
+
def update_all_games(currency = nil, display = true)
|
75
|
+
self.update_all(GAME, currency, display)
|
76
|
+
end
|
77
|
+
|
78
|
+
def update_all_packs(currency = nil, display = true)
|
79
|
+
self.update_all(PACK, currency, display)
|
80
|
+
end
|
37
81
|
|
38
82
|
# display stolen from https://github.com/spezifanta/SteamCalculator-Scripts/blob/master/getGames
|
39
|
-
def update_all(currency = nil, display = true)
|
40
|
-
games =
|
83
|
+
def update_all(category, currency = nil, display = true)
|
84
|
+
games = Hash.new
|
41
85
|
|
42
86
|
@countries = self.currency(currency) if !currency.nil?
|
43
87
|
|
44
88
|
@countries.each do |curr, country|
|
45
|
-
doc = Nokogiri::HTML(open(URI.encode("http://store.steampowered.com/search/results?sort_by=Name&sort_order=ASC&category1
|
89
|
+
doc = Nokogiri::HTML(open(URI.encode("http://store.steampowered.com/search/results?sort_by=Name&sort_order=ASC&category1=#{category}&cc=#{country}&v6=1&page=1")))
|
46
90
|
gamesPerPage, totalGames = doc.search('.search_pagination_left')[0].text.match(/showing\s\d+\s-\s(\d+)\sof\s(\d+)/m).captures
|
47
91
|
|
48
92
|
totalPages = (totalGames.to_i / gamesPerPage.to_i).ceil
|
49
93
|
|
94
|
+
exceptions = Array.new
|
95
|
+
|
96
|
+
|
50
97
|
for i in 1..totalPages
|
51
98
|
|
52
99
|
if display then
|
@@ -58,21 +105,27 @@ module SteamPrices
|
|
58
105
|
end
|
59
106
|
|
60
107
|
doc.search('.search_result_row').each do |game|
|
61
|
-
url = game.attr('href').match(/(.*store\.steampowered\.com\/app\/([\d]+)\/)/)
|
108
|
+
url = game.attr('href').match(/(.*store\.steampowered\.com\/(app|sub)\/([\d]+)\/)/)
|
109
|
+
# for things like /sale/
|
62
110
|
if !url then
|
63
|
-
games
|
111
|
+
games[game.attr('href')] = Hash.new if !games[game.attr('href')]
|
112
|
+
games[game.attr('href')][curr] = { :status => :bad_request, :game => nil}
|
64
113
|
else
|
65
|
-
link, app_id = url.captures
|
114
|
+
link, type, app_id = url.captures
|
115
|
+
|
66
116
|
#remove retail price and put sale price
|
67
|
-
game.search('.search_price')
|
68
|
-
price = game.search('.search_price').text.gsub(/[\W_]/, '').to_f
|
117
|
+
price = self.get_price(game.search('.search_price'))
|
69
118
|
date = game.search('.search_released').text
|
70
119
|
name = game.search('h4').text
|
71
120
|
logo = game.search('.search_capsule img').attr('src').value
|
72
121
|
|
73
122
|
print "|% 8s |" % app_id + "% 8.2f |" % (price.to_f / 100) + "% 14s |" % date if display
|
74
123
|
printf " %s%" + (43 - name[0,43].length).to_s + "s\n", name[0,42], " " if display
|
75
|
-
|
124
|
+
status = self.status(price)
|
125
|
+
game = SteamPrices::Game.new(name, app_id, link, logo, date, (status == :ok ? Money.new(price.to_f, curr) : nil))
|
126
|
+
|
127
|
+
games[app_id.to_i] = Hash.new if !games[app_id.to_i]
|
128
|
+
games[app_id.to_i][curr] = { :game => game, :status => status }
|
76
129
|
end
|
77
130
|
end
|
78
131
|
|
@@ -82,6 +135,28 @@ module SteamPrices
|
|
82
135
|
|
83
136
|
end
|
84
137
|
|
138
|
+
# check if there are any special cases
|
139
|
+
EXCEPTIONS.each do |app_id, v|
|
140
|
+
if games.key? app_id then
|
141
|
+
|
142
|
+
games[app_id].each do |currency, game|
|
143
|
+
if v.class.name == 'Fixnum' then
|
144
|
+
# it's an app id, so we need to either fetch the real price, or get it if we already have it
|
145
|
+
price = (games.key?(v) ? games[v][currency][:game].price : self.update_one(game[:game].app_name, v, currency)[currency][:price])
|
146
|
+
elsif v.class.name == 'Float' then
|
147
|
+
# it's a price
|
148
|
+
price = v
|
149
|
+
else
|
150
|
+
# it's a sub
|
151
|
+
# get the price of the sub
|
152
|
+
end
|
153
|
+
# update the price
|
154
|
+
game[:game].price = price
|
155
|
+
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
85
160
|
end
|
86
161
|
games
|
87
162
|
end
|
data/lib/steam_prices/version.rb
CHANGED
data/spec/steam_updater_spec.rb
CHANGED
@@ -5,35 +5,119 @@ describe SteamPrices::Updater do
|
|
5
5
|
before(:each) do
|
6
6
|
URI.stub!(:encode)
|
7
7
|
end
|
8
|
+
|
9
|
+
|
10
|
+
context "packs", :packs => true do
|
11
|
+
before(:each) do
|
12
|
+
# it says there are 5 pages
|
13
|
+
URI.should_receive(:encode).exactly(1).times.and_return(File.dirname(__FILE__) + '/support/packs.html')
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should be able to scrape steam and give a bunch of prices for a pack" do
|
17
|
+
games = SteamPrices::Game.update_all_packs('usd', true)
|
18
|
+
games.size.should == 25
|
19
|
+
games[6433]['usd'][:game].price.should == 39.99
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should be able to find a single pack" do
|
23
|
+
g = SteamPrices::Game.new('1C Action Collection', 6433, 'http://store.steampowered.com/sub/6433/?snr=1_7_7_230_150_1')
|
24
|
+
g.update('usd')['usd'][:price].should == 39.99
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should be able to update EVERYTHING", :everything => true do
|
29
|
+
URI.should_receive(:encode).exactly(5).times.and_return(File.dirname(__FILE__) + '/support/us.html')
|
30
|
+
URI.should_receive(:encode).exactly(1).times.and_return(File.dirname(__FILE__) + '/support/packs.html')
|
31
|
+
games = SteamPrices::Game.update_everything('usd', false)
|
32
|
+
games.size.should == 25+19
|
33
|
+
#pack
|
34
|
+
games[6433]['usd'][:game].price.should == 39.99
|
35
|
+
games[6433]['usd'][:status].should == :ok
|
36
|
+
#game
|
37
|
+
games[22350]['usd'][:game].price.should == 49.99
|
38
|
+
games[22350]['usd'][:status].should == :ok
|
39
|
+
|
40
|
+
end
|
41
|
+
|
8
42
|
context "all prices" do
|
9
43
|
|
10
|
-
|
44
|
+
before(:each) do
|
45
|
+
# it says there are 5 pages
|
11
46
|
URI.should_receive(:encode).exactly(5).times.and_return(File.dirname(__FILE__) + '/support/us.html')
|
12
|
-
games = SteamPrices::Game.
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
games.size.should == 95
|
47
|
+
@games = SteamPrices::Game.update_all_games('usd', true)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should be able to scrape steam and give a bunch of prices" do
|
51
|
+
@games.size.should == 19
|
18
52
|
end
|
53
|
+
|
54
|
+
|
55
|
+
context "exceptions" do
|
56
|
+
it "should be able to handle games like lost coast, which are part of a pack only and list the pack price" do
|
57
|
+
@games[340]['usd'][:game].price.should == 0.00
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should be able to handle games like warhammer retribution where it points to a different app id" do
|
61
|
+
@games[56400]['usd'][:game].price.should == 29.99
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should have an ok status if the price is ok" do
|
65
|
+
@games[22350]['usd'][:game].price.should == 49.99
|
66
|
+
@games[22350]['usd'][:status].should == :ok
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should have a not found status if the price is empty but the url is found (preorder)" do
|
70
|
+
@games[55150]['usd'][:game].price.should == nil
|
71
|
+
@games[55150]['usd'][:status].should == :not_found
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
it "should have a bad request status if the url is invalid or some other crazy error" do
|
76
|
+
@games['http://store.steampowered.com/sale/magic2011?snr=1_7_7_230_150_27']['usd'][:status].should == :bad_request
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
19
81
|
|
20
82
|
end
|
21
83
|
|
84
|
+
|
85
|
+
|
22
86
|
context "a single price" do
|
23
87
|
before(:each) do
|
24
88
|
URI.should_receive(:encode).and_return(File.dirname(__FILE__) + '/support/us.html')
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
it "should be able to return a status if it was ok" do
|
93
|
+
g = SteamPrices::Game.new('brink', 22350)
|
94
|
+
p = g.update('usd')['usd']
|
95
|
+
p[:price].should == 49.99
|
96
|
+
p[:status].should == :ok
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
it "should be able to return not found if it wasn't ok" do
|
101
|
+
g = SteamPrices::Game.new('Warhammer 40,000: Space Marine', 55150)
|
102
|
+
p = g.update('usd')['usd']
|
103
|
+
p[:price].should == nil
|
104
|
+
p[:status].should == :not_found
|
105
|
+
end
|
25
106
|
|
107
|
+
it "should be able to get confused if something went crazy or wasn't there" do
|
108
|
+
g = SteamPrices::Game.new('awdwad', 21231232350)
|
109
|
+
g.update('usd')['usd'][:status].should == :bad_request
|
26
110
|
end
|
27
111
|
|
28
112
|
it "should be able to find a single game and update it's price (instance)" do
|
29
113
|
g = SteamPrices::Game.new('brink', 22350)
|
30
|
-
g.update('usd')['usd'].should == 49.99
|
114
|
+
g.update('usd')['usd'][:price].should == 49.99
|
31
115
|
|
32
116
|
end
|
33
117
|
|
34
118
|
it "should be able to find a single game and update it's price (class)" do
|
35
|
-
prices = SteamPrices::Game.
|
36
|
-
prices['usd'].should == 49.99
|
119
|
+
prices = SteamPrices::Game.update_one_game('brink', 22350, 'usd')
|
120
|
+
prices['usd'][:price].should == 49.99
|
37
121
|
end
|
38
122
|
end
|
39
123
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: steam-prices
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 17
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 5
|
10
|
+
version: 0.1.5
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- scott tesoriere
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-05-
|
18
|
+
date: 2011-05-25 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: rspec
|
@@ -126,7 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
126
126
|
requirements: []
|
127
127
|
|
128
128
|
rubyforge_project:
|
129
|
-
rubygems_version: 1.
|
129
|
+
rubygems_version: 1.8.3
|
130
130
|
signing_key:
|
131
131
|
specification_version: 3
|
132
132
|
summary: Prices for steam.
|