alexandria-book-collection-manager 0.7.5 → 0.7.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +9 -0
- data/.github/workflows/ruby.yml +72 -0
- data/.gitignore +4 -1
- data/.rubocop.yml +65 -30
- data/.rubocop_todo.yml +49 -165
- data/.simplecov +5 -2
- data/CHANGELOG.md +64 -0
- data/ChangeLog.0 +19 -19
- data/INSTALL.md +26 -16
- data/README.md +31 -35
- data/Rakefile +18 -16
- data/alexandria-book-collection-manager.gemspec +35 -29
- data/doc/FAQ +2 -2
- data/doc/dependency_decisions.yml +22 -3
- data/lib/alexandria/about.rb +1 -1
- data/lib/alexandria/book_providers/bl_provider.rb +88 -0
- data/lib/alexandria/book_providers/douban.rb +2 -2
- data/lib/alexandria/book_providers/loc_provider.rb +38 -0
- data/lib/alexandria/book_providers/pseudomarc.rb +61 -71
- data/lib/alexandria/book_providers/sbn_provider.rb +108 -0
- data/lib/alexandria/book_providers/{thalia.rb → thalia_provider.rb} +37 -74
- data/lib/alexandria/book_providers/web.rb +2 -2
- data/lib/alexandria/book_providers/worldcat.rb +34 -38
- data/lib/alexandria/book_providers/z3950_provider.rb +199 -0
- data/lib/alexandria/book_providers.rb +48 -65
- data/lib/alexandria/default_preferences.rb +2 -1
- data/lib/alexandria/execution_queue.rb +13 -12
- data/lib/alexandria/export_library.rb +21 -22
- data/lib/alexandria/image_fetcher.rb +25 -0
- data/lib/alexandria/import_library.rb +46 -70
- data/lib/alexandria/import_library_csv.rb +16 -16
- data/lib/alexandria/library_sort_order.rb +3 -1
- data/lib/alexandria/library_store.rb +19 -20
- data/lib/alexandria/logging.rb +5 -9
- data/lib/alexandria/models/book.rb +15 -2
- data/lib/alexandria/models/library.rb +31 -35
- data/lib/alexandria/net.rb +1 -2
- data/lib/alexandria/preferences.rb +27 -33
- data/lib/alexandria/scanners/cue_cat.rb +6 -6
- data/lib/alexandria/scanners/keyboard.rb +1 -1
- data/lib/alexandria/scanners.rb +2 -2
- data/lib/alexandria/smart_library.rb +22 -26
- data/lib/alexandria/ui/about_dialog.rb +1 -1
- data/lib/alexandria/ui/acquire_dialog.rb +15 -19
- data/lib/alexandria/ui/alert_dialog.rb +36 -19
- data/lib/alexandria/ui/bad_isbns_dialog.rb +13 -9
- data/lib/alexandria/ui/barcode_animation.rb +6 -6
- data/lib/alexandria/ui/book_properties_dialog.rb +2 -3
- data/lib/alexandria/ui/book_properties_dialog_base.rb +35 -137
- data/lib/alexandria/ui/calendar_popup.rb +58 -0
- data/lib/alexandria/ui/callbacks.rb +144 -123
- data/lib/alexandria/ui/completion_models.rb +2 -6
- data/lib/alexandria/ui/confirm_erase_dialog.rb +1 -1
- data/lib/alexandria/ui/conflict_while_copying_dialog.rb +2 -2
- data/lib/alexandria/ui/error_dialog.rb +1 -1
- data/lib/alexandria/ui/export_dialog.rb +19 -18
- data/lib/alexandria/ui/icons.rb +34 -40
- data/lib/alexandria/ui/iconview_tooltips.rb +40 -53
- data/lib/alexandria/ui/import_dialog.rb +49 -48
- data/lib/alexandria/ui/init.rb +14 -12
- data/lib/alexandria/ui/keep_bad_isbn_dialog.rb +2 -2
- data/lib/alexandria/ui/libraries_combo.rb +10 -9
- data/lib/alexandria/ui/listview.rb +6 -7
- data/lib/alexandria/ui/main_app.rb +2 -2
- data/lib/alexandria/ui/multi_drag_treeview.rb +5 -7
- data/lib/alexandria/ui/new_book_dialog.rb +63 -65
- data/lib/alexandria/ui/new_book_dialog_manual.rb +1 -1
- data/lib/alexandria/ui/new_provider_dialog.rb +12 -11
- data/lib/alexandria/ui/new_smart_library_dialog.rb +39 -27
- data/lib/alexandria/ui/preferences_dialog.rb +25 -84
- data/lib/alexandria/ui/provider_preferences_base_dialog.rb +10 -6
- data/lib/alexandria/ui/provider_preferences_dialog.rb +5 -5
- data/lib/alexandria/ui/really_delete_dialog.rb +2 -2
- data/lib/alexandria/ui/sidepane_manager.rb +38 -38
- data/lib/alexandria/ui/skip_entry_dialog.rb +3 -2
- data/lib/alexandria/ui/smart_library_properties_dialog.rb +35 -36
- data/lib/alexandria/ui/smart_library_properties_dialog_base.rb +61 -244
- data/lib/alexandria/ui/smart_library_rule_box.rb +119 -0
- data/lib/alexandria/ui/sound.rb +4 -6
- data/lib/alexandria/ui/ui_manager.rb +80 -83
- data/lib/alexandria/ui.rb +7 -7
- data/lib/alexandria/version.rb +2 -2
- data/lib/alexandria/web_themes.rb +15 -15
- data/lib/alexandria.rb +2 -2
- data/po/cs.po +947 -865
- data/po/cy.po +913 -864
- data/po/de.po +961 -865
- data/po/el.po +956 -861
- data/po/es.po +952 -857
- data/po/fr.po +950 -865
- data/po/ga.po +866 -819
- data/po/gl.po +946 -861
- data/po/it.po +945 -858
- data/po/ja.po +921 -836
- data/po/mk.po +953 -858
- data/po/nb.po +932 -847
- data/po/nl.po +955 -849
- data/po/pl.po +999 -963
- data/po/pt.po +946 -850
- data/po/pt_BR.po +944 -859
- data/po/ru.po +959 -868
- data/po/sk.po +950 -863
- data/po/sv.po +944 -859
- data/po/uk.po +925 -846
- data/po/zh_TW.po +926 -841
- data/schemas/alexandria.schemas +1 -1
- data/share/alexandria/glade/main_app__builder.glade +6 -21
- data/share/gnome/help/alexandria/C/adding-books.xml +3 -4
- data/share/gnome/help/alexandria/C/introduction.xml +0 -16
- data/share/gnome/help/alexandria/C/searching.xml +1 -4
- data/share/gnome/help/alexandria/C/settings.xml +0 -30
- data/share/gnome/help/alexandria/C/smart-libraries.xml +2 -2
- data/share/gnome/help/alexandria/C/working-with-libraries.xml +1 -1
- data/share/gnome/help/alexandria/fr/alexandria.xml +5 -160
- data/share/gnome/help/alexandria/ja/adding-books.xml +1 -1
- data/share/gnome/help/alexandria/ja/introduction.xml +0 -15
- data/share/gnome/help/alexandria/ja/searching.xml +3 -7
- data/share/gnome/help/alexandria/ja/settings.xml +0 -27
- data/share/gnome/help/alexandria/ja/smart-libraries.xml +1 -1
- data/spec/alexandria/book_providers/bl_provider_spec.rb +13 -0
- data/spec/alexandria/book_providers/loc_provider_spec.rb +17 -0
- data/spec/alexandria/book_providers/sbn_provider_spec.rb +13 -0
- data/spec/alexandria/book_providers/thalia_provider_spec.rb +119 -0
- data/spec/alexandria/book_providers/world_cat_provider_spec.rb +160 -0
- data/spec/alexandria/book_providers_spec.rb +0 -154
- data/spec/alexandria/console_spec.rb +0 -5
- data/spec/alexandria/export_library_spec.rb +27 -38
- data/spec/alexandria/library_spec.rb +76 -46
- data/spec/alexandria/preferences_spec.rb +29 -3
- data/spec/alexandria/scanners/cue_cat_spec.rb +1 -1
- data/spec/alexandria/ui/about_dialog_spec.rb +1 -1
- data/spec/alexandria/ui/acquire_dialog_spec.rb +1 -1
- data/spec/alexandria/ui/alert_dialog_spec.rb +1 -1
- data/spec/alexandria/ui/bad_isbns_dialog_spec.rb +1 -1
- data/spec/alexandria/ui/book_properties_dialog_spec.rb +47 -5
- data/spec/alexandria/ui/confirm_erase_dialog_spec.rb +1 -1
- data/spec/alexandria/ui/conflict_while_copying_dialog_spec.rb +1 -1
- data/spec/alexandria/ui/error_dialog_spec.rb +1 -1
- data/spec/alexandria/ui/export_dialog_spec.rb +25 -4
- data/spec/alexandria/ui/icons_spec.rb +26 -0
- data/spec/alexandria/ui/iconview_spec.rb +1 -1
- data/spec/alexandria/ui/import_dialog_spec.rb +35 -3
- data/spec/alexandria/ui/keep_bad_isbn_dialog_spec.rb +1 -1
- data/spec/alexandria/ui/main_app_spec.rb +1 -1
- data/spec/alexandria/ui/new_book_dialog_manual_spec.rb +39 -3
- data/spec/alexandria/ui/new_provider_dialog_spec.rb +19 -3
- data/spec/alexandria/ui/new_smart_library_dialog_spec.rb +28 -3
- data/spec/alexandria/ui/preferences_dialog_spec.rb +2 -2
- data/spec/alexandria/ui/provider_preferences_dialog_spec.rb +23 -8
- data/spec/alexandria/ui/really_delete_dialog_spec.rb +1 -1
- data/spec/alexandria/ui/sidepane_manager_spec.rb +2 -2
- data/spec/alexandria/ui/skip_entry_dialog_spec.rb +1 -1
- data/spec/alexandria/ui/smart_library_properties_dialog_spec.rb +37 -6
- data/spec/alexandria/ui/ui_manager_spec.rb +116 -2
- data/spec/data/libraries/0.6.2/My Library/9780571147168.yaml +2 -0
- data/spec/end_to_end/basic_run_spec.rb +3 -8
- data/spec/fixtures/cover.jpg +0 -0
- data/spec/spec_helper.rb +47 -3
- data/tasks/spec.rake +3 -5
- data/util/rake/fileinstall.rb +16 -15
- data/util/rake/omfgenerate.rb +1 -1
- metadata +141 -52
- data/.travis.yml +0 -39
- data/lib/alexandria/book_providers/adlibris.rb +0 -196
- data/lib/alexandria/book_providers/amazon_aws.rb +0 -252
- data/lib/alexandria/book_providers/amazon_ecs_util.rb +0 -388
- data/lib/alexandria/book_providers/barnes_and_noble.rb +0 -209
- data/lib/alexandria/book_providers/proxis.rb +0 -175
- data/lib/alexandria/book_providers/siciliano.rb +0 -257
- data/lib/alexandria/book_providers/z3950.rb +0 -415
- data/spec/alexandria/ui/ui_utilities_spec.rb +0 -62
- data/spec/alexandria/utilities_spec.rb +0 -52
@@ -11,6 +11,7 @@ module Alexandria
|
|
11
11
|
class ImportFilter
|
12
12
|
attr_reader :name, :patterns, :message
|
13
13
|
|
14
|
+
include Logging
|
14
15
|
include GetText
|
15
16
|
extend GetText
|
16
17
|
bindtextdomain(Alexandria::TEXTDOMAIN, charset: "UTF-8")
|
@@ -34,7 +35,7 @@ module Alexandria
|
|
34
35
|
end
|
35
36
|
|
36
37
|
def invoke(library_name, filename)
|
37
|
-
|
38
|
+
log.debug { "Selected: #{@message} -- #{library_name} -- #{filename}" }
|
38
39
|
Library.send(@message, library_name, filename,
|
39
40
|
@on_iterate_cb, @on_error_cb)
|
40
41
|
end
|
@@ -50,30 +51,24 @@ module Alexandria
|
|
50
51
|
|
51
52
|
class Library
|
52
53
|
def self.import_autodetect(*args)
|
53
|
-
|
54
|
+
log.debug { args.inspect }
|
54
55
|
filename = args[1]
|
55
|
-
|
56
|
-
|
57
|
-
if filename[-4
|
56
|
+
log.debug { "Filename is #{filename} and ext is #{filename[-4..]}" }
|
57
|
+
log.debug { "Beginning import: #{args[0]}, #{args[1]}" }
|
58
|
+
if filename[-4..] == ".txt"
|
58
59
|
import_as_isbn_list(*args)
|
59
|
-
elsif [".tc", ".bc"].include? filename[-3
|
60
|
-
|
61
|
-
|
62
|
-
rescue StandardError => ex
|
63
|
-
puts ex.message
|
64
|
-
puts ex.backtrace.join("\n>> ")
|
65
|
-
end
|
66
|
-
elsif [".csv"].include? filename[-4..-1]
|
60
|
+
elsif [".tc", ".bc"].include? filename[-3..]
|
61
|
+
import_as_tellico_xml_archive(*args)
|
62
|
+
elsif [".csv"].include? filename[-4..]
|
67
63
|
import_as_csv_file(*args)
|
68
64
|
else
|
69
|
-
|
70
|
-
raise "Not supported type"
|
65
|
+
raise _("Unsupported type")
|
71
66
|
end
|
72
67
|
end
|
73
68
|
|
74
69
|
def self.import_as_tellico_xml_archive(name, filename,
|
75
70
|
on_iterate_cb, _on_error_cb)
|
76
|
-
|
71
|
+
log.debug { "Starting import_as_tellico_xml_archive... " }
|
77
72
|
return nil unless system("unzip -qqt \"#{filename}\"")
|
78
73
|
|
79
74
|
tmpdir = File.join(Dir.tmpdir, "tellico_export")
|
@@ -102,34 +97,21 @@ module Alexandria
|
|
102
97
|
keys = ["isbn", "publisher", "pub_year", "binding"]
|
103
98
|
|
104
99
|
book_elements = [neaten(elements["title"].text)]
|
105
|
-
book_elements += if
|
100
|
+
book_elements += if elements["authors"].nil?
|
101
|
+
[[]]
|
102
|
+
else
|
106
103
|
[elements["authors"].elements.to_a.map \
|
107
104
|
{ |x| neaten(x.text) }]
|
108
|
-
else
|
109
|
-
[[]]
|
110
105
|
end
|
111
106
|
book_elements += keys.map do |key|
|
112
107
|
neaten(elements[key].text) if elements[key]
|
113
108
|
end
|
114
|
-
|
115
|
-
if book_elements[2].nil? || book_elements[2].strip.empty?
|
116
|
-
book_elements[2] = nil
|
117
|
-
else
|
118
|
-
begin
|
119
|
-
book_elements[2] = book_elements[2].strip
|
120
|
-
book_elements[2] = Library.canonicalise_ean(book_elements[2])
|
121
|
-
rescue StandardError => ex
|
122
|
-
puts book_elements[2]
|
123
|
-
puts ex.message
|
124
|
-
puts ex.backtrace.join("\n> ")
|
125
|
-
raise ex
|
126
|
-
end
|
127
|
-
end
|
109
|
+
book_elements[2] = Library.canonicalise_ean(book_elements[2])
|
128
110
|
# publishing_year
|
129
111
|
book_elements[4] = book_elements[4].to_i unless book_elements[4].nil?
|
130
|
-
|
112
|
+
log.debug { book_elements.inspect }
|
131
113
|
cover = (neaten(elements["cover"].text) if elements["cover"])
|
132
|
-
|
114
|
+
log.debug { cover }
|
133
115
|
book = Book.new(*book_elements)
|
134
116
|
if elements["rating"]
|
135
117
|
rating = elements["rating"].text.to_i
|
@@ -140,19 +122,16 @@ module Alexandria
|
|
140
122
|
on_iterate_cb&.call(n + 1, total)
|
141
123
|
end
|
142
124
|
|
143
|
-
library
|
125
|
+
# TODO: Pass in library store as an argument
|
126
|
+
library = LibraryCollection.instance.library_store.load_library name
|
144
127
|
content.each do |book, cover|
|
145
|
-
unless cover.nil?
|
146
|
-
library.save_cover(book,
|
147
|
-
File.join(Dir.pwd, "images",
|
148
|
-
cover))
|
149
|
-
end
|
128
|
+
library.save_cover(book, File.join(Dir.pwd, "images", cover)) unless cover.nil?
|
150
129
|
library << book
|
151
130
|
library.save(book)
|
152
131
|
end
|
153
132
|
return [library, []]
|
154
133
|
rescue StandardError => ex
|
155
|
-
|
134
|
+
log.info { ex.message }
|
156
135
|
return nil
|
157
136
|
end
|
158
137
|
end
|
@@ -160,7 +139,7 @@ module Alexandria
|
|
160
139
|
def self.import_as_csv_file(name, filename, on_iterate_cb, _on_error_cb)
|
161
140
|
require "alexandria/import_library_csv"
|
162
141
|
books_and_covers = []
|
163
|
-
line_count =
|
142
|
+
line_count = File.readlines(filename).reduce(0) { |count, _line| count + 1 }
|
164
143
|
|
165
144
|
import_count = 0
|
166
145
|
max_import = line_count - 1
|
@@ -177,7 +156,7 @@ module Alexandria
|
|
177
156
|
if book.isbn
|
178
157
|
# if we can search by ISBN, try to grab the cover
|
179
158
|
begin
|
180
|
-
dl_book, dl_cover =
|
159
|
+
dl_book, dl_cover = BookProviders.isbn_search(book.isbn)
|
181
160
|
if dl_book.authors.size > book.authors.size
|
182
161
|
# LibraryThing only supports a single author, so
|
183
162
|
# attempt to include more author information if it's
|
@@ -187,8 +166,7 @@ module Alexandria
|
|
187
166
|
book.edition = dl_book.edition unless book.edition
|
188
167
|
cover = dl_cover
|
189
168
|
rescue StandardError
|
190
|
-
|
191
|
-
# note failure
|
169
|
+
log.debug { "Failed to get cover for #{book.title} #{book.isbn}" }
|
192
170
|
end
|
193
171
|
end
|
194
172
|
|
@@ -203,7 +181,7 @@ module Alexandria
|
|
203
181
|
# probably Goodreads' wonky ISBN fields ,,="043432432X",
|
204
182
|
# this is a hack to fix up such files
|
205
183
|
data = File.read(filename)
|
206
|
-
data.gsub!(
|
184
|
+
data.gsub!(/,="/, ',"')
|
207
185
|
csv_fixed = Tempfile.new("alexandria_import_csv_fixed_")
|
208
186
|
csv_fixed.write(data)
|
209
187
|
csv_fixed.close
|
@@ -216,12 +194,13 @@ module Alexandria
|
|
216
194
|
end
|
217
195
|
end
|
218
196
|
|
219
|
-
library
|
197
|
+
# TODO: Pass in library store as an argument
|
198
|
+
library = LibraryCollection.instance.library_store.load_library name
|
220
199
|
|
221
200
|
books_and_covers.each do |book, cover_uri|
|
222
|
-
|
201
|
+
log.debug { "Saving #{book.isbn} cover" }
|
223
202
|
library.save_cover(book, cover_uri) unless cover_uri.nil?
|
224
|
-
|
203
|
+
log.debug { "Saving #{book.isbn}" }
|
225
204
|
library << book
|
226
205
|
library.save(book)
|
227
206
|
end
|
@@ -230,18 +209,12 @@ module Alexandria
|
|
230
209
|
|
231
210
|
def self.import_as_isbn_list(name, filename, on_iterate_cb,
|
232
211
|
on_error_cb)
|
233
|
-
|
234
|
-
isbn_list =
|
235
|
-
|
236
|
-
|
237
|
-
begin
|
238
|
-
[line.chomp, canonicalise_isbn(line.chomp)] unless line == "\n"
|
239
|
-
rescue StandardError => ex
|
240
|
-
puts ex.message
|
241
|
-
[line.chomp, nil]
|
242
|
-
end
|
212
|
+
log.debug { "Starting import_as_isbn_list... " }
|
213
|
+
isbn_list = File.readlines(filename).map do |line|
|
214
|
+
log.debug { "Trying line #{line}" }
|
215
|
+
[line.chomp, canonicalise_isbn(line.chomp)] unless line == "\n"
|
243
216
|
end
|
244
|
-
|
217
|
+
log.debug { "Isbn list: #{isbn_list.inspect}" }
|
245
218
|
isbn_list.compact!
|
246
219
|
return nil if isbn_list.empty?
|
247
220
|
|
@@ -253,27 +226,30 @@ module Alexandria
|
|
253
226
|
isbn_list.each do |isbn|
|
254
227
|
begin
|
255
228
|
if isbn[1]
|
256
|
-
books <<
|
229
|
+
books << BookProviders.isbn_search(isbn[1])
|
257
230
|
else
|
258
231
|
bad_isbns << isbn[0]
|
259
232
|
end
|
260
|
-
rescue
|
261
|
-
|
233
|
+
rescue BookProviders::SearchEmptyError => ex
|
234
|
+
log.debug { ex.message }
|
262
235
|
failed_lookup_isbns << isbn[1]
|
263
|
-
|
236
|
+
log.debug { "NOTE : ignoring on_error_cb #{on_error_cb}" }
|
264
237
|
# return nil unless
|
265
238
|
# (on_error_cb and on_error_cb.call(e.message))
|
266
239
|
end
|
267
240
|
|
268
241
|
on_iterate_cb&.call(current_iteration += 1, max_iterations)
|
269
242
|
end
|
270
|
-
|
271
|
-
|
272
|
-
|
243
|
+
log.debug { "Bad Isbn list: #{bad_isbns.inspect}" } if bad_isbns
|
244
|
+
|
245
|
+
# TODO: Pass in library store as an argument
|
246
|
+
library = LibraryCollection.instance.library_store.load_library name
|
247
|
+
|
248
|
+
log.debug { "Going with these #{books.length} books: #{books.inspect}" }
|
273
249
|
books.each do |book, cover_uri|
|
274
|
-
|
250
|
+
log.debug { "Saving #{book.isbn} cover..." }
|
275
251
|
library.save_cover(book, cover_uri) unless cover_uri.nil?
|
276
|
-
|
252
|
+
log.debug { "Saving #{book.isbn}..." }
|
277
253
|
library << book
|
278
254
|
library.save(book)
|
279
255
|
on_iterate_cb&.call(current_iteration += 1, max_iterations)
|
@@ -72,8 +72,7 @@ module Alexandria
|
|
72
72
|
additional.split(",").each do |add|
|
73
73
|
authors << normalize(add)
|
74
74
|
end
|
75
|
-
isbn = row[@isbn]
|
76
|
-
isbn = Library.canonicalise_ean(isbn) if isbn
|
75
|
+
isbn = Library.canonicalise_ean(row[@isbn])
|
77
76
|
publisher = normalize(row[@publisher])
|
78
77
|
year = row[@publishing_year].to_i
|
79
78
|
edition = normalize(row[@edition])
|
@@ -95,12 +94,13 @@ module Alexandria
|
|
95
94
|
book.redd = true
|
96
95
|
end
|
97
96
|
if row[@mainshelf]
|
98
|
-
|
97
|
+
case row[@mainshelf]
|
98
|
+
when "read"
|
99
99
|
book.redd = true
|
100
|
-
|
100
|
+
when "to-read"
|
101
101
|
book.redd = false
|
102
102
|
book.tags = ["to read"]
|
103
|
-
|
103
|
+
when "currently-reading"
|
104
104
|
book.redd = false
|
105
105
|
book.tags = ["currently reading"]
|
106
106
|
end
|
@@ -112,7 +112,7 @@ module Alexandria
|
|
112
112
|
book.tags << tag unless book.tags.include? tag
|
113
113
|
end
|
114
114
|
end
|
115
|
-
|
115
|
+
log.debug { "Goodreads loading #{book.title}" }
|
116
116
|
book
|
117
117
|
end
|
118
118
|
end
|
@@ -146,7 +146,7 @@ module Alexandria
|
|
146
146
|
# sometimes "Publisher (YEAR), Edition: NUM, Binding, NUM pages"
|
147
147
|
publisher_info = normalize(row[@publisher_info])
|
148
148
|
publisher = publisher_info
|
149
|
-
publisher = Regexp.last_match[1] if publisher_info =~ /([
|
149
|
+
publisher = Regexp.last_match[1] if publisher_info =~ /([^(]+)\(/
|
150
150
|
edition = publisher_info # binding
|
151
151
|
edition_info = publisher_info.split(",")
|
152
152
|
edition = publisher_info.split(",")[-2] if edition_info.size >= 3
|
@@ -169,7 +169,7 @@ module Alexandria
|
|
169
169
|
end
|
170
170
|
end
|
171
171
|
|
172
|
-
|
172
|
+
log.debug { "LibraryThing loading #{book.title}" }
|
173
173
|
book
|
174
174
|
end
|
175
175
|
end
|
@@ -183,20 +183,20 @@ module Alexandria
|
|
183
183
|
is_librarything = false
|
184
184
|
is_goodreads = false
|
185
185
|
header.each do |head|
|
186
|
-
|
186
|
+
case head
|
187
|
+
when "'PUBLICATION INFO'"
|
187
188
|
is_librarything = true
|
188
189
|
break
|
189
|
-
|
190
|
+
when "Year Published"
|
190
191
|
is_goodreads = true
|
191
192
|
break
|
192
193
|
end
|
193
194
|
end
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
raise "Not Recognized" unless is_librarything || is_goodreads
|
195
|
+
|
196
|
+
return LibraryThingCSVImport.new(header) if is_librarything
|
197
|
+
return GoodreadsCSVImport.new(header) if is_goodreads
|
198
|
+
|
199
|
+
raise _("Not Recognized") unless is_librarything || is_goodreads
|
200
200
|
end
|
201
201
|
end
|
202
202
|
end
|
@@ -9,7 +9,7 @@ module Alexandria
|
|
9
9
|
include Logging
|
10
10
|
|
11
11
|
FIX_BIGNUM_REGEX =
|
12
|
-
%r{loaned_since:\s*(
|
12
|
+
%r{loaned_since:\s*(!ruby/object:Bignum\s*)?(\d+)\n}.freeze
|
13
13
|
|
14
14
|
include GetText
|
15
15
|
bindtextdomain(Alexandria::TEXTDOMAIN, charset: "UTF-8")
|
@@ -23,7 +23,7 @@ module Alexandria
|
|
23
23
|
begin
|
24
24
|
Dir.entries(library_dir).each do |file|
|
25
25
|
# Skip hidden files.
|
26
|
-
next if
|
26
|
+
next if file.start_with?(".")
|
27
27
|
# Skip non-directory files.
|
28
28
|
next unless File.stat(File.join(library_dir, file)).directory?
|
29
29
|
|
@@ -64,7 +64,7 @@ module Alexandria
|
|
64
64
|
old_isbn = book.isbn
|
65
65
|
old_pub_year = book.publishing_year
|
66
66
|
begin
|
67
|
-
raise "Not a book:
|
67
|
+
raise format(_("Not a book: %<book>s"), book.inspect) unless book.is_a?(Book)
|
68
68
|
|
69
69
|
ean = Library.canonicalise_ean(book.isbn)
|
70
70
|
book.isbn = ean if ean
|
@@ -74,16 +74,18 @@ module Alexandria
|
|
74
74
|
end
|
75
75
|
|
76
76
|
# Or if isbn has changed
|
77
|
-
|
77
|
+
unless book.isbn == old_isbn
|
78
|
+
raise format(_("%<file>s isbn is not okay"), file: test[1])
|
79
|
+
end
|
78
80
|
|
79
81
|
# Re-save book if Alexandria::DATA_VERSION changes
|
80
82
|
unless book.version == Alexandria::DATA_VERSION
|
81
|
-
raise "
|
83
|
+
raise format(_("%<file>s version is not okay"), file: test[1])
|
82
84
|
end
|
83
85
|
|
84
86
|
# Or if publishing year has changed
|
85
87
|
unless book.publishing_year == old_pub_year
|
86
|
-
raise "
|
88
|
+
raise format(_("%<file>s pub year is not okay"), file: test[1])
|
87
89
|
end
|
88
90
|
|
89
91
|
# ruined_books << [book, book.isbn, library]
|
@@ -92,13 +94,11 @@ module Alexandria
|
|
92
94
|
## TODO copy cover image file, if necessary
|
93
95
|
# due to #26909 cover files for books without ISBN are re-saved as
|
94
96
|
# "g#{ident}.cover"
|
95
|
-
if book.isbn.nil? || book.isbn.empty?
|
96
|
-
|
97
|
-
|
98
|
-
"#{library.name}; book #{book.title} has no ISBN, fixing cover image"
|
99
|
-
end
|
100
|
-
FileUtils::Verbose.mv(library.old_cover(book), library.cover(book))
|
97
|
+
if (book.isbn.nil? || book.isbn.empty?) && File.exist?(library.old_cover(book))
|
98
|
+
log.debug do
|
99
|
+
"#{library.name}; book #{book.title} has no ISBN, fixing cover image"
|
101
100
|
end
|
101
|
+
FileUtils::Verbose.mv(library.old_cover(book), library.cover(book))
|
102
102
|
end
|
103
103
|
|
104
104
|
library << book
|
@@ -152,7 +152,7 @@ module Alexandria
|
|
152
152
|
# Skip non-regular files.
|
153
153
|
next unless File.stat(filename).file?
|
154
154
|
|
155
|
-
text =
|
155
|
+
text = File.read(filename)
|
156
156
|
hash = YAML.safe_load(text, permitted_classes: [Symbol])
|
157
157
|
smart_library = SmartLibrary.from_hash(hash, self)
|
158
158
|
a << smart_library
|
@@ -181,7 +181,7 @@ module Alexandria
|
|
181
181
|
private
|
182
182
|
|
183
183
|
def regularize_book_from_yaml(name)
|
184
|
-
text =
|
184
|
+
text = File.read(name)
|
185
185
|
|
186
186
|
# Code to remove the mystery string in books imported from Amazon
|
187
187
|
# (In the past, still?) To allow ruby-amazon to be removed.
|
@@ -198,14 +198,13 @@ module Alexandria
|
|
198
198
|
if (md = FIX_BIGNUM_REGEX.match(text))
|
199
199
|
new_yaml = Time.at(md[2].to_i).to_yaml
|
200
200
|
# Remove the "---" prefix.
|
201
|
-
new_yaml.sub!(/^\s
|
201
|
+
new_yaml.sub!(/^\s*-+\s*/, "")
|
202
202
|
text.sub!(md[0], "loaned_since: #{new_yaml}\n")
|
203
203
|
end
|
204
204
|
|
205
|
-
|
206
|
-
book = YAML.safe_load(text, permitted_classes: [Book, Time])
|
205
|
+
book = Book.from_yaml(text)
|
207
206
|
|
208
|
-
unless book.isbn.
|
207
|
+
unless book.isbn.instance_of? String
|
209
208
|
# HACK
|
210
209
|
md = /isbn: (.+)/.match(text)
|
211
210
|
if md
|
@@ -215,7 +214,7 @@ module Alexandria
|
|
215
214
|
end
|
216
215
|
|
217
216
|
# another HACK of the same type as above
|
218
|
-
unless book.saved_ident.
|
217
|
+
unless book.saved_ident.instance_of? String
|
219
218
|
|
220
219
|
md2 = /saved_ident: (.+)/.match(text)
|
221
220
|
if md2
|
@@ -224,7 +223,7 @@ module Alexandria
|
|
224
223
|
book.saved_ident = string_saved_ident
|
225
224
|
end
|
226
225
|
end
|
227
|
-
if (book.isbn.
|
226
|
+
if (book.isbn.instance_of? String) && book.isbn.empty?
|
228
227
|
book.isbn = nil # save trouble later
|
229
228
|
end
|
230
229
|
book
|
data/lib/alexandria/logging.rb
CHANGED
@@ -25,13 +25,13 @@ module Alexandria
|
|
25
25
|
# A Logger subclass which accepts a source for log messages
|
26
26
|
# in order to improve legibility of the logs.
|
27
27
|
# The source should usually be +self+, whether that be a Class, Module
|
28
|
-
# or Object. A
|
28
|
+
# or Object. A LogWrapper can be used to simplify this procedure.
|
29
29
|
class Logger < ::Logger
|
30
30
|
def add(severity, message = nil, source = nil, progname = nil, &block)
|
31
31
|
return super(severity, message, progname, &block) if source.nil?
|
32
32
|
|
33
33
|
category = self.class.category(source)
|
34
|
-
return super(severity, progname, category) unless
|
34
|
+
return super(severity, progname, category) unless block
|
35
35
|
|
36
36
|
category = "#{category} #{progname}" if progname
|
37
37
|
super(severity, message, category, &block)
|
@@ -118,7 +118,7 @@ module Alexandria
|
|
118
118
|
module Logging
|
119
119
|
module ClassMethods
|
120
120
|
def log
|
121
|
-
@
|
121
|
+
@log ||= LogWrapper.new(Alexandria.log, self)
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
@@ -127,15 +127,13 @@ module Alexandria
|
|
127
127
|
end
|
128
128
|
|
129
129
|
def log
|
130
|
-
@
|
130
|
+
@log ||= LogWrapper.new(Alexandria.log, self)
|
131
131
|
end
|
132
132
|
end
|
133
133
|
|
134
|
-
private
|
135
|
-
|
136
134
|
# Creates the Logger for Alexandria
|
137
135
|
def self.create_logger
|
138
|
-
logger = Alexandria::Logger.new(
|
136
|
+
logger = Alexandria::Logger.new($stderr)
|
139
137
|
|
140
138
|
level = ENV["LOGLEVEL"] ? ENV["LOGLEVEL"].intern : nil
|
141
139
|
if [:FATAL, :ERROR, :WARN, :INFO, :DEBUG].include? level
|
@@ -150,8 +148,6 @@ module Alexandria
|
|
150
148
|
|
151
149
|
@@logger = create_logger
|
152
150
|
|
153
|
-
public
|
154
|
-
|
155
151
|
# Returns the Logger for Alexandria
|
156
152
|
def self.log
|
157
153
|
@@logger
|
@@ -64,12 +64,25 @@ module Alexandria
|
|
64
64
|
own || false
|
65
65
|
end
|
66
66
|
|
67
|
-
def ==(
|
68
|
-
|
67
|
+
def ==(other)
|
68
|
+
other.is_a?(self.class) && (ident == other.ident)
|
69
69
|
end
|
70
70
|
|
71
71
|
def inspect
|
72
72
|
"#<Alexandria::Book title: #{@title}>"
|
73
73
|
end
|
74
|
+
|
75
|
+
def self.from_yaml(text)
|
76
|
+
node = YAML.parse_stream text
|
77
|
+
doc = node.children.first
|
78
|
+
mapping = doc.children.first
|
79
|
+
mapping.children.each_slice(2) do |_k, v|
|
80
|
+
v.tag = nil if v.tag == "!ruby/array:Alexandria:Library"
|
81
|
+
end
|
82
|
+
yaml = node.to_yaml
|
83
|
+
|
84
|
+
# TODO: Ensure book loading passes through Book#initialize
|
85
|
+
YAML.safe_load(yaml, permitted_classes: [Book, Time])
|
86
|
+
end
|
74
87
|
end
|
75
88
|
end
|