Add Table of Contents capability to OpenLibrary added content plugin.
authordbs <dbs@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Mon, 7 Dec 2009 15:01:04 +0000 (15:01 +0000)
committerdbs <dbs@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Mon, 7 Dec 2009 15:01:04 +0000 (15:01 +0000)
Hard code the URLs for OpenLibrary in the module, as requiring the URLs
to be set in opensrf.xml is an unnecessary configuration step.

Add a GPL header to the module, crediting David Christensen as the originator
and myself as the extender.

Some other miscellaneous code cleanup.

TODO: Enable toc_json() method; probably by refactoring toc_html().

git-svn-id: svn://svn.open-ils.org/ILS/trunk@15089 dcc99617-32d9-48b4-a31d-7c20da2025e4

Open-ILS/src/perlmods/OpenILS/WWW/AddedContent/OpenLibrary.pm

index e2f1b84..634fdc7 100644 (file)
@@ -1,3 +1,18 @@
+# ---------------------------------------------------------------
+# Copyright (C) 2009 David Christensen <david.a.christensen@gmail.com>
+# Copyright (C) 2009 Dan Scott <dscott@laurentian.ca>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# ---------------------------------------------------------------
+
 package OpenILS::WWW::AddedContent::OpenLibrary;
 use strict; use warnings;
 use OpenSRF::Utils::Logger qw/$logger/;
@@ -5,55 +20,117 @@ use OpenSRF::Utils::SettingsParser;
 use OpenILS::WWW::AddedContent;
 use OpenSRF::Utils::JSON;
 use OpenSRF::EX qw/:try/;
-use XML::LibXML;
+use Data::Dumper;
 
 # Edit the <added_content> section of /openils/conf/opensrf.xml
 # Change <module> to:
 #   <module>OpenILS::WWW::AddedContent::OpenLibrary</module>
-# Change <base_url> to:
-#   <base_url>http://covers.openlibrary.org/b/isbn/</base_url>
-
 
 my $AC = 'OpenILS::WWW::AddedContent';
 
+# These URLs are always the same for OpenLibrary, so there's no advantage to
+# pulling from opensrf.xml; we hardcode them here
+my $base_url = 'http://openlibrary.org/api/books?details=true&bibkeys=ISBN:';
+my $cover_base_url = 'http://covers.openlibrary.org/b/isbn/';
+
 sub new {
     my( $class, $args ) = @_;
     $class = ref $class || $class;
     return bless($args, $class);
 }
 
-sub base_url {
-    my $self = shift;
-    return $self->{base_url};
-}
-
-sub userid {
-    my $self = shift;
-    return $self->{userid};
-}
-
-
 # --------------------------------------------------------------------------
 sub jacket_small {
     my( $self, $key ) = @_;
     return $self->send_img(
-        $self->fetch_response('-S.jpg', $key));
+        $self->fetch_cover_response('-S.jpg', $key));
 }
 
 sub jacket_medium {
     my( $self, $key ) = @_;
     return $self->send_img(
-        $self->fetch_response('-M.jpg', $key));
+        $self->fetch_cover_response('-M.jpg', $key));
 
 }
 sub jacket_large {
     my( $self, $key ) = @_;
     return $self->send_img(
-        $self->fetch_response('-L.jpg', $key));
+        $self->fetch_cover_response('-L.jpg', $key));
 }
 
 # --------------------------------------------------------------------------
 
+=head1
+
+OpenLibrary returns a JSON hash of zero or more book responses matching our
+request. Each response may contain a table of contents within the details
+section of the response.
+
+For now, we check only the first response in the hash for a table of
+contents, and if we find a table of contents, we transform it to a simple
+HTML table.
+
+=cut
+
+sub toc_html {
+    my( $self, $key ) = @_;
+    my $book_details_json = $self->fetch_response($key)->content();
+
+
+    # Trim the "var _OlBookInfo = " declaration that makes this
+    # invalid JSON
+    $book_details_json =~ s/^.+?({.*?});$/$1/s;
+
+    $logger->debug("$key: " . $book_details_json);
+
+    my $toc_html;
+    
+    my $book_details = OpenSRF::Utils::JSON->JSON2perl($book_details_json);
+    my $book_key = (keys %$book_details)[0];
+
+    # We didn't find a matching book; short-circuit our response
+    if (!$book_key) {
+        $logger->debug("$key: no found book");
+        return 0;
+    }
+
+    my $toc_json = $book_details->{$book_key}->{details}->{table_of_contents};
+
+    # No table of contents is available for this book; short-circuit
+    if (!$toc_json or !scalar(@$toc_json)) {
+        $logger->debug("$key: no TOC");
+        return 0;
+    }
+
+    # Build a basic HTML table containing the section number, section title,
+    # and page number. Some rows may not contain section numbers, we should
+    # protect against empty page numbers too.
+    foreach my $chapter (@$toc_json) {
+       my $label = $chapter->{label};
+        if ($label) {
+            $label .= '. ';
+        }
+        my $title = $chapter->{title} || '';
+        my $page_number = $chapter->{pagenum} || '';
+        $toc_html .= '<tr>' .
+            "<td style='text-align: right;'>$label</td>" .
+            "<td style='text-align: left; padding-right: 2em;'>$title</td>" .
+            "<td style='text-align: right;'>$page_number</td>" .
+            "</tr>\n";
+    }
+
+    $logger->debug("$key: $toc_html");
+    $self->send_html("<table>$toc_html</table>");
+}
+
+sub toc_json {
+    my( $self, $key ) = @_;
+    my $toc = $self->send_json(
+        $self->fetch_response($key)
+    );
+}
+
 sub send_img {
     my($self, $response) = @_;
     return { 
@@ -63,20 +140,46 @@ sub send_img {
     };
 }
 
-# returns the raw content returned from the URL fetch
-sub fetch_content {
-    my( $self, $page, $key ) = @_;
-    return $self->fetch_response($page, $key)->content;
+sub send_json {
+    my( $self, $content ) = @_;
+    return 0 unless $content;
+
+    return { content_type => 'text/plain', content => $content };
+}
+
+sub send_html {
+    my( $self, $content ) = @_;
+    return 0 unless $content;
+
+    # Hide anything that might contain a link since it will be broken
+    my $HTML = <<"    HTML";
+        <div>
+            <style type='text/css'>
+                div.ac input, div.ac a[href],div.ac img, div.ac button { display: none; visibility: hidden }
+            </style>
+            <div class='ac'>
+                $content
+            </div>
+        </div>
+    HTML
+
+    return { content_type => 'text/html', content => $HTML };
 }
 
 # returns the HTTP response object from the URL fetch
 sub fetch_response {
-    my( $self, $page, $key ) = @_;
-    my $uname = $self->userid;
-    my $url = $self->base_url . "$key$page";
-    return $AC->get_url($url);
+    my( $self, $key ) = @_;
+    my $url = $base_url . "$key";
+    my $response = $AC->get_url($url);
+    return $response;
 }
 
+# returns the HTTP response object from the URL fetch
+sub fetch_cover_response {
+    my( $self, $size, $key ) = @_;
+    my $url = $cover_base_url . "$key$size";
+    return $AC->get_url($url);
+}
 
 
 1;