alexandria-book-collection-manager 0.7.2 → 0.7.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.hound.yml +2 -0
- data/.rubocop.yml +4 -4
- data/.rubocop_todo.yml +55 -82
- data/CHANGELOG.md +17 -0
- data/INSTALL.md +3 -3
- data/README.md +1 -2
- data/Rakefile +14 -33
- data/TODO.md +9 -1
- data/alexandria-book-collection-manager.gemspec +4 -3
- data/bin/alexandria +21 -34
- data/doc/FAQ +2 -5
- data/lib/alexandria.rb +4 -16
- data/lib/alexandria/book_providers.rb +5 -7
- data/lib/alexandria/book_providers/adlibris.rb +5 -3
- data/lib/alexandria/book_providers/amazon_aws.rb +3 -1
- data/lib/alexandria/book_providers/amazon_ecs_util.rb +8 -0
- data/lib/alexandria/book_providers/barnes_and_noble.rb +7 -4
- data/lib/alexandria/book_providers/douban.rb +1 -1
- data/lib/alexandria/book_providers/proxis.rb +11 -27
- data/lib/alexandria/book_providers/renaud.rb +9 -3
- data/lib/alexandria/book_providers/siciliano.rb +7 -4
- data/lib/alexandria/book_providers/thalia.rb +5 -3
- data/lib/alexandria/book_providers/web.rb +11 -29
- data/lib/alexandria/book_providers/worldcat.rb +7 -5
- data/lib/alexandria/book_providers/z3950.rb +10 -7
- data/lib/alexandria/console.rb +5 -18
- data/lib/alexandria/execution_queue.rb +2 -1
- data/lib/alexandria/export_format.rb +47 -0
- data/lib/alexandria/export_library.rb +72 -180
- data/lib/alexandria/import_library.rb +14 -23
- data/lib/alexandria/import_library_csv.rb +3 -6
- data/lib/alexandria/library_collection.rb +78 -0
- data/lib/alexandria/library_sort_order.rb +43 -0
- data/lib/alexandria/library_store.rb +222 -0
- data/lib/alexandria/logging.rb +2 -0
- data/lib/alexandria/models/book.rb +8 -16
- data/lib/alexandria/models/library.rb +26 -308
- data/lib/alexandria/preferences.rb +7 -24
- data/lib/alexandria/scanners/cuecat.rb +3 -1
- data/lib/alexandria/smart_library.rb +32 -67
- data/lib/alexandria/ui/builder_base.rb +6 -26
- data/lib/alexandria/ui/callbacks.rb +8 -34
- data/lib/alexandria/ui/completion_models.rb +2 -1
- data/lib/alexandria/ui/dialogs/about_dialog.rb +35 -47
- data/lib/alexandria/ui/dialogs/acquire_dialog.rb +14 -30
- data/lib/alexandria/ui/dialogs/alert_dialog.rb +8 -17
- data/lib/alexandria/ui/dialogs/bad_isbns_dialog.rb +10 -24
- data/lib/alexandria/ui/dialogs/book_properties_dialog.rb +17 -18
- data/lib/alexandria/ui/dialogs/book_properties_dialog_base.rb +25 -41
- data/lib/alexandria/ui/dialogs/export_dialog.rb +48 -56
- data/lib/alexandria/ui/dialogs/import_dialog.rb +31 -51
- data/lib/alexandria/ui/dialogs/keep_bad_isbn_dialog.rb +33 -0
- data/lib/alexandria/ui/dialogs/misc_dialogs.rb +12 -25
- data/lib/alexandria/ui/dialogs/new_book_dialog.rb +57 -94
- data/lib/alexandria/ui/dialogs/new_book_dialog_manual.rb +24 -42
- data/lib/alexandria/ui/dialogs/new_smart_library_dialog.rb +9 -21
- data/lib/alexandria/ui/dialogs/preferences_dialog.rb +27 -32
- data/lib/alexandria/ui/dialogs/smart_library_properties_dialog.rb +5 -3
- data/lib/alexandria/ui/dialogs/smart_library_properties_dialog_base.rb +15 -12
- data/lib/alexandria/ui/icons.rb +11 -22
- data/lib/alexandria/ui/init.rb +3 -3
- data/lib/alexandria/ui/libraries_combo.rb +1 -0
- data/lib/alexandria/ui/listview.rb +5 -21
- data/lib/alexandria/ui/multi_drag_treeview.rb +20 -32
- data/lib/alexandria/ui/sidepane.rb +9 -24
- data/lib/alexandria/ui/ui_manager.rb +36 -60
- data/lib/alexandria/undo_manager.rb +1 -0
- data/lib/alexandria/version.rb +2 -2
- data/lib/alexandria/web_themes.rb +1 -0
- data/po/cs.po +0 -4
- data/po/cy.po +0 -4
- data/po/de.po +0 -4
- data/po/el.po +0 -4
- data/po/es.po +0 -4
- data/po/fr.po +0 -4
- data/po/ga.po +0 -4
- data/po/gl.po +0 -4
- data/po/it.po +0 -4
- data/po/ja.po +0 -4
- data/po/mk.po +0 -4
- data/po/nb.po +0 -4
- data/po/nl.po +0 -4
- data/po/pl.po +0 -4
- data/po/pt.po +0 -4
- data/po/pt_BR.po +0 -4
- data/po/ru.po +0 -4
- data/po/sk.po +0 -4
- data/po/sv.po +0 -4
- data/po/uk.po +0 -4
- data/po/zh_TW.po +0 -4
- data/schemas/alexandria.schemas +1 -1
- data/share/alexandria/glade/acquire_dialog__builder.glade +14 -11
- data/share/alexandria/glade/book_properties_dialog__builder.glade +170 -298
- data/share/alexandria/glade/main_app__builder.glade +22 -16
- data/share/alexandria/glade/new_book_dialog__builder.glade +26 -58
- data/share/alexandria/glade/preferences_dialog__builder.glade +249 -289
- data/share/gnome/help/alexandria/C/introduction.xml +0 -4
- data/share/gnome/help/alexandria/ja/introduction.xml +0 -4
- data/spec/alexandria/book_providers_spec.rb +1 -20
- data/spec/alexandria/console_spec.rb +32 -0
- data/spec/alexandria/export_library_spec.rb +141 -0
- data/spec/alexandria/library_spec.rb +24 -80
- data/spec/alexandria/library_store_spec.rb +37 -0
- data/spec/alexandria/smart_library_spec.rb +27 -22
- data/spec/alexandria/ui/dialogs/new_book_dialog_spec.rb +22 -0
- data/spec/alexandria/ui/dialogs_spec.rb +104 -38
- data/spec/end_to_end/basic_run_spec.rb +69 -0
- data/spec/spec_helper.rb +13 -25
- data/tasks/spec.rake +15 -2
- data/util/rake/fileinstall.rb +1 -0
- metadata +38 -16
- data/lib/alexandria/book_providers/deastore.rb +0 -265
- data/lib/alexandria/book_providers/mcu.rb +0 -182
data/TODO.md
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
Alexandria's TODO list
|
2
2
|
======================
|
3
3
|
|
4
|
-
|
4
|
+
## New TODOs
|
5
|
+
|
6
|
+
* [ ] Clean up broken providers
|
7
|
+
* [ ] Add openlibrary provider
|
8
|
+
* [ ] Allow searching for cover image for existing books
|
9
|
+
|
10
|
+
## Old TODOs
|
11
|
+
|
12
|
+
This is an old list of TODO's that should be cleaned up.
|
5
13
|
|
6
14
|
For the next release:
|
7
15
|
|
@@ -45,14 +45,15 @@ Gem::Specification.new do |s|
|
|
45
45
|
s.rdoc_options = ['--main', 'README.md']
|
46
46
|
|
47
47
|
s.add_runtime_dependency('gettext', ['~> 3.1'])
|
48
|
-
s.add_runtime_dependency('gstreamer', ['3.
|
49
|
-
s.add_runtime_dependency('gtk3', ['3.
|
48
|
+
s.add_runtime_dependency('gstreamer', ['~> 3.3.0'])
|
49
|
+
s.add_runtime_dependency('gtk3', ['~> 3.3.0'])
|
50
50
|
s.add_runtime_dependency('hpricot', ['~> 0.8.5'])
|
51
51
|
s.add_runtime_dependency('htmlentities', ['~> 4.3'])
|
52
|
-
s.add_runtime_dependency('image_size', ['~>
|
52
|
+
s.add_runtime_dependency('image_size', ['~> 2.0'])
|
53
53
|
s.add_runtime_dependency('marc', ['~> 1.0.0'])
|
54
54
|
s.add_runtime_dependency('zoom', ['~> 0.5.0'])
|
55
55
|
|
56
|
+
s.add_development_dependency('gnome_app_driver', ['~> 0.2.1'])
|
56
57
|
s.add_development_dependency('minitest', ['~> 5.0'])
|
57
58
|
s.add_development_dependency('rake', ['~> 12.0'])
|
58
59
|
s.add_development_dependency('rspec', ['~> 3.0'])
|
data/bin/alexandria
CHANGED
@@ -1,31 +1,18 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
#
|
5
|
-
# Copyright (C) 2007, 2008 Joseph Method
|
6
|
-
# Copyright (C) 2007, 2009 Cathal Mc Ginley
|
7
|
-
# Copyright (C) 2014, 2015 Matijs van Zuijlen
|
4
|
+
# This file is part of Alexandria.
|
8
5
|
#
|
9
|
-
#
|
10
|
-
# modify it under the terms of the GNU General Public License as
|
11
|
-
# published by the Free Software Foundation; either version 2 of the
|
12
|
-
# License, or (at your option) any later version.
|
13
|
-
#
|
14
|
-
# Alexandria is distributed in the hope that it will be useful,
|
15
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
17
|
-
# General Public License for more details.
|
18
|
-
#
|
19
|
-
# You should have received a copy of the GNU General Public
|
20
|
-
# License along with Alexandria; see the file COPYING. If not,
|
21
|
-
# write to the Free Software Foundation, Inc., 51 Franklin Street,
|
22
|
-
# Fifth Floor, Boston, MA 02110-1301 USA.
|
6
|
+
# See the file README.md for authorship and licensing information.
|
23
7
|
|
24
8
|
require 'gettext'
|
25
9
|
require 'alexandria'
|
26
10
|
require 'optparse'
|
27
11
|
require 'ostruct'
|
28
12
|
|
13
|
+
store = Alexandria::LibraryStore.new(Alexandria::Library::DEFAULT_DIR)
|
14
|
+
Alexandria::LibraryCollection.instance.library_store = store
|
15
|
+
|
29
16
|
# options = OpenStruct.new
|
30
17
|
OptionParser.new do |opts|
|
31
18
|
opts.banner = 'Usage: alexandria [options]'
|
@@ -58,21 +45,21 @@ end.parse!
|
|
58
45
|
|
59
46
|
begin
|
60
47
|
Alexandria.main
|
61
|
-
rescue => e
|
62
|
-
warn
|
63
|
-
-----------------------
|
64
|
-
Alexandria just crashed
|
65
|
-
-----------------------
|
66
|
-
Timestamp: #{Time.now}
|
67
|
-
Message: #{e.message}
|
68
|
-
Backtrace:
|
69
|
-
#{e.backtrace.join("\n")}
|
70
|
-
Release: #{Alexandria::VERSION}(#{Alexandria::DISPLAY_VERSION})
|
71
|
-
Uname -a: #{`uname -a`.chomp}
|
72
|
-
--
|
73
|
-
Please report this dump to '#{Alexandria::BUGREPORT_URL}' with some additional
|
74
|
-
information, such as the description of the crash and the steps to reproduce it
|
75
|
-
(if it's possible).
|
76
|
-
EOS
|
48
|
+
rescue StandardError => e
|
49
|
+
warn <<~EOS
|
50
|
+
-----------------------
|
51
|
+
Alexandria just crashed
|
52
|
+
-----------------------
|
53
|
+
Timestamp: #{Time.now}
|
54
|
+
Message: #{e.message}
|
55
|
+
Backtrace:
|
56
|
+
#{e.backtrace.join("\n")}
|
57
|
+
Release: #{Alexandria::VERSION}(#{Alexandria::DISPLAY_VERSION})
|
58
|
+
Uname -a: #{`uname -a`.chomp}
|
59
|
+
--
|
60
|
+
Please report this dump to '#{Alexandria::BUGREPORT_URL}' with some additional
|
61
|
+
information, such as the description of the crash and the steps to reproduce it
|
62
|
+
(if it's possible).
|
63
|
+
EOS
|
77
64
|
exit 1
|
78
65
|
end
|
data/doc/FAQ
CHANGED
@@ -159,8 +159,6 @@ for public libraries, and very unlikely for commercial booksellers.
|
|
159
159
|
It is useful if you choose a provider that allows to specify the ISBN in
|
160
160
|
the address, such as
|
161
161
|
http://www.internetbookshop.it/ame/ser/serdsp.asp?e=0060748222&shop=1
|
162
|
-
or
|
163
|
-
http://www.deastore.com/product.asp?isbn=9780060748227
|
164
162
|
|
165
163
|
It is necessary that the HTML page of each provider is easily parsable,
|
166
164
|
that is, that the computer can easily find title, author(s), ISBN,
|
@@ -184,8 +182,7 @@ information: title, author(s), ISBN, publisher, year of publication,
|
|
184
182
|
binding. In case that one of these is missing, Alexandria will not get
|
185
183
|
it.
|
186
184
|
|
187
|
-
It is easier, if the provider doesn't use cookies
|
188
|
-
Deastore uses cookies and has been implemented).
|
185
|
+
It is easier, if the provider doesn't use cookies.
|
189
186
|
|
190
187
|
After the choice of the provider, try by yourself to modify the file for
|
191
188
|
an already implemented provider. Probably it may be only required that
|
@@ -293,7 +290,7 @@ Question: I prefer to have the field "Author" as "Surname, Name" instead
|
|
293
290
|
of "Name Surname".
|
294
291
|
|
295
292
|
Answer: Alexandria relies on what the providers say:
|
296
|
-
some providers report "Surname, Name":
|
293
|
+
some providers report "Surname, Name": Renaud,
|
297
294
|
some "Surname Name": Webster.it, Ibs.it,
|
298
295
|
some "Name Surname": Bn, Thalia, Bol.it, Adlibris, L Siciliano, Worldcat,
|
299
296
|
and some without any rule: Amazon, Proxis.
|
data/lib/alexandria.rb
CHANGED
@@ -1,22 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
# Copyright (C) 2011, 2016 Matijs van Zuijlen
|
3
|
+
# This file is part of Alexandria.
|
5
4
|
#
|
6
|
-
#
|
7
|
-
# modify it under the terms of the GNU General Public License as
|
8
|
-
# published by the Free Software Foundation; either version 2 of the
|
9
|
-
# License, or (at your option) any later version.
|
10
|
-
#
|
11
|
-
# Alexandria is distributed in the hope that it will be useful,
|
12
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
-
# General Public License for more details.
|
15
|
-
#
|
16
|
-
# You should have received a copy of the GNU General Public
|
17
|
-
# License along with Alexandria; see the file COPYING. If not,
|
18
|
-
# write to the Free Software Foundation, Inc., 51 Franklin Street,
|
19
|
-
# Fifth Floor, Boston, MA 02110-1301 USA.
|
5
|
+
# See the file README.md for authorship and licensing information.
|
20
6
|
|
21
7
|
require 'gettext'
|
22
8
|
|
@@ -66,6 +52,8 @@ require 'alexandria/version'
|
|
66
52
|
# end
|
67
53
|
|
68
54
|
require 'alexandria/models/book'
|
55
|
+
require 'alexandria/library_store'
|
56
|
+
require 'alexandria/library_collection'
|
69
57
|
require 'alexandria/models/library'
|
70
58
|
|
71
59
|
require 'alexandria/smart_library'
|
@@ -69,7 +69,7 @@ module Alexandria
|
|
69
69
|
instance.notify_observers(:found, factory.fullname) # new
|
70
70
|
return results
|
71
71
|
end
|
72
|
-
rescue => boom
|
72
|
+
rescue StandardError => boom
|
73
73
|
if boom.is_a? NoResultsError
|
74
74
|
unless boom.instance_of? ProviderSkippedError
|
75
75
|
instance.changed
|
@@ -289,7 +289,6 @@ module Alexandria
|
|
289
289
|
unabstract
|
290
290
|
end
|
291
291
|
|
292
|
-
require 'alexandria/book_providers/mcu' # yep, still mostly works !
|
293
292
|
require 'alexandria/book_providers/douban' # only requires YAML
|
294
293
|
|
295
294
|
# require 'alexandria/book_providers/renaud'
|
@@ -301,7 +300,6 @@ module Alexandria
|
|
301
300
|
# Website based providers
|
302
301
|
require 'alexandria/book_providers/adlibris'
|
303
302
|
require 'alexandria/book_providers/barnes_and_noble'
|
304
|
-
require 'alexandria/book_providers/deastore'
|
305
303
|
require 'alexandria/book_providers/proxis'
|
306
304
|
require 'alexandria/book_providers/siciliano'
|
307
305
|
require 'alexandria/book_providers/thalia'
|
@@ -328,6 +326,7 @@ module Alexandria
|
|
328
326
|
self.class.constants.each do |constant|
|
329
327
|
md = /(.+)Provider$/.match(constant)
|
330
328
|
next unless md
|
329
|
+
|
331
330
|
klass = self.class.module_eval(constant.to_s)
|
332
331
|
if klass.ancestors.include?(AbstractProvider) &&
|
333
332
|
(klass != GenericProvider) &&
|
@@ -345,11 +344,14 @@ module Alexandria
|
|
345
344
|
ary.each do |name|
|
346
345
|
md = /^(.+)_/.match(name)
|
347
346
|
next unless md
|
347
|
+
|
348
348
|
klass_name = md[1] + 'Provider'
|
349
349
|
klass = @abstract_classes.find { |x| x.name.include?(klass_name) }
|
350
350
|
next unless klass
|
351
|
+
|
351
352
|
fullname = @prefs.send(name.downcase + '_name')
|
352
353
|
next unless fullname
|
354
|
+
|
353
355
|
instance = klass.new
|
354
356
|
instance.name = name
|
355
357
|
instance.fullname = fullname
|
@@ -388,10 +390,6 @@ module Alexandria
|
|
388
390
|
priority.uniq! # remove any other "Amazon" from the list
|
389
391
|
changed = true
|
390
392
|
end
|
391
|
-
if (deastore_index = priority.index('DeaStore_it'))
|
392
|
-
priority[deastore_index] = 'DeaStore'
|
393
|
-
changed = true
|
394
|
-
end
|
395
393
|
if (worldcat_index = priority.index('Worldcat'))
|
396
394
|
priority[worldcat_index] = 'WorldCat'
|
397
395
|
changed = true
|
@@ -67,7 +67,7 @@ module Alexandria
|
|
67
67
|
## url
|
68
68
|
def url(book)
|
69
69
|
create_search_uri(SEARCH_BY_ISBN, book.isbn)
|
70
|
-
rescue => ex
|
70
|
+
rescue StandardError => ex
|
71
71
|
log.warn { "Cannot create url for book #{book}; #{ex.message}" }
|
72
72
|
nil
|
73
73
|
end
|
@@ -80,7 +80,7 @@ module Alexandria
|
|
80
80
|
else
|
81
81
|
(search_type_code = {
|
82
82
|
SEARCH_BY_AUTHORS => 'author',
|
83
|
-
SEARCH_BY_TITLE
|
83
|
+
SEARCH_BY_TITLE => 'title',
|
84
84
|
SEARCH_BY_KEYWORD => 'keyword'
|
85
85
|
}[search_type]) || 'keyword'
|
86
86
|
search_term_encoded = CGI.escape(search_term)
|
@@ -185,6 +185,7 @@ module Alexandria
|
|
185
185
|
isbn_tds.each do |isbn_td|
|
186
186
|
isbn = isbn_td.inner_text
|
187
187
|
next unless isbn =~ /[0-9x]{10,13}/i
|
188
|
+
|
188
189
|
isbn.gsub(/(\n|\r)/, ' ')
|
189
190
|
isbn = Regexp.last_match[1] if isbn =~ /:[\s]*([0-9x]+)/i
|
190
191
|
isbns << isbn
|
@@ -211,8 +212,9 @@ module Alexandria
|
|
211
212
|
book = Book.new(title, authors, isbn, publisher, year, binding)
|
212
213
|
|
213
214
|
return [book, image_url]
|
214
|
-
rescue => ex
|
215
|
+
rescue StandardError => ex
|
215
216
|
raise ex if ex.instance_of? NoResultsError
|
217
|
+
|
216
218
|
trace = ex.backtrace.join("\n> ")
|
217
219
|
log.warn {
|
218
220
|
'Failed parsing search results for AdLibris ' \
|
@@ -169,6 +169,7 @@ module Alexandria
|
|
169
169
|
results = []
|
170
170
|
products.each do |item|
|
171
171
|
next unless item.get('itemattributes/productgroup') == 'Book'
|
172
|
+
|
172
173
|
atts = item.search_and_convert('itemattributes')
|
173
174
|
title = normalize(atts.get('title'))
|
174
175
|
|
@@ -201,6 +202,7 @@ module Alexandria
|
|
201
202
|
book = rslt[0]
|
202
203
|
book_isbn_canon = Library.canonicalise_ean(book.isbn)
|
203
204
|
return rslt if query_isbn_canon == book_isbn_canon
|
205
|
+
|
204
206
|
log.debug { "rejected possible result #{book}" }
|
205
207
|
end
|
206
208
|
# gone through all and no ISBN match, so just return first result
|
@@ -229,7 +231,7 @@ module Alexandria
|
|
229
231
|
'http://www.amazon.com/exec/obidos/ASIN/%s'
|
230
232
|
end
|
231
233
|
url % isbn
|
232
|
-
rescue => ex
|
234
|
+
rescue StandardError => ex
|
233
235
|
log.warn { "Cannot create url for book #{book}; #{ex.message}" }
|
234
236
|
nil
|
235
237
|
end
|
@@ -80,6 +80,7 @@ module Amazon
|
|
80
80
|
|
81
81
|
def self.configure(&_proc)
|
82
82
|
raise ArgumentError, 'Block is required.' unless block_given?
|
83
|
+
|
83
84
|
yield @@options
|
84
85
|
end
|
85
86
|
|
@@ -123,6 +124,7 @@ module Amazon
|
|
123
124
|
unless res.is_a? Net::HTTPSuccess
|
124
125
|
raise Amazon::RequestError, "HTTP Response: #{res.code} #{res.message}"
|
125
126
|
end
|
127
|
+
|
126
128
|
Response.new(res.body)
|
127
129
|
end
|
128
130
|
|
@@ -202,6 +204,7 @@ module Amazon
|
|
202
204
|
qs = ''
|
203
205
|
opts.each { |k, v|
|
204
206
|
next unless v
|
207
|
+
|
205
208
|
v = v.join(',') if v.is_a? Array
|
206
209
|
qs << "&#{camelize(k.to_s)}=#{URI.encode(v.to_s)}"
|
207
210
|
}
|
@@ -255,6 +258,7 @@ module Amazon
|
|
255
258
|
|
256
259
|
def self.sign_request(request)
|
257
260
|
raise AmazonNotConfiguredError unless @@secret_access_key
|
261
|
+
|
258
262
|
# Step 0 : Split apart request string
|
259
263
|
url_pattern = /http:\/\/([^\/]+)(\/[^\?]+)\?(.*$)/
|
260
264
|
url_pattern =~ request
|
@@ -313,6 +317,7 @@ module Amazon
|
|
313
317
|
def /(path)
|
314
318
|
elements = @element / path
|
315
319
|
return nil if elements.empty?
|
320
|
+
|
316
321
|
elements
|
317
322
|
end
|
318
323
|
|
@@ -321,8 +326,10 @@ module Amazon
|
|
321
326
|
def search_and_convert(path)
|
322
327
|
elements = self./(path)
|
323
328
|
return unless elements
|
329
|
+
|
324
330
|
elements = elements.map { |element| Element.new(element) }
|
325
331
|
return elements.first if elements.size == 1
|
332
|
+
|
326
333
|
elements
|
327
334
|
end
|
328
335
|
|
@@ -349,6 +356,7 @@ module Amazon
|
|
349
356
|
# Similar to #get, except an element object must be passed-in.
|
350
357
|
def self.get(element, path = '')
|
351
358
|
return unless element
|
359
|
+
|
352
360
|
result = element.at(path)
|
353
361
|
## inner_html doesn't decode entities, hence bug #21659
|
354
362
|
# result = result.inner_html if result
|
@@ -57,6 +57,7 @@ module Alexandria
|
|
57
57
|
|
58
58
|
def fetch_redirectly(uri_str, limit = 5)
|
59
59
|
raise NoResultsError, 'HTTP redirect too deep' if limit.zero?
|
60
|
+
|
60
61
|
if limit < 10
|
61
62
|
sleep 0.1
|
62
63
|
log.debug { "Redirectly :: #{uri_str}" }
|
@@ -93,7 +94,7 @@ module Alexandria
|
|
93
94
|
|
94
95
|
def url(book)
|
95
96
|
create_search_uri(SEARCH_BY_ISBN, book.isbn)
|
96
|
-
rescue => ex
|
97
|
+
rescue StandardError => ex
|
97
98
|
log.warn { "Cannot create url for book #{book}; #{ex.message}" }
|
98
99
|
nil
|
99
100
|
end
|
@@ -101,7 +102,7 @@ module Alexandria
|
|
101
102
|
def create_search_uri(search_type, search_term)
|
102
103
|
(search_type_code = {
|
103
104
|
SEARCH_BY_AUTHORS => 'ATH',
|
104
|
-
SEARCH_BY_TITLE
|
105
|
+
SEARCH_BY_TITLE => 'TTL',
|
105
106
|
SEARCH_BY_KEYWORD => 'WRD' # SEARCH_BY_PUBLISHER => 'PBL' # not implemented
|
106
107
|
}[search_type]) || ''
|
107
108
|
if search_type == SEARCH_BY_ISBN
|
@@ -134,7 +135,7 @@ module Alexandria
|
|
134
135
|
|
135
136
|
book_search_results << result
|
136
137
|
end
|
137
|
-
rescue => ex
|
138
|
+
rescue StandardError => ex
|
138
139
|
trace = ex.backtrace.join("\n> ")
|
139
140
|
log.warn {
|
140
141
|
'Failed parsing search results for Barnes & Noble ' \
|
@@ -170,6 +171,7 @@ module Alexandria
|
|
170
171
|
attrs = it.attributes
|
171
172
|
property = attrs['property']
|
172
173
|
next unless property
|
174
|
+
|
173
175
|
case property
|
174
176
|
when 'og:title'
|
175
177
|
book_data[:title] = attrs['content']
|
@@ -191,8 +193,9 @@ module Alexandria
|
|
191
193
|
book_data[:publication_year],
|
192
194
|
book_data[:binding])
|
193
195
|
return [book, book_data[:image_url]]
|
194
|
-
rescue => ex
|
196
|
+
rescue StandardError => ex
|
195
197
|
raise ex if ex.instance_of? NoResultsError
|
198
|
+
|
196
199
|
trace = ex.backtrace.join("\n> ")
|
197
200
|
log.warn {
|
198
201
|
'Failed parsing search results for BarnesAndNoble ' \
|
@@ -1,22 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
# Copyright (C) 2014-2016 Matijs van Zuijlen
|
3
|
+
# This file is part of Alexandria.
|
5
4
|
#
|
6
|
-
#
|
7
|
-
# modify it under the terms of the GNU General Public License as
|
8
|
-
# published by the Free Software Foundation; either version 2 of the
|
9
|
-
# License, or (at your option) any later version.
|
10
|
-
#
|
11
|
-
# Alexandria is distributed in the hope that it will be useful,
|
12
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
-
# General Public License for more details.
|
15
|
-
#
|
16
|
-
# You should have received a copy of the GNU General Public
|
17
|
-
# License along with Alexandria; see the file COPYING. If not,
|
18
|
-
# write to the Free Software Foundation, Inc., 51 Franklin Street,
|
19
|
-
# Fifth Floor, Boston, MA 02110-1301 USA.
|
5
|
+
# See the file README.md for authorship and licensing information.
|
20
6
|
|
21
7
|
# New Proxis provider, taken from Palatina MetaDataSource and modified
|
22
8
|
# for Alexandria. (20 Dec 2009)
|
@@ -56,6 +42,7 @@ module Alexandria
|
|
56
42
|
|
57
43
|
results = parse_search_result_data(html_data.body)
|
58
44
|
raise NoResultsError if results.empty?
|
45
|
+
|
59
46
|
if type == SEARCH_BY_ISBN
|
60
47
|
get_book_from_search_result(results.first)
|
61
48
|
else
|
@@ -85,18 +72,15 @@ module Alexandria
|
|
85
72
|
def text_of(node)
|
86
73
|
if node.nil?
|
87
74
|
nil
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
node_text.strip.squeeze(' ')
|
97
|
-
end
|
75
|
+
elsif node.text?
|
76
|
+
node.to_html
|
77
|
+
elsif node.elem?
|
78
|
+
if node.children.nil?
|
79
|
+
nil
|
80
|
+
else
|
81
|
+
node_text = node.children.map { |n| text_of(n) }.join
|
82
|
+
node_text.strip.squeeze(' ')
|
98
83
|
end
|
99
|
-
# node.inner_html.strip
|
100
84
|
end
|
101
85
|
end
|
102
86
|
|