android_app_index 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5a7cdb9746766ca8825fb6ab4906811507f2f96a
4
- data.tar.gz: 1d9fc4698103a913f8a61425882d29013db7e6b8
3
+ metadata.gz: 8e020f3f623e4bb69b81c5e18f7fee22f6f73c7a
4
+ data.tar.gz: b7ac8d2205abe7834ec827758726df2e4c46015d
5
5
  SHA512:
6
- metadata.gz: ce2a916bc4f15863595cc8cb49f89b0609bdbff692a414b690232b9f338bbcc6234baeb08c228853c2263f13817dfd98adfc023d12379a2a0e273b397102409c
7
- data.tar.gz: 8aa9da2034411a2d7c975c595fec793aeffdd3bb5c1f29996374410201d85f9aec4377ba82ed5c09e82e6ea0bd2dc3f22e211207c5213e4dbca5345f794da46d
6
+ metadata.gz: 30c137c6f3c67411eb15e259df03fbb755ae6bc6b62f45c3c0fb0c3fa8f369ab9cbfa3979cbd8a37c337cf090f4f04ac532a16eaf76ea539fec9aa5bfdd15889
7
+ data.tar.gz: 180c2ea98451dabe8aa99a1cee83386a68680255c4f7c3d93e695effbdc7f61d6295744444f25ce1c9f2cee65825b7c95db30f5b46831497dba0fa2b338d4e53
data/.gitignore CHANGED
@@ -9,4 +9,5 @@
9
9
 
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
- .idea
12
+ .idea
13
+ android_app_index*.gem
@@ -2,11 +2,21 @@ PATH
2
2
  remote: .
3
3
  specs:
4
4
  android_app_index (0.1.0)
5
+ algoliasearch (= 1.19.1)
6
+ nokogiri (= 1.8.1)
5
7
 
6
8
  GEM
7
9
  remote: https://rubygems.org/
8
10
  specs:
11
+ algoliasearch (1.19.1)
12
+ httpclient (~> 2.8.3)
13
+ json (>= 1.5.1)
9
14
  diff-lcs (1.3)
15
+ httpclient (2.8.3)
16
+ json (2.0.4)
17
+ mini_portile2 (2.3.0)
18
+ nokogiri (1.8.1)
19
+ mini_portile2 (~> 2.3.0)
10
20
  rake (10.5.0)
11
21
  rspec (3.7.0)
12
22
  rspec-core (~> 3.7.0)
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
11
11
 
12
12
  spec.summary = 'Index and search android app details'
13
13
  spec.description = 'Search and store <package, name, icon_url> in Algolia'
14
- spec.homepage = "https://reactiverobot.com"
14
+ spec.homepage = 'https://reactiverobot.com'
15
15
  spec.license = 'MIT'
16
16
 
17
17
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
@@ -21,6 +21,9 @@ Gem::Specification.new do |spec|
21
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
22
  spec.require_paths = ['lib']
23
23
 
24
+ spec.add_runtime_dependency 'algoliasearch', '= 1.19.1'
25
+ spec.add_runtime_dependency 'nokogiri', '= 1.8.1'
26
+
24
27
  spec.add_development_dependency 'bundler', '~> 1.16'
25
28
  spec.add_development_dependency 'rake', '~> 10.0'
26
29
  spec.add_development_dependency 'rspec', '~> 3.0'
@@ -1,30 +1,102 @@
1
1
  require 'android_app_index/version'
2
2
  require 'algoliasearch'
3
+ require 'nokogiri'
4
+ require 'open-uri'
3
5
 
