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,237 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
class HipHoldingSearch < Hip3Service
|
4
|
+
required_config_params :base_path, :display_name
|
5
|
+
attr_reader :base_path
|
6
|
+
|
7
|
+
include MarcHelper
|
8
|
+
|
9
|
+
def initialize(config)
|
10
|
+
# Default preemption by any holding
|
11
|
+
@bib_limit = 4
|
12
|
+
@preempted_by = { "existing_type" => "holding" }
|
13
|
+
@keyword_exact_match = true
|
14
|
+
# If you are sending an OpenURL from a library service, you may
|
15
|
+
# have the HIP bibnum, and include it in the OpenURL as, eg.
|
16
|
+
# rft_id=http://catalog.library.jhu.edu/bib/343434 (except URL-encoded)
|
17
|
+
# Then you'd set rft_id_bibnum_prefix to http://catalog.library.jhu.edu/bib/
|
18
|
+
@rft_id_bibnum_prefix = nil
|
19
|
+
@profile = "general"
|
20
|
+
super(config)
|
21
|
+
# Trim question-mark from base_url, if given
|
22
|
+
@base_path.chop! if (@base_path.rindex('?') == @base_path.length)
|
23
|
+
end
|
24
|
+
|
25
|
+
def service_types_generated
|
26
|
+
# Add one more to whatever the Hip3Service does.
|
27
|
+
return super.push(ServiceTypeValue['holding_search'])
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def handle(request)
|
32
|
+
|
33
|
+
# Only do anything if we have no holdings results from someone else.
|
34
|
+
holdings = request.service_types.find(:all, :conditions=>["service_type_value_name = ?", "holding"])
|
35
|
+
|
36
|
+
if (holdings.length > 0)
|
37
|
+
return request.dispatched(self, true)
|
38
|
+
end
|
39
|
+
|
40
|
+
ref_metadata = request.referent.metadata
|
41
|
+
|
42
|
+
bib_searcher = Hip3::BibSearcher.new(@base_path)
|
43
|
+
|
44
|
+
search_hash = {}
|
45
|
+
|
46
|
+
if ( request.referent.format != "book" &&
|
47
|
+
(! ref_metadata['jtitle'].blank?) &&
|
48
|
+
ref_metadata['bititle'].blank? )
|
49
|
+
hip_title_index = Hip3::BibSearcher::SERIAL_TITLE_KW_INDEX
|
50
|
+
else
|
51
|
+
hip_title_index = Hip3::BibSearcher::TITLE_KW_INDEX
|
52
|
+
end
|
53
|
+
|
54
|
+
title = ref_metadata['jtitle']
|
55
|
+
title = ref_metadata['btitle'] if title.blank?
|
56
|
+
title = ref_metadata['title'] if title.blank?
|
57
|
+
|
58
|
+
#title_terms = search_terms_for_title_tokenized(title)
|
59
|
+
# tokenized was too much recall, not enough precision. Try phrase
|
60
|
+
# search.
|
61
|
+
title_terms = search_terms_for_title_phrase(title)
|
62
|
+
unless ( title_terms )
|
63
|
+
Rails.logger.debug("#{self.service_id} is missing title, can not search.")
|
64
|
+
return request.dispatched(self, true)
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
search_hash[hip_title_index] = title_terms
|
69
|
+
|
70
|
+
# Do we have the bibnum?
|
71
|
+
bibnum = get_bibnum(request.referent)
|
72
|
+
bib_searcher.bibnum = bibnum if bibnum
|
73
|
+
|
74
|
+
# If it's a non-journal thing, add the author if we have an aulast (preferred) or au.
|
75
|
+
# But wait--if it's a book _part_, don't include the author name, since
|
76
|
+
# it _might_ just be the author of the part, not of the book.
|
77
|
+
unless (request.referent.format == "journal" ||
|
78
|
+
( request.referent.format == "book" && ! ref_metadata['atitle'].blank?))
|
79
|
+
# prefer aulast
|
80
|
+
if (! ref_metadata['aulast'].blank?)
|
81
|
+
search_hash[ Hip3::BibSearcher::AUTHOR_KW_INDEX ] = [ref_metadata['aulast']]
|
82
|
+
elsif (! ref_metadata['au'].blank?)
|
83
|
+
search_hash[ Hip3::BibSearcher::AUTHOR_KW_INDEX ] = [ref_metadata['au']]
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
bib_searcher.search_hash = search_hash
|
89
|
+
unless bib_searcher.insufficient_query
|
90
|
+
timing_debug("start search")
|
91
|
+
|
92
|
+
bibs = bib_searcher.search
|
93
|
+
|
94
|
+
timing_debug("bib searching")
|
95
|
+
|
96
|
+
# Ssee if any our matches are exact title matches. 'exact' after normalizing a bit, including removing subtitles.
|
97
|
+
matches = [];
|
98
|
+
|
99
|
+
# Various variant normalized forms of the title from the OpenURL
|
100
|
+
# request. #compact removes nil values.
|
101
|
+
request_titles = [title,
|
102
|
+
normalize_title( title ),
|
103
|
+
normalize_title( title, :remove_subtitle => true) ].compact
|
104
|
+
|
105
|
+
|
106
|
+
|
107
|
+
if ( @keyword_exact_match )
|
108
|
+
bibs.each do |bib|
|
109
|
+
# various variant normalized forms of the title from the bib
|
110
|
+
# #compact removes nil values.
|
111
|
+
bib_titles = [ bib.title,
|
112
|
+
normalize_title(bib.title, :remove_subtitle => true),
|
113
|
+
normalize_title(bib.title) ].compact
|
114
|
+
|
115
|
+
# Do any of the various forms match? Set intersection on our
|
116
|
+
# two sets.
|
117
|
+
if ( bib_titles & request_titles ).length > 0
|
118
|
+
matches.push( bib )
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
responses_added = Hash.new
|
124
|
+
|
125
|
+
timing_debug("Finding matches")
|
126
|
+
|
127
|
+
if (matches.length > 0 )
|
128
|
+
|
129
|
+
# process as exact matches with method from Hip3Service
|
130
|
+
# Add copies
|
131
|
+
# Add 856 urls.
|
132
|
+
responses_added = {}
|
133
|
+
|
134
|
+
unless preempted_by(request, "fulltext")
|
135
|
+
|
136
|
+
# Let's do some analysis of our results. If it's got a matching
|
137
|
+
# bibnum, then include it as an EXACT match.
|
138
|
+
req_bibnum = get_bibnum(request.referent)
|
139
|
+
if ( req_bibnum )
|
140
|
+
matches.each do |bib|
|
141
|
+
if (req_bibnum == bib.bibNum)
|
142
|
+
responses_added.merge!( add_856_links(request, [bib.marc_xml]) )
|
143
|
+
responses_added.merge!( add_copies( request, [bib] ))
|
144
|
+
matches.delete(bib)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
timing_debug("Identified matches")
|
150
|
+
|
151
|
+
# Otherwise, sort records with matching dates FIRST.
|
152
|
+
# Some link generators use an illegal 'year' parameter, bah.
|
153
|
+
if ( date = (request.referent['date'] || request.referent['year']))
|
154
|
+
req_year = date[0,4]
|
155
|
+
matches = matches.partition {|bib| get_years(bib.marc_xml).include?( req_year )}.flatten
|
156
|
+
end
|
157
|
+
|
158
|
+
timing_debug("Date sorted")
|
159
|
+
|
160
|
+
responses_added.merge!( add_856_links(request, matches.collect{|b| b.marc_xml}, :match_reliability => ServiceResponse::MatchUnsure ) )
|
161
|
+
|
162
|
+
timing_debug("added 856's")
|
163
|
+
end
|
164
|
+
|
165
|
+
responses_added.merge!( add_copies(request, matches, :match_reliability => ServiceResponse::MatchUnsure ) )
|
166
|
+
|
167
|
+
timing_debug("added copies")
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
if (bibs.length > 0 && (! responses_added['holding']))
|
172
|
+
# process as holdings_search
|
173
|
+
request.add_service_response(
|
174
|
+
:service => self,
|
175
|
+
:source_name => @display_name,
|
176
|
+
:count => bibs.length,
|
177
|
+
:display_text => "#{bibs.length} possible #{case; when bibs.length > 1 ; 'matches' ; else; 'match' ; end} in #{display_name}",
|
178
|
+
:url => bib_searcher.search_url,
|
179
|
+
:service_type_value => :holding_search)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
return request.dispatched(self, true)
|
183
|
+
end
|
184
|
+
|
185
|
+
# One algorithm for turning a title into HIP search terms.
|
186
|
+
# Tokenizes the title into individual words, eliminates stop-words,
|
187
|
+
# and combines each word with 'AND'. We started with this for maximum
|
188
|
+
# recall, but after some experimentation seems to have too low precision
|
189
|
+
# without sufficient enough increase in recall.
|
190
|
+
# Returns an array of keywords.
|
191
|
+
def search_terms_for_title_tokenized(title)
|
192
|
+
title_cleaned = normalize_title(title)
|
193
|
+
|
194
|
+
if title_cleaned.blank?
|
195
|
+
# Not enough metadata to search.
|
196
|
+
return nil
|
197
|
+
end
|
198
|
+
|
199
|
+
# plus remove some obvious stop words, cause HIP is going to choke on em
|
200
|
+
title_cleaned.gsub!(/\bthe\b|\band\b|\bor\b|\bof\b|\ba\b/i,'')
|
201
|
+
|
202
|
+
title_kws = title_cleaned.split
|
203
|
+
# limit to 12 keywords
|
204
|
+
title_kws = title_kws.slice( (0..11) )
|
205
|
+
|
206
|
+
return title_kws
|
207
|
+
end
|
208
|
+
|
209
|
+
# Another algorithm for turning a title into HIP search terms.
|
210
|
+
# This one doesn't tokenize, but keeps the whole title as a phrase
|
211
|
+
# search. Does eliminate punctuation. Does not remove things that
|
212
|
+
# look like a sub-title.
|
213
|
+
# Returns an array with one item.
|
214
|
+
def search_terms_for_title_phrase(title)
|
215
|
+
title_cleaned = normalize_title(title)
|
216
|
+
|
217
|
+
if title_cleaned.blank?
|
218
|
+
# Not enough metadata to search.
|
219
|
+
return nil
|
220
|
+
end
|
221
|
+
|
222
|
+
return [title_cleaned]
|
223
|
+
end
|
224
|
+
|
225
|
+
def timing_debug(waypoint = "Waypoint")
|
226
|
+
@last_timed ||= Time.now
|
227
|
+
|
228
|
+
before = @last_timed
|
229
|
+
@last_timed = Time.now
|
230
|
+
|
231
|
+
interval = @last_timed - before
|
232
|
+
|
233
|
+
Rails.logger.debug("#{service_id}: #{waypoint}: #{interval}")
|
234
|
+
|
235
|
+
end
|
236
|
+
|
237
|
+
end
|
@@ -0,0 +1,488 @@
|
|
1
|
+
# This service searches the Internet Archive (archive.org) by title
|
2
|
+
# and, if present, creator. Results are broken down by mediatypes. Which
|
3
|
+
# mediatypes are searched can be configured via umlaut_config/services.yml.
|
4
|
+
# Also an optional link to a full search in the native interface can be
|
5
|
+
# presented to the user.
|
6
|
+
|
7
|
+
# Property settings can be set in services.yml
|
8
|
+
# url:
|
9
|
+
# num_results: a number. This is the number of results returned for each
|
10
|
+
# mediatype within the main section of the view
|
11
|
+
# mediatypes: an array of the mediatypes searched. insure there is an
|
12
|
+
# appropriate mediatype as defined by IA. Searching by mediatype searches
|
13
|
+
# across collections.
|
14
|
+
# The following link will (currently) show the possible mediatypes:
|
15
|
+
# http://homeserver7.us.archive.org:8983/solr/select?q=[*+TO+*]&fl=identifier&wt=json&rows=0&indent=yes&facet=true&facet.field=mediatype
|
16
|
+
# show_web_link: boolean. If set to true, if there are more results than
|
17
|
+
# num_results a link to those further results will display
|
18
|
+
# with highlighted_links
|
19
|
+
# display_name: defaults to "Internet Archive"
|
20
|
+
|
21
|
+
|
22
|
+
class InternetArchive < Service
|
23
|
+
require 'open-uri' #
|
24
|
+
require 'cgi'
|
25
|
+
require 'multi_json' #we ask IA for json
|
26
|
+
require 'timeout' # used to timeout our requests
|
27
|
+
include MetadataHelper
|
28
|
+
|
29
|
+
# No parameters are required, we have working defaults for them all.
|
30
|
+
|
31
|
+
attr_reader :url, :num_results, :mediatypes
|
32
|
+
|
33
|
+
# maps the IA mediatype to Umlaut service type
|
34
|
+
SERVICE_TYPE_MAP = {
|
35
|
+
"texts" => :fulltext,
|
36
|
+
"audio" => :audio
|
37
|
+
}
|
38
|
+
|
39
|
+
def service_types_generated
|
40
|
+
types = [
|
41
|
+
ServiceTypeValue[:fulltext],
|
42
|
+
ServiceTypeValue[:audio],
|
43
|
+
ServiceTypeValue[:'highlighted_link']
|
44
|
+
]
|
45
|
+
types << ServiceTypeValue[:search_inside] if @include_search_inside
|
46
|
+
return types
|
47
|
+
end
|
48
|
+
|
49
|
+
def initialize(config)
|
50
|
+
# Default base URL for IA advanced search. We use this base link rather than
|
51
|
+
# the this rather than the IA Solr index directly because IA suggests that
|
52
|
+
# the Solr home may change over time.
|
53
|
+
@url = 'http://www.archive.org/advancedsearch.php?'
|
54
|
+
# default number of results to return
|
55
|
+
@num_results = 1
|
56
|
+
# default IA mediatypes to search
|
57
|
+
@mediatypes = ["texts", "audio"]
|
58
|
+
# Should the web link to further results be shown? default to true
|
59
|
+
@show_web_link = true
|
60
|
+
@display_name = "the Internet Archive"
|
61
|
+
@http_timeout = 5.seconds
|
62
|
+
@include_search_inside = false
|
63
|
+
|
64
|
+
@credits = {
|
65
|
+
"The Internet Archive" => "http://archive.org/"
|
66
|
+
}
|
67
|
+
|
68
|
+
super(config)
|
69
|
+
@num_results_for_types ||= {}
|
70
|
+
@mediatypes.each do |type|
|
71
|
+
@num_results_for_types[type] ||= @num_results
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def handle(request)
|
76
|
+
begin
|
77
|
+
do_query(request)
|
78
|
+
rescue Timeout::Error => e
|
79
|
+
return request.dispatched(self, false, e)
|
80
|
+
end
|
81
|
+
return request.dispatched(self, true)
|
82
|
+
end
|
83
|
+
|
84
|
+
def do_query(request)
|
85
|
+
# get the search terms for use in both fulltext search and highlighted_link
|
86
|
+
# IA does index apostrophes, although not generally other puncutation. Need to keep em.
|
87
|
+
search_terms = {:title => get_search_title(request.referent ,:keep_apostrophes=>true),
|
88
|
+
:creator => get_search_creator(request.referent)}
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
# We need both title and author to continue
|
93
|
+
return nil if (search_terms[:title].blank? || search_terms[:creator].blank?)
|
94
|
+
|
95
|
+
# Return if this is an journal article link, an IA search can do nothing
|
96
|
+
# for us except waste CPU cycles for us and IA.
|
97
|
+
metadata = request.referent.metadata
|
98
|
+
return nil unless metadata["atitle"].blank? &&
|
99
|
+
metadata["issue"].blank? &&
|
100
|
+
metadata["volume"].blank?
|
101
|
+
|
102
|
+
# create one link that searches all configured mediatypes
|
103
|
+
link = @url + ia_params(search_terms)
|
104
|
+
|
105
|
+
# using open() conveniently follows the redirect for us. Alas, it
|
106
|
+
# doesn't give us access to the IA http status code response though.
|
107
|
+
begin
|
108
|
+
response = nil
|
109
|
+
timeout(@http_timeout.to_i) {
|
110
|
+
response = open(link).read
|
111
|
+
}
|
112
|
+
rescue Exception => e
|
113
|
+
# Log more info for exception, and then just forward exception on,
|
114
|
+
# we don't have any way to handle it.
|
115
|
+
Rails.logger.error("InternetArchive exception, for url[[#{link}]] , Exception #{e.class}")
|
116
|
+
raise e
|
117
|
+
end
|
118
|
+
|
119
|
+
if response.blank?
|
120
|
+
Rails.logger.warn("InternetArchive returned empty response for #{link}")
|
121
|
+
return nil
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
doc = MultiJson.decode(response)
|
126
|
+
results = doc['response']['docs']
|
127
|
+
|
128
|
+
@mediatypes.each do |type|
|
129
|
+
type_results = get_results_by_type(results, type)
|
130
|
+
|
131
|
+
|
132
|
+
|
133
|
+
|
134
|
+
# if we have more results than we want to show in the main view
|
135
|
+
# we can ceate a link (highlighted_link) to the search in the sidebar
|
136
|
+
num_found = type_results.length #doc['response']['numFound']
|
137
|
+
if (@show_web_link and not type_results.empty? and @num_results_for_types[type] < num_found )
|
138
|
+
do_web_link(request, search_terms, type, num_found)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Check for search inside only for first result of type 'text'
|
142
|
+
if (@include_search_inside &&
|
143
|
+
type == 'texts' &&
|
144
|
+
(first_hit = type_results[0]) &&
|
145
|
+
(identifier = first_hit["identifier"])
|
146
|
+
)
|
147
|
+
direct_url = URI.parse("http://www.archive.org/stream/" + identifier)
|
148
|
+
|
149
|
+
# Head request, if we get a 200, we think it means we have page
|
150
|
+
# turner with search.
|
151
|
+
req = Net::HTTP.new(direct_url.host, direct_url.port)
|
152
|
+
response = req.request_head(direct_url.path)
|
153
|
+
if response.code == "200"
|
154
|
+
# search inside!
|
155
|
+
request.add_service_response(
|
156
|
+
:service => self,
|
157
|
+
:display_text=> @display_name,
|
158
|
+
:url => direct_url.to_s,
|
159
|
+
:service_type_value => :search_inside
|
160
|
+
)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# add a service response for each result for this mediatype
|
165
|
+
type_results.each_with_index do |result, index|
|
166
|
+
break if index == @num_results_for_types[type]
|
167
|
+
display_name = @display_name
|
168
|
+
|
169
|
+
if ( result["collection"] && COLLECTION_LABELS[result["collection"][0]])
|
170
|
+
display_name += ": " + COLLECTION_LABELS[result["collection"][0]]
|
171
|
+
elsif ( result["collection"])
|
172
|
+
display_name += ": " + result["collection"][0].titlecase
|
173
|
+
end
|
174
|
+
|
175
|
+
#note = result['title']
|
176
|
+
#note << " by " << result['creator'].join(', ') if result['creator']
|
177
|
+
|
178
|
+
service_type = SERVICE_TYPE_MAP[type]
|
179
|
+
request.add_service_response(
|
180
|
+
:service=>self,
|
181
|
+
:display_text=>display_name,
|
182
|
+
:url=>create_result_url(result),
|
183
|
+
:match_reliability => ServiceResponse::MatchUnsure,
|
184
|
+
:edition_str => edition_str(result),
|
185
|
+
:service_type_value => service_type )
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# Here we create params in the format that the IA advanced search needs.
|
191
|
+
# These are solr-like params.
|
192
|
+
def ia_params(search_terms)
|
193
|
+
return nil if search_terms[:title].nil?
|
194
|
+
params = 'fl%5B%5D=*&fmt=json&xmlsearch=Search' #&indent=yes
|
195
|
+
params << "&rows=999&q=" #is 999 too many or even too few?
|
196
|
+
params << create_query_params(search_terms)
|
197
|
+
end
|
198
|
+
|
199
|
+
def create_result_url(result)
|
200
|
+
'http://archive.org/details/' + result['identifier']
|
201
|
+
end
|
202
|
+
|
203
|
+
# displaying the num_found relies on the number of results from ia_params being
|
204
|
+
# enough to capture all results for a mediatype. If there are more potential
|
205
|
+
# results then num_found will not be accurate. But good enough.
|
206
|
+
def do_web_link(request, search_terms, type, num_found)
|
207
|
+
display_text = "#{num_found} digital #{type.singularize} " + (num_found > 1 ? "files" : "file")
|
208
|
+
|
209
|
+
|
210
|
+
url = create_web_link_url(search_terms, type)
|
211
|
+
request.add_service_response(
|
212
|
+
:service=>self,
|
213
|
+
:url=>url,
|
214
|
+
:display_text=>display_text,
|
215
|
+
:service_type_value => :highlighted_link
|
216
|
+
)
|
217
|
+
end
|
218
|
+
|
219
|
+
def create_web_link_url(search_terms, type)
|
220
|
+
'http://www.archive.org/search.php?query=' << create_query_params(search_terms, type)
|
221
|
+
#url << CGI.escape('mediatype:' << type << ' AND ')
|
222
|
+
|
223
|
+
end
|
224
|
+
|
225
|
+
# if given a type it will only search for one mediatype. otherwise it
|
226
|
+
# does an OR search for all configured mediatypes
|
227
|
+
def create_query_params(search_terms, type=nil)
|
228
|
+
# Downcase params to avoid weird misconfiguration in IA's SOLR
|
229
|
+
# installation, where it's interpreting uppercase words as
|
230
|
+
# commands even within quotes. Also take out any parens in input.
|
231
|
+
# Also IA does not semi-colons in input?!?
|
232
|
+
title = safe_argument(search_terms[:title])
|
233
|
+
|
234
|
+
|
235
|
+
params = 'title:' << CGI.escape('"' << title << '"')
|
236
|
+
if (! search_terms[:creator].blank?)
|
237
|
+
creator = safe_argument(search_terms[:creator])
|
238
|
+
params << '+AND+creator:' << CGI.escape('(' << creator << ')')
|
239
|
+
end
|
240
|
+
mt = []
|
241
|
+
params << '+AND+('
|
242
|
+
if type
|
243
|
+
params << 'mediatype:' << type
|
244
|
+
else
|
245
|
+
@mediatypes.each do |t|
|
246
|
+
mt << ('mediatype:' << t)
|
247
|
+
end
|
248
|
+
params << mt.join('+OR+')
|
249
|
+
end
|
250
|
+
params << ')' #closing the mediatypes with a paren
|
251
|
+
end
|
252
|
+
|
253
|
+
# used on what will be values stuck into a URL as search terms,
|
254
|
+
# does NOT cgi escape, but does safe-ify them in other ways for IA.
|
255
|
+
def safe_argument(string)
|
256
|
+
# Downcase params to avoid weird misconfiguration in IA's SOLR
|
257
|
+
# installation, where it's interpreting uppercase words as
|
258
|
+
# commands even within quotes.
|
259
|
+
output = string.downcase
|
260
|
+
|
261
|
+
# Remove parens, semi-colons, and brackets -- they all mess
|
262
|
+
# up IA, which thinks they are special chars. Remove double quote,
|
263
|
+
# special char, which sometimes we want to use ourselves. Replace
|
264
|
+
# all with spaces to avoid accidentally conjoining words.
|
265
|
+
# (could be
|
266
|
+
# escaping instead? Not worth it, we don't want to search
|
267
|
+
# on these anyway. Remove ALL punctuation? Not sure.)
|
268
|
+
output.gsub!(/[)(\]\[;"\=]/, ' ')
|
269
|
+
|
270
|
+
return output
|
271
|
+
end
|
272
|
+
|
273
|
+
|
274
|
+
def get_results_by_type(results, type)
|
275
|
+
results.map{|doc| doc if doc["mediatype"] == type}.compact
|
276
|
+
end
|
277
|
+
|
278
|
+
def edition_str(result)
|
279
|
+
parts = []
|
280
|
+
|
281
|
+
parts.push( result['title']) unless result['title'].blank?
|
282
|
+
parts.push( result['publisher'] ) unless result['publisher'].blank?
|
283
|
+
parts.push( result['year']) unless result['year'].blank?
|
284
|
+
|
285
|
+
edition_str = parts.join(', ')
|
286
|
+
edition_str = nil if edition_str.blank?
|
287
|
+
|
288
|
+
return edition_str
|
289
|
+
end
|
290
|
+
|
291
|
+
# catch and redirect response_url fo rsearch_inside
|
292
|
+
def response_url(service_type, submitted_params)
|
293
|
+
if ( ! (service_type.service_type_value.name == "search_inside" ))
|
294
|
+
return super(service_type, submitted_params)
|
295
|
+
else
|
296
|
+
base = service_type.service_response[:url]
|
297
|
+
query = CGI.escape(submitted_params["query"] || "")
|
298
|
+
url = base + "#search/#{query}"
|
299
|
+
return url
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
## collection labels
|
304
|
+
# list of collection labels can be found here:
|
305
|
+
# http://www.archive.org/advancedsearch.php?q=mediatype%3Acollection&fl[]=collection&fl[]=identifier&fl[]=title&sort[]=&sort[]=&sort[]=&rows=9999&indent=yes&fmt=json&xmlsearch=Search
|
306
|
+
# FIXME either get these dynamically at intervals or add a fuller set below.
|
307
|
+
# Currently there are over 4300 collections.
|
308
|
+
# If we're going to do this as a static hash then it should be a class
|
309
|
+
# constant. Currently this hash contains a small selection of collections
|
310
|
+
# which include the 'audio' mediatype and all that contain the 'texts' mediatype.
|
311
|
+
COLLECTION_LABELS = {
|
312
|
+
"CaliforniaFishandGame"=>"California Fish and Game",
|
313
|
+
"ol_data"=>"Open Library Data",
|
314
|
+
"worldhealthorganization"=>"World Health Organization",
|
315
|
+
"opensource_movies"=>"Open Source Movies",
|
316
|
+
"clairetcarneylibrary"=>
|
317
|
+
"Claire T. Carney Library, University of Massachusetts Dartmouth",
|
318
|
+
"university_of_illinois_urbana-champaign"=>
|
319
|
+
"University of Illinois Urbana-Champaign",
|
320
|
+
"smithsonian_books"=>"Smithsonian",
|
321
|
+
"nhml_london"=>"Natural History Museum Library, London",
|
322
|
+
"animationandcartoons"=>"Animation & Cartoons",
|
323
|
+
"university_of_toronto_regis"=>"Regis College Library",
|
324
|
+
"vlogs"=>"Vlogs",
|
325
|
+
"opensource"=>"Open Source Books",
|
326
|
+
"USGovernmentDocuments"=>"US Government Documents",
|
327
|
+
"danceman"=>"Dance Manuals",
|
328
|
+
"additional_collections"=>"Additional Collections",
|
329
|
+
"internet_archive_books"=>"Internet Archive Books",
|
330
|
+
"sloan"=>"Sloan Foundation",
|
331
|
+
"iacl"=>"Children's Library",
|
332
|
+
"audio_religion"=>"Spirituality & Religion",
|
333
|
+
"microfilm"=>"Books from Microfilm",
|
334
|
+
"toronto"=>"Canadian Libraries",
|
335
|
+
"prelinger"=>"Prelinger Archives",
|
336
|
+
"bostonpubliclibrary"=>"Boston Public Library",
|
337
|
+
"sports"=>"Sports Videos",
|
338
|
+
"universallibrary"=>"Universal Library",
|
339
|
+
"sfpl"=>"The San Francisco Public Library",
|
340
|
+
"university_of_toronto_knox"=>"Caven Library, Knox College",
|
341
|
+
"memorial_university"=>"Memorial University of Newfoundland & Labrador",
|
342
|
+
"MBLWHOI"=>"MBLWHOI Library",
|
343
|
+
"oreilly_books"=>"O'Reilly",
|
344
|
+
"burstein"=>"The Burstein Alice in Wonderland Collection",
|
345
|
+
"ucroho"=>"Regional Oral History Office",
|
346
|
+
"Brandeis_University"=>"Brandeis University Libraries",
|
347
|
+
"birney_anti_slavery_collection"=>"Birney Anti-Slavery Collection",
|
348
|
+
"Johns_Hopkins_University"=>"The Johns Hopkins University Sheridan Libraries",
|
349
|
+
"culturalandacademicfilms"=>"Cultural & Academic Films",
|
350
|
+
"Harvard_University"=>"Harvard University",
|
351
|
+
"montana_state_publications"=>"Montana State Government Publications",
|
352
|
+
"national_institute_for_newman_studies"=>
|
353
|
+
"National Institute for Newman Studies",
|
354
|
+
"buddha"=>"Buddha Books",
|
355
|
+
"university_of_toronto_fisher"=>"Thomas Fisher Rare Book Library",
|
356
|
+
"ryerson_university"=>"Ryerson University",
|
357
|
+
"university_of_toronto_emmanuel"=>
|
358
|
+
"Emmanuel College Library, Victoria University",
|
359
|
+
"unica"=>"Unica: Rare Books from UIUC",
|
360
|
+
"mugar"=>"The Mugar Memorial Library, Boston University",
|
361
|
+
"havergal"=>"Havergal College",
|
362
|
+
"university_of_toronto_gerstein"=>
|
363
|
+
"University of Toronto - Gerstein Science Information Centre",
|
364
|
+
"NY_Botanical_Garden"=>"The New York Botanical Garden",
|
365
|
+
"calacademy"=>"California Academy of Sciences",
|
366
|
+
"chm_fiche"=>"Computer History Museum",
|
367
|
+
"university_of_toronto_crrs"=>
|
368
|
+
"Centre for Reformation and Renaissance Studies Library",
|
369
|
+
"djo"=>"Dickens Journals Online",
|
370
|
+
"unclibraries"=>"University of North Carolina at Chapel Hill",
|
371
|
+
"university_of_toronto_oise"=>"OISE/UT Library",
|
372
|
+
"newsandpublicaffairs"=>"News & Public Affairs",
|
373
|
+
"biodiversity"=>"Biodiversity Heritage Library",
|
374
|
+
"university_of_ottawa"=>"University of Ottawa",
|
375
|
+
"Wellesley_College_Library"=>"Wellesley College Library",
|
376
|
+
"audio_foreign"=>"Non-English Audio",
|
377
|
+
"national_library_of_australia"=>"National Library of Australia",
|
378
|
+
"datadumps"=>"Open Library Data",
|
379
|
+
"microfilmreel"=>"Reels of Microfilm",
|
380
|
+
"saint_marys_college"=>"Saint Mary's College of California",
|
381
|
+
"university_of_toronto_pratt"=>"E.J. Pratt Library",
|
382
|
+
"Boston_College_Library"=>"Boston College Library",
|
383
|
+
"uchicago"=>"University of Chicago",
|
384
|
+
"audio_podcast"=>"Podcasts",
|
385
|
+
"tufts"=>"Tufts University",
|
386
|
+
"opensource_audio"=>"Open Source Audio",
|
387
|
+
"university_of_toronto_trinity"=>"John W. Graham Library, Trinity College",
|
388
|
+
"audio_tech"=>"Computers & Technology",
|
389
|
+
"moviesandfilms"=>"Movies",
|
390
|
+
"etree"=>"Live Music Archive",
|
391
|
+
"marcuslucero"=>"the Marucs Lucero",
|
392
|
+
"opencontentalliance"=>"Open Content Alliance",
|
393
|
+
"radioprograms"=>"Radio Programs",
|
394
|
+
"university_of_toronto_pims"=>"PIMS - University of Toronto",
|
395
|
+
"newspapers"=>"Newspapers",
|
396
|
+
"university_of_california_libraries"=>"University of California Libraries",
|
397
|
+
"millionbooks"=>"Million Book Project",
|
398
|
+
"university_of_toronto_robarts"=>"University of Toronto - Robarts Library",
|
399
|
+
"university_of_toronto"=>"University of Toronto",
|
400
|
+
"montana_state_library"=>"Montana State Library",
|
401
|
+
"bancroft_library"=>"The Bancroft Library",
|
402
|
+
"prelinger_library"=>"Prelinger Library",
|
403
|
+
"libraryofcongress"=>"The Library of Congress",
|
404
|
+
"richtest"=>"Test books from California",
|
405
|
+
"mobot"=>"Missouri Botanical Garden",
|
406
|
+
"gamevideos"=>"Video Games",
|
407
|
+
"blc"=>"The Boston Library Consortium",
|
408
|
+
"cdl"=>"California Digital Library",
|
409
|
+
"Princeton"=>"Princeton Theological Seminary",
|
410
|
+
"mcmaster_university"=>"McMaster University",
|
411
|
+
"sanfranciscopubliclibrary"=>"San Francisco Public Library",
|
412
|
+
"spanish_texts"=>"The Spanish Language Library",
|
413
|
+
"boston_college_libraries"=>"The Boston College Libraries",
|
414
|
+
"gutenberg"=>"Project Gutenberg",
|
415
|
+
"Music_UniversityofToronto"=>"Music - University of Toronto",
|
416
|
+
"msn_books"=>"Microsoft",
|
417
|
+
"youth_media"=>"Youth Media",
|
418
|
+
"independent"=>"independent texts",
|
419
|
+
"carletonlibrary"=>"Carleton University Library",
|
420
|
+
"arpanet"=>"Arpanet",
|
421
|
+
"yahoo_books"=>"Yahoo!",
|
422
|
+
"johnadamsBPL"=>"The John Adams Library at the Boston Public Library",
|
423
|
+
"library_of_congress"=>"The Library of Congress",
|
424
|
+
"ColumbiaUniversityLibraries"=>"Columbia University Libraries",
|
425
|
+
"university_of_guelph"=>"University of Guelph",
|
426
|
+
"GratefulDead"=>"Grateful Dead",
|
427
|
+
"audio_bookspoetry"=>"Audio Books & Poetry",
|
428
|
+
"ncsulibraries"=>"North Carolina State University Libraries",
|
429
|
+
"brown_university_library"=>"Brown University Library",
|
430
|
+
"Allen_County_Public_Library"=>"Allen County Public Library",
|
431
|
+
"yrlsc"=>"The Charles E. Young Research Library Special Collections",
|
432
|
+
"torontotest"=>"Test books from Canada",
|
433
|
+
"americana"=>"American Libraries",
|
434
|
+
"librivoxaudio"=>"LibriVox",
|
435
|
+
"audio_music"=>"Music & Arts",
|
436
|
+
"toronto_public_library"=>"Toronto Public Library",
|
437
|
+
"getty"=>"Research Library, Getty Research Institute",
|
438
|
+
"ontla"=>"The Legislative Assembly of Ontario Collection",
|
439
|
+
"TheChristianRadical"=>"The Christian Radical",
|
440
|
+
"netlabels"=>"Netlabels",
|
441
|
+
"newyorkpubliclibrary"=>"New York Public Library",
|
442
|
+
"University_of_New_Hampshire_Library"=>"University of New Hampshire Library",
|
443
|
+
"cbk"=>"Cook Books and Home Economics",
|
444
|
+
"audio_news"=>"News & Public Affairs",
|
445
|
+
"ant_texts"=>"Ant Texts",
|
446
|
+
"computersandtechvideos"=>"Computers & Technology",
|
447
|
+
"the_beat_within"=>"The Beat Within Magazine",
|
448
|
+
"university_of_toronto_kelly"=>"University of Toronto - John M Kelly Library",
|
449
|
+
"library_and_archives_canada"=>"Library and Archives Canada",
|
450
|
+
"ephemera"=>"Ephemeral Films",
|
451
|
+
"OXFAM"=>"Oxfam",
|
452
|
+
"foreignlanguagevideos"=>"Non-English Videos",
|
453
|
+
"MontanaStateLibrary"=>"Montana State Library",
|
454
|
+
"EarthSciences_UniversityofToronto"=>"Earth Sciences University of Toronto",
|
455
|
+
"octavo"=>"Octavo",
|
456
|
+
"artsandmusicvideos"=>"Arts & Music"
|
457
|
+
}
|
458
|
+
|
459
|
+
|
460
|
+
end
|
461
|
+
|
462
|
+
# Test URLs using defaults
|
463
|
+
# Shows texts and audio under fulltext, but only a see also for texts
|
464
|
+
# http://localhost:3000/resolve?&rft.title=Fairy+Tales&rft.aulast=Andersen&ctx_ver=Z39.88-2004&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Abook
|
465
|
+
#
|
466
|
+
# Shows texts and audio, but only see also for audio
|
467
|
+
# http://localhost:3000/resolve?&rft.title=Frankenstein&rft.aulast=Shelley&ctx_ver=Z39.88-2004&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Abook
|
468
|
+
#
|
469
|
+
|
470
|
+
# WorldCat links
|
471
|
+
# If you have OpenURL Referrer or another Firefox add-on configured to
|
472
|
+
# turn COiNS into an OpenURL to localhost:3000, these links have hits in IA.
|
473
|
+
# Frankenstein: http://www.worldcat.org/oclc/33045872
|
474
|
+
# Alice in Wonderland: http://www.worldcat.org/oclc/221499
|
475
|
+
# Fairy Tales by Andersen: http://www.worldcat.org/oclc/68711386
|
476
|
+
# Adventures of Huckleberry Finn: http://www.worldcat.org/oclc/2985768
|
477
|
+
# Gift of the Magi: http://www.worldcat.org/oclc/9065223
|
478
|
+
# Heart of the West: http://www.worldcat.org/oclc/49293242
|
479
|
+
# Little Women; or, Meg, Jo, Beth, and Amy: http://www.worldcat.org/oclc/1157
|
480
|
+
# FIXME should we remove everything after ; as well?
|
481
|
+
# Letters from a Cat: http://www.worldcat.org/oclc/13529549
|
482
|
+
# Uncle Tom's Cabin: http://www.worldcat.org/oclc/7945691
|
483
|
+
# needed apostrophe to succeed
|
484
|
+
# Goody Two-Shoes: http://www.worldcat.org/oclc/32678428
|
485
|
+
# The Snow-Image: http://www.worldcat.org/oclc/5020610
|
486
|
+
# Les Canadiens-Français: http://www.worldcat.org/oclc/186641188
|
487
|
+
# FIXME should match 1 record and doesn't. character encoding problems?
|
488
|
+
# John L. Stoddard's Lectures: http://www.worldcat.org/oclc/2181690
|