android_app_index 0.1.0 → 0.2.0

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.
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