market_bot 0.17.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/Guardfile +70 -0
  4. data/README.markdown +45 -95
  5. data/Rakefile +0 -89
  6. data/bin/app_categories +17 -0
  7. data/bin/benchmark_parser_app +24 -0
  8. data/bin/console +14 -0
  9. data/bin/setup +7 -0
  10. data/bin/update_test_data +30 -0
  11. data/lib/market_bot.rb +20 -15
  12. data/lib/market_bot/exceptions.rb +2 -1
  13. data/lib/market_bot/play/app.rb +188 -0
  14. data/lib/market_bot/play/app/constants.rb +33 -0
  15. data/lib/market_bot/play/chart.rb +118 -0
  16. data/lib/market_bot/play/chart/constants.rb +74 -0
  17. data/lib/market_bot/play/constants.rb +7 -0
  18. data/lib/market_bot/play/developer.rb +32 -0
  19. data/lib/market_bot/util.rb +17 -0
  20. data/lib/market_bot/version.rb +1 -1
  21. data/market_bot.gemspec +6 -3
  22. data/spec/market_bot/play/app_spec.rb +201 -0
  23. data/spec/market_bot/play/chart_spec.rb +126 -0
  24. data/spec/market_bot/play/data/app-com.bluefroggaming.popdat.txt +99 -0
  25. data/spec/market_bot/play/data/app-com.mg.android.txt +103 -0
  26. data/spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-0.txt +97 -0
  27. data/spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-1.txt +97 -0
  28. data/spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-2.txt +97 -0
  29. data/spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-3.txt +97 -0
  30. data/spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-4.txt +97 -0
  31. data/spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-5.txt +97 -0
  32. data/spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-6.txt +97 -0
  33. data/spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-7.txt +97 -0
  34. data/spec/market_bot/play/data/developer-zynga.txt +97 -0
  35. data/spec/market_bot/play/developer_spec.rb +52 -0
  36. data/spec/market_bot_spec.rb +14 -0
  37. data/spec/spec_helper.rb +5 -11
  38. metadata +57 -52
  39. data/NOTES.txt +0 -61
  40. data/lib/market_bot/android/app.rb +0 -273
  41. data/lib/market_bot/android/developer.rb +0 -32
  42. data/lib/market_bot/android/leaderboard.rb +0 -232
  43. data/lib/market_bot/android/leaderboard/constants.rb +0 -59
  44. data/lib/market_bot/android/search_query.rb +0 -35
  45. data/lib/market_bot/movie/leaderboard.rb +0 -167
  46. data/lib/market_bot/movie/leaderboard/constants.rb +0 -30
  47. data/lib/market_bot/movie/search_query.rb +0 -32
  48. data/spec/market_bot/android/app_spec.rb +0 -253
  49. data/spec/market_bot/android/data/app_1.txt +0 -99
  50. data/spec/market_bot/android/data/app_2.txt +0 -100
  51. data/spec/market_bot/android/data/app_3.txt +0 -103
  52. data/spec/market_bot/android/data/app_4.txt +0 -117
  53. data/spec/market_bot/android/data/developer-zynga.txt +0 -97
  54. data/spec/market_bot/android/data/leaderboard-apps_editors_choice.txt +0 -97
  55. data/spec/market_bot/android/data/leaderboard-apps_topselling_paid-page1.txt +0 -97
  56. data/spec/market_bot/android/data/leaderboard-apps_topselling_paid-page2.txt +0 -97
  57. data/spec/market_bot/android/data/leaderboard-apps_topselling_paid-page3.txt +0 -97
  58. data/spec/market_bot/android/data/leaderboard-apps_topselling_paid-page4.txt +0 -97
  59. data/spec/market_bot/android/developer_spec.rb +0 -57
  60. data/spec/market_bot/android/leaderboard_spec.rb +0 -140
  61. data/spec/market_bot/android/search_query_spec.rb +0 -6
  62. data/spec/market_bot/movie/data/leaderboard-movies_comedy_topselling_paid.txt +0 -327
  63. data/spec/market_bot/movie/leaderboard_spec.rb +0 -67