4
- class AlgoliaConnetor
5
- def initialize(account_id, account_key)
6
- @account_id = account_id
7
- @account_key = account_key
6
+ # Note that we use the singleton instance of the Algolia client.
7
+ # To use the instance version, we use Algolia::Client.new(application_id, api_key)
8
+ # and pass that Client to Algolia::Index. This is an interesting decision for
9
+ # the algolia api to make. It makes a simple example very easy but actually
10
+ # removes any opinion about how the api should be used. It seems easy enough for
11
+ # users to create a singleton if they want so this seems like a poor API choice on
12
+ # their part.
13
+ Algolia.init application_id: ENV['ANDROID_APP_INDEX_ALGOLIA_APP_ID'],
14
+ api_key: ENV['ANDROID_APP_INDEX_ALGOLIA_API_KEY']
15
+
16
+ class PlayStoreParser
17
+ private def get_page(package)
18
+ Nokogiri::HTML(open("https://play.google.com/store/apps/details?id=#{package}&hl=en"))
19
+ end
20
+
21
+ private def get_icon_url(page)
22
+ images = page.search('img.cover-image').map do |node|
23
+ { alt: node.attribute('alt').value, url: "https:#{node.attribute('src').value}" }
24
+ end
25
+
26
+ images.select { |image| image[:alt] == 'Cover art' }[0][:url]
27
+ end
28
+
29
+ # TODO: Figure out how to properly handle charset.
30
+ private def replace_dash(name)
31
+ name.gsub('&acirc;&#128;&#147;', '-')
32
+ end
33
+
34
+ private def get_name(page)
35
+ replace_dash page.search('div.id-app-title').first.inner_html
36
+ end
37
+
38
+ def parse_play_store(package)
39
+ page = get_page package
40
+
41
+ {
42
+ icon_url: get_icon_url(page),
43
+ name: get_name(page),
44
+ package: package,
45
+ }
8
46
  end
9
47
  end
10
48
 
49
+
11
50
  module AndroidAppIndex
12
- # Your code goes here...
13
- def init(application_id, api_key)
14
- Algolia.init application_id: 'OYBJN03W91',
15
- api_key: 'c5e6af079b42a249e2131c5b5d9d8a37'
16
- end
17
-
18
- def index(package, name, icon_url)
19
- index = Algolia::Index.new('android_apps')
20
- index.add_objects([
21
- {
22
- package: 'com.instagram.android',
23
- icon_url: 'https://lh3.googleusercontent.com/aYbdIM1abwyVSUZLDKoE0CDZGRhlkpsaPOg9tNnBktUQYsXflwknnOn2Ge1Yr7rImGk=w300-rw',
24
- name: 'Instagram',
25
- }
26
- ])
51
+ @play_store_parser = PlayStoreParser.new
52
+ @index = Algolia::Index.new('android_apps')
53
+
54
+ @hit_to_result = lambda { |hit|
55
+ {
56
+ name: hit['name'],
57
+ package: hit['package'],
58
+ icon_url: hit['icon_url']
59
+ }
60
+ }
61
+
62
+ @index_and_parse_play_store = lambda { |package, name, icon_url|
63
+ app_data = {
64
+ package: package,
65
+ icon_url: icon_url,
66
+ name: name
67
+ }
68
+
69
+ needs_details = name.nil? || icon_url.nil?
70
+ app_data = @play_store_parser.parse_play_store(package) if needs_details
71
+
72
+ app_data[:objectID] = package
73
+ @index.add_object(app_data)
74
+ app_data
75
+ }
76
+
77
+ def self.get(package)
78
+ @index.get_object(package)
79
+ rescue Algolia::AlgoliaProtocolError
80
+ # Handle the error that occurs if the app is not yet indexed.
81
+ index package
82
+ end
83
+
84
+ def self.index(package, name = nil, icon_url = nil)
85
+ @index_and_parse_play_store.call(package, name, icon_url)
86
+ rescue OpenURI::HTTPError
87
+ {
88
+ error: 'no_app_found',
89
+ error_message: "Unable to find an app with package=#{package}"
90
+ }
27
91
  end
28
- end
29
92
 
93
+ def self.search(query)
94
+ search_results = @index.search(
95
+ query,
96
+ attributesToRetrieve: 'package,icon_url,name',
97
+ hitsPerPage: 100
98
+ )
30
99
 
100
+ search_results['hits'].map(&@hit_to_result)
101
+ end
102
+ end
@@ -1,3 +1,3 @@
1
1
  module AndroidAppIndex
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: android_app_index
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Dailey
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-01-02 00:00:00.000000000 Z
11
+ date: 2018-01-03 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: algoliasearch
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.19.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.19.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: nokogiri
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 1.8.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 1.8.1
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: bundler
15
43
  requirement: !ruby/object:Gem::Requirement
@@ -60,10 +88,6 @@ extensions: []
60
88
  extra_rdoc_files: []
61
89
  files:
62
90
  - ".gitignore"
63
- - ".idea/android_app_index.iml"
64
- - ".idea/misc.xml"
65
- - ".idea/modules.xml"
66
- - ".idea/workspace.xml"
67
91
  - ".rspec"
68
92
  - ".travis.yml"
69
93
  - CODE_OF_CONDUCT.md