umlaut 3.0.0alpha1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|