@@ -0,0 +1,52 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '../../../spec_helper')
2
+
3
+ describe MarketBot::Play::Developer do
4
+ shared_context('parsing a developer') do
5
+ it 'should be a valid length' do
6
+ expect(@parsed.length).to be > 1
7
+ end
8
+
9
+ it 'should have attributes' do
10
+ expect(@parsed).to all(have_key(:package)).and \
11
+ all(have_key(:title)).and all(have_key(:store_url)).and \
12
+ all(have_key(:developer)).and all(have_key(:icon_url))
13
+ end
14
+ end
15
+
16
+ describe "(zynga)" do
17
+ include_context 'parsing a developer'
18
+
19
+ before(:all) do
20
+ @name = 'zynga'
21
+ @html = read_play_data('developer-zynga.txt')
22
+ @parsed = MarketBot::Play::Chart.parse(@html)
23
+ end
24
+ end
25
+
26
+ it 'should generate store_urls' do
27
+ name ='zynga'
28
+ dev = MarketBot::Play::Developer.new(name)
29
+
30
+ expect(dev.store_urls.length).to eq(1)
31
+
32
+ dev.store_urls.each_with_index do |url, i|
33
+ msg = "i=#{i}, url=#{url}"
34
+ pattern = /\Ahttps:\/\/play\.google\.com\/store\/apps\/developer\?id=zynga&start=0&gl=us&num=100&hl=en\z/
35
+ expect(url).to match(Regexp.new(pattern)), msg
36
+ end
37
+ end
38
+
39
+ it 'should update' do
40
+ name = 'zynga'
41
+ dev = MarketBot::Play::Developer.new(name)
42
+ code = 200
43
+
44
+ dev.store_urls.each_with_index do |url, i|
45
+ html = read_play_data('developer-zynga.txt')
46
+ response = Typhoeus::Response.new(code: code, headers: '', body: html)
47
+ Typhoeus.stub(url).and_return(response)
48
+ end
49
+
50
+ dev.update
51
+ end
52
+ end
@@ -1,4 +1,18 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
3
  describe "MarketBot" do
4
+ it 'should support changing the default request timeout' do
5
+ MarketBot.timeout = 5
6
+ expect(MarketBot.timeout).to eq(5)
7
+ end
8
+
9
+ it 'should support changing the default request connect timeout' do
10
+ MarketBot.connect_timeout = 5
11
+ expect(MarketBot.connect_timeout).to eq(5)
12
+ end
13
+
14
+ it 'should support changing the default request user agent' do
15
+ MarketBot.user_agent = 'My Custom Bot'
16
+ expect(MarketBot.user_agent).to eq('My Custom Bot')
17
+ end
4
18
  end
data/spec/spec_helper.rb CHANGED
@@ -7,13 +7,7 @@ require 'rspec'
7
7
 
8
8
  begin
9
9
  require 'byebug'
10
- rescue Exception => e
11
- end
12
-
13
- begin
14
- require 'simplecov'
15
- SimpleCov.start
16
- rescue Exception => e
10
+ rescue Exception
17
11
  end
18
12
 
19
13
  require 'market_bot'
@@ -29,8 +23,8 @@ Typhoeus.configure do |config|
29
23
  config.block_connection = true
30
24
  end
31
25
 
32
- def read_file(*path)
33
- data = nil
34
- File.open(File.join(path), 'r') { |f| data = f.read }
35
- return data
26
+ def read_play_data(name)
27
+ path = File.join(File.expand_path(File.dirname(__FILE__)),
28
+ 'market_bot', 'play', 'data', name)
29
+ File.read(path)
36
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: market_bot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chad Remesch
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-06 00:00:00.000000000 Z
11
+ date: 2016-05-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: typhoeus
@@ -42,49 +42,54 @@ dependencies:
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '1.10'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.10'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">"
60
60
  - !ruby/object:Gem::Version
61
61
  version: '10.0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '10.0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '='
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 2.8.0
75
+ version: '3.4'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '='
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 2.8.0
82
+ version: '3.4'
83
83
  description: Market Bot is a high performance Ruby scraper for Google's Android Market
84
84
  with a simple to use API. It is built on top of Nokogiri and Typhoeus.
85
85
  email:
86
86
  - chad@remesch.com
