bookle 0.0.1
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.
- data/lib/bookle/google_books_access_info.rb +26 -0
- data/lib/bookle/google_books_api.rb +155 -0
- data/lib/bookle/google_books_epub.rb +18 -0
- data/lib/bookle/google_books_image_links.rb +15 -0
- data/lib/bookle/google_books_industry_identifier.rb +17 -0
- data/lib/bookle/google_books_item.rb +29 -0
- data/lib/bookle/google_books_items.rb +23 -0
- data/lib/bookle/google_books_list_price.rb +13 -0
- data/lib/bookle/google_books_pdf.rb +18 -0
- data/lib/bookle/google_books_price.rb +15 -0
- data/lib/bookle/google_books_retail_price.rb +13 -0
- data/lib/bookle/google_books_sale_info.rb +22 -0
- data/lib/bookle/google_books_search_info.rb +13 -0
- data/lib/bookle/google_books_volume_info.rb +38 -0
- data/lib/bookle.rb +8 -0
- data/lib/cacert/cacert.pem +3390 -0
- metadata +83 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'bookle/google_books_epub'
|
2
|
+
require 'bookle/google_books_pdf'
|
3
|
+
|
4
|
+
module Google
|
5
|
+
module Books
|
6
|
+
class AccessInfo
|
7
|
+
attr_reader :access_country, :viewability, :embeddable, :public_domain, :text_to_speech_permission, :epub, :pdf, :web_reader_link,
|
8
|
+
:access_view_status
|
9
|
+
|
10
|
+
def initialize(access_info)
|
11
|
+
if access_info
|
12
|
+
@access_country = access_info["country"]
|
13
|
+
@viewability = access_info["viewability"]
|
14
|
+
@embeddable = access_info["embeddable"]
|
15
|
+
@public_domain = access_info["publicDomain"]
|
16
|
+
@text_to_speech_permission = access_info["textToSpeechPermission"]
|
17
|
+
@epub = Google::Books::Epub.new(access_info["epub"])
|
18
|
+
@pdf = Google::Books::Pdf.new(access_info["pdf"])
|
19
|
+
@web_reader_link = access_info["webReaderLink"]
|
20
|
+
@access_view_status = access_info["accessViewStatus"]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
# OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
|
2
|
+
# Solution to SSL problem on Windows:
|
3
|
+
# https://gist.github.com/867550
|
4
|
+
# https://www.googleapis.com/books/v1/volumes?key=AIzaSyAUJ0psGl0udam2kFzT29L2YWAhCF748ik&q=inauthor:keyes&maxResults=40&startIndex=40
|
5
|
+
|
6
|
+
require 'net/https'
|
7
|
+
require 'bookle/google_books_items'
|
8
|
+
|
9
|
+
module Google
|
10
|
+
module Books
|
11
|
+
class API
|
12
|
+
|
13
|
+
GOOGLE_OPTIONAL_PARAMETERS = {
|
14
|
+
'start_index_at' => 'startIndex', # starts at 0 (default)
|
15
|
+
'maximum_results' => 'maxResults' # [0..40], default=10
|
16
|
+
}
|
17
|
+
|
18
|
+
# Prefixed some of the keywords with 'in_' to convey the Google meaning that the value is found *in* the content.
|
19
|
+
# Google differentiates between *in* content and *is* content.
|
20
|
+
GOOGLE_QUERY_KEYWORDS = {
|
21
|
+
'title' => 'intitle',
|
22
|
+
'author' => 'inauthor',
|
23
|
+
'publisher' => 'inpublisher',
|
24
|
+
'subject' => 'subject', # *in* subject
|
25
|
+
'isbn' => 'isbn', # ISBN
|
26
|
+
'lccn' => 'lccn', # Library of Congress Control Number
|
27
|
+
'oclc' => 'oclc' # Online Computer Library Center number
|
28
|
+
}
|
29
|
+
|
30
|
+
attr_reader :total_volumes, :volumes, :volume, :raw_response
|
31
|
+
|
32
|
+
attr_accessor *(GOOGLE_QUERY_KEYWORDS.keys + GOOGLE_OPTIONAL_PARAMETERS.keys).map{|method_name| method_name.to_sym} << :google_books_api_key
|
33
|
+
|
34
|
+
def initialize(google_books_api_key)
|
35
|
+
@google_books_api_key = google_books_api_key
|
36
|
+
@total_volumes = 0
|
37
|
+
@volumes = []
|
38
|
+
end
|
39
|
+
|
40
|
+
def search_accessors
|
41
|
+
GOOGLE_QUERY_KEYWORDS.keys + GOOGLE_OPTIONAL_PARAMETERS.keys
|
42
|
+
end
|
43
|
+
|
44
|
+
def clear_search_options
|
45
|
+
search_accessors.each do |method_name|
|
46
|
+
__send__ "#{method_name}=".to_sym, nil
|
47
|
+
end
|
48
|
+
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
|
52
|
+
# Build and also let the user query the string.
|
53
|
+
# schema = https
|
54
|
+
# host = www.googleapis.com`
|
55
|
+
# path = books/v1/volumes
|
56
|
+
# key marker = key
|
57
|
+
# query marker = q
|
58
|
+
# keyword separator = + (used in build_query_options())
|
59
|
+
def uri_string
|
60
|
+
"https://www.googleapis.com/books/v1/volumes?key=#{@google_books_api_key}#{build_optional_parameters}&q=#{build_query_options}"
|
61
|
+
end
|
62
|
+
|
63
|
+
# The Google Books API builds its query using 'OR', not 'AND'. That means that the more keywords used during the search
|
64
|
+
# the wider the range of results.
|
65
|
+
# When search options are passed to this method prior search options set with the set_search_option method will be disregarded.
|
66
|
+
# def search(isbn='9780140196092')
|
67
|
+
def search
|
68
|
+
google_response = nil
|
69
|
+
uri = URI(uri_string)
|
70
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
71
|
+
http.use_ssl = uri.scheme == 'https'
|
72
|
+
http.ca_file = cacert_path
|
73
|
+
|
74
|
+
http.start {http.request_get("#{uri.path}?#{uri.query}") {|response| @raw_response = response.body}}
|
75
|
+
|
76
|
+
items = Google::Books::Items.new(@raw_response)
|
77
|
+
|
78
|
+
@total_volumes = items.total_items || 0
|
79
|
+
@volumes = items.items || []
|
80
|
+
@volume = volumes.first
|
81
|
+
|
82
|
+
items
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
# cacert = certification authority certificates
|
87
|
+
def update_cacert_file
|
88
|
+
file_path = cacert_path
|
89
|
+
|
90
|
+
Net::HTTP.start("curl.haxx.se") do |http|
|
91
|
+
resp = http.get("/ca/cacert.pem")
|
92
|
+
|
93
|
+
if resp.code == "200"
|
94
|
+
File.delete("#{file_path}_old") if File.exists?("#{file_path}_old")
|
95
|
+
File.rename(file_path, "#{file_path}_old")
|
96
|
+
File.open(file_path, "w") {|file| file.write(resp.body)}
|
97
|
+
|
98
|
+
puts "\n\nAn updated version of the file with the certfication authority certificates has been installed to"
|
99
|
+
puts "#{cacert_path}\n\n"
|
100
|
+
else
|
101
|
+
puts "\n\nUnable to download a new version of the certification authority certificates.\n"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
rescue => e
|
105
|
+
puts "\n\nErrors were encountered while updating the certification authority certificates file.\n"
|
106
|
+
|
107
|
+
unless File.exists?(file_path)
|
108
|
+
if File.exists?("#{file_path}_old")
|
109
|
+
File.rename("#{file_path}_old", file_path)
|
110
|
+
else
|
111
|
+
puts "\nThe certification authority certificates file could not be found nor restored.\n"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
puts "\nError information:\n"
|
116
|
+
puts e.message
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
def build_optional_parameters
|
123
|
+
string = ''
|
124
|
+
|
125
|
+
GOOGLE_OPTIONAL_PARAMETERS.each do |method_name, query_parameter|
|
126
|
+
unless __send__(method_name.to_sym).nil?
|
127
|
+
# Need to escape values or search might fail due to spaces, etc.
|
128
|
+
string += "&#{query_parameter}=#{URI.escape(__send__(method_name.to_sym).to_s)}"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
string
|
133
|
+
end
|
134
|
+
|
135
|
+
def build_query_options
|
136
|
+
string = ''
|
137
|
+
|
138
|
+
GOOGLE_QUERY_KEYWORDS.each do |method_name, query_keyword|
|
139
|
+
unless __send__(method_name.to_sym).nil?
|
140
|
+
# Need to escape values or search might fail due to spaces, etc.
|
141
|
+
string += "#{query_keyword}:#{URI.escape(__send__(method_name.to_sym).to_s)}+"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# Return string except for last keyword separator.
|
146
|
+
string.chop
|
147
|
+
end
|
148
|
+
|
149
|
+
def cacert_path
|
150
|
+
File.dirname(`gem which bookle`.chomp) + '/cacert/cacert.pem'
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Google
|
2
|
+
module Books
|
3
|
+
class Epub
|
4
|
+
attr_reader :is_available
|
5
|
+
|
6
|
+
def initialize(epub)
|
7
|
+
if epub
|
8
|
+
@is_available = epub["isAvailable"]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_hash
|
13
|
+
{"is_epub_available" => self.is_available}
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Google
|
2
|
+
module Books
|
3
|
+
class ImageLinks
|
4
|
+
attr_reader :small_thumbnail, :thumbnail
|
5
|
+
|
6
|
+
def initialize(image_links)
|
7
|
+
if image_links
|
8
|
+
@small_thumbnail = image_links["smallThumbnail"]
|
9
|
+
@thumbnail = image_links["thumbnail"]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Google
|
2
|
+
module Books
|
3
|
+
class IndustryIdentifier
|
4
|
+
attr_reader :type, :identifier
|
5
|
+
|
6
|
+
def initialize(identifier)
|
7
|
+
@type = identifier["type"]
|
8
|
+
@identifier = identifier["identifier"]
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_hash
|
12
|
+
{self.type.downcase => self.identifier}
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'hasherizer'
|
2
|
+
require 'bookle/google_books_volume_info'
|
3
|
+
require 'bookle/google_books_sale_info'
|
4
|
+
require 'bookle/google_books_access_info'
|
5
|
+
require 'bookle/google_books_search_info'
|
6
|
+
|
7
|
+
module Google
|
8
|
+
module Books
|
9
|
+
class Item
|
10
|
+
attr_reader :kind, :id, :etag, :self_link, :volume_info, :sale_info, :access_info, :search_info
|
11
|
+
|
12
|
+
def initialize(item)
|
13
|
+
@kind = item["kind"]
|
14
|
+
@id = item["id"]
|
15
|
+
@etag = item["etag"]
|
16
|
+
@self_link = item["selfLink"]
|
17
|
+
@volume_info = Google::Books::VolumeInfo.new(item["volumeInfo"])
|
18
|
+
@sale_info = Google::Books::SaleInfo.new(item["saleInfo"])
|
19
|
+
@access_info = Google::Books::AccessInfo.new(item["accessInfo"])
|
20
|
+
@search_info = Google::Books::SearchInfo.new(item["searchInfo"])
|
21
|
+
end
|
22
|
+
|
23
|
+
def hash
|
24
|
+
Hasherizer.to_hash(self)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'bookle/google_books_item'
|
3
|
+
|
4
|
+
module Google
|
5
|
+
module Books
|
6
|
+
class Items
|
7
|
+
attr_reader :kind, :total_items, :items
|
8
|
+
|
9
|
+
def initialize(google_response)
|
10
|
+
books_info = JSON.parse(google_response)
|
11
|
+
|
12
|
+
@kind = books_info["kind"]
|
13
|
+
@total_items = books_info["totalItems"] || 0
|
14
|
+
|
15
|
+
if books_info["items"]
|
16
|
+
@items = books_info["items"].collect {|item| Google::Books::Item.new(item)}
|
17
|
+
else
|
18
|
+
@items = []
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Google
|
2
|
+
module Books
|
3
|
+
class Pdf
|
4
|
+
attr_reader :is_available
|
5
|
+
|
6
|
+
def initialize(pdf)
|
7
|
+
if pdf
|
8
|
+
@is_available = pdf["isAvailable"]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_hash
|
13
|
+
{"is_pdf_available" => self.is_available}
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'bookle/google_books_list_price'
|
2
|
+
require 'bookle/google_books_retail_price'
|
3
|
+
|
4
|
+
module Google
|
5
|
+
module Books
|
6
|
+
class SaleInfo
|
7
|
+
attr_reader :sale_country, :saleability, :is_ebook, :list_price, :retail_price, :buy_link
|
8
|
+
|
9
|
+
def initialize(sale_info)
|
10
|
+
if sale_info
|
11
|
+
@sale_country = sale_info["country"]
|
12
|
+
@saleability = sale_info["saleability"]
|
13
|
+
@is_ebook = sale_info["isEbook"]
|
14
|
+
@list_price = Google::Books::ListPrice.new(sale_info["listPrice"])
|
15
|
+
@retail_price = Google::Books::RetailPrice.new(sale_info["retailPrice"])
|
16
|
+
@buy_link = sale_info["buyLink"]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'bookle/google_books_industry_identifier'
|
2
|
+
require 'bookle/google_books_image_links'
|
3
|
+
|
4
|
+
module Google
|
5
|
+
module Books
|
6
|
+
class VolumeInfo
|
7
|
+
attr_reader :title, :subtitle, :authors, :publisher, :published_date, :description, :industry_identifiers, :page_count,
|
8
|
+
:print_type, :categories, :average_rating, :ratings_count, :content_version, :image_links, :language, :preview_link,
|
9
|
+
:info_link, :canonical_volume_link
|
10
|
+
|
11
|
+
def initialize(volume_info)
|
12
|
+
if volume_info
|
13
|
+
@title = volume_info["title"]
|
14
|
+
@subtitle = volume_info["subtitle"]
|
15
|
+
@authors = volume_info["authors"]
|
16
|
+
@publisher = volume_info["publisher"]
|
17
|
+
@published_date = volume_info["published_date"]
|
18
|
+
@description = volume_info["description"]
|
19
|
+
@industry_identifiers = volume_info["industryIdentifiers"].collect do
|
20
|
+
|i| Google::Books::IndustryIdentifier.new(i)
|
21
|
+
end if volume_info["industryIdentifiers"]
|
22
|
+
@page_count = volume_info["pageCount"]
|
23
|
+
@print_type = volume_info["printType"]
|
24
|
+
@categories = volume_info["categories"]
|
25
|
+
@average_rating = volume_info["averageRating"]
|
26
|
+
@ratings_count = volume_info["ratingsCount"]
|
27
|
+
@content_version = volume_info["contentVersion"]
|
28
|
+
@image_links = Google::Books::ImageLinks.new(volume_info["imageLinks"])
|
29
|
+
@language = volume_info["language"]
|
30
|
+
@preview_link = volume_info["previewLink"]
|
31
|
+
@info_link = volume_info["infoLink"]
|
32
|
+
@canonical_volume_link = volume_info["canonicalVolumeLink"]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|