diff --git a/lib/app_store/application.rb b/lib/app_store/application.rb
index b47cc37..ce30ffa 100644
--- a/lib/app_store/application.rb
+++ b/lib/app_store/application.rb
@@ -1,9 +1,9 @@
require "app_store/base"
require "app_store/company"
require "app_store/user_review"
-require "app_store/artwork"
require "app_store/list"
require "app_store/link"
+require "app_store/image"
# Represents an application in the AppStore.
# = Available attributes:
@@ -54,16 +54,15 @@ class AppStore::Application < AppStore::Base
attr_reader :company, :price, :size, :artworks, :icon, :icon_thumbnail, :screenshots
- plist :accepted_type => 'software',
- :mapping => {
- 'average-user-rating' => :average_user_rating,
- 'user-rating-count' => :user_rating_count,
- 'release-date' => :release_date,
- 'description' => :description,
- 'item-id' => :item_id,
- 'version' => :version,
- 'title' => :title
- }
+ plist :mapping => {
+ 'average-user-rating' => :average_user_rating,
+ 'user-rating-count' => :user_rating_count,
+ 'release-date' => :release_date,
+ 'description' => :description,
+ 'item-id' => :item_id,
+ 'version' => :version,
+ 'title' => :title
+ }
# Search an Application by its id. Accepts only one id and returns an Application instance.
def self.find_by_id(id, options = {})
@@ -101,8 +100,10 @@ def itunes_url
def icon
if @icon.nil?
- parsed = @client.itunes_get(AppStore::Client::ApplicationURL, :id => item_id)
- @icon = AppStore::Image.new(:plist => parsed.search('PictureView[@height="100"][@width="100"]').first)
+ parsed = @client.browser_get(AppStore::Client::ApplicationURL, :id => item_id)
+
+ plist = parsed.search('PictureView[@height="100"][@width="100"]').first
+ @icon = AppStore::Image.new(:plist => plist) if plist
end
@icon
@@ -110,6 +111,8 @@ def icon
protected
def custom_init_from_plist(plist)
+ client = AppStore::Client.new
+
# Set size and price
@price = plist['store-offers']['STDQ']['price']
@size = plist['store-offers']['STDQ']['size']
@@ -117,16 +120,39 @@ def custom_init_from_plist(plist)
# Seek for company
@company = AppStore::Company.new(:plist => plist['company'])
+ icons = []
+
# Parse artwork
- @artworks = plist['artwork-urls'].collect do |plist_artwork|
- # OPTIMIZE : handle default_screenshot
- if plist_artwork['image-type'] and plist_artwork['default']
- artwork = AppStore::Artwork.new :plist => plist_artwork
- @icon_thumbnail ||= artwork.default if artwork.is_icon?
- @screenshots << artwork.default unless artwork.is_icon?
- artwork
+ @artworks = plist['artwork-urls'].collect do |plist_artwork_p|
+ if plist_artwork_p.include?("default@2x")
+ plist_artwork = plist_artwork_p["default@2x"]
+ elsif plist_artwork_p.include?("default")
+ plist_artwork = plist_artwork_p["default"]
+ else
+ plist_artwork = plist_artwork_p
end
+
+ result = AppStore::Image.new :plist => plist_artwork
+
+ icons << result if plist_artwork_p["image-type"] == "software-icon"
+
+ result
end
+
@artworks.compact!
+
+ @icon_thumbnail ||= @artworks.first if @artworks.size > 0
+
+ if icons.size > 0
+ @icon = icons.sort_by { |icon| icon.width * icon.height }.last
+
+ icon_url = @icon.url.dup
+ icon_url[/\d+x\d+/] = "512x512"
+
+ if icon_url != @icon.url then
+ result = begin; client.browser_get(icon_url); rescue Mechanize::ResponseCodeError; nil; end
+ @icon.url.replace(icon_url) if result
+ end
+ end
end
end
\ No newline at end of file
diff --git a/lib/app_store/artwork.rb b/lib/app_store/artwork.rb
deleted file mode 100644
index 0accaba..0000000
--- a/lib/app_store/artwork.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require "app_store/base"
-require "app_store/image"
-
-class AppStore::Artwork < AppStore::Base
- attr_reader :default, :thumbnail
-
- plist :mapping => { 'image-type' => :image_type }
-
- def is_icon?
- image_type == 'software-icon'
- end
-
- protected
- def custom_init_from_plist(plist)
- @default = AppStore::Image.new(:plist => plist['default']) if plist['default']
- @thumbnail = AppStore::Image.new(:plist => plist['thumbnail']) if plist['thumbnail']
- end
-
-end
\ No newline at end of file
diff --git a/lib/app_store/client.rb b/lib/app_store/client.rb
index bc31074..f9f84f7 100644
--- a/lib/app_store/client.rb
+++ b/lib/app_store/client.rb
@@ -4,6 +4,7 @@
require "plist"
require "app_store"
+require "app_store/plist_parser"
# Client regroups all the calling and xml parsing mechanism to call the AppStore.
class AppStore::Client
@@ -44,7 +45,7 @@ def initialize(args = {})
# Call the Apple AppStore using given url and passing params with an HTTP Get method.
# Call is seen as a fake iPhone iTunes client.
def iphone_get(url, params = {})
- Plist::parse_xml make_call_and_handle_answer(iphone_agent, url, params).body
+ make_call_and_handle_answer(iphone_agent, url, params)
end
alias :get :iphone_get
@@ -52,16 +53,28 @@ def iphone_get(url, params = {})
# Call the Apple AppStore using given url and passing params with HTTP Get method.
# Call is seen as a fake Mac OS X iTunes client.
def itunes_get(url, params = {})
- Nokogiri.parse make_call_and_handle_answer(itunes_agent, url, params).body
+ make_call_and_handle_answer(itunes_agent, url, params)
+ end
+
+ def browser_get(url, params = {})
+ make_call_and_handle_answer(browser_agent, url, params)
end
protected
+ def setup_agent(agent)
+ agent.pluggable_parser['text/xml'] = PlistParser
+ end
+
def iphone_agent
- @iphone_agent ||= WWW::Mechanize.new { |a| a.user_agent = 'iTunes-iPhone/3.0 (2)' }
+ @iphone_agent ||= Mechanize.new { |a| setup_agent(a); a.user_agent = 'iTunes-iPhone/3.0 (2)' }
end
def itunes_agent
- @itunes_agent ||= WWW::Mechanize.new { |a| a.user_agent = 'iTunes/9.0.1 (Macintosh; Intel Mac OS X 10.6.1) AppleWebKit/531.9' }
+ @itunes_agent ||= Mechanize.new { |a| setup_agent(a); a.user_agent = 'iTunes/9.0.1 (Macintosh; Intel Mac OS X 10.6.1) AppleWebKit/531.9' }
+ end
+
+ def browser_agent
+ @itunes_agent ||= Mechanize.new { |a| setup_agent(a); a.user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7.4) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.56 Safari/536.5' }
end
def headers
@@ -74,7 +87,7 @@ def headers
# Make call using given agent, url and params.
# Handle answer code and returns answer if answer code was correct.
def make_call_and_handle_answer(agent, url, params)
- answer = agent.get(:url => url, :headers => headers, :params => params)
+ answer = agent.get(url, params, nil, headers)
raise AppStore::RequestError if answer.code.to_s != '200'
answer
end
diff --git a/lib/app_store/link.rb b/lib/app_store/link.rb
index 3cdec18..444a145 100644
--- a/lib/app_store/link.rb
+++ b/lib/app_store/link.rb
@@ -11,7 +11,7 @@ class AppStore::Link < AppStore::Base
def destination
@destination ||= case @item_type
when 'software'
- AppStore::Application.new :plist => @client.get(@url)['item-metadata'],
+ AppStore::Application.new :plist => @client.itunes_get(@url)['item-metadata'] || @raw,
:client => @client
else
raise 'unsupported'
diff --git a/lib/app_store/plist_parser.rb b/lib/app_store/plist_parser.rb
new file mode 100644
index 0000000..8ee42ea
--- /dev/null
+++ b/lib/app_store/plist_parser.rb
@@ -0,0 +1,20 @@
+require 'mechanize'
+
+class PlistParser < Mechanize::File
+ extend Forwardable
+
+ attr_accessor :mech, :plist
+
+ def initialize(uri=nil, response=nil, body=nil, code=nil, mech=nil)
+ raise 'no' if mech and not Mechanize === mech
+ @mech = mech
+
+ super uri, response, body, code
+
+ @plist = @body ? Plist::parse_xml(@body) : nil
+ end
+
+ def_delegator :plist, :[], :[]
+ def_delegator :plist, :search, :search
+end
+
\ No newline at end of file
diff --git a/test/client_test.rb b/test/client_test.rb
index 89271c5..5756435 100644
--- a/test/client_test.rb
+++ b/test/client_test.rb
@@ -10,7 +10,7 @@ class ClientTest < Test::Unit::TestCase
end
should "returns a mechanize agent on call to iphone_agent" do
- assert_kind_of WWW::Mechanize, @client.iphone_agent
+ assert_kind_of Mechanize, @client.iphone_agent
end
should "set mechanize user agent to iTunes-iPhone/3.0 (2) for iphone_agent" do
@@ -18,7 +18,7 @@ class ClientTest < Test::Unit::TestCase
end
should "returns a mechanize agent on call to itunes_agent" do
- assert_kind_of WWW::Mechanize, @client.itunes_agent
+ assert_kind_of Mechanize, @client.itunes_agent
end
should "set mechanize user agent to iTunes/9.0.1 (Macintosh; Intel Mac OS X 10.6.1) AppleWebKit/531.9 for itunes_agent" do