87
- executables: []
87
+ executables:
88
+ - app_categories
89
+ - benchmark_parser_app
90
+ - console
91
+ - setup
92
+ - update_test_data
88
93
  extensions: []
89
94
  extra_rdoc_files: []
90
95
  files:
@@ -92,38 +97,40 @@ files:
92
97
  - ".rspec"
93
98
  - ".travis.yml"
94
99
  - Gemfile
100
+ - Guardfile
95
101
  - LICENSE.txt
96
- - NOTES.txt
97
102
  - README.markdown
98
103
  - Rakefile
104
+ - bin/app_categories
105
+ - bin/benchmark_parser_app
106
+ - bin/console
107
+ - bin/setup
108
+ - bin/update_test_data
99
109
  - lib/market_bot.rb
100
- - lib/market_bot/android/app.rb
101
- - lib/market_bot/android/developer.rb
102
- - lib/market_bot/android/leaderboard.rb
103
- - lib/market_bot/android/leaderboard/constants.rb
104
- - lib/market_bot/android/search_query.rb
105
110
  - lib/market_bot/exceptions.rb
106
- - lib/market_bot/movie/leaderboard.rb
107
- - lib/market_bot/movie/leaderboard/constants.rb
108
- - lib/market_bot/movie/search_query.rb
111
+ - lib/market_bot/play/app.rb
112
+ - lib/market_bot/play/app/constants.rb
113
+ - lib/market_bot/play/chart.rb
114
+ - lib/market_bot/play/chart/constants.rb
115
+ - lib/market_bot/play/constants.rb
116
+ - lib/market_bot/play/developer.rb
117
+ - lib/market_bot/util.rb
109
118
  - lib/market_bot/version.rb
110
119
  - market_bot.gemspec
111
- - spec/market_bot/android/app_spec.rb
112
- - spec/market_bot/android/data/app_1.txt
113
- - spec/market_bot/android/data/app_2.txt
114
- - spec/market_bot/android/data/app_3.txt
115
- - spec/market_bot/android/data/app_4.txt
116
- - spec/market_bot/android/data/developer-zynga.txt
117
- - spec/market_bot/android/data/leaderboard-apps_editors_choice.txt
118
- - spec/market_bot/android/data/leaderboard-apps_topselling_paid-page1.txt
119
- - spec/market_bot/android/data/leaderboard-apps_topselling_paid-page2.txt
120
- - spec/market_bot/android/data/leaderboard-apps_topselling_paid-page3.txt
121
- - spec/market_bot/android/data/leaderboard-apps_topselling_paid-page4.txt
122
- - spec/market_bot/android/developer_spec.rb
123
- - spec/market_bot/android/leaderboard_spec.rb
124
- - spec/market_bot/android/search_query_spec.rb
125
- - spec/market_bot/movie/data/leaderboard-movies_comedy_topselling_paid.txt
126
- - spec/market_bot/movie/leaderboard_spec.rb
120
+ - spec/market_bot/play/app_spec.rb
121
+ - spec/market_bot/play/chart_spec.rb
122
+ - spec/market_bot/play/data/app-com.bluefroggaming.popdat.txt
123
+ - spec/market_bot/play/data/app-com.mg.android.txt
124
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-0.txt
125
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-1.txt
126
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-2.txt
127
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-3.txt
128
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-4.txt
129
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-5.txt
130
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-6.txt
131
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-7.txt
132
+ - spec/market_bot/play/data/developer-zynga.txt
133
+ - spec/market_bot/play/developer_spec.rb
127
134
  - spec/market_bot_spec.rb
128
135
  - spec/spec_helper.rb
129
136
  homepage: https://github.com/chadrem/market_bot
@@ -150,21 +157,19 @@ signing_key:
150
157
  specification_version: 4
151
158
  summary: 'Market Bot: High performance Ruby scraper for Google''s Android Market'
152
159
  test_files:
