alexandria-book-collection-manager 0.7.7 → 0.7.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +1 -2
- data/CHANGELOG.md +8 -0
- data/alexandria-book-collection-manager.gemspec +2 -2
- data/lib/alexandria/book_providers.rb +1 -1
- data/lib/alexandria/book_providers/{thalia.rb → thalia_provider.rb} +33 -69
- data/lib/alexandria/logging.rb +1 -1
- data/lib/alexandria/ui/alert_dialog.rb +3 -1
- data/lib/alexandria/ui/book_properties_dialog.rb +0 -1
- data/lib/alexandria/ui/book_properties_dialog_base.rb +7 -8
- data/lib/alexandria/ui/callbacks.rb +3 -3
- data/lib/alexandria/ui/init.rb +11 -10
- data/lib/alexandria/ui/sidepane_manager.rb +3 -1
- data/lib/alexandria/ui/ui_manager.rb +15 -8
- data/lib/alexandria/version.rb +2 -2
- data/spec/alexandria/book_providers/thalia_provider_spec.rb +119 -0
- data/spec/alexandria/book_providers_spec.rb +0 -17
- data/spec/alexandria/ui/book_properties_dialog_spec.rb +46 -4
- data/spec/alexandria/ui/new_book_dialog_manual_spec.rb +38 -2
- data/spec/alexandria/ui/ui_manager_spec.rb +1 -0
- data/spec/fixtures/cover.jpg +0 -0
- metadata +14 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 86ff53adf7e1792c32534b149370ab80a99a24c8a363273a1ca3d3f83e2c73c0
|
4
|
+
data.tar.gz: 6a38d050f6cf13a9d86e0c387cdbe472442a02c33f74563f4902f4338deac228
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fbd36ea7f9caaabff7979e3ab57471e27a6a1a5daa33ce140d4a8df590b07d91f4302267db64c601281f3513401e5726a1874dba622a4d9e72a361c7898c1284
|
7
|
+
data.tar.gz: 87c17e9d9bc4c4bd057a1013068d034a48ca38e3fcd5784a743a1c1d971671165df4347bcb2aa710dd4a636ecc3d1bfdbee1f0bfe7a4eb7fccd7d4fb8acddd77
|
data/.rubocop_todo.yml
CHANGED
@@ -21,7 +21,7 @@ Metrics/BlockNesting:
|
|
21
21
|
|
22
22
|
# Configuration parameters: CountComments, CountAsOne.
|
23
23
|
Metrics/ClassLength:
|
24
|
-
Max:
|
24
|
+
Max: 997
|
25
25
|
|
26
26
|
# Configuration parameters: IgnoredMethods.
|
27
27
|
Metrics/CyclomaticComplexity:
|
@@ -125,7 +125,6 @@ Style/OptionalBooleanParameter:
|
|
125
125
|
- 'lib/alexandria/book_providers.rb'
|
126
126
|
- 'lib/alexandria/book_providers/barnes_and_noble.rb'
|
127
127
|
- 'lib/alexandria/book_providers/siciliano.rb'
|
128
|
-
- 'lib/alexandria/book_providers/thalia.rb'
|
129
128
|
- 'lib/alexandria/book_providers/worldcat.rb'
|
130
129
|
- 'lib/alexandria/console.rb'
|
131
130
|
- 'lib/alexandria/execution_queue.rb'
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 0.7.8 / 2020-11-29
|
4
|
+
|
5
|
+
* Fix ThaliaProvider
|
6
|
+
* Avoid warnings for calendar popup
|
7
|
+
* Make Rename menu item work
|
8
|
+
* Fix crash when changing covers
|
9
|
+
* Make alerts show alert details if available
|
10
|
+
|
3
11
|
## 0.7.7 / 2020-11-15
|
4
12
|
|
5
13
|
* Update Polish translation ([#88] by [Piotr Drąg][piotrdrag])
|
@@ -54,13 +54,13 @@ Gem::Specification.new do |s|
|
|
54
54
|
s.add_runtime_dependency("psych", ["~> 3.2.0"])
|
55
55
|
s.add_runtime_dependency("zoom", ["~> 0.5.0"])
|
56
56
|
|
57
|
-
s.add_development_dependency("gnome_app_driver",
|
57
|
+
s.add_development_dependency("gnome_app_driver", "~> 0.3.0")
|
58
58
|
s.add_development_dependency("minitest", ["~> 5.0"])
|
59
59
|
s.add_development_dependency("rake", ["~> 13.0"])
|
60
60
|
s.add_development_dependency("rspec", ["~> 3.0"])
|
61
61
|
s.add_development_dependency("rubocop", "~> 0.93.1")
|
62
62
|
s.add_development_dependency("rubocop-i18n", ["~> 2.0.2"])
|
63
|
-
s.add_development_dependency("rubocop-performance",
|
63
|
+
s.add_development_dependency("rubocop-performance", "~> 1.9.0")
|
64
64
|
s.add_development_dependency("rubocop-rspec", "~> 1.44.1")
|
65
65
|
s.add_development_dependency("webmock", "~> 3.9")
|
66
66
|
|
@@ -299,7 +299,7 @@ module Alexandria
|
|
299
299
|
require "alexandria/book_providers/barnes_and_noble"
|
300
300
|
require "alexandria/book_providers/proxis"
|
301
301
|
require "alexandria/book_providers/siciliano"
|
302
|
-
require "alexandria/book_providers/
|
302
|
+
require "alexandria/book_providers/thalia_provider"
|
303
303
|
require "alexandria/book_providers/worldcat"
|
304
304
|
|
305
305
|
# Z39.50 based providers
|
@@ -1,27 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
# Copyright (C) 2014 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
|
# http://de.wikipedia.org/wiki/Thalia_%28Buchhandel%29
|
22
8
|
# Thalia.de bought the Austrian book trade chain Amadeus
|
23
9
|
|
24
|
-
# New
|
10
|
+
# New Thalia provider, taken from Palatina MetaDataSource and modified
|
25
11
|
# for Alexandria. (21 Dec 2009)
|
26
12
|
|
27
13
|
require "net/http"
|
@@ -33,7 +19,7 @@ module Alexandria
|
|
33
19
|
class ThaliaProvider < WebsiteBasedProvider
|
34
20
|
include Logging
|
35
21
|
|
36
|
-
SITE = "
|
22
|
+
SITE = "https://www.thalia.de"
|
37
23
|
BASE_SEARCH_URL = "#{SITE}/shop/bde_bu_hg_startseite/suche/?%s=%s" # type,term
|
38
24
|
|
39
25
|
def initialize
|
@@ -80,40 +66,36 @@ module Alexandria
|
|
80
66
|
def parse_search_result_data(html)
|
81
67
|
doc = html_to_doc(html)
|
82
68
|
book_search_results = []
|
83
|
-
|
84
|
-
|
69
|
+
|
70
|
+
results_items = doc / "ul.weitere-formate li.format"
|
71
|
+
|
72
|
+
results_items.each do |item|
|
85
73
|
result = {}
|
86
|
-
|
87
|
-
result[:
|
88
|
-
result[:lookup_url] = title_link["href"]
|
74
|
+
item_link = item % "a"
|
75
|
+
result[:lookup_url] = "#{SITE}#{item_link['href']}"
|
89
76
|
book_search_results << result
|
90
77
|
end
|
91
78
|
book_search_results
|
92
79
|
end
|
93
80
|
|
94
81
|
def data_from_label(node, label_text)
|
95
|
-
label_node = node % "
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
end
|
101
|
-
data.strip
|
102
|
-
else
|
103
|
-
""
|
104
|
-
end
|
82
|
+
label_node = node % "th[text()*='#{label_text}']"
|
83
|
+
return "" unless label_node
|
84
|
+
|
85
|
+
item_node = label_node.parent % "td"
|
86
|
+
item_node.inner_text.strip
|
105
87
|
end
|
106
88
|
|
107
89
|
def get_book_from_search_result(result)
|
108
90
|
log.debug { "Fetching book from #{result[:lookup_url]}" }
|
109
91
|
html_data = transport.get_response(URI.parse(result[:lookup_url]))
|
110
|
-
parse_result_data(html_data.body, "noisbn", true)
|
92
|
+
parse_result_data(html_data.body, "noisbn", recursing: true)
|
111
93
|
end
|
112
94
|
|
113
|
-
def parse_result_data(html, isbn, recursing
|
95
|
+
def parse_result_data(html, isbn, recursing: false)
|
114
96
|
doc = html_to_doc(html)
|
115
97
|
|
116
|
-
results_divs = doc / "
|
98
|
+
results_divs = doc / "ul.weitere-formate"
|
117
99
|
unless results_divs.empty?
|
118
100
|
if recursing
|
119
101
|
# already recursing, avoid doing so endlessly second time
|
@@ -122,66 +104,48 @@ module Alexandria
|
|
122
104
|
return
|
123
105
|
end
|
124
106
|
|
125
|
-
# ISBN-lookup results in multiple results
|
126
|
-
# useful, such as for new editions e.g. 9780974514055
|
127
|
-
# "Programming Ruby" )
|
107
|
+
# ISBN-lookup results in multiple results
|
128
108
|
results = parse_search_result_data(html)
|
129
|
-
isbn10 = Library.canonicalise_isbn(isbn)
|
130
|
-
# e.g. .../dave_thomas/ISBN0-9745140-5-5/ID6017044.html
|
131
109
|
chosen = results.first # fallback!
|
132
|
-
results.each do |rslt|
|
133
|
-
if rslt[:lookup_url] =~ %r{/ISBN(\d+[\d-]*)/} &&
|
134
|
-
(Regexp.last_match[1].delete("-") == isbn10)
|
135
|
-
chosen = rslt
|
136
|
-
break
|
137
|
-
end
|
138
|
-
end
|
139
110
|
html_data = transport.get_response(URI.parse(chosen[:lookup_url]))
|
140
|
-
return parse_result_data(html_data.body, isbn, true)
|
111
|
+
return parse_result_data(html_data.body, isbn, recursing: true)
|
141
112
|
end
|
142
113
|
|
143
114
|
begin
|
144
|
-
if (div = doc % "
|
145
|
-
|
146
|
-
title = title_img["alt"]
|
147
|
-
|
148
|
-
# note, the following img also has alt="von Author, Author..."
|
115
|
+
if (div = doc % "section#sbe-product-details")
|
116
|
+
title = div["data-titel"]
|
149
117
|
|
150
|
-
if (
|
118
|
+
if (author_p = doc % "p.aim-author")
|
151
119
|
authors = []
|
152
|
-
author_links =
|
120
|
+
author_links = author_p / :a
|
153
121
|
author_links.each do |a|
|
154
|
-
|
155
|
-
# 'sa' means search author, there may also be 'ssw' (search keyword) links
|
156
|
-
authors << a.inner_text[0..-2].strip
|
157
|
-
# NOTE stripping the little >> character here...
|
158
|
-
end
|
122
|
+
authors << a.inner_text.strip
|
159
123
|
end
|
160
124
|
end
|
161
125
|
|
162
|
-
item_details = doc % "
|
126
|
+
item_details = doc % "section.artikeldetails"
|
163
127
|
isbns = []
|
164
128
|
isbns << data_from_label(item_details, "EAN")
|
165
129
|
isbns << data_from_label(item_details, "ISBN")
|
130
|
+
isbns.reject!(&:empty?)
|
166
131
|
|
167
132
|
year = nil
|
168
|
-
date = data_from_label(item_details, "
|
133
|
+
date = data_from_label(item_details, "Erscheinungsdatum")
|
169
134
|
year = Regexp.last_match[1].to_i if date =~ /(\d{4})/
|
170
135
|
|
171
|
-
|
136
|
+
book_binding = data_from_label(item_details, "Einband")
|
172
137
|
|
173
|
-
publisher = data_from_label(item_details, "
|
138
|
+
publisher = data_from_label(item_details, "Verlag")
|
174
139
|
|
175
140
|
book = Book.new(title, authors, isbns.first,
|
176
|
-
publisher, year,
|
141
|
+
publisher, year, book_binding)
|
177
142
|
|
178
143
|
image_url = nil
|
179
|
-
if (
|
180
|
-
image_url =
|
144
|
+
if (image = doc % "section.imagesPreview img")
|
145
|
+
image_url = image["src"]
|
181
146
|
end
|
182
147
|
|
183
148
|
[book, image_url]
|
184
|
-
|
185
149
|
end
|
186
150
|
rescue StandardError => ex
|
187
151
|
trace = ex.backtrace.join("\n> ")
|
data/lib/alexandria/logging.rb
CHANGED
@@ -31,7 +31,7 @@ module Alexandria
|
|
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)
|
@@ -4,6 +4,8 @@
|
|
4
4
|
#
|
5
5
|
# See the file README.md for authorship and licensing information.
|
6
6
|
|
7
|
+
require "cgi"
|
8
|
+
|
7
9
|
module Alexandria
|
8
10
|
module UI
|
9
11
|
class AlertDialog
|
@@ -26,7 +28,7 @@ module Alexandria
|
|
26
28
|
vbox = Gtk::Box.new(:vertical, 6)
|
27
29
|
vbox.homogeneous = false
|
28
30
|
vbox.pack_start make_label("<b><big>#{title}</big></b>")
|
29
|
-
vbox.pack_start make_label(message.strip)
|
31
|
+
vbox.pack_start make_label CGI.escapeHTML(message.strip) if message
|
30
32
|
hbox.pack_start(vbox)
|
31
33
|
|
32
34
|
@dialog.child.pack_start(hbox)
|
@@ -12,6 +12,7 @@ module Alexandria
|
|
12
12
|
module UI
|
13
13
|
class BookPropertiesDialogBase < BuilderBase
|
14
14
|
include CalendarPopup
|
15
|
+
include Logging
|
15
16
|
include GetText
|
16
17
|
extend GetText
|
17
18
|
GetText.bindtextdomain(Alexandria::TEXTDOMAIN, charset: "UTF-8")
|
@@ -156,14 +157,12 @@ module Alexandria
|
|
156
157
|
|
157
158
|
@@latest_filechooser_directory = ENV["HOME"]
|
158
159
|
def on_change_cover
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
[Gtk::Stock::CANCEL, Gtk::ResponseType::CANCEL],
|
166
|
-
[Gtk::Stock::OPEN, Gtk::ResponseType::ACCEPT])
|
160
|
+
dialog = Gtk::FileChooserDialog.new(title: _("Select a cover image"),
|
161
|
+
parent: @book_properties_dialog,
|
162
|
+
action: :open,
|
163
|
+
buttons: [[_("No Cover"), :reject],
|
164
|
+
[Gtk::Stock::CANCEL, :cancel],
|
165
|
+
[Gtk::Stock::OPEN, :accept]])
|
167
166
|
dialog.current_folder = @@latest_filechooser_directory
|
168
167
|
response = dialog.run
|
169
168
|
case response
|
@@ -201,9 +201,9 @@ module Alexandria
|
|
201
201
|
|
202
202
|
def on_rename(*)
|
203
203
|
iter = @library_listview.selection.selected
|
204
|
-
@library_listview.
|
205
|
-
|
206
|
-
|
204
|
+
column = @library_listview.get_column(0)
|
205
|
+
cell = column.cells.last
|
206
|
+
@library_listview.set_cursor_on_cell(iter.path, column, cell, true)
|
207
207
|
end
|
208
208
|
|
209
209
|
def on_delete(*)
|
data/lib/alexandria/ui/init.rb
CHANGED
@@ -24,28 +24,29 @@ class Gtk::ActionGroup
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
|
28
|
-
def
|
29
|
-
@old_model
|
30
|
-
self.model = nil
|
27
|
+
module Alexandria::UI::FreezeThaw
|
28
|
+
def frozen?
|
29
|
+
@old_model && !model
|
31
30
|
end
|
32
31
|
|
33
|
-
def unfreeze
|
34
|
-
self.model = @old_model
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
class Gtk::TreeView
|
39
32
|
def freeze
|
33
|
+
return if frozen?
|
34
|
+
|
40
35
|
@old_model = model
|
41
36
|
self.model = nil
|
42
37
|
end
|
43
38
|
|
44
39
|
def unfreeze
|
40
|
+
return unless frozen?
|
41
|
+
|
45
42
|
self.model = @old_model
|
43
|
+
@old_model = nil
|
46
44
|
end
|
47
45
|
end
|
48
46
|
|
47
|
+
Gtk::IconView.include Alexandria::UI::FreezeThaw
|
48
|
+
Gtk::TreeView.include Alexandria::UI::FreezeThaw
|
49
|
+
|
49
50
|
class Alexandria::Library
|
50
51
|
def action_name
|
51
52
|
"MoveIn" + name.gsub(/\s/, "")
|
@@ -108,7 +108,9 @@ module Alexandria
|
|
108
108
|
cell.editable = iter[2]
|
109
109
|
# log.debug { "exit sidepane: editable #{cell}, #{iter}" }
|
110
110
|
end
|
111
|
-
renderer.signal_connect("edited",
|
111
|
+
renderer.signal_connect("edited") do |cell, path_string, new_text|
|
112
|
+
on_edited_library(cell, path_string, new_text)
|
113
|
+
end
|
112
114
|
@library_listview.append_column(column)
|
113
115
|
|
114
116
|
@library_listview.set_row_separator_func do |model, iter|
|
@@ -123,7 +123,9 @@ module Alexandria
|
|
123
123
|
|
124
124
|
def setup_toolbar_filter_entry
|
125
125
|
@filter_entry = Gtk::Entry.new
|
126
|
-
@filter_entry.signal_connect("changed"
|
126
|
+
@filter_entry.signal_connect("changed") do |entry|
|
127
|
+
on_toolbar_filter_entry_changed(entry)
|
128
|
+
end
|
127
129
|
@toolitem = Gtk::ToolItem.new
|
128
130
|
@toolitem.expand = true
|
129
131
|
@toolitem.border_width = 5
|
@@ -149,7 +151,7 @@ module Alexandria
|
|
149
151
|
cb.append_text(item)
|
150
152
|
end
|
151
153
|
cb.active = 0
|
152
|
-
cb.signal_connect("changed"
|
154
|
+
cb.signal_connect("changed") { |combo| on_criterion_combobox_changed(combo) }
|
153
155
|
|
154
156
|
# Put the combo box in a event box because it is not currently
|
155
157
|
# possible assign a tooltip to a combo box.
|
@@ -167,8 +169,9 @@ module Alexandria
|
|
167
169
|
@toolbar_view_as.append_text(_("View as Icons"))
|
168
170
|
@toolbar_view_as.append_text(_("View as List"))
|
169
171
|
@toolbar_view_as.active = 0
|
170
|
-
@toolbar_view_as_signal_hid =
|
171
|
-
|
172
|
+
@toolbar_view_as_signal_hid = @toolbar_view_as.signal_connect("changed") do |combo|
|
173
|
+
on_toolbar_view_as_changed(combo)
|
174
|
+
end
|
172
175
|
|
173
176
|
# Put the combo box in a event box because it is not currently
|
174
177
|
# possible assign a tooltip to a combo box.
|
@@ -226,8 +229,12 @@ module Alexandria
|
|
226
229
|
|
227
230
|
def setup_window_events
|
228
231
|
log.debug { "setup_window_events" }
|
229
|
-
@main_app.signal_connect("window-state-event",
|
230
|
-
|
232
|
+
@main_app.signal_connect("window-state-event") do |window, event|
|
233
|
+
on_window_state_event(window, event)
|
234
|
+
end
|
235
|
+
@main_app.signal_connect("destroy") do |window|
|
236
|
+
on_window_destroy(window)
|
237
|
+
end
|
231
238
|
end
|
232
239
|
|
233
240
|
def setup_active_model
|
@@ -343,7 +350,7 @@ module Alexandria
|
|
343
350
|
sensitize_library selected_library if library_already_selected
|
344
351
|
|
345
352
|
GLib::Idle.add do
|
346
|
-
menu.
|
353
|
+
menu.popup_at_pointer(event)
|
347
354
|
false
|
348
355
|
end
|
349
356
|
|
@@ -391,7 +398,7 @@ module Alexandria
|
|
391
398
|
end
|
392
399
|
|
393
400
|
menu = selected_books.empty? ? @nobook_popup : @book_popup
|
394
|
-
menu.
|
401
|
+
menu.popup_at_pointer(event)
|
395
402
|
end
|
396
403
|
|
397
404
|
def get_library_selection_text(library)
|
data/lib/alexandria/version.rb
CHANGED
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This file is part of Alexandria.
|
4
|
+
#
|
5
|
+
# See the file README.md for authorship and licensing information.
|
6
|
+
|
7
|
+
require "spec_helper"
|
8
|
+
|
9
|
+
RSpec.describe Alexandria::BookProviders::ThaliaProvider do
|
10
|
+
let(:normal_people_main) do
|
11
|
+
+<<~HTML
|
12
|
+
<!DOCTYPE html>
|
13
|
+
<html lang="de" data-environment="prod">
|
14
|
+
<head>
|
15
|
+
<title>Artikel von 0571334652 ansehen | Thalia</title>
|
16
|
+
</head>
|
17
|
+
<body data-mandant="2" data-version="20201112100740_528b0df" data-environment="prod">
|
18
|
+
<main class="suche-grid--main nur-suchergebnis">
|
19
|
+
<section class="suchergebnis">
|
20
|
+
<ul class="suchergebnis-liste no-bullets">
|
21
|
+
<li class="suchergebnis" data-seite="1"
|
22
|
+
data-ean="9780571334650"
|
23
|
+
data-id="134292338"
|
24
|
+
data-preis="9.49"
|
25
|
+
data-preis-reduziert="false"
|
26
|
+
data-alterpreis="">
|
27
|
+
<a href="/shop/home/artikeldetails/ID134292338.html" class="layered-link">Normal People von Sally Rooney</a>
|
28
|
+
|
29
|
+
<ul class="weitere-formate no-bullets" impression="product-variant">
|
30
|
+
<li class="format aktiv">
|
31
|
+
<a href="/shop/home/artikeldetails/ID134292338.html">Buch (Taschenbuch)</a>
|
32
|
+
</li>
|
33
|
+
<li class="format">
|
34
|
+
<a href="/shop/home/artikeldetails/ID95227195.html">Weitere: Buch (Taschenbuch)</a>
|
35
|
+
</li>
|
36
|
+
</ul>
|
37
|
+
</li>
|
38
|
+
</ul>
|
39
|
+
</section>
|
40
|
+
</main>
|
41
|
+
</body>
|
42
|
+
</html>
|
43
|
+
HTML
|
44
|
+
end
|
45
|
+
let(:normal_people_details) do
|
46
|
+
+<<~HTML
|
47
|
+
<!DOCTYPE html>
|
48
|
+
<html class="no-js" id="ID-2" lang="de">
|
49
|
+
<head>
|
50
|
+
<title>Normal People von Sally Rooney - Taschenbuch - 978-0-571-33465-0 | Thalia</title>
|
51
|
+
</head>
|
52
|
+
<body>
|
53
|
+
<section class="artikel-medien imagesPreview">
|
54
|
+
<img src="https://assets.thalia.media/img/artikel/ae9934c90f2c7d595146807ea6253c99532043ec-00-00.jpeg" class='largeImg'>
|
55
|
+
</section>
|
56
|
+
|
57
|
+
<section class="artikel-infos" id="sbe-product-details"
|
58
|
+
data-shopid="2"
|
59
|
+
data-id="A1051452169"
|
60
|
+
data-id-alt="134292338"
|
61
|
+
data-titel="Normal People"
|
62
|
+
data-verfuegbarkeit="Sofort lieferbar"
|
63
|
+
data-preis-netto="9.02"
|
64
|
+
data-preis-brutto="9.49"
|
65
|
+
data-ean="9780571334650"
|
66
|
+
data-reduziert="false"
|
67
|
+
data-waehrung="EUR"
|
68
|
+
data-preis-liste="9.49"
|
69
|
+
data-hersteller="Faber & Faber"
|
70
|
+
data-form="Taschenbuch"
|
71
|
+
data-verkaufsrang="5"
|
72
|
+
data-anzahlbewertungen="19"
|
73
|
+
data-durchschnittsbewertung="4.5"
|
74
|
+
data-preisbindung="false"
|
75
|
+
data-mandant="2"
|
76
|
+
data-environment="prod"
|
77
|
+
component="artikeldetails-produktdetails">
|
78
|
+
|
79
|
+
<h1 class="ncTitle">
|
80
|
+
Normal People
|
81
|
+
</h1>
|
82
|
+
|
83
|
+
<p class="aim-author">
|
84
|
+
<a href="https://www.thalia.de/shop/home/mehr-von-suche/ANY/sp/suche.html?mehrVon=Sally%20Rooney" interaction="autor-klick">Sally Rooney</a>
|
85
|
+
</p>
|
86
|
+
</section>
|
87
|
+
|
88
|
+
<section class="artikeldetails">
|
89
|
+
<table>
|
90
|
+
<tr> <th> Einband </th> <td> Taschenbuch </td> </tr>
|
91
|
+
<tr> <th> Erscheinungsdatum </th> <td> 02.05.2019 </td> </tr>
|
92
|
+
<tr> <th> ISBN </th> <td> 978-0-571-33465-0 </td> </tr>
|
93
|
+
</table>
|
94
|
+
<table>
|
95
|
+
<tr>
|
96
|
+
<th> Verlag </th>
|
97
|
+
<td>
|
98
|
+
<a href="https://www.thalia.de/shop/home/mehr-von-suche/ANY/sv/suche.html?mehrVon=Faber%20%26%20Faber" interaction="auswahl">
|
99
|
+
Faber & Faber
|
100
|
+
</a>
|
101
|
+
</td>
|
102
|
+
</tr>
|
103
|
+
</table>
|
104
|
+
</section>
|
105
|
+
</body>
|
106
|
+
</html>
|
107
|
+
HTML
|
108
|
+
end
|
109
|
+
|
110
|
+
it "works when searching by ISBN" do
|
111
|
+
stub_request(:get,
|
112
|
+
"https://www.thalia.de/shop/bde_bu_hg_startseite/suche/?sq=0571334652")
|
113
|
+
.to_return(status: 200, body: normal_people_main, headers: {})
|
114
|
+
stub_request(:get, "https://www.thalia.de/shop/home/artikeldetails/ID134292338.html")
|
115
|
+
.to_return(status: 200, body: normal_people_details, headers: {})
|
116
|
+
|
117
|
+
assert_correct_search_result(described_class, "9780571334650")
|
118
|
+
end
|
119
|
+
end
|
@@ -76,23 +76,6 @@ describe Alexandria::BookProviders do
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
|
-
describe Alexandria::BookProviders::ThaliaProvider do
|
80
|
-
before do
|
81
|
-
skip "Needs fixing"
|
82
|
-
end
|
83
|
-
|
84
|
-
it "works" do
|
85
|
-
# german book
|
86
|
-
assert_correct_search_result(described_class, "9783896673305")
|
87
|
-
# international book
|
88
|
-
assert_correct_search_result(described_class, "9780440241904")
|
89
|
-
# movie dvd
|
90
|
-
assert_correct_search_result(described_class, "4010232037824")
|
91
|
-
# music cd
|
92
|
-
assert_correct_search_result(described_class, "0094638203520")
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
79
|
describe Alexandria::BookProviders::AdLibrisProvider do
|
97
80
|
it "works" do
|
98
81
|
skip "Needs fixing: site has changed"
|
@@ -7,11 +7,53 @@
|
|
7
7
|
require_relative "../../spec_helper"
|
8
8
|
|
9
9
|
describe Alexandria::UI::BookPropertiesDialog do
|
10
|
+
let(:parent) { Gtk::Window.new :toplevel }
|
11
|
+
let(:library) do
|
12
|
+
store = Alexandria::LibraryCollection.instance.library_store
|
13
|
+
store.load_library("Bar Library")
|
14
|
+
end
|
15
|
+
let(:book) do
|
16
|
+
Alexandria::Book.new("Foo Book", ["Jane Doe"], "98765432", "Bar Publisher",
|
17
|
+
1972, "edition")
|
18
|
+
end
|
19
|
+
|
20
|
+
before do
|
21
|
+
library << book
|
22
|
+
end
|
23
|
+
|
10
24
|
it "works" do
|
11
|
-
parent = Gtk::Window.new :toplevel
|
12
|
-
library = instance_double(Alexandria::Library, name: "Bar Library", cover: "")
|
13
|
-
book = Alexandria::Book.new("Foo Book", ["Jane Doe"], "98765432", "Bar Publisher",
|
14
|
-
1972, "edition")
|
15
25
|
described_class.new parent, library, book
|
16
26
|
end
|
27
|
+
|
28
|
+
describe "#on_change_cover" do
|
29
|
+
let(:dialog) { described_class.new parent, library, book }
|
30
|
+
let(:filechooser) { instance_double(Gtk::FileChooserDialog).as_null_object }
|
31
|
+
|
32
|
+
before do
|
33
|
+
allow(Gtk::FileChooserDialog).to receive(:new).and_return(filechooser)
|
34
|
+
allow(filechooser).to receive(:filename)
|
35
|
+
.and_return File.join(__dir__, "../../fixtures/cover.jpg")
|
36
|
+
end
|
37
|
+
|
38
|
+
it "works when response is accept" do
|
39
|
+
allow(filechooser)
|
40
|
+
.to receive(:run).and_return(Gtk::ResponseType::ACCEPT)
|
41
|
+
|
42
|
+
dialog.on_change_cover
|
43
|
+
end
|
44
|
+
|
45
|
+
it "works when response is reject" do
|
46
|
+
allow(filechooser)
|
47
|
+
.to receive(:run).and_return(Gtk::ResponseType::REJECT)
|
48
|
+
|
49
|
+
dialog.on_change_cover
|
50
|
+
end
|
51
|
+
|
52
|
+
it "works when response is cancel" do
|
53
|
+
allow(filechooser)
|
54
|
+
.to receive(:run).and_return(Gtk::ResponseType::CANCEL)
|
55
|
+
|
56
|
+
dialog.on_change_cover
|
57
|
+
end
|
58
|
+
end
|
17
59
|
end
|
@@ -7,9 +7,45 @@
|
|
7
7
|
require_relative "../../spec_helper"
|
8
8
|
|
9
9
|
describe Alexandria::UI::NewBookDialogManual do
|
10
|
+
let(:parent) { Gtk::Window.new :toplevel }
|
11
|
+
let(:library) do
|
12
|
+
store = Alexandria::LibraryCollection.instance.library_store
|
13
|
+
store.load_library("Bar Library")
|
14
|
+
end
|
15
|
+
|
10
16
|
it "works" do
|
11
|
-
parent = Gtk::Window.new :toplevel
|
12
|
-
library = instance_double(Alexandria::Library)
|
13
17
|
described_class.new parent, library
|
14
18
|
end
|
19
|
+
|
20
|
+
describe "#on_change_cover" do
|
21
|
+
let(:dialog) { described_class.new parent, library }
|
22
|
+
let(:filechooser) { instance_double(Gtk::FileChooserDialog).as_null_object }
|
23
|
+
|
24
|
+
before do
|
25
|
+
allow(Gtk::FileChooserDialog).to receive(:new).and_return(filechooser)
|
26
|
+
allow(filechooser).to receive(:filename)
|
27
|
+
.and_return File.join(__dir__, "../../fixtures/cover.jpg")
|
28
|
+
end
|
29
|
+
|
30
|
+
it "works when response is accept" do
|
31
|
+
allow(filechooser)
|
32
|
+
.to receive(:run).and_return(Gtk::ResponseType::ACCEPT)
|
33
|
+
|
34
|
+
dialog.on_change_cover
|
35
|
+
end
|
36
|
+
|
37
|
+
it "works when response is reject" do
|
38
|
+
allow(filechooser)
|
39
|
+
.to receive(:run).and_return(Gtk::ResponseType::REJECT)
|
40
|
+
|
41
|
+
dialog.on_change_cover
|
42
|
+
end
|
43
|
+
|
44
|
+
it "works when response is cancel" do
|
45
|
+
allow(filechooser)
|
46
|
+
.to receive(:run).and_return(Gtk::ResponseType::CANCEL)
|
47
|
+
|
48
|
+
dialog.on_change_cover
|
49
|
+
end
|
50
|
+
end
|
15
51
|
end
|
@@ -39,6 +39,7 @@ describe Alexandria::UI::UIManager do
|
|
39
39
|
# FIXME: This is needed because right now UIManager#refresh_books doesn't
|
40
40
|
# work without Gtk loop.
|
41
41
|
regular_library.each { |book| ui.append_book book }
|
42
|
+
# This makes the iconview model re-appear
|
42
43
|
ui.iconview.unfreeze
|
43
44
|
expect(ui.model.iter_n_children).to eq regular_library.count
|
44
45
|
|
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alexandria-book-collection-manager
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander McCormmach
|
@@ -25,10 +25,10 @@ authors:
|
|
25
25
|
- Takayuki Kusano
|
26
26
|
- Timothy Malone
|
27
27
|
- Zachary P. Landau
|
28
|
-
autorequire:
|
28
|
+
autorequire:
|
29
29
|
bindir: bin
|
30
30
|
cert_chain: []
|
31
|
-
date: 2020-11-
|
31
|
+
date: 2020-11-29 00:00:00.000000000 Z
|
32
32
|
dependencies:
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: gettext
|
@@ -162,14 +162,14 @@ dependencies:
|
|
162
162
|
requirements:
|
163
163
|
- - "~>"
|
164
164
|
- !ruby/object:Gem::Version
|
165
|
-
version: 0.
|
165
|
+
version: 0.3.0
|
166
166
|
type: :development
|
167
167
|
prerelease: false
|
168
168
|
version_requirements: !ruby/object:Gem::Requirement
|
169
169
|
requirements:
|
170
170
|
- - "~>"
|
171
171
|
- !ruby/object:Gem::Version
|
172
|
-
version: 0.
|
172
|
+
version: 0.3.0
|
173
173
|
- !ruby/object:Gem::Dependency
|
174
174
|
name: minitest
|
175
175
|
requirement: !ruby/object:Gem::Requirement
|
@@ -246,14 +246,14 @@ dependencies:
|
|
246
246
|
requirements:
|
247
247
|
- - "~>"
|
248
248
|
- !ruby/object:Gem::Version
|
249
|
-
version: 1.
|
249
|
+
version: 1.9.0
|
250
250
|
type: :development
|
251
251
|
prerelease: false
|
252
252
|
version_requirements: !ruby/object:Gem::Requirement
|
253
253
|
requirements:
|
254
254
|
- - "~>"
|
255
255
|
- !ruby/object:Gem::Version
|
256
|
-
version: 1.
|
256
|
+
version: 1.9.0
|
257
257
|
- !ruby/object:Gem::Dependency
|
258
258
|
name: rubocop-rspec
|
259
259
|
requirement: !ruby/object:Gem::Requirement
|
@@ -282,7 +282,7 @@ dependencies:
|
|
282
282
|
- - "~>"
|
283
283
|
- !ruby/object:Gem::Version
|
284
284
|
version: '3.9'
|
285
|
-
description:
|
285
|
+
description:
|
286
286
|
email:
|
287
287
|
- matijs@matijs.net
|
288
288
|
executables:
|
@@ -331,7 +331,7 @@ files:
|
|
331
331
|
- lib/alexandria/book_providers/proxis.rb
|
332
332
|
- lib/alexandria/book_providers/pseudomarc.rb
|
333
333
|
- lib/alexandria/book_providers/siciliano.rb
|
334
|
-
- lib/alexandria/book_providers/
|
334
|
+
- lib/alexandria/book_providers/thalia_provider.rb
|
335
335
|
- lib/alexandria/book_providers/web.rb
|
336
336
|
- lib/alexandria/book_providers/worldcat.rb
|
337
337
|
- lib/alexandria/book_providers/z3950.rb
|
@@ -555,6 +555,7 @@ files:
|
|
555
555
|
- share/sounds/alexandria/good_scan.wav
|
556
556
|
- share/sounds/alexandria/scanning.ogg
|
557
557
|
- share/sounds/alexandria/scanning.wav
|
558
|
+
- spec/alexandria/book_providers/thalia_provider_spec.rb
|
558
559
|
- spec/alexandria/book_providers/world_cat_provider_spec.rb
|
559
560
|
- spec/alexandria/book_providers_spec.rb
|
560
561
|
- spec/alexandria/book_spec.rb
|
@@ -609,6 +610,7 @@ files:
|
|
609
610
|
- spec/data/libraries/0.6.2/My Library/9780755322800.cover
|
610
611
|
- spec/data/libraries/0.6.2/My Library/9780755322800.yaml
|
611
612
|
- spec/end_to_end/basic_run_spec.rb
|
613
|
+
- spec/fixtures/cover.jpg
|
612
614
|
- spec/spec_helper.rb
|
613
615
|
- tasks/setup.rb
|
614
616
|
- tasks/spec.rake
|
@@ -619,7 +621,7 @@ homepage: http://www.github.com/mvz/alexandria-book-collection-manager
|
|
619
621
|
licenses:
|
620
622
|
- GPL-2
|
621
623
|
metadata: {}
|
622
|
-
post_install_message:
|
624
|
+
post_install_message:
|
623
625
|
rdoc_options:
|
624
626
|
- "--main"
|
625
627
|
- README.md
|
@@ -636,8 +638,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
636
638
|
- !ruby/object:Gem::Version
|
637
639
|
version: '0'
|
638
640
|
requirements: []
|
639
|
-
rubygems_version: 3.1.
|
640
|
-
signing_key:
|
641
|
+
rubygems_version: 3.1.4
|
642
|
+
signing_key:
|
641
643
|
specification_version: 4
|
642
644
|
summary: GNOME application for managing collections of books
|
643
645
|
test_files: []
|