umlaut 3.0.0alpha1
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/LICENSE +7 -0
- data/README.md +49 -0
- data/Rakefile +37 -0
- data/app/assets/images/error.gif +0 -0
- data/app/assets/images/export_bg_bot.gif +0 -0
- data/app/assets/images/export_bg_mid.gif +0 -0
- data/app/assets/images/export_bg_top.gif +0 -0
- data/app/assets/images/famfamfam/book_open.png +0 -0
- data/app/assets/images/famfamfam/cross.png +0 -0
- data/app/assets/images/famfamfam/page_sound.gif +0 -0
- data/app/assets/images/famfamfam/page_text.gif +0 -0
- data/app/assets/images/famfamfam/page_up.gif +0 -0
- data/app/assets/images/famfamfam/page_white.png +0 -0
- data/app/assets/images/famfamfam/readme.html +1495 -0
- data/app/assets/images/famfamfam/tiny_cross.png +0 -0
- data/app/assets/images/frame_remove.gif +0 -0
- data/app/assets/images/ico_go.gif +0 -0
- data/app/assets/images/jhu_findit.gif +0 -0
- data/app/assets/images/list_closed.png +0 -0
- data/app/assets/images/list_open.png +0 -0
- data/app/assets/images/more_info.gif +0 -0
- data/app/assets/images/rails.png +0 -0
- data/app/assets/images/request.gif +0 -0
- data/app/assets/images/spinner.gif +0 -0
- data/app/assets/javascripts/umlaut/ajax_windows.js +35 -0
- data/app/assets/javascripts/umlaut/ensure_window_size.js.erb +34 -0
- data/app/assets/javascripts/umlaut/expand_contract_toggle.js +25 -0
- data/app/assets/javascripts/umlaut/search_autocomplete.js +46 -0
- data/app/assets/javascripts/umlaut/simple_visible_toggle.js +8 -0
- data/app/assets/javascripts/umlaut/update_html.js +152 -0
- data/app/assets/javascripts/umlaut.js +17 -0
- data/app/assets/stylesheets/umlaut.css +857 -0
- data/app/controllers/application_controller.rb +14 -0
- data/app/controllers/export_email_controller.rb +123 -0
- data/app/controllers/js_helper_controller.rb +10 -0
- data/app/controllers/link_router_controller.rb +87 -0
- data/app/controllers/open_search_controller.rb +9 -0
- data/app/controllers/resolve_controller.rb +288 -0
- data/app/controllers/resource_controller.rb +83 -0
- data/app/controllers/search_controller.rb +328 -0
- data/app/controllers/search_methods/sfx3.rb +148 -0
- data/app/controllers/search_methods/sfx4.rb +257 -0
- data/app/controllers/search_methods/sfx_api.rb +47 -0
- data/app/controllers/store_controller.rb +64 -0
- data/app/controllers/umlaut/controller_behavior.rb +20 -0
- data/app/controllers/umlaut/controller_logic.rb +96 -0
- data/app/controllers/umlaut/error_handling.rb +48 -0
- data/app/controllers/umlaut_controller.rb +112 -0
- data/app/helpers/application_helper.rb +4 -0
- data/app/helpers/emailer_helper.rb +43 -0
- data/app/helpers/export_email_helper.rb +34 -0
- data/app/helpers/open_search_helper.rb +7 -0
- data/app/helpers/resolve_helper.rb +225 -0
- data/app/helpers/search_helper.rb +50 -0
- data/app/helpers/umlaut/footer_helper.rb +64 -0
- data/app/helpers/umlaut/helper.rb +62 -0
- data/app/helpers/umlaut/html_head_helper.rb +37 -0
- data/app/helpers/umlaut/url_generation.rb +77 -0
- data/app/mailers/emailer.rb +48 -0
- data/app/models/clickthrough.rb +2 -0
- data/app/models/collection.rb +259 -0
- data/app/models/crossref_lookup.rb +2 -0
- data/app/models/dispatched_service.rb +58 -0
- data/app/models/permalink.rb +29 -0
- data/app/models/referent.rb +473 -0
- data/app/models/referent_value.rb +14 -0
- data/app/models/request.rb +449 -0
- data/app/models/service_response.rb +179 -0
- data/app/models/service_store.rb +59 -0
- data/app/models/service_type_value.rb +58 -0
- data/app/models/service_wave.rb +150 -0
- data/app/models/sfx_db/az_additional_title.rb +11 -0
- data/app/models/sfx_db/az_letter_group.rb +11 -0
- data/app/models/sfx_db/az_title.rb +38 -0
- data/app/models/sfx_db/az_title_v2.rb +34 -0
- data/app/models/sfx_db/isbn.rb +12 -0
- data/app/models/sfx_db/issn.rb +12 -0
- data/app/models/sfx_db/object.rb +35 -0
- data/app/models/sfx_db/object_portfolio.rb +6 -0
- data/app/models/sfx_db/publisher.rb +10 -0
- data/app/models/sfx_db/sfx_db_base.rb +54 -0
- data/app/models/sfx_db/target.rb +9 -0
- data/app/models/sfx_db/target_service.rb +10 -0
- data/app/models/sfx_db/title.rb +10 -0
- data/app/models/sfx_db.rb +10 -0
- data/app/models/sfx_url.rb +35 -0
- data/app/views/emailer/citation.text.erb +28 -0
- data/app/views/emailer/short_citation.text.erb +8 -0
- data/app/views/export_email/_email.html.erb +25 -0
- data/app/views/export_email/_send_email.html.erb +3 -0
- data/app/views/export_email/_send_txt.html.erb +3 -0
- data/app/views/export_email/_txt.html.erb +62 -0
- data/app/views/export_email/email.html.erb +3 -0
- data/app/views/export_email/send_email.html.erb +1 -0
- data/app/views/export_email/send_txt.html.erb +1 -0
- data/app/views/export_email/txt.html.erb +3 -0
- data/app/views/js_helper/loader.erb.js +13 -0
- data/app/views/layouts/umlaut.html.erb +52 -0
- data/app/views/open_search/index.html.erb +9 -0
- data/app/views/resolve/_api_in_progress.xml.erb +21 -0
- data/app/views/resolve/_background_progress.html.erb +51 -0
- data/app/views/resolve/_background_updater.html.erb +38 -0
- data/app/views/resolve/_citation.html.erb +87 -0
- data/app/views/resolve/_coins.html.erb +1 -0
- data/app/views/resolve/_compact_citation.html.erb +33 -0
- data/app/views/resolve/_cover_image.html.erb +35 -0
- data/app/views/resolve/_fulltext.html.erb +55 -0
- data/app/views/resolve/_help.html.erb +17 -0
- data/app/views/resolve/_holding.html.erb +91 -0
- data/app/views/resolve/_related_items.html.erb +35 -0
- data/app/views/resolve/_search_inside.html.erb +62 -0
- data/app/views/resolve/_section_display.html.erb +49 -0
- data/app/views/resolve/_service_errors.html.erb +29 -0
- data/app/views/resolve/_standard_response_item.html.erb +89 -0
- data/app/views/resolve/api.xml.builder +72 -0
- data/app/views/resolve/background_status.html.erb +26 -0
- data/app/views/resolve/index.html.erb +73 -0
- data/app/views/resolve/partial_html_sections.xml.erb +30 -0
- data/app/views/search/_a_to_z.html.erb +6 -0
- data/app/views/search/_citation.html.erb +94 -0
- data/app/views/search/_pager.html.erb +60 -0
- data/app/views/search/books.html.erb +103 -0
- data/app/views/search/journal_search.html.erb +90 -0
- data/app/views/search/journals.html.erb +167 -0
- data/app/views/search/opensearch_description.rxml +10 -0
- data/app/views/testing/index.html.erb +1 -0
- data/app/views/umlaut/README +5 -0
- data/app/views/umlaut/error.html.erb +45 -0
- data/db/migrate/01_umlaut_init.rb +113 -0
- data/db/orig_fixed_data/service_type_values.yml +120 -0
- data/db/seeds.rb +7 -0
- data/lib/CronTab.rb +192 -0
- data/lib/aws_product_sign.rb +146 -0
- data/lib/exlibris/aleph/patron.rb +64 -0
- data/lib/exlibris/aleph/record.rb +54 -0
- data/lib/exlibris/aleph/rest_api.rb +29 -0
- data/lib/exlibris/primo/holding.rb +192 -0
- data/lib/exlibris/primo/rsrc.rb +17 -0
- data/lib/exlibris/primo/searcher.rb +276 -0
- data/lib/exlibris/primo/source/aleph.rb +46 -0
- data/lib/exlibris/primo/source/distribution/nyu_aleph.rb +323 -0
- data/lib/exlibris/primo/toc.rb +17 -0
- data/lib/exlibris/primo_ws.rb +140 -0
- data/lib/generators/templates/umlaut_services.yml +237 -0
- data/lib/generators/umlaut/asset_hooks_generator.rb +44 -0
- data/lib/generators/umlaut/install_generator.rb +110 -0
- data/lib/hip3/bib.rb +291 -0
- data/lib/hip3/bib_searcher.rb +302 -0
- data/lib/hip3/custom_field_lookup.rb +44 -0
- data/lib/hip3/holding.rb +50 -0
- data/lib/hip3/item.rb +65 -0
- data/lib/hip3/receipt.rb +7 -0
- data/lib/hip3/serial_copy.rb +82 -0
- data/lib/holding.rb +32 -0
- data/lib/marc_helper.rb +254 -0
- data/lib/metadata_helper.rb +312 -0
- data/lib/opensearch_feed.rb +398 -0
- data/lib/opensearch_query.rb +98 -0
- data/lib/referent_filter.rb +16 -0
- data/lib/referent_filters/dissertation_catch.rb +45 -0
- data/lib/section_renderer.rb +503 -0
- data/lib/service.rb +336 -0
- data/lib/service_adaptors/ajax_export.rb +37 -0
- data/lib/service_adaptors/amazon.rb +412 -0
- data/lib/service_adaptors/blacklight.rb +327 -0
- data/lib/service_adaptors/book_finder.rb +40 -0
- data/lib/service_adaptors/bx.rb +51 -0
- data/lib/service_adaptors/cover_thing.rb +73 -0
- data/lib/service_adaptors/elsevier_cover.rb +57 -0
- data/lib/service_adaptors/email_export.rb +10 -0
- data/lib/service_adaptors/ezproxy.rb +171 -0
- data/lib/service_adaptors/google_book_search.rb +442 -0
- data/lib/service_adaptors/gpo.rb +124 -0
- data/lib/service_adaptors/hathi_trust.rb +308 -0
- data/lib/service_adaptors/hip3_service.rb +150 -0
- data/lib/service_adaptors/hip_holding_search.rb +237 -0
- data/lib/service_adaptors/internet_archive.rb +488 -0
- data/lib/service_adaptors/isbn_db.rb +86 -0
- data/lib/service_adaptors/isi.rb +258 -0
- data/lib/service_adaptors/jcr.rb +146 -0
- data/lib/service_adaptors/opac.rb +351 -0
- data/lib/service_adaptors/open_library.rb +316 -0
- data/lib/service_adaptors/open_library_cover.rb +73 -0
- data/lib/service_adaptors/primo_service.rb +392 -0
- data/lib/service_adaptors/primo_source.rb +78 -0
- data/lib/service_adaptors/pubmed.rb +133 -0
- data/lib/service_adaptors/request_to_fixture.rb +68 -0
- data/lib/service_adaptors/scopus.rb +295 -0
- data/lib/service_adaptors/sfx-new.rb +557 -0
- data/lib/service_adaptors/sfx.rb +566 -0
- data/lib/service_adaptors/sfx_backchannel_record.rb +69 -0
- data/lib/service_adaptors/txt_holding_export.rb +32 -0
- data/lib/service_adaptors/ulrichs_cover.rb +57 -0
- data/lib/service_adaptors/ulrichs_link.rb +47 -0
- data/lib/service_adaptors/worldcat.rb +116 -0
- data/lib/service_adaptors/worldcat_identities.rb +591 -0
- data/lib/tasks/umlaut.rake +134 -0
- data/lib/umlaut/default_configuration.rb +5 -0
- data/lib/umlaut/routes.rb +136 -0
- data/lib/umlaut/version.rb +3 -0
- data/lib/umlaut.rb +37 -0
- data/lib/umlaut_configurable.rb +343 -0
- data/lib/umlaut_http.rb +100 -0
- data/lib/xml_schema_helper.rb +109 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/controllers/umlaut_controller.rb +112 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config/application.rb +45 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database-jhu.yml +44 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +34 -0
- data/test/dummy/config/environments/production.rb +60 -0
- data/test/dummy/config/environments/test.rb +39 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +10 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +61 -0
- data/test/dummy/config/umlaut_services.yml +237 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/db/migrate/20111228211210_umlaut_init.rb +113 -0
- data/test/dummy/db/schema.rb +124 -0
- data/test/dummy/log/development.log +12981 -0
- data/test/dummy/log/production.log +0 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +26 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/dummy/tmp/cache/assets/C5F/340/sprockets%2F99692920160b7a279b86a80415b79db7 +0 -0
- data/test/dummy/tmp/cache/assets/C70/4D0/sprockets%2F034ad2036e623081bd352800786dfe80 +0 -0
- data/test/dummy/tmp/cache/assets/C73/920/sprockets%2Fd371318f22900492fd180f17c5e2a504 +9268 -0
- data/test/dummy/tmp/cache/assets/C80/980/sprockets%2Fc94807409c1523d43e18d25f35d93c41 +0 -0
- data/test/dummy/tmp/cache/assets/C8F/780/sprockets%2Fe47e28558116fb5f8038754e60d1961d +11769 -0
- data/test/dummy/tmp/cache/assets/CAA/EB0/sprockets%2F1d179210e8b76f1ea63c802688a015e4 +9271 -0
- data/test/dummy/tmp/cache/assets/CBB/9C0/sprockets%2F706f28923fb754cad04b9107c89986a1 +0 -0
- data/test/dummy/tmp/cache/assets/CBF/B60/sprockets%2F08ca89671549936265dcb673bf02e36f +0 -0
- data/test/dummy/tmp/cache/assets/CC9/9F0/sprockets%2F306166316e2cafd13c15e62b51a2339d +0 -0
- data/test/dummy/tmp/cache/assets/CF6/F20/sprockets%2F5b2ffa1103079dfd555197838f87a99f +0 -0
- data/test/dummy/tmp/cache/assets/CF7/2B0/sprockets%2F25a7c73655bd3598173b39d9f98bcd46 +862 -0
- data/test/dummy/tmp/cache/assets/CFE/080/sprockets%2F37fe9f4255baddbd549a659914929398 +0 -0
- data/test/dummy/tmp/cache/assets/D22/060/sprockets%2F9aec77b768e91a802d284271c58e2f7e +21357 -0
- data/test/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/test/dummy/tmp/cache/assets/D33/6D0/sprockets%2F500129c57f1146e556ec3aacd6cd38c1 +0 -0
- data/test/dummy/tmp/cache/assets/D33/FD0/sprockets%2F2ba0b4e6334a77b923e5f770381bb2bf +0 -0
- data/test/dummy/tmp/cache/assets/D42/C20/sprockets%2Fbcf14e437b1582bf93b77670acf8e090 +21353 -0
- data/test/dummy/tmp/cache/assets/D50/A30/sprockets%2F7d8b294ac433db5d056538f8cf7c66b9 +0 -0
- data/test/dummy/tmp/cache/assets/D54/ED0/sprockets%2F71c9fa01091d432b131da3bb73faf3d4 +872 -0
- data/test/dummy/tmp/cache/assets/D65/590/sprockets%2Fc1bb92fc3406a126b7dd302edc96d629 +0 -0
- data/test/dummy/tmp/cache/assets/D71/6B0/sprockets%2Fde558b71b494cf09b1bf055c8dff0353 +0 -0
- data/test/dummy/tmp/cache/assets/D72/610/sprockets%2Fa8c708eeb30ef93de34d755d4f45d023 +859 -0
- data/test/dummy/tmp/cache/assets/D76/AD0/sprockets%2Fe2158cde93188cf5ab6457bc6d6602ec +0 -0
- data/test/dummy/tmp/cache/assets/D7A/E40/sprockets%2F9622ffcc499a57627cd1bb18fe31b8e4 +11772 -0
- data/test/dummy/tmp/cache/assets/D84/210/sprockets%2Fabd0103ccec2b428ac62c94e4c40b384 +0 -0
- data/test/dummy/tmp/cache/assets/D9B/770/sprockets%2F8aacf02eb7dbb0949704b28f27b87e0b +0 -0
- data/test/dummy/tmp/cache/assets/DA6/A80/sprockets%2F92e26d8e58d5bcc8b8f6c25d1b05b9c1 +0 -0
- data/test/dummy/tmp/cache/assets/DE8/790/sprockets%2Fd1333bde2b9aafcc712d11dd09ab35d8 +0 -0
- data/test/dummy/tmp/cache/assets/DF7/F30/sprockets%2F7bc16c4109b17fabe29f8ddbbf732d1c +374 -0
- data/test/dummy/tmp/cache/assets/E03/570/sprockets%2F493bdc0ac14cd4f57fdfe4253f992bde +0 -0
- data/test/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/test/dummy/tmp/cache/assets/E0B/4B0/sprockets%2F7988df51a61c81ce6ede4a2d4c8cce4f +377 -0
- data/test/dummy/tmp/cache/assets/E5F/960/sprockets%2Fdc007b6cad5c7ef08e33ec28cfff0ef6 +0 -0
- data/test/fixtures/dispatched_services.yml +5 -0
- data/test/fixtures/permalinks.yml +5 -0
- data/test/fixtures/referent_values.yml +1734 -0
- data/test/fixtures/referents.yml +156 -0
- data/test/fixtures/requests.yml +284 -0
- data/test/fixtures/service_responses.yml +5 -0
- data/test/fixtures/sfx_urls.yml +4 -0
- data/test/performance/browsing_test.rb +9 -0
- data/test/test_helper.rb +10 -0
- data/test/umlaut_test.rb +7 -0
- data/test/unit/aleph_patron_test.rb +39 -0
- data/test/unit/aleph_record_benchmarks.rb +28 -0
- data/test/unit/aleph_record_test.rb +30 -0
- data/test/unit/aws_product_sign_test.rb +93 -0
- data/test/unit/collection_test.rb +76 -0
- data/test/unit/google_book_search_test.rb +101 -0
- data/test/unit/primo_searcher_test.rb +403 -0
- data/test/unit/primo_service_test.rb +939 -0
- data/test/unit/primo_ws_test.rb +131 -0
- data/test/unit/service_response_test.rb +9 -0
- data/test/unit/service_test.rb +33 -0
- metadata +580 -0
@@ -0,0 +1,351 @@
|
|
1
|
+
# FIXME This service is not working
|
2
|
+
# For starters it needs the method service_types_generated()
|
3
|
+
|
4
|
+
class Opac < Service
|
5
|
+
attr_reader :record_attributes, :display_name
|
6
|
+
|
7
|
+
# The Opac class has a few assumptions
|
8
|
+
# * You have some sort of bib client to get MARC records from your OPAC
|
9
|
+
# * This operates independently of holdings data
|
10
|
+
# * If your client can supply holdings information, you have the methods:
|
11
|
+
# - init_holdings_client
|
12
|
+
# - get_holdings
|
13
|
+
#
|
14
|
+
# The Opac class should be extended with your local connection client and
|
15
|
+
# not called directly.
|
16
|
+
|
17
|
+
def handle(request)
|
18
|
+
# It's unlikely that consortial catalogs allow borrowing
|
19
|
+
# of journals, but this may need to pushed to a client class
|
20
|
+
|
21
|
+
if request.referent.format == 'journal' and @consortial
|
22
|
+
return request.dispatched(self, true)
|
23
|
+
end
|
24
|
+
@record_attributes = {}
|
25
|
+
self.search_bib_data(request)
|
26
|
+
if self.respond_to?(:init_holdings_client)
|
27
|
+
opac_client = self.init_holdings_client
|
28
|
+
opac_client.get_holdings(@record_attributes.keys)
|
29
|
+
self.check_holdings(opac_client.results, request)
|
30
|
+
else
|
31
|
+
self.add_link_to_opac(client,request)
|
32
|
+
end
|
33
|
+
return request.dispatched(self, true)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Searches the bibliographic database
|
37
|
+
def search_bib_data(request)
|
38
|
+
client = self.init_bib_client
|
39
|
+
client.search_by_referent(request.referent)
|
40
|
+
self.collect_record_attributes(client, request)
|
41
|
+
end
|
42
|
+
|
43
|
+
# The client is expected to respond to <b>results</b> and return
|
44
|
+
# an array of MARC records. Override this method (and parse_for_fulltext,
|
45
|
+
# collect_subjects, and enhance_referent) if your client does not return
|
46
|
+
# MARC.
|
47
|
+
def collect_record_attributes(client, request)
|
48
|
+
require 'marc'
|
49
|
+
client.results.each do | record |
|
50
|
+
MARC::XMLReader.new(StringIO.new(record.to_s)).each do | rec |
|
51
|
+
id = nil
|
52
|
+
|
53
|
+
# Assumes your local control number to be defined in 001
|
54
|
+
rec.find_all { | f| '001' === f.tag}.each do | bibnum |
|
55
|
+
id = bibnum.value
|
56
|
+
@record_attributes[id] = {}
|
57
|
+
end
|
58
|
+
|
59
|
+
# Conferences have their own crazy logic
|
60
|
+
if self.is_conference?(rec)
|
61
|
+
@record_attributes[id][:conference] = true
|
62
|
+
else
|
63
|
+
@record_attributes[id][:conference] = false
|
64
|
+
end
|
65
|
+
self.parse_for_fulltext_links(rec, request)
|
66
|
+
self.enhance_referent(rec, request, client.accuracy)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Searches the MARC record for 856 tags, checks to see
|
72
|
+
# if they seem to be digital representations and, if so,
|
73
|
+
# adds them as fulltext service types
|
74
|
+
def parse_for_fulltext_links(marc, request)
|
75
|
+
eight_fifty_sixes = []
|
76
|
+
marc.find_all { | f| '856' === f.tag}.each do | link |
|
77
|
+
eight_fifty_sixes << link
|
78
|
+
end
|
79
|
+
eight_fifty_sixes.each do | link |
|
80
|
+
next if link.indicator2.match(/[28]/)
|
81
|
+
next if link['u'].match(/(sfx\.galib\.uga\.edu)|(findit\.library\.gatech\.edu)/)
|
82
|
+
label = (link['z']||'Electronic Access')
|
83
|
+
request.add_service_response(
|
84
|
+
:service=>self,
|
85
|
+
:key=>label,
|
86
|
+
:value_string=>link['u'],
|
87
|
+
:service_type_value => 'fulltext'
|
88
|
+
)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# The client should be able to return an array of holdings objects
|
93
|
+
def check_holdings(holdings, request)
|
94
|
+
return if holdings.empty?
|
95
|
+
# These need to moved to services.yml
|
96
|
+
electronic_locations = ['INTERNET', 'NETLIBRARY', 'GALILEO']
|
97
|
+
holdings.each do | holding |
|
98
|
+
@record_attributes[holding.identifier.to_s][:holdings] = holding
|
99
|
+
holding.locations.each do | location |
|
100
|
+
next if electronic_locations.index(location.code)
|
101
|
+
location.items.each do | item |
|
102
|
+
if request.referent.format == 'journal' and request.referent.metadata["volume"] and @record_attributes[holding.identifier.to_s][:conference] == false
|
103
|
+
copy_match = false
|
104
|
+
if item.enumeration
|
105
|
+
if vol_match = item.enumeration.match(/VOL [A-z0-9\-]*/)
|
106
|
+
vol = vol_match[0]
|
107
|
+
vol.sub!(/^VOL\s*/, '')
|
108
|
+
(svol, evol) = vol.split('-')
|
109
|
+
if request.referent.metadata["volume"] == svol
|
110
|
+
copy_match = true
|
111
|
+
elsif evol
|
112
|
+
if request.referent.metadata["volume"] == evol
|
113
|
+
copy_match = true
|
114
|
+
elsif request.referent.metadata["volume"].to_i > svol.to_i and request.referent.metadata["volume"].to_i < evol.to_i
|
115
|
+
copy_match = true
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
if copy_match == true
|
121
|
+
request.add_service_response(:service=>self,:key=>holding.identifier.to_s,:value_string=>location.name,:value_alt_string=>item.call_number,:value_text=>item.status.to_s, :service_type_value => 'holding')
|
122
|
+
break
|
123
|
+
end
|
124
|
+
else
|
125
|
+
request.add_service_response(:service=>self,:key=>holding.identifier.to_s,:value_string=>location.name,:value_alt_string=>item.call_number,:value_text=>item.status.to_s,:service_type_value=>'holding')
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# Check the leader to determine if this is defined as a conference or proceeding
|
133
|
+
# in the MARC
|
134
|
+
def is_conference?(marc)
|
135
|
+
# Check the leader/008 for books and serials
|
136
|
+
return true if marc['008'].value[29,1] == '1' && marc.leader[6,1].match(/[at]/) && marc.leader[7,1].match(/[abcdms]/)
|
137
|
+
# Check the leader/008 for scores and recordings
|
138
|
+
return true if marc['008'].value[30,2] == 'c' && marc.leader[6,1].match(/[cdij]/) && marc.leader[7,1].match(/[abcdms]/)
|
139
|
+
# Loop through the 006s
|
140
|
+
marc.find_all {|f| ('006') === f.tag}.each { | fxd_fld |
|
141
|
+
return true if fxd_fld.value[12,1] == '1' && fxd_fld.value[0,1].match(/[ats]{1}/)
|
142
|
+
return true if fxd_fld.value[13,2]== 'c' && fxd_fld.value[0,1].match(/[cdij]{1}/)
|
143
|
+
}
|
144
|
+
return false
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
# Determines the kind of record referred to in the MARC leader/fixed fields
|
149
|
+
# (Book, Serial, Map, etc.)
|
150
|
+
def record_type(marc)
|
151
|
+
type = marc.leader[6,1]
|
152
|
+
blvl = marc.leader[7,1]
|
153
|
+
valid_types = ['a','t','g','k','r','o','p','e','f','c','d','i','j','m']
|
154
|
+
rec_types = {
|
155
|
+
'BKS' => { :type => /[at]{1}/, :blvl => /[acdm]{1}/ },
|
156
|
+
'SER' => { :type => /[a]{1}/, :blvl => /[bs]{1}/ },
|
157
|
+
'VIS' => { :type => /[gkro]{1}/, :blvl => /[abcdms]{1}/ },
|
158
|
+
'MIX' => { :type => /[p]{1}/, :blvl => /[cd]{1}/ },
|
159
|
+
'MAP' => { :type => /[ef]{1}/, :blvl => /[abcdms]{1}/ },
|
160
|
+
'SCO' => { :type => /[cd]{1}/, :blvl => /[abcdms]{1}/ },
|
161
|
+
'REC' => { :type => /[ij]{1}/, :blvl => /[abcdms]{1}/ },
|
162
|
+
'COM' => { :type => /[m]{1}/, :blvl => /[abcdms]{1}/ }
|
163
|
+
}
|
164
|
+
|
165
|
+
rec_types.each_key do | rec_type |
|
166
|
+
return rec_type if type.match(rec_types[rec_type][:type]) and blvl.match(rec_types[rec_type][:blvl])
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# When given a ServiceResponse object as its argument, returns the anchor text and URL
|
171
|
+
def to_fulltext(response)
|
172
|
+
return {:display_text=>response.response_key, :url=>response.value_string}
|
173
|
+
end
|
174
|
+
|
175
|
+
# When given a ServiceResponse object as its argument, returns the object as a hash
|
176
|
+
# with the keys:
|
177
|
+
# - :display_text
|
178
|
+
# - :call_number
|
179
|
+
# - :status
|
180
|
+
# - :source_name (which equates to self.display_name)
|
181
|
+
def to_holding(response)
|
182
|
+
return {:display_text=>response.value_string,:call_number=>response.value_alt_string,:status=>response.value_text,:source_name=>self.display_name}
|
183
|
+
end
|
184
|
+
|
185
|
+
|
186
|
+
|
187
|
+
# When given a MARC record, this method fills in any missing
|
188
|
+
# pieces of the Request.referent. 'accuracy' is a 3 point scale
|
189
|
+
# determined by the client, 1 = 'possibly the correct resource', 2 =
|
190
|
+
# same resource, but not necessarily the same edition, 3 = exactly the
|
191
|
+
# same resource
|
192
|
+
def enhance_referent(marc, request, accuracy)
|
193
|
+
return unless accuracy > 2
|
194
|
+
|
195
|
+
title_key = case request.referent.format
|
196
|
+
when "book" then "btitle"
|
197
|
+
when "journal" then "jtitle"
|
198
|
+
when "dissertation" then "title"
|
199
|
+
end
|
200
|
+
metadata = request.referent.metadata
|
201
|
+
unless metadata[title_key]
|
202
|
+
if request.referent.metadata["title"] && title_key != "title"
|
203
|
+
request.referent.enhance_referent(title_key, metadata["title"])
|
204
|
+
else
|
205
|
+
request.referent.enhance_referent(title_key, marc['245'].value)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
unless metadata["au"]
|
209
|
+
if marc['100'] && marc['100']['a']
|
210
|
+
request.referent.enhance_referent('au', marc['100']['a'])
|
211
|
+
end
|
212
|
+
end
|
213
|
+
unless metadata["aucorp"]
|
214
|
+
if marc['110'] && marc['110']['a']
|
215
|
+
request.referent.enhance_referent('aucorp', marc['110']['a'])
|
216
|
+
end
|
217
|
+
end
|
218
|
+
return unless accuracy > 3
|
219
|
+
unless metadata["place"]
|
220
|
+
if marc['260'] && marc['260']['a']
|
221
|
+
request.referent.enhance_referent('place', marc['260']['a'])
|
222
|
+
end
|
223
|
+
end
|
224
|
+
unless metadata["pub"]
|
225
|
+
if marc['260'] && marc['260']['b']
|
226
|
+
request.referent.enhance_referent('pub', marc['260']['b'])
|
227
|
+
end
|
228
|
+
end
|
229
|
+
unless metadata["edition"]
|
230
|
+
if marc['250'] && marc['250']['a']
|
231
|
+
request.referent.enhance_referent('edition', marc['250']['a'])
|
232
|
+
end
|
233
|
+
end
|
234
|
+
unless metadata["series"]
|
235
|
+
if marc['490'] && marc['490']['a']
|
236
|
+
request.referent.enhance_referent('series', marc['490']['a'])
|
237
|
+
elsif marc['730'] && marc['730']['a']
|
238
|
+
request.referent.enhance_referent('series', marc['730']['a'])
|
239
|
+
end
|
240
|
+
end
|
241
|
+
unless metadata["date"] or request.referent.format == 'journal'
|
242
|
+
if marc['260'] && marc['260']['c']
|
243
|
+
request.referent.enhance_referent('date', marc['260']['c'])
|
244
|
+
end
|
245
|
+
end
|
246
|
+
unless request.referent.format
|
247
|
+
type = self.record_type(marc)
|
248
|
+
request.referent.enhance_referent('format', 'book', false) if type == "BKS"
|
249
|
+
request.referent.enhance_referent('format', 'journal', false) if type == "SER"
|
250
|
+
end
|
251
|
+
unless metadata["genre"]
|
252
|
+
if self.is_conference?(marc)
|
253
|
+
if metadata["atitle"]
|
254
|
+
request.referent.enhance_referent('genre', 'proceeding')
|
255
|
+
else
|
256
|
+
request.referent.enhance_referent('genre', 'conference')
|
257
|
+
end
|
258
|
+
elsif type = self.nature_of_contents(marc)
|
259
|
+
case type
|
260
|
+
when "dissertation" then request.referent.enhance_referent('format', 'dissertation', false)
|
261
|
+
when "patent" then request.referent.enhance_referent('format', 'patent', false)
|
262
|
+
when "report" then request.referent.enhance_referent('genre', 'report')
|
263
|
+
end
|
264
|
+
else
|
265
|
+
type = self.record_type(marc)
|
266
|
+
if type == "BKS"
|
267
|
+
request.referent.enhance_referent('format', 'book', false) unless request.referent.format == 'book'
|
268
|
+
if metadata["atitle"]
|
269
|
+
request.referent.enhance_referent('genre', 'bookpart')
|
270
|
+
else
|
271
|
+
request.referent.enhance_referent('genre', 'book')
|
272
|
+
end
|
273
|
+
elsif type == "SER"
|
274
|
+
request.referent.enhance_referent('format', 'journal', false) unless request.referent.format == 'journal'
|
275
|
+
if metadata["atitle"]
|
276
|
+
request.referent.enhance_referent('genre', 'article')
|
277
|
+
elsif metadata["issue"]
|
278
|
+
request.referent.enhance_referent('genre', 'issue')
|
279
|
+
else
|
280
|
+
request.referent.enhance_referent('genre', 'journal')
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
unless metadata["isbn"]
|
287
|
+
if marc['020'] && marc['020']['a']
|
288
|
+
request.referent.enhance_referent('isbn', marc['020']['a'])
|
289
|
+
end
|
290
|
+
end
|
291
|
+
unless metadata["issn"]
|
292
|
+
if marc['022'] && marc['022']['a']
|
293
|
+
request.referent.enhance_referent('issn', marc['022']['a'])
|
294
|
+
end
|
295
|
+
end
|
296
|
+
unless metadata["sici"]
|
297
|
+
if marc['024'] && marc['024'].indicator1 == "4"
|
298
|
+
request.referent.enhance_referent('sici', marc['024']['a'])
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
unless metadata["coden"]
|
303
|
+
if marc['030'] && marc['030']['a']
|
304
|
+
request.referent.enhance_referent('coden', marc['030']['a'])
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
# When given a MARC record, determines if the referent should be
|
310
|
+
# defined as a dissertation, report or patent.
|
311
|
+
def nature_of_contents(marc)
|
312
|
+
types = {'m'=>'dissertation','t'=>'report','j'=>'patent'}
|
313
|
+
idx = nil
|
314
|
+
if self.record_type(marc) == 'BKS'
|
315
|
+
idx = 24
|
316
|
+
len = 4
|
317
|
+
elsif self.record_type(marc) == 'SER'
|
318
|
+
idx = 25
|
319
|
+
len = 3
|
320
|
+
end
|
321
|
+
if idx
|
322
|
+
marc['008'].value[idx,len].split(//).each do | char |
|
323
|
+
return types[char] if types.keys.index(char)
|
324
|
+
end
|
325
|
+
end
|
326
|
+
marc.find_all {|f| ('006') === f.tag}.each do | fxd_fld |
|
327
|
+
idx = nil
|
328
|
+
if fxd_fld.value[0,1].match(/[at]{1}/)
|
329
|
+
idx = 7
|
330
|
+
len = 4
|
331
|
+
elsif fxd_fld.value[0,1].match('s')
|
332
|
+
idx = 8
|
333
|
+
len = 3
|
334
|
+
end
|
335
|
+
if idx
|
336
|
+
fxd_fld.value[idx,len].split(//).each do | char |
|
337
|
+
return types[char] if types.keys.index(char)
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
return false
|
342
|
+
end
|
343
|
+
|
344
|
+
# Builds a URL either based on a URL in the value_string or builds a link to the
|
345
|
+
# OPAC using the direct_link_arg and the bib ID.
|
346
|
+
def response_url(service_type, http_params)
|
347
|
+
response service_type.service_response
|
348
|
+
return CGI.unescapeHTML(response.value_string) if response.value_string.match(/^http(s)?:\/\//)
|
349
|
+
return @url+'&'+@direct_link_arg+response.response_key
|
350
|
+
end
|
351
|
+
end
|
@@ -0,0 +1,316 @@
|
|
1
|
+
# EXPERIMENTAL, uncomplete.
|
2
|
+
# Searches Open Library for fulltext, and cover images.
|
3
|
+
# To some extent duplicates what the InternetArchive service does,
|
4
|
+
# but using the OpenLibrary API.
|
5
|
+
#
|
6
|
+
# This service right now will only search on isbn/oclcnum/lccn identifiers,
|
7
|
+
# not on title/author keyword.
|
8
|
+
#
|
9
|
+
# Only a subset of OL cover images are actually available via API (those
|
10
|
+
# submitted by users). Here is an example: ?rft.isbn=0921307802
|
11
|
+
# Size of images returned is unpredictable. They can be huge sometimes.
|
12
|
+
# Counting on enforced re-sizing in img tag attributes.
|
13
|
+
#
|
14
|
+
#
|
15
|
+
|
16
|
+
class OpenLibrary < Service
|
17
|
+
require 'open-uri'
|
18
|
+
require 'json'
|
19
|
+
include MetadataHelper
|
20
|
+
|
21
|
+
attr_reader :url
|
22
|
+
|
23
|
+
def service_types_generated
|
24
|
+
|
25
|
+
types = Array.new
|
26
|
+
types.push( ServiceTypeValue[:fulltext]) if @get_fulltext
|
27
|
+
types.push( ServiceTypeValue[:highlighted_link]) if @get_fulltext
|
28
|
+
types.push( ServiceTypeValue[:cover_image]) if @get_covers
|
29
|
+
|
30
|
+
return types
|
31
|
+
|
32
|
+
# FIXME add these service types
|
33
|
+
#ServiceTypeValue[:table_of_contents]
|
34
|
+
#ServiceTypeValue[:search_inside]
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize(config)
|
39
|
+
@api_url = "http://openlibrary.org/api"
|
40
|
+
@display_name = "Open Library"
|
41
|
+
# in case the structure of an empty response changes
|
42
|
+
@empty_response = {"result" => [], "status" => "ok"}
|
43
|
+
@num_full_views = 1
|
44
|
+
|
45
|
+
# Can turn on and off each type of service
|
46
|
+
@get_fulltext = true
|
47
|
+
@get_covers = true
|
48
|
+
@enhance_metadata = true
|
49
|
+
|
50
|
+
# openlibrary goes straight to the flipbook; archive.org to main page
|
51
|
+
@fulltext_base_url = 'http://archive.org/details' #'http://openlibrary.org/details'
|
52
|
+
@download_link = true
|
53
|
+
|
54
|
+
@credits = {
|
55
|
+
"OpenLibrary" => "http://openlibrary.org/"
|
56
|
+
}
|
57
|
+
|
58
|
+
super(config)
|
59
|
+
end
|
60
|
+
|
61
|
+
def handle(request)
|
62
|
+
get_data(request)
|
63
|
+
return request.dispatched(self,true)
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_data(request)
|
67
|
+
ids = get_identifiers(request.referent)
|
68
|
+
return nil if ids.blank?
|
69
|
+
ol_keys = do_id_query(ids)
|
70
|
+
return nil if ol_keys.blank?
|
71
|
+
|
72
|
+
editions = get_editions(ol_keys)
|
73
|
+
return nil if editions.blank?
|
74
|
+
|
75
|
+
enhance_metadata(request.referent, editions) if @enhance_metadata
|
76
|
+
|
77
|
+
add_cover_image(request, editions) if @get_cover_image
|
78
|
+
|
79
|
+
if ( @get_fulltext)
|
80
|
+
full_text_editions = select_fulltext(editions)
|
81
|
+
unless full_text_editions.blank?
|
82
|
+
create_fulltext_service_responses(request, full_text_editions)
|
83
|
+
create_download_link(request, full_text_editions) if @download_link
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Open Libary metadata looks messy right now and incomplete
|
88
|
+
# if there is only one edition returned then we return a highlighted link
|
89
|
+
# otherwise best to just leave it off
|
90
|
+
if editions.length == 1
|
91
|
+
# FIXME add this method
|
92
|
+
#create_highlighted_link(request, editions)
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
def get_identifiers(rft)
|
98
|
+
isbn = get_identifier(:urn, "isbn", rft)
|
99
|
+
oclcnum = get_identifier(:info, "oclcnum", rft)
|
100
|
+
lccn = get_identifier(:info, "lccn", rft)
|
101
|
+
|
102
|
+
h = {}
|
103
|
+
h['isbn'] = isbn unless isbn.blank?
|
104
|
+
h['oclcnum'] = oclcnum unless oclcnum.blank?
|
105
|
+
h['lccn'] = lccn unless lccn.blank?
|
106
|
+
return h
|
107
|
+
end
|
108
|
+
|
109
|
+
# only returns the unique keys from all the results
|
110
|
+
def do_id_query(ids)
|
111
|
+
responses = []
|
112
|
+
ids.each do |k, v|
|
113
|
+
new_key_value = map_key(k, v)
|
114
|
+
next if new_key_value.blank? #we probably have bad ISBN, could be bad key though
|
115
|
+
responses << get_thing(new_key_value)
|
116
|
+
end
|
117
|
+
selected = responses.map { |r| r['result'] }.flatten.compact.uniq
|
118
|
+
return selected
|
119
|
+
end
|
120
|
+
|
121
|
+
# given a hash as a query it returns a hash
|
122
|
+
def get_thing(query_hash)
|
123
|
+
query = {"type" => "/type/edition"}.merge(query_hash)
|
124
|
+
response = open(@api_url + "/things?query=" + CGI.escape(query.to_json) ).read
|
125
|
+
JSON.parse(response)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Contacts OL and gets data records for editions/manifestations
|
129
|
+
# matching any of keys we have.
|
130
|
+
def get_editions(ol_keys)
|
131
|
+
editions = []
|
132
|
+
ol_keys.each do |k|
|
133
|
+
link = @api_url + "/get?key=" + k
|
134
|
+
resp = open(link).read
|
135
|
+
editions << JSON.parse(resp)['result']
|
136
|
+
end
|
137
|
+
return editions
|
138
|
+
end
|
139
|
+
|
140
|
+
def map_key(k, v)
|
141
|
+
new_key = case k
|
142
|
+
when "lccn" then "lccn"
|
143
|
+
when "oclcnum" then "oclc_numbers"
|
144
|
+
when "isbn"
|
145
|
+
if v.length == 10
|
146
|
+
"isbn_10"
|
147
|
+
elsif v.length == 13
|
148
|
+
"isbn_13"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
return { new_key => v}
|
152
|
+
end
|
153
|
+
|
154
|
+
# right now we only know of a work having fulltext if it has an ocaid
|
155
|
+
# in case we discover other ways to determine fulltext availability we
|
156
|
+
# move it to its own method
|
157
|
+
def select_fulltext(editions)
|
158
|
+
editions.select do |ed|
|
159
|
+
! ed['ocaid'].blank?
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def create_fulltext_service_responses(request, editions)
|
164
|
+
count = 0
|
165
|
+
#note = @note
|
166
|
+
editions.each do |ed|
|
167
|
+
title = ed['title']
|
168
|
+
url = @fulltext_base_url + '/' +ed['ocaid']
|
169
|
+
request.add_service_response(
|
170
|
+
:service=>self,
|
171
|
+
:display_text=>@display_name,
|
172
|
+
:url=>url,
|
173
|
+
:notes=>title,
|
174
|
+
:service_type_value => :fulltext )
|
175
|
+
|
176
|
+
count += 1
|
177
|
+
break if count == @num_full_views
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# TODO: If first one doesn't have a download, try second?
|
182
|
+
# In general, we need a better way of grouping ALL the results
|
183
|
+
# available for the user.
|
184
|
+
# Creates a highlighted_link for download of PDF
|
185
|
+
# for first edition listed.
|
186
|
+
def create_download_link(request, editions)
|
187
|
+
return nil unless editions
|
188
|
+
ed = editions[0] if editions.length
|
189
|
+
return nil unless ed['ocaid']
|
190
|
+
server = "www.archive.org"
|
191
|
+
pdf = "/download/"<< ed['ocaid'] << "/" <<
|
192
|
+
ed['ocaid'] << ".pdf"
|
193
|
+
url = "http://" << server << pdf
|
194
|
+
|
195
|
+
bytes = determine_download_size(server, pdf)
|
196
|
+
return nil if bytes.nil? || bytes == 0
|
197
|
+
|
198
|
+
note = bytes_to_mb(bytes)
|
199
|
+
|
200
|
+
|
201
|
+
request.add_service_response(
|
202
|
+
:service=>self,
|
203
|
+
:display_text=>"Download: " << ed['title'],
|
204
|
+
:url=>url,
|
205
|
+
:notes=> ("%.1f" % note) + " MB",
|
206
|
+
:service_type_value => :highlighted_link )
|
207
|
+
end
|
208
|
+
|
209
|
+
# they redirect so we actually have to do two HEAD requests to get the
|
210
|
+
# actual content length. Returns bytes as int.
|
211
|
+
def determine_download_size(server, pdf)
|
212
|
+
real_location = ''
|
213
|
+
Net::HTTP.start(server, 80) do |http|
|
214
|
+
# Send a HEAD request
|
215
|
+
response = http.head(pdf)
|
216
|
+
# Get the real location
|
217
|
+
real_location = response['Location']
|
218
|
+
end
|
219
|
+
m = real_location.match(/http:\/\/(.*?)(\/.*)/)
|
220
|
+
real_server = m[1]
|
221
|
+
real_pdf = m[2]
|
222
|
+
Net::HTTP.start(real_server, 80) do |http|
|
223
|
+
# Send a HEAD request
|
224
|
+
resp = http.head(real_pdf)
|
225
|
+
|
226
|
+
return nil if resp.kind_of?(Net::HTTPServerError) || resp.kind_of?(Net::HTTPClientError)
|
227
|
+
|
228
|
+
bytes = resp['Content-Length'].to_i
|
229
|
+
return bytes
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def bytes_to_mb(bytes)
|
234
|
+
bytes / (1024.0 * 1024.0)
|
235
|
+
end
|
236
|
+
|
237
|
+
def add_cover_image(request, editions)
|
238
|
+
cover_image = find_coverimages(editions)
|
239
|
+
return nil if cover_image.blank?
|
240
|
+
#FIXME need to add other sizes
|
241
|
+
#FIXME correct @urls and use one of those
|
242
|
+
url = "http://openlibrary.org" + cover_image
|
243
|
+
request.add_service_response(
|
244
|
+
:service=>self,
|
245
|
+
:display_text => 'Cover Image',
|
246
|
+
:key=> 'medium',
|
247
|
+
:url => url,
|
248
|
+
:size => 'medium',
|
249
|
+
:service_type_value => :cover_image)
|
250
|
+
end
|
251
|
+
|
252
|
+
# pick the first of the coverimages found
|
253
|
+
def find_coverimages(editions)
|
254
|
+
images = editions.map{|ed| ed['coverimage']}.compact
|
255
|
+
# filter out fake ones
|
256
|
+
images.reject! { |url| url =~ /book\.trans\.gif$/ }
|
257
|
+
return images[0]
|
258
|
+
end
|
259
|
+
|
260
|
+
def enhance_metadata(referent, editions)
|
261
|
+
# Which one should we use to enhance? Whichever has the largest
|
262
|
+
# oclcnum, or if none of them have an oclcnum, then whichever
|
263
|
+
# has the most metadata elements.
|
264
|
+
winner = nil
|
265
|
+
winner_oclcnum = 0
|
266
|
+
winner_numfields = 0
|
267
|
+
editions.each do |e|
|
268
|
+
score = score_metadata(e)
|
269
|
+
if ( ( score[:oclcnum] && score[:oclcnum] > winner_oclcnum ) ||
|
270
|
+
( winner_oclcnum == 0 && score[:numfields] > winner_numfields))
|
271
|
+
winner = e
|
272
|
+
winner_oclcnum = score[:oclcnum] if score[:oclcnum]
|
273
|
+
winner_numfields = score[:numfields]
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
if (winner)
|
278
|
+
referent.enhance_referent("title", winner["title"], true, false, {:overwrite=>false}) unless winner["title"].blank?
|
279
|
+
|
280
|
+
referent.enhance_referent("pub", winner["publishers"].join(","), true, false, {:overwrite=>false}) unless winner["publishers"].blank?
|
281
|
+
|
282
|
+
referent.enhance_referent("date", winner["publish_date"], true, false, {:overwrite=>false}) if winner["publish_date"] =~ /^\d\d\d\d$/
|
283
|
+
|
284
|
+
referent.enhance_referent("pub", winner["publish_places"].join(","), true, false, {:overwrite=>false}) unless winner["publish_places"].blank?
|
285
|
+
|
286
|
+
referent.enhance_referent("lccn", winner["lccn"][0], true, false, {:overwrite=>false}) unless winner["lccn"].blank?
|
287
|
+
|
288
|
+
# ISBN, prefer 13 if possible
|
289
|
+
referent.enhance_referent("isbn", winner["isbn_13"][0], true, false, {:overwrite=>false}) unless winner["isbn_13"].blank?
|
290
|
+
|
291
|
+
referent.enhance_referent("isbn", winner["isbn_10"][0], true, false, {:overwrite=>false}) if winner["isbn_13"].blank? && ! winner["isbn_10"].blank?
|
292
|
+
|
293
|
+
referent.enhance_referent("oclcnum", winner["oclc_numbers"][0], true, false, {:overwrite=>false}) unless winner["oclc_numbers"].blank?
|
294
|
+
|
295
|
+
end
|
296
|
+
|
297
|
+
end
|
298
|
+
|
299
|
+
# Score an edition in terms of how good it's metadata is.
|
300
|
+
# Returns a two-element array, first element is OCLCnum (or nil),
|
301
|
+
# second element is number of complete metadata elements.
|
302
|
+
# We like an OCLCnum, especially a higher one, and we like more
|
303
|
+
# elements.
|
304
|
+
def score_metadata(edition)
|
305
|
+
oclcnum = edition["oclc_numbers"].collect {|i| i.to_i}.max unless edition["oclc_numbers"].blank?
|
306
|
+
oclcnum = nil if oclcnum == 0
|
307
|
+
|
308
|
+
score = 0
|
309
|
+
["title", "publish_places", "publishers", "publish_date", "isbn_10", "isbn_13", "lccn"].each do |key|
|
310
|
+
score = score + 1 unless edition[key].blank?
|
311
|
+
end
|
312
|
+
|
313
|
+
return {:oclcnum => oclcnum, :numfields => score}
|
314
|
+
end
|
315
|
+
|
316
|
+
end
|