Skip to content

Commit

Permalink
rework initilizaton for cleaner public API.
Browse files Browse the repository at this point in the history
  • Loading branch information
sfaxon committed Aug 20, 2011
1 parent ebab630 commit e12bfb9
Show file tree
Hide file tree
Showing 10 changed files with 184 additions and 78 deletions.
4 changes: 4 additions & 0 deletions Gemfile
Expand Up @@ -2,3 +2,7 @@ source "http://rubygems.org"

# Specify your gem's dependencies in remote_book.gemspec
gemspec

group :development do
gem 'ruby-debug19', :require => 'ruby-debug'
end
34 changes: 34 additions & 0 deletions README
@@ -0,0 +1,34 @@
# RemoteBook

RemoteBook is a gem for searching Amazon & B&N for books. Returned links have associate information in the links.

## Installation

It's a gem. Either run `gem install remote_book` at the command line, or add `gem 'remote_book'` to your Gemfile.

## Usage

Get your affiliate digits:

https://affiliate-program.amazon.com/
http://affiliates.barnesandnoble.com/ - sign up with LinkShare

for rails, run the install generator:

add something like this to an initializer

RemoteBook::Amazon.associate_keys = {:associates_id => "me",
:key_id => "digits",
:secret_key => "secret_digits"}

Right now it just searches by ISBN, so:

a = RemoteBook::Amazon.find_by_isbn("somedigits")
a.large_image
a.medium_image
a.small_image
a.link
a.author
a.title


1 change: 1 addition & 0 deletions VERSION
@@ -0,0 +1 @@
0.0.1
13 changes: 9 additions & 4 deletions lib/remote_book.rb
@@ -1,7 +1,12 @@
require "remote_book/version"
require "remote_book/remote_book"
require "remote_book/amazon_book"
require "rubygems"
require "uri"
require "openssl"
require "typhoeus"
require "nokogiri"

require "remote_book/base"
require "remote_book/amazon"

module RemoteBook
# Your code goes here...
VERSION = File.read(File.dirname(__FILE__) + "/../VERSION").chomp
end
87 changes: 87 additions & 0 deletions lib/remote_book/amazon.rb
@@ -0,0 +1,87 @@
module RemoteBook
class Amazon < RemoteBook::Base
# mac os 10.5 does not ship with SHA256 support built into ruby, 10.6 does.
DIGEST_SUPPORT = ::OpenSSL::Digest.constants.include?('SHA256') || ::OpenSSL::Digest.constants.include?(:SHA256)
DIGEST = ::OpenSSL::Digest::Digest.new('sha256') if DIGEST_SUPPORT

def self.find(options)
a = new
# unless DIGEST_SUPPORT raise "no digest sup"
if options[:isbn]
req = build_isbn_lookup_query(options[:isbn])
response = Typhoeus::Request.get(req)

if 200 == response.code
xml_doc = Nokogiri.XML(response.body)
else
return false
end

if 1 == xml_doc.xpath("//xmlns:Items").size
if xml_doc.xpath("//xmlns:Items/xmlns:Item/xmlns:LargeImage/xmlns:URL")
a.large_image = xml_doc.xpath("//xmlns:Items/xmlns:Item/xmlns:LargeImage/xmlns:URL").inner_text
end
if xml_doc.xpath("//xmlns:Items/xmlns:Item/xmlns:MediumImage/xmlns:URL")
a.medium_image = xml_doc.xpath("//xmlns:Items/xmlns:Item/xmlns:MediumImage/xmlns:URL").inner_text
end
if xml_doc.xpath("//xmlns:Items/xmlns:Item/xmlns:SmallImage/xmlns:URL")
a.small_image = xml_doc.xpath("//xmlns:Items/xmlns:Item/xmlns:SmallImage/xmlns:URL")
end
a.title = xml_doc.xpath("//xmlns:Items/xmlns:Item/xmlns:ItemAttributes/xmlns:Title").inner_text
a.authors = []
xml_doc.xpath("//xmlns:Items/xmlns:Item/xmlns:ItemAttributes/xmlns:Author").each do |author|
a.authors << author.inner_text
end
# ewww
if xml_doc.xpath("//xmlns:Items/xmlns:Item/xmlns:ItemLinks/xmlns:ItemLink/xmlns:Description='Technical Details'")
xml_doc.xpath("//xmlns:Items/xmlns:Item/xmlns:ItemLinks/xmlns:ItemLink").each do |item_link|
if "Technical Details" == item_link.xpath("xmlns:Description").inner_text
a.link = item_link.xpath("xmlns:URL").inner_text
end
end
end
end
end
return a
end

