supermarket 0.0.2-universal-java → 0.0.3-universal-java

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES ADDED
@@ -0,0 +1,15 @@
1
+ 0.0.3 (10/08/20010)
2
+
3
+ * Added Sinatra based web API, deployable to GAE
4
+ * Categories
5
+
6
+ 0.0.2 (03/28/2010)
7
+ 0.0.1
8
+
9
+ * Different output formats (json, xml, html)
10
+ * Image output support
11
+ * Display all comments
12
+
13
+ 0.0.0 (03/23/2010)
14
+
15
+ * Initial Release
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem "json-jruby", :require=>'json'
4
+
5
+ group :development do
6
+ #gem "sinatra-reloader", :require=>"sinatra/reloader"
7
+ #gem "appengine-sdk"
8
+ end
9
+
10
+ group :web do
11
+ gem "sinatra", :require=>"sinatra/base"
12
+ gem "rack-respond_to", :require=>"rack/respond_to"
13
+ gem "rack-abstract-format", :require=>"rack/abstract_format"
14
+ end
15
+
data/README.md CHANGED
@@ -5,7 +5,7 @@ This is a thin JRuby wrapper for the [Android Market API](http://code.google.com
5
5
 
6
6
  It's a new project and only some parts of the protocol have been implemented. I decided to build on top of Java/JRuby because the native Ruby Protocolbuffer implementation ([ruby-protobuf](http://code.google.com/p/ruby-protobuf/)) could not properly handle the [.proto file](http://github.com/jberkel/android-market-api/blob/master/AndroidMarketApi/proto/market.proto) used by the API.
7
7
 
8
- ## Synopis
8
+ ## Synopsis
9
9
  require 'supermarket'
10
10
  session = Supermarket::Session.new
11
11
 
data/Rakefile ADDED
@@ -0,0 +1,167 @@
1
+ require 'rake/clean'
2
+ require 'date'
3
+ CLEAN.include('pkg', 'tmp')
4
+
5
+ #############################################################################
6
+ #
7
+ # Gem related stuff
8
+ #
9
+ #############################################################################
10
+
11
+ def name
12
+ @name ||= Dir['*.gemspec'].first.split('.').first
13
+ end
14
+
15
+ def version
16
+ line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
17
+ line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
18
+ end
19
+
20
+ def date
21
+ Date.today.to_s
22
+ end
23
+
24
+ def rubyforge_project
25
+ name
26
+ end
27
+
28
+ def gemspec_file
29
+ "#{name}.gemspec"
30
+ end
31
+
32
+ def platform
33
+ eval(IO.read(gemspec_file)).platform.to_s
34
+ end
35
+
36
+ def gem_file
37
+ "#{name}-#{version}-#{platform}.gem"
38
+ end
39
+
40
+ def replace_header(head, header_name)
41
+ head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
42
+ end
43
+
44
+ #############################################################################
45
+ #
46
+ # Standard tasks
47
+ #
48
+ #############################################################################
49
+
50
+ task :default => :test
51
+
52
+ desc "Open an irb session preloaded with this library"
53
+ task :console do
54
+ sh "irb -rubygems -r ./lib/#{name}.rb"
55
+ end
56
+
57
+ #############################################################################
58
+ #
59
+ # Packaging tasks
60
+ #
61
+ #############################################################################
62
+
63
+ task :release => :build do
64
+ unless `git branch` =~ /^\* master$/
65
+ puts "You must be on the master branch to release!"
66
+ exit!
67
+ end
68
+ sh "git commit --allow-empty -a -m 'Release #{version}'"
69
+ sh "git tag v#{version}"
70
+ sh "git push origin master --tags"
71
+ sh "gem push pkg/#{name}-#{version}.gem"
72
+ end
73
+
74
+ desc "Builds the gem"
75
+ task :build => :gemspec do
76
+ sh "mkdir -p pkg"
77
+ sh "gem build #{gemspec_file}"
78
+ sh "mv #{gem_file} pkg"
79
+ end
80
+
81
+ task :gemspec => :validate do
82
+ # read spec file and split out manifest section
83
+ spec = File.read(gemspec_file)
84
+ head, manifest, tail = spec.split(" # = MANIFEST =\n")
85
+
86
+ # replace name version and date
87
+ replace_header(head, :name)
88
+ replace_header(head, :version)
89
+ replace_header(head, :date)
90
+ #comment this out if your rubyforge_project has a different name
91
+ replace_header(head, :rubyforge_project)
92
+
93
+ # determine file list from git ls-files
94
+ files = `git ls-files`.
95
+ split("\n").
96
+ sort.
97
+ reject { |file| file =~ /^\./ }.
98
+ reject { |file| file =~ /^(rdoc|pkg)/ }.
99
+ map { |file| " #{file}" }.
100
+ join("\n")
101
+
102
+ # piece file back together and write
103
+ manifest = " s.files = %w[\n#{files}\n ]\n"
104
+ spec = [head, manifest, tail].join(" # = MANIFEST =\n")
105
+ File.open(gemspec_file, 'w') { |io| io.write(spec) }
106
+ puts "Updated #{gemspec_file}"
107
+ end
108
+
109
+ task :validate do
110
+ libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
111
+ unless libfiles.empty?
112
+ puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
113
+ exit!
114
+ end
115
+ unless Dir['VERSION*'].empty?
116
+ puts "A `VERSION` file at root level violates Gem best practices."
117
+ exit!
118
+ end
119
+ end
120
+
121
+ #############################################################################
122
+ #
123
+ # Appengine
124
+ #
125
+ #############################################################################
126
+
127
+ begin
128
+ require 'warber'
129
+
130
+ APPENGINE_WEB_XML = "appengine-web.xml"
131
+ war_dir = "tmp/war"
132
+ directory war_dir
133
+
134
+ warbler = Warbler::Task.new
135
+
136
+ task :explode => [:clean, :war, war_dir] do
137
+ sh "unzip #{warbler.config.war_name}.war -d #{war_dir}"
138
+ sh "mv #{war_dir}/WEB-INF/{.bundle,bundle}"
139
+ end
140
+
141
+ task :explode_gemjar => [:clean, 'war:gemjar', :war, war_dir] do
142
+ sh "unzip #{warbler.config.war_name}.war -d #{war_dir}"
143
+ end
144
+
145
+ desc "deploy to gae"
146
+ task :deploy => [:explode] do
147
+ begin
148
+ require '/opt/homebrew/Cellar/app-engine-java-sdk/1.3.2/lib/appengine-tools-api.jar'
149
+ Java::ComGoogleAppengineToolsAdmin::AppCfg.main(['update', war_dir].to_java(:string))
150
+ rescue LoadError
151
+ sh "appcfg.sh update #{war_dir}"
152
+ end
153
+ end
154
+
155
+ namespace :bundle do
156
+ task :install do
157
+ sh "jruby -S bundle install vendor/gems --disable-shared-gems"
158
+ end
159
+ end
160
+
161
+ def app_version
162
+ require 'rexml/document'
163
+ doc = REXML::Document.new(IO.read(APPENGINE_WEB_XML))
164
+ REXML::XPath.first(doc, 'appengine-web-app/version').text.to_i
165
+ end
166
+ rescue LoadError => e
167
+ end
data/appengine-web.xml ADDED
@@ -0,0 +1,30 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
3
+ <application>supermarket-api</application>
4
+
5
+ <version>6</version>
6
+
7
+ <static-files/>
8
+
9
+ <resource-files>
10
+ </resource-files>
11
+
12
+ <sessions-enabled>false</sessions-enabled>
13
+
14
+ <system-properties>
15
+ <property name="jruby.management.enabled" value="false" />
16
+ <property name="os.arch" value=""/>
17
+ <property name="jruby.compile.mode" value="JIT"/> <!-- JIT|FORCE|OFF -->
18
+ <property name="jruby.compile.fastest" value="true"/>
19
+ <property name="jruby.compile.frameless" value="true"/>
20
+ <property name="jruby.compile.positionless" value="true"/>
21
+ <property name="jruby.compile.threadless" value="false"/>
22
+ <property name="jruby.compile.fastops" value="false"/>
23
+ <property name="jruby.compile.fastcase" value="false"/>
24
+ <property name="jruby.compile.chainsize" value="500"/>
25
+ <property name="jruby.compile.lazyHandles" value="false"/>
26
+ <property name="jruby.compile.peephole" value="true"/>
27
+ <property name="jruby.debug.loadService" value="false"/>
28
+ </system-properties>
29
+ </appengine-web-app>
30
+
data/bin/market CHANGED
@@ -6,17 +6,22 @@ format = ARGV.map { |a| a[/--format=(\w+)/, 1]}.compact.first || "json"
6
6
  image = ARGV.map { |a| a[/--image-out=([^\s]+)/, 1]}.compact.first || "image.jpg"
7
7
 
8
8
  def usage
9
- puts "#{File.basename($0)} [search|comments|all_comments|image|imagedata] [query|app_id] [--format=json|xml|html] [--image-out=file]"
9
+ puts "#{File.basename($0)} [search|comments|all_comments|categories|image|imagedata|icondata] [query|app_id] [--format=json|xml|html] [--image-out=file]"
10
10
  exit 1
11
11
  end
12
12
 
13
13
  case command = ARGV.shift
14
+ when "categories"
15
+ puts Supermarket::Session.new.send(command).send("to_#{format.downcase}")
14
16
  when /\A(search|(all_)?comments|image)\Z/
15
17
  arg = ARGV.shift or usage
16
18
  puts Supermarket::Session.new.send(command, arg).send("to_#{format.downcase}")
17
19
  when 'imagedata'
18
20
  arg = ARGV.shift or usage
19
21
  File.open(image, 'w') { |f| f << Supermarket::Session.new.image_data(arg) }
22
+ when 'icondata'
23
+ arg = ARGV.shift or usage
24
+ File.open(image, 'w') { |f| f << Supermarket::Session.new.image_data(arg, :icon) }
20
25
  else usage
21
26
  end
22
27
 
data/config/warble.rb ADDED
@@ -0,0 +1,16 @@
1
+ require File.join('lib', 'supermarket')
2
+
3
+ Warbler::Config.new do |config|
4
+ config.dirs = %w(lib)
5
+ config.includes = FileList["appengine-web.xml", "config.ru"]
6
+ config.webxml.booter = :rack
7
+
8
+ config.webxml.jruby.min.runtimes = 1
9
+ config.webxml.jruby.max.runtimes = 1
10
+ config.webxml.jruby.init.serial = true
11
+
12
+ market_config = Supermarket::Session.config
13
+ config.webxml['market_login'] = market_config['login']
14
+ config.webxml['market_password'] = market_config['password']
15
+ end
16
+
data/config.ru ADDED
@@ -0,0 +1,13 @@
1
+ require File.expand_path('lib/supermarket/api.rb')
2
+ require 'rack/reloader'
3
+ #Sinatra::Application.set :environment, :production
4
+ use Rack::AbstractFormat
5
+ use Rack::Reloader, 0 if Sinatra::Application.development?
6
+
7
+ map '/login' do
8
+ run Supermarket::ClientLogin
9
+ end
10
+
11
+ map '/api' do
12
+ run Supermarket::Api
13
+ end
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env jruby
2
+
3
+ environment = ['.bundle', 'bundle'].map { |f|
4
+ File.expand_path("../../../#{f}/environment.rb", __FILE__)
5
+ }.select { |f| File.exists?(f) }
6
+
7
+ if environment.empty?
8
+ require 'rubygems'
9
+ require 'bundler'
10
+ Bundler.setup
11
+ else
12
+ require environment.first
13
+ end
14
+
15
+ require File.join(File.dirname(__FILE__), 'session')
16
+ Bundler.require(:default, :web)
17
+
18
+ module Supermarket
19
+ class Api < Sinatra::Base
20
+ include Rack::RespondTo
21
+ reset!
22
+
23
+ not_found do
24
+ content_type :json
25
+ [404, { 'error' => 'not found' }.to_json]
26
+ end
27
+
28
+ get("/:id/comments") do
29
+ session = Session.new
30
+ if comments = session.comments(params[:id])
31
+ respond_to do |wants|
32
+ wants.json {comments.to_json}
33
+ wants.xml {comments.to_xml}
34
+ wants.html {comments.to_html}
35
+ end
36
+ else
37
+ raise Sinatra::NotFound
38
+ end
39
+ end
40
+
41
+ # get("/:id/image") do
42
+ # content_type :jpeg
43
+ #
44
+ # session = Session.new
45
+ # session.image_data(params[:id])
46
+ # end
47
+
48
+ def respond_to
49
+ env['HTTP_ACCEPT'] ||= 'text/html'
50
+ Rack::RespondTo.env = env
51
+
52
+ super { |format|
53
+ yield(format).tap do |response|
54
+ type = Rack::RespondTo::Helpers.match(Rack::RespondTo.media_types, format).first
55
+ content_type(type) if type
56
+ end
57
+ }
58
+ end
59
+ end
60
+
61
+
62
+ class ClientLogin < Sinatra::Base
63
+ reset!
64
+ end
65
+ end
@@ -5,20 +5,17 @@ require File.dirname(__FILE__) + "/jars/protobuf-format-java-1.2-SNAPSHOT.jar"
5
5
  #http://code.google.com/p/protobuf-java-format/
6
6
  module Supermarket
7
7
  module Formats
8
- import 'com.google.protobuf.JsonFormat'
9
- import 'com.google.protobuf.XmlFormat'
10
- import 'com.google.protobuf.HtmlFormat'
11
8
 
12
9
  def to_json(*a)
13
- JsonFormat.printToString(self)
10
+ Java::ComGoogleProtobuf::JsonFormat.printToString(self)
14
11
  end
15
12
 
16
13
  def to_xml
17
- XmlFormat.printToString(self)
14
+ Java::ComGoogleProtobuf::XmlFormat.printToString(self)
18
15
  end
19
16
 
20
17
  def to_html
21
- HtmlFormat.printToString(self)
18
+ Java::ComGoogleProtobuf::HtmlFormat.printToString(self)
22
19
  end
23
20
 
24
21
  def to_ruby
@@ -19,22 +19,30 @@ module Supermarket
19
19
  class Session
20
20
  attr_reader :_session
21
21
 
22
- def initialize
22
+ def initialize(opts={})
23
+ opts.merge!(self.class.config)
23
24
  @_session = MarketSession.new
24
- @_session.login(config['login'], config['password'])
25
+ if opts['authToken']
26
+ @_session.setAuthToken(opts['authToken'])
27
+ else
28
+ raise "Need login and password" unless opts['login'] && opts['password']
29
+ @_session.login(opts['login'], opts['password'])
30
+ end
25
31
  end
26
32
 
27
- def config_file
33
+
34
+ def self.config_file
28
35
  File.join(ENV['HOME'], '.supermarket.yml')
29
36
  end
30
37
 
31
- def config
38
+ def self.config
32
39
  @config ||= begin
33
- unless File.exists?(config_file)
34
- File.open(config_file, 'w') { |f| f << YAML.dump('login'=>'someone@gmail.com', 'password'=>'secr3t') }
35
- raise "Android market config file not found. Please edit #{config_file}"
40
+ if defined? $servlet_context
41
+ { 'login' => $servlet_context.getInitParameter('market_login') ,
42
+ 'password' => $servlet_context.getInitParameter('market_password') }
43
+ else
44
+ File.exists?(config_file) ? YAML.load_file(config_file) : {}
36
45
  end
37
- YAML.load_file(config_file)
38
46
  end
39
47
  end
40
48
 
@@ -48,6 +56,10 @@ module Supermarket
48
56
  execute(request)
49
57
  end
50
58
 
59
+ def categories()
60
+ request = Market::CategoriesRequest.newBuilder().build()
61
+ execute(request)
62
+ end
51
63
 
52
64
  def comments(app_id, start=0, count=10)
53
65
  raise ArgumentError, "need app id" unless app_id
@@ -60,7 +72,8 @@ module Supermarket
60
72
  if resp = execute(request)
61
73
  resp
62
74
  else
63
- raise ArgumentError, "request returned nil"
75
+ #raise ArgumentError, "request returned nil"
76
+ nil
64
77
  end
65
78
  end
66
79
 
@@ -75,16 +88,23 @@ module Supermarket
75
88
  end
76
89
  end
77
90
 
78
- def image(app_id, usage=Market::GetImageRequest::AppImageUsage::SCREENSHOT, image_id='1')
91
+ def image(app_id, usage=:screenshot, image_id='1')
92
+ case usage
93
+ when :screenshot
94
+ usage_const = Market::GetImageRequest::AppImageUsage::SCREENSHOT
95
+ when :icon
96
+ usage_const = Market::GetImageRequest::AppImageUsage::ICON
97
+ end
98
+
79
99
  request = Market::GetImageRequest.newBuilder().
80
100
  setAppId(pkg_to_app_id(app_id)).
81
- setImageUsage(usage).
101
+ setImageUsage(usage_const).
82
102
  setImageId(image_id).build()
83
103
 
84
104
  execute(request)
85
105
  end
86
106
 
87
- def image_data(app_id, usage=Market::GetImageRequest::AppImageUsage::SCREENSHOT, image_id='1')
107
+ def image_data(app_id, usage=:screenshot, image_id='1')
88
108
  if resp = image(app_id, usage, image_id)
89
109
  String.from_java_bytes(resp.getImageData().toByteArray())
90
110
  else
data/lib/supermarket.rb CHANGED
@@ -1 +1,5 @@
1
+ module Supermarket
2
+ VERSION = '0.0.3'
3
+ end
4
+
1
5
  require File.join(File.dirname(__FILE__), 'supermarket', 'session')
@@ -0,0 +1,46 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'supermarket'
3
+ s.version = '0.0.3'
4
+ s.platform = 'universal-java'
5
+
6
+ s.rubyforge_project = 'supermarket'
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Jan Berkel"]
9
+ s.date = '2010-08-10'
10
+ s.default_executable = %q{market}
11
+ s.description = %q{An unoffical/reverse engineered API for Android market.}
12
+ s.email = %q{jan.berkel@gmail.com}
13
+ s.executables = ["market"]
14
+ s.extra_rdoc_files = [
15
+ "README.md"
16
+ ]
17
+
18
+ # = MANIFEST =
19
+ s.files = %w[
20
+ CHANGES
21
+ Gemfile
22
+ README.md
23
+ Rakefile
24
+ appengine-web.xml
25
+ bin/market
26
+ config.ru
27
+ config/warble.rb
28
+ lib/supermarket.rb
29
+ lib/supermarket/api.rb
30
+ lib/supermarket/formats.rb
31
+ lib/supermarket/jars/AndroidMarketApi.jar
32
+ lib/supermarket/jars/protobuf-format-java-1.2-SNAPSHOT.jar
33
+ lib/supermarket/jars/protobuf-java-2.2.0.jar
34
+ lib/supermarket/session.rb
35
+ supermarket.gemspec
36
+ ]
37
+ # = MANIFEST =
38
+ s.homepage = %q{http://github.com/jberkel/supermarket}
39
+ s.rdoc_options = ["--charset=UTF-8"]
40
+ s.require_paths = ["lib"]
41
+ s.rubygems_version = %q{1.3.6}
42
+ s.summary = %q{JRuby bindings for android-market-api}
43
+
44
+ s.add_dependency(%q<json-jruby>, [">= 0"])
45
+ end
46
+
metadata CHANGED
@@ -3,75 +3,83 @@ name: supermarket
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
- - 0
7
- - 0
8
- - 2
9
- version: 0.0.2
6
+ - 0
7
+ - 0
8
+ - 3
9
+ version: 0.0.3
10
10
  platform: universal-java
11
11
  authors:
12
- - Jan Berkel
12
+ - Jan Berkel
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-03-29 00:00:00 +02:00
17
+ date: 2010-08-10 00:00:00 +02:00
18
18
  default_executable: market
19
19
  dependencies:
20
- - !ruby/object:Gem::Dependency
21
- name: json-jruby
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
24
- requirements:
25
- - - ">="
26
- - !ruby/object:Gem::Version
27
- segments:
28
- - 0
29
- version: "0"
30
- type: :runtime
31
- version_requirements: *id001
20
+ - !ruby/object:Gem::Dependency
21
+ name: json-jruby
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ version_requirements: *id001
32
32
  description: An unoffical/reverse engineered API for Android market.
33
33
  email: jan.berkel@gmail.com
34
34
  executables:
35
- - market
35
+ - market
36
36
  extensions: []
37
37
 
38
38
  extra_rdoc_files:
39
- - README.md
39
+ - README.md
40
40
  files:
41
- - bin/market
42
- - lib/supermarket.rb
43
- - lib/supermarket/formats.rb
44
- - lib/supermarket/jars/AndroidMarketApi.jar
45
- - lib/supermarket/jars/protobuf-format-java-1.2-SNAPSHOT.jar
46
- - lib/supermarket/jars/protobuf-java-2.2.0.jar
47
- - lib/supermarket/session.rb
48
- - README.md
41
+ - CHANGES
42
+ - Gemfile
43
+ - README.md
44
+ - Rakefile
45
+ - appengine-web.xml
46
+ - bin/market
47
+ - config.ru
48
+ - config/warble.rb
49
+ - lib/supermarket.rb
50
+ - lib/supermarket/api.rb
51
+ - lib/supermarket/formats.rb
52
+ - lib/supermarket/jars/AndroidMarketApi.jar
53
+ - lib/supermarket/jars/protobuf-format-java-1.2-SNAPSHOT.jar
54
+ - lib/supermarket/jars/protobuf-java-2.2.0.jar
55
+ - lib/supermarket/session.rb
56
+ - supermarket.gemspec
49
57
  has_rdoc: true
50
58
  homepage: http://github.com/jberkel/supermarket
51
59
  licenses: []
52
60
 
53
61
  post_install_message:
54
62
  rdoc_options:
55
- - --charset=UTF-8
63
+ - --charset=UTF-8
56
64
  require_paths:
57
- - lib
65
+ - lib
58
66
  required_ruby_version: !ruby/object:Gem::Requirement
59
67
  requirements:
60
- - - ">="
61
- - !ruby/object:Gem::Version
62
- segments:
63
- - 0
64
- version: "0"
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
72
+ version: "0"
65
73
  required_rubygems_version: !ruby/object:Gem::Requirement
66
74
  requirements:
67
- - - ">="
68
- - !ruby/object:Gem::Version
69
- segments:
70
- - 0
71
- version: "0"
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ segments:
78
+ - 0
79
+ version: "0"
72
80
  requirements: []
73
81
 
74
- rubyforge_project:
82
+ rubyforge_project: supermarket
75
83
  rubygems_version: 1.3.6
76
84
  signing_key:
77
85
  specification_version: 3