7806425210a480e7490a67cf14939b42d3a210d7
[Biblio-Z3950.git] / GoogleBooks.pm
1 package GoogleBooks;
2
3 use warnings;
4 use strict;
5
6 use MARC::Record;
7 use Data::Dump qw/dump/;
8 use JSON::XS;
9
10 use base 'Scraper';
11
12 my $debug = $ENV{DEBUG} || 0;
13
14 sub diag {
15         warn "# ", @_, $/;
16 }
17
18 # based on http://code.google.com/apis/books/docs/v1/using.html#PerformingSearch
19 #
20 # https://www.googleapis.com/books/v1/volumes?q=search+terms
21 #
22 # This request has a single required parameter:
23 #
24 # q - Search for volumes that contain this text string. There are special keywords you can specify in the search terms to search in particular fields, such as:
25 #     intitle: Returns results where the text following this keyword is found in the title.
26 #     inauthor: Returns results where the text following this keyword is found in the author.
27 #     inpublisher: Returns results where the text following this keyword is found in the publisher.
28 #     subject: Returns results where the text following this keyword is listed in the category list of the volume.
29 #     isbn: Returns results where the text following this keyword is the ISBN number.
30 #     lccn: Returns results where the text following this keyword is the Library of Congress Control Number.
31 #     oclc: Returns results where the text following this keyword is the Online Computer Library Center number.
32 #
33
34 # Koha Z39.50 query:
35 #
36 # Bib-1 @and @and @and @and @and @and @and @or
37 # @attr 1=4 title 
38 # @attr 1=7 isbn
39 # @attr 1=8 issn 
40 # @attr 1=1003 author 
41 # @attr 1=16 dewey 
42 # @attr 1=21 subject-holding 
43 # @attr 1=12 control-no 
44 # @attr 1=1007 standard-id 
45 # @attr 1=1016 any
46
47 sub usemap {{
48         4               => 'intitle:',
49         7               => 'isbn:',
50         8               => 'isbn:', # FIXME?
51         1003    => 'inauthor:',
52 #       16              => '',
53         21              => 'subject:',
54         12              => 'lccn:',
55 #       1007    => '',
56         1016    => '',
57 }};
58
59 sub search {
60         my ( $self, $query ) = @_;
61
62         die "need query" unless defined $query;
63
64         my $url = 'https://www.googleapis.com/books/v1/volumes?q=' . $query;
65
66 diag "get $url";
67
68         my $mech = $self->{mech} || die "no mech?";
69         $mech->get( $url );
70
71         my $json = decode_json $mech->content;
72         diag "# json = ", dump($json) if $debug;
73
74         my $hits = 0;
75
76         if ( exists $json->{items} ) {
77                 $hits = $#{ $json->{items} } + 1;
78         } else {
79                 diag "get't find results in ", $mech->content;
80                 return;
81         }
82
83 diag "got $hits results, get first one";
84
85         $self->{_json} = $json;
86         $self->{_json_item} = 0;
87
88         return $self->{hits} = $hits;
89 }
90
91
92 our ( $hash, $marc );
93
94 sub next_marc {
95         my ($self,$format) = @_;
96
97         $format ||= 'marc';
98
99         my $item = $self->{_json}->{items}->[ $self->{_json_item}++ ];
100
101         warn "# item = ",dump($item) if $debug;
102
103         my $id = $item->{id} || die "no id";
104
105         $marc = MARC::Record->new;
106         $marc->encoding('utf-8');
107
108         if ( my $vi = $item->{volumeInfo} ) {
109
110                 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
111
112                 $marc->add_fields('008',sprintf("%02d%02d%02ds%04d%25s%-3s",
113                                 $year % 100, $mon + 1, $mday, substr($vi->{publishedDate},0,4), ' ', $vi->{language}));
114
115                 if ( ref $vi->{industryIdentifiers} eq 'ARRAY' ) {
116                         foreach my $i ( @{ $vi->{industryIdentifiers} } ) {
117                                 if ( $i->{type} =~ m/ISBN/i ) {
118                                         $marc->add_fields('020',' ',' ','a' => $i->{identifier} )
119                                 } else {
120                                         $marc->add_fields('035',' ',' ','a' => $i->{identifier} )
121                                 }
122                         }
123                 }
124
125                 my $first_author;
126                 if ( ref $vi->{authors} eq 'ARRAY' ) {
127                         $first_author = shift @{ $vi->{authors} };
128                         $marc->add_fields(100,'0',' ','a' => $first_author );
129                         $marc->add_fields(700,'0',' ','a' => $_ ) foreach @{ $vi->{authors} };
130                 }
131
132                 $marc->add_fields(245, ($first_author ? '1':'0') ,' ',
133                         'a' => $vi->{title},
134                         $vi->{subtitle} ? ( 'b' => $vi->{subtitle} ) : (),
135                 );
136
137                 if ( exists $vi->{publisher} or exists $vi->{publishedDate} ) {
138                         $marc->add_fields(260,' ',' ',
139                                 $vi->{publisher} ? ( 'b' => $vi->{publisher} ) : (),
140                                 $vi->{publishedDate} ? ( 'c' => $vi->{publishedDate} ) : ()
141                         );
142                 }
143
144                 $marc->add_fields(300,' ',' ','a' => $vi->{pageCount} . 'p.' ) if $vi->{pageCount};
145                 
146                 $marc->add_fields(520,' ',' ','a' => $vi->{description} ) if $vi->{description};
147
148                 if ( ref $vi->{categories} eq 'ARRAY' ) {
149                         $marc->add_fields(650,' ','4','a' => $_ ) foreach @{ $vi->{categories} };
150                 }
151
152                 if ( exists $vi->{imageLinks} ) {
153
154                         $marc->add_fields(856,'4','2',
155                                 '3'=> 'Image link',
156                                 'u' => $vi->{imageLinks}->{smallThumbnail},
157                                 'x' => 'smallThumbnail',
158                         ) if exists $vi->{imageLinks}->{smallThumbnail};
159                         $marc->add_fields(856,'4','2',
160                                 '3'=> 'Image link',
161                                 'u' => $vi->{imageLinks}->{thumbnail},
162                                 'x' => 'thumbnail',
163                         ) if exists $vi->{imageLinks}->{thumbnail};
164
165                 } # if imageLinks
166
167                 $marc->add_fields(856,'4','2',
168                         '3'=> 'Info link',
169                         'u' => $vi->{infoLink},
170                 );
171                 $marc->add_fields(856,'4','2',
172                         '3'=> 'Show reviews link',
173                         'u' => $vi->{showReviewsLink},
174                 );
175
176                 my $leader = $marc->leader;
177                 warn "# leader [$leader]";
178                 $leader =~ s/^(....).../$1nam/;
179                 $marc->leader( $leader );
180
181         } else {
182                 warn "ERROR: no volumeInfo in ",dump($item);
183         }
184
185         $marc->add_fields( 856, ' ', ' ', 'u' => $item->{accessInfo}->{webReaderLink} );
186 #       $marc->add_fields( 520, ' ', ' ', 'a' => $item->{searchInfo}->{textSnippet} ); # duplicate of description
187
188 #       diag "# hash ",dump($hash);
189         diag "# marc ", $marc->as_formatted;
190
191         $self->save_marc( "$id.marc", $marc->as_usmarc );
192
193         return $id;
194
195 }
196
197 1;