private
def self.build_isbn_lookup_query(item_id)
base = "http://ecs.amazonaws.com/onca/xml"
query = "Service=AWSECommerceService&"
query << "AWSAccessKeyId=#{associate_keys[:key_id]}&"
query << "AssociateTag=#{associate_keys[:associates_id]}&"
query << "Operation=ItemLookup&"
query << "ItemId=#{item_id}&"
query << "ResponseGroup=ItemAttributes,Offers,Images&"
# query << "ResponseGroup=ItemAttributes&"
query << "Version=2009-07-01"
sig_query = sign_query base, query, associate_keys[:secret_key]
base + "?" + sig_query
end
# most of this is from http://www.justinball.com/2009/09/02/amazon-ruby-and-signing_authenticating-your-requests/
# which is actually from the ruby-aaws gem
def self.sign_query(uri, query, amazon_secret_access_key = "", locale = :us)
uri = URI.parse(uri)
# only add current timestamp if it's not in the query, a timestamp passed in via query takes precedence
# I'm only doing this so the checksum comes out correctly with the example from the amazon documentation
query << "&Timestamp=#{Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')}" unless query.include?("Timestamp")
new_query = query.split('&').collect{|param| "#{param.split('=')[0]}=#{url_encode(param.split('=')[1])}"}.sort.join('&')
# puts new_query
to_sign = "GET\n%s\n%s\n%s" % [uri.host, uri.path, new_query]
# step 7 of http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/index.html?rest-signature.html
hmac = OpenSSL::HMAC.digest(DIGEST, amazon_secret_access_key, to_sign)
base64_hmac = [hmac].pack('m').chomp
signature = url_encode(base64_hmac)

new_query << "&Signature=#{signature}"
end

# Shamelessly plagiarised from Wakou Aoyama's cgi.rb, but then altered slightly to please AWS.
def self.url_encode(str)
str.gsub( /([^a-zA-Z0-9_.~-]+)/ ) do
'%' + $1.unpack( 'H2' * $1.bytesize ).join( '%' ).upcase
end
end
end
end
55 changes: 0 additions & 55 deletions lib/remote_book/amazon_book.rb

This file was deleted.

31 changes: 31 additions & 0 deletions lib/remote_book/base.rb
@@ -0,0 +1,31 @@
module RemoteBook
class Base
attr_accessor :large_image, :medium_image, :small_image, :link, :authors, :title, :isbn, :digital_link

def author
@authors.join(", ")
end

class << self
def associate_keys
@@associate_keys ||= {}
end

def associate_keys=(obj)
@@associate_keys = obj
end

def setup
yield self
end

def find_by_isbn(isbn)
self.find(:isbn => isbn)
end

def find(options)

end
end
end
end
13 changes: 0 additions & 13 deletions lib/remote_book/remote_book.rb

This file was deleted.

3 changes: 0 additions & 3 deletions lib/remote_book/version.rb

This file was deleted.

21 changes: 18 additions & 3 deletions remote_book.gemspec
@@ -1,20 +1,35 @@
# -*- encoding: utf-8 -*-
$:.push File.expand_path("../lib", __FILE__)
require "remote_book/version"
require "remote_book"

Gem::Specification.new do |s|
s.name = "remote_book"
s.version = RemoteBook::VERSION
s.authors = ["Seth Faxon"]
s.email = ["seth.faxon@gmail.com"]
s.homepage = ""
s.summary = %q{TODO: Write a gem summary}
s.description = %q{TODO: Write a gem description}
s.summary = %q{Pull book affiliate links and images from Amazon, Barns & Noble}
s.description = %q{Pull book affiliate links and images from Amazon, Barns & Noble}

s.rubyforge_project = "remote_book"

s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
s.require_paths = ["lib"]

if s.respond_to? :specification_version then
s.specification_version = 3

if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
s.add_runtime_dependency(%q<typhoeus>)
s.add_runtime_dependency(%q<nokogiri>)
else
s.add_dependency(%q<typhoeus>)
s.add_dependency(%q<nokogiri>)
end
else
s.add_dependency(%q<typhoeus>)
s.add_dependency(%q<nokogiri>)
end
end

0 comments on commit e12bfb9

Please sign in to comment.