153
- - spec/market_bot/android/app_spec.rb
154
- - spec/market_bot/android/data/app_1.txt
155
- - spec/market_bot/android/data/app_2.txt
156
- - spec/market_bot/android/data/app_3.txt
157
- - spec/market_bot/android/data/app_4.txt
158
- - spec/market_bot/android/data/developer-zynga.txt
159
- - spec/market_bot/android/data/leaderboard-apps_editors_choice.txt
160
- - spec/market_bot/android/data/leaderboard-apps_topselling_paid-page1.txt
161
- - spec/market_bot/android/data/leaderboard-apps_topselling_paid-page2.txt
162
- - spec/market_bot/android/data/leaderboard-apps_topselling_paid-page3.txt
163
- - spec/market_bot/android/data/leaderboard-apps_topselling_paid-page4.txt
164
- - spec/market_bot/android/developer_spec.rb
165
- - spec/market_bot/android/leaderboard_spec.rb
166
- - spec/market_bot/android/search_query_spec.rb
167
- - spec/market_bot/movie/data/leaderboard-movies_comedy_topselling_paid.txt
168
- - spec/market_bot/movie/leaderboard_spec.rb
160
+ - spec/market_bot/play/app_spec.rb
161
+ - spec/market_bot/play/chart_spec.rb
162
+ - spec/market_bot/play/data/app-com.bluefroggaming.popdat.txt
163
+ - spec/market_bot/play/data/app-com.mg.android.txt
164
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-0.txt
165
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-1.txt
166
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-2.txt
167
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-3.txt
168
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-4.txt
169
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-5.txt
170
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-6.txt
171
+ - spec/market_bot/play/data/chart-topselling_paid-GAME_ARCADE-7.txt
172
+ - spec/market_bot/play/data/developer-zynga.txt
173
+ - spec/market_bot/play/developer_spec.rb
169
174
  - spec/market_bot_spec.rb
170
175
  - spec/spec_helper.rb
data/NOTES.txt DELETED
@@ -1,61 +0,0 @@
1
- URLs:
2
- - id can be one of the below IDs or an application ID which usually starts with com.
3
- - category is optional and works with a subset of the below IDs.
4
- https://market.android.com/details?id=&cat=
5
- https://market.android.com/details?id=com.angrymobgames.muffinknightfree
6
-
7
- Data Models:
8
- Android::Leaderboard
9
- Android::Leaderboard::Stat
10
- Android::App
11
- Android::App::Stat
12
-
13
- IDs:
14
- apps_topselling_paid
15
- apps_topselling_free
16
- apps_topselling_new_free
17
- apps_topselling_new_paid
18
- apps_editors_choice
19
- apps_topselling_paid_game
20
- apps_movers_shakers
21
- apps_featured
22
- apps_tablet_featured
23
- apps_topgrossing
24
-
25
- Categories:
26
- GAME
27
- ARCADE
28
- BRAIN
29
- CARDS
30
- CASUAL
31
- GAME_WALLPAPER
32
- RACING
33
- SPORTS_GAMES
34
- GAME_WIDGETS
35
- APPLICATION
36
- BOOKS_AND_REFERENCE
37
- BUSINESS
38
- COMICS
39
- COMMUNICATION
40
- EDUCATION
41
- ENTERTAINMENT
42
- FINANCE
43
- HEALTH_AND_FITNESS
44
- LIBRARIES_AND_DEMO
45
- LIFESTYLE
46
- APP_WALLPAPER
47
- MEDIA_AND_VIDEO
48
- MEDICAL
49
- MUSIC_AND_AUDIO
50
- NEWS_AND_MAGAZINES
51
- PERSONALIZATION
52
- PHOTOGRAPHY
53
- PRODUCTIVITY
54
- SHOPPING
55
- SOCIAL
56
- SPORTS
57
- TOOLS
58
- TRANSPORTATION
59
- TRAVEL_AND_LOCAL
60
- WEATHER
61
- APP_WIDGETS
@@ -1,273 +0,0 @@
1
- module MarketBot
2
- module Android
3
-
4
- class App
5
- MARKET_ATTRIBUTES = [
6
- :title,
7
- :rating,
8
- :updated,
9
- :current_version,
10
- :requires_android,
11
- :category,
12
- :installs,
13
- :size,
14
- :price,
15
- :content_rating,
16
- :description,
17
- :votes,
18
- :developer,
19
- :more_from_developer,
20
- :users_also_installed,
21
- :related,
22
- :banner_icon_url,
23
- :banner_image_url,
24
- :website_url,
25
- :email,
26
- :screenshot_urls,
27
- :whats_new,
28
- :permissions,
29
- :rating_distribution,
30
- :html,
31
- :category_url,
32
- :full_screenshot_urls,
33
- :reviews,
34
- ]
35
-
36
- attr_reader :app_id
37
- attr_reader *MARKET_ATTRIBUTES
38
- attr_reader :hydra
39
- attr_reader :lang
40
- attr_reader :callback
41
- attr_reader :error
42
- attr_reader :result
43
-
44
- def self.parse(html)
45
- result = {}
46
-
47
- doc = Nokogiri::HTML(html)
48
- meta_info = doc.css('.meta-info')
49
- meta_info.each do |info|
50
- field_name = info.css('.title').text.strip
51
-
52
- case field_name
53
- when 'Updated'
54
- result[:updated] = info.css('.content').text.strip
55
- when 'Installs'
56
- result[:installs] = info.css('.content').text.strip
57
- when 'Size'
58
- result[:size] = info.css('.content').text.strip
59
- when 'Current Version'
60
- result[:current_version] = info.css('.content').text.strip
61
- when 'Requires Android'
62
- result[:requires_android] = info.css('.content').text.strip
63
- when 'Contact Developer', 'Developer'
64
- info.css('.dev-link').each do |node|
65
- node_href = node[:href]
66
- if node_href =~ /^mailto:/
67
- result[:email] = node_href.gsub(/^mailto:/,'')
68
- else
69
- if q_param = URI(node_href).query.split('&').select{ |p| p =~ /q=/ }.first
70
- actual_url = q_param.gsub('q=', '')
71
- end
72
-
73
- result[:website_url] = actual_url
74
- end
75
- end
76
-
77
- end
78
- end
79
-
80
- result[:content_rating] = doc.css("div.content[itemprop='contentRating']").text
81
-
82
- node = doc.xpath("//meta[@itemprop='price']").first
83
- result[:price] = node[:content].strip rescue 'Free'
84
-
85
- category_div = doc.css('.category').first
86
- result[:category] = category_div.text.strip rescue ''
87
- cat_link = category_div["href"]
88
- path, cat_name = File.split(cat_link)
89
- result[:category_url] = cat_name
90
-
91
- result[:description] = doc.xpath("//div[@itemprop='description']").first.inner_html.strip
92
- result[:title] = doc.css('div.id-app-title').text
93
-
94
- score = doc.css('.score-container').first
95
- unless score.nil?
96
- node = score.css('.score').first
97
- result[:rating] = node.text.strip
98
- node = score.xpath("//meta[@itemprop='ratingCount']").first
99
- result[:votes] = node[:content].strip
100
- end
101
-
102
- node = doc.xpath("//div[@itemprop='author']")
103
- result[:developer] = node.css('.primary').first.text.strip
104
-
105
- result[:more_from_developer] = []
106
- result[:users_also_installed] = []
107
- result[:related] = []
108
-
109
- node = doc.css('.recommendation')
110
- node.css('.rec-cluster').each do |recommended|
111
- assoc_app_type = recommended.css('.heading').first.text.strip.eql?('Similar' ) ? :related : :more_from_developer
112
- recommended.css('.card').each do |card|
113
- assoc_app = {}
114
- assoc_app[:app_id] = card['data-docid'].strip
115
-
116
- result[assoc_app_type] << assoc_app
117
- end
118
- end
119
- # Users also installed is no longer on the page, adding this for backwards compatibility, well, sort of....
120
- result[:users_also_installed] = result[:related]
121
-
122
- node = doc.css('.cover-image').first
123
- unless node.nil?
124
- url = fix_content_url(node[:src])
125
- result[:banner_icon_url] = url
126
- result[:banner_image_url] = url
127
- end
128
-
129
- result[:screenshot_urls] = []
130
- doc.css('.screenshot').each do |node|
131
- result[:screenshot_urls] << fix_content_url(node[:src])
132
- end
133
-
134
- result[:full_screenshot_urls] = []
135
- doc.css('.full-screenshot').each do |node|
136
- result[:full_screenshot_urls] << fix_content_url(node[:src])
137
- end
138
-
139
- node = doc.css('.whatsnew').first
140
- result[:whats_new] = node.inner_html.strip unless node.nil?
141
-
142
- # Stubbing out for now, can't find them in the redesigned page.
143
- result[:permissions] = permissions = []
144
-
145
- result[:reviews] = []
146
- doc.css('.single-review').each do |node|
147
- review = {}
148
- review[:author_name] = node.css('.author-name').text.strip if node.css('.author-name')
149
- raw_tag = node.css('.current-rating').to_s
150
- if raw_tag.match(/100%;/i)
151
- review[:review_score] = 5
152
- elsif raw_tag.match(/80%;/i)
153
- review[:review_score] = 4
154
- elsif raw_tag.match(/60%;/i)
155
- review[:review_score] = 3
156
- elsif raw_tag.match(/40%;/i)
157
- review[:review_score] = 2
158
- elsif raw_tag.match(/20%;/i)
159
- review[:review_score] = 1
160
- end
161
- if node.css('.review-title')
162
- review[:review_title] = node.css('.review-title').text.strip
163
- end
164
- if node.css('.review-body')
165
- review[:review_text] = node.css('.review-body').text
166
- .sub!(review[:review_title],'')
167
- .sub!(node.css('.review-link').text,'')
168
- .strip
169
- end
170
- if review
171
- result[:reviews] << review
172
- end
173
- end
174
-
175
- result[:rating_distribution] = { 5 => nil, 4 => nil, 3 => nil, 2 => nil, 1 => nil }
176
-
177
- histogram = doc.css('div.rating-histogram')
178
- cur_index = 5
179
- %w(five four three two one).each do |slot|
180
- node = histogram.css(".#{slot.to_s}")
181
- result[:rating_distribution][cur_index] = node.css('.bar-number').text.gsub(/,/,'').to_i
182
- cur_index -= 1
183
-
184
- end
185
-
186
- result[:html] = html
187
-
188
- result
189
- end
190
-
191
- def initialize(app_id, options={})
192
- @app_id = app_id
193
- @hydra = options[:hydra] || MarketBot.hydra
194
- @lang = options[:lang] || 'en'
195
- @callback = nil
196
- @error = nil
197
- @request_opts = options[:request_opts] || {}
198
- @request_opts[:timeout] ||= MarketBot.timeout
199
- @request_opts[:connecttimeout] ||= MarketBot.connecttimeout
200
- end
201
-
202
- def market_url
203
- "https://play.google.com/store/apps/details?id=#{@app_id}&hl=#{lang}"
204
- end
205
-
206
- def update
207
- req = Typhoeus::Request.new(market_url, @request_opts)
208
- req.run
209
- result = handle_response(req.response)
210
- update_callback(result)
211
-
212
- self
213
- end
214
-
215
- def enqueue_update(&block)
216
- @callback = block
217
- @error = nil
218
-
219
- request = Typhoeus::Request.new(market_url, @request_opts)
220
-
221
- request.on_complete do |response|
222
- result = nil
223
-
224
- begin
225
- result = handle_response(response)
226
- rescue Exception => e
227
- @error = e
228
- end
229
-
230
- update_callback(result)
231
- end
232
-
233
- hydra.queue(request)
234
-
235
- self
236
- end
237
-
238
- private
239
-
240
- def self.fix_content_url(url)
241
- url =~ /\A\/\// ? "https:#{url}" : url
242
- end
243
-
244
- def handle_response(response)
245
- if response.success?
246
- App.parse(response.body)
247
- else
248
- codes = "code=#{response.code}, return_code=#{response.return_code}"
249
- case response.code
250
- when 404
251
- raise MarketBot::AppNotFoundError.new("Unable to find app in store: #{codes}")
252
- else
253
- raise MarketBot::ResponseError.new("Unhandled response: #{codes}")
254
- end
255
- end
256
- end
257
-
258
- def update_callback(result)
259
- unless @error
260
- @result = result
261
-
262
- MARKET_ATTRIBUTES.each do |a|
263
- attr_name = "@#{a}"
264
- attr_value = result[a]
265
- instance_variable_set(attr_name, attr_value)
266
- end
267
- end
268
-
269
- @callback.call(self) if @callback
270
- end
271
- end
272
- end
273
- end