File Coverage

blib/lib/App/Kramerius/To/Images.pm
Criterion Covered Total %
statement 105 167 62.8
branch 18 54 33.3
condition 3 9 33.3
subroutine 19 21 90.4
pod 2 2 100.0
total 147 253 58.1


line stmt bran cond sub pod time code
1              
2             use strict;
3 4     4   80222 use warnings;
  4         24  
  4         113  
4 4     4   23  
  4         9  
  4         111  
5             use App::Kramerius::V4;
6 4     4   1897 use Class::Utils qw(set_params);
  4         401291  
  4         187  
7 4     4   47 use Cwd qw(cwd);
  4         9  
  4         220  
8 4     4   28 use Data::Kramerius;
  4         11  
  4         166  
9 4     4   23 use English;
  4         8  
  4         87  
10 4     4   23 use Error::Pure qw(err);
  4         30  
  4         36  
11 4     4   2206 use File::Spec::Functions qw(catfile);
  4         11  
  4         211  
12 4     4   1996 use Getopt::Std;
  4         3598  
  4         244  
13 4     4   37 use HTTP::Request;
  4         8  
  4         214  
14 4     4   60 use IO::Barf qw(barf);
  4         9  
  4         122  
15 4     4   35 use JSON::XS;
  4         7  
  4         210  
16 4     4   24 use LWP::UserAgent;
  4         12  
  4         246  
17 4     4   27 use METS::Files;
  4         9  
  4         95  
18 4     4   1899 use Perl6::Slurp qw(slurp);
  4         46160  
  4         139  
19 4     4   2102  
  4         6209  
  4         32  
20             our $VERSION = 0.04;
21              
22             # Constructor.
23             my ($class, @params) = @_;
24              
25 3     3 1 5042 # Create object.
26             my $self = bless {}, $class;
27              
28 3         9 # Directory to store files.
29             $self->{'dir_to_store_files'} = undef;
30              
31 3         18 # LWP::UserAgent object.
32             $self->{'lwp_user_agent'} = undef;
33              
34 3         8 # Process parameters.
35             set_params($self, @params);
36              
37 3         15 $self->{'_kramerius'} = Data::Kramerius->new;
38              
39 3         63 if (defined $self->{'lwp_user_agent'}) {
40             if (! $self->{'lwp_user_agent'}->isa('LWP::UserAgent')) {
41 3 100       6492 err "Parameter 'lwp_user_agent' must be a LWP::UserAgent instance.";
42 2 100       22 }
43 1         5 } else {
44             $self->{'lwp_user_agent'} = LWP::UserAgent->new;
45             $self->{'lwp_user_agent'}->agent('kramerius2images/'.$VERSION);
46 1         8 }
47 1         3013  
48             # Object.
49             return $self;
50             }
51 2         110  
52             # Run.
53             my $self = shift;
54              
55             # Process arguments.
56 1     1 1 1042 $self->{'_opts'} = {
57             'h' => 0,
58             'q' => 0,
59 1         12 'v' => 0,
60             };
61             if (! getopts('hqv', $self->{'_opts'}) || (! -r 'ROOT' && @ARGV < 2)
62             || $self->{'_opts'}->{'h'}) {
63              
64 1 50 33     9 print STDERR "Usage: $0 [-h] [-q] [-v] [--version] [kramerius_id object_id]\n";
      33        
      33        
65             print STDERR "\t-h\t\tHelp.\n";
66             print STDERR "\t-q\t\tQuiet mode.\n";
67 0         0 print STDERR "\t-v\t\tVerbose mode.\n";
68 0         0 print STDERR "\t--version\tPrint version.\n";
69 0         0 print STDERR "\tkramerius_id\tKramerius system id. e.g. ".
70 0         0 "mzk\n";
71 0         0 print STDERR "\tobject_id\tKramerius object id (could be ".
72 0         0 "page, series or book edition).\n";
73             return 1;
74 0         0 }
75             my ($kramerius_id, $object_id);
76 0         0 if (@ARGV > 1) {
77             $kramerius_id = shift @ARGV;
78 1         74 $object_id = shift @ARGV;
79 1 50       4 } elsif (-r 'ROOT') {
    0          
80 1         3 ($kramerius_id, $object_id) = slurp('ROOT', { chomp => 1 });
81 1         3 } else {
82             err 'Cannot read library id and work id.';
83 0         0 }
84              
85 0         0 # Directory to store files.
86             my $dir_to_store_files;
87             if ($self->{'dir_to_store_files'}) {
88             $dir_to_store_files = $self->{'dir_to_store_files'};
89 1         2 } else {
90 1 50       4 $dir_to_store_files = cwd();
91 1         3 }
92              
93 0         0 $self->{'_kramerius_obj'} = $self->{'_kramerius'}->get($kramerius_id);
94             if (! defined $self->{'_kramerius_obj'}) {
95             err "Library with ID '$kramerius_id' is unknown.";
96 1         6 }
97 1 50       102 barf(catfile($dir_to_store_files, 'ROOT'), <<"END");
98 0         0 $kramerius_id
99             $object_id
100 1         29 END
101              
102             my $quiet = '-q ';
103             if ($self->{'_opts'}->{'v'}) {
104             $quiet = '';
105 1         181 }
106 1 50       21  
107 0         0 my @pages;
108             if ($self->{'_kramerius_obj'}->version == 3) {
109              
110 1         3 # URI for METS.
111 1 50       6 my $mets_uri = $self->{'_kramerius_obj'}->url.'kramerius/mets/'.$kramerius_id.
    50          
112             '/'.$object_id;
113              
114 0         0 # Get METS.
115             if ($self->{'_opts'}->{'v'}) {
116             print "Downloads $mets_uri\n";
117             }
118 0 0       0 my $req = HTTP::Request->new('GET' => $mets_uri);
119 0         0 my $res = $self->{'lwp_user_agent'}->request($req);
120             my $mets;
121 0         0 if ($res->is_success) {
122 0         0 $mets = $res->content;
123 0         0  
124 0 0       0 # Get images from METS file.
125 0         0 my $obj = METS::Files->new(
126             'mets_data' => $mets,
127             );
128 0         0  
129             # Get 'img' files.
130             my @page_uris = $obj->get_use_files('img');
131              
132             if (! @page_uris) {
133 0         0 err 'No images to download.';
134             }
135 0 0       0  
136 0         0 # Get images.
137             foreach my $page (@page_uris) {
138             my $uri = URI->new($page);
139             my @path_segments = $uri->path_segments;
140 0         0 if (! -r $path_segments[-1]) {
141 0         0 if (! $self->{'_opts'}->{'q'}) {
142 0         0 print "$page\n";
143 0 0       0 }
144 0 0       0 $self->_download($page, catfile($dir_to_store_files, $path_segments[-1]));
145 0         0 }
146              
147 0         0 # Strip URI part.
148             push @pages, $path_segments[-1];
149             }
150              
151 0         0 # Direct file.
152             } else {
153              
154             # TODO Stahnout primo soubor. Udelat na to skript.
155             err "Cannot get '$mets_uri' URI.",
156             'HTTP code', $res->code,
157             'Message', $res->message;
158 0         0 }
159              
160             } elsif ($self->{'_kramerius_obj'}->version == 4) {
161              
162             # URI for children JSON.
163             my $json_uri = $self->{'_kramerius_obj'}->url.'search/api/v5.0/item/uuid:'.
164             $object_id.'/children';
165              
166 1         23 # Get JSON.
167             my $req = HTTP::Request->new('GET' => $json_uri);
168             my $res = $self->{'lwp_user_agent'}->request($req);
169             my $json;
170 1         16 if ($res->is_success) {
171 1         7581 $json = $res->content;
172 1         1825 barf(catfile($dir_to_store_files, $object_id.'.json'), $json);
173 1 50       6 } else {
174 1         14 err "Cannot get '$json_uri' URI.",
175 1         23 'HTTP code', $res->code,
176             'message', $res->message;
177 0         0 }
178              
179             # Check JSON content type.
180             if ($res->headers->content_type ne 'application/json') {
181             err "Content type isn't 'application/json' for '$json_uri' URI.",
182             'Content-Type', $res->headers->content_type;
183 1 50       194 }
184 0         0  
185             # Get perl structure.
186             my $json_ar = eval {
187             JSON::XS->new->decode($json);
188             };
189 1         35 if ($EVAL_ERROR) {
190 1         21 err "Cannot parse JSON on '$json_uri' URI.",
191             'JSON decode error', $EVAL_ERROR;
192 1 50       5 }
193 0         0  
194             # Each page.
195             my $images = 0;
196             foreach my $page_hr (@{$json_ar}) {
197             if ($page_hr->{'model'} ne 'page') {
198 1         4 next;
199 1         2 }
  1         3  
200 0 0       0 my $title = $self->_get_page_title($page_hr);
201 0         0 my $pid = $page_hr->{'pid'};
202             $pid =~ s/^uuid://ms;
203 0         0 # TODO Support for page number in $pid =~ uuid:__uuid__@__page_number__ (PDF and number of page in PDF)
204 0         0 if (! $self->{'_opts'}->{'q'}) {
205 0         0 print "$pid: $title\n";
206             }
207 0 0       0 # XXX Support of jpg only
208 0         0 if (! -r $pid.'.jpg') {
209             my $out_file = '-o '.catfile($dir_to_store_files, $pid.'.jpg');
210             $self->_do_command("kramerius4 $out_file $quiet $kramerius_id $pid");
211 0 0       0 }
212 0         0 push @pages, $pid.'.jpg';
213 0         0 $images++;
214             }
215 0         0  
216 0         0 # One page.
217             if ($images == 0) {
218             my $pid = $object_id;
219             if (! $self->{'_opts'}->{'q'}) {
220 1 50       6 print "$pid: ?\n";
221 1         2 }
222 1 50       4 # XXX Support of jpg only
223 1         40 my $output_file = $pid.'.jpg';
224             if (! -r $output_file) {
225             my $out_file = '-o '.catfile($dir_to_store_files, $output_file);
226 1         10 $self->_do_command("kramerius4 $out_file $quiet $kramerius_id $pid");
227 1 50       24 }
228 1         9 push @pages, $output_file;
229 1         14 }
230             } else {
231 1         146 err 'Bad version of Kramerius.',
232             'Kramerius version', $self->{'_kramerius_obj'}->version;
233             }
234             barf(catfile($dir_to_store_files, 'LIST'), join "\n", @pages);
235 0         0  
236             return 0;
237 1         105 }
238              
239 1         468 my ($self, $uri, $local_file) = @_;
240              
241             $self->{'lwp_user_agent'}->get($uri,
242             ':content_file' => $local_file,
243 0     0   0 );
244              
245 0         0 return;
246             }
247              
248             # Get title from page.
249 0         0 my ($self, $page_hr) = @_;
250              
251             my $title;
252             if (ref $page_hr->{'title'} eq 'ARRAY') {
253             $title = $page_hr->{'title'}->[0];
254 0     0   0 } elsif (ref $page_hr->{'title'} eq '') {
255             $title = $page_hr->{'title'};
256 0         0 } else {
257 0 0       0 err "Cannot get title for page '$page_hr->{'pid'}.'.";
    0          
258 0         0 }
259             $title =~ s/\s+/_/msg;
260 0         0  
261             return $title;
262 0         0 }
263              
264 0         0 my ($self, $command) = @_;
265              
266 0         0 if ($self->{'_opts'}->{'v'}) {
267             print $command."\n";
268             }
269              
270 1     1   20 system $command;
271             }
272 1 50       8  
273 0         0 1;
274              
275             =pod
276 1         347224  
277             =encoding utf8
278              
279             =head1 NAME
280              
281             App::Kramerius::To::Images - Base class for kramerius2images script.
282              
283             =head1 SYNOPSIS
284              
285             use App::Kramerius::To::Images;
286              
287             my $app = App::Kramerius::To::Images->new;
288             my $exit_code = $app->run;
289              
290             =head1 METHODS
291              
292             =head2 C<new>
293              
294             my $app = App::Kramerius::To::Images->new;
295              
296             Constructor.
297              
298             Returns instance of object.
299              
300             =over 8
301              
302             =item * C<dir_to_store_files>
303              
304             Directory to store files.
305              
306             Default value is undef, which means actual directory.
307              
308             =item * C<lwp_user_agent>
309              
310             LWP::UserAgent object.
311              
312             Default value is instance of LWP::UserAgent with set user agent to 'kramerius2images/__PACKAGE_VERSION__'.
313              
314             =back
315              
316             =head2 C<run>
317              
318             my $exit_code = $app->run;
319              
320             Run.
321              
322             Returns 1 for error, 0 for success.
323              
324             =head1 ERRORS
325              
326             new():
327             From Class::Utils::set_params():
328             Unknown parameter '%s'.
329             Parameter 'lwp_user_agent' must be a LWP::UserAgent instance.
330              
331             run():
332             Bad version of Kramerius.
333             Kramerius version: %s
334             Cannot get title for page '%s'.
335             Cannot get '%s' URI.
336             HTTP code: %s
337             message: %s
338             Cannot parse JSON on '%s' URI.
339             JSON decode error: %s
340             Cannot read library id and work id.
341             Content type isn't 'application/json' for '%s' URI.
342             Content-Type: %s
343             Library with ID '%s' is unknown.
344             No images to download.
345              
346             =head1 EXAMPLE
347              
348             =for comment filename=print_help.pl
349              
350             use strict;
351             use warnings;
352              
353             use App::Kramerius::To::Images;
354              
355             # Arguments.
356             @ARGV = (
357             '-h',
358             );
359              
360             # Run.
361             exit App::Kramerius::To::Images->new->run;
362              
363             # Output like:
364             # Usage: ./ex1.pl [-h] [-q] [-v] [--version] [kramerius_id object_id]
365             # -h Help.
366             # -q Quiet mode.
367             # -v Verbose mode.
368             # --version Print version.
369             # kramerius_id Kramerius system id. e.g. mzk
370             # object_id Kramerius object id (could be page, series or book edition).
371              
372             =head1 DEPENDENCIES
373              
374             L<App::Kramerius::V4>,
375             L<Class::Utils>,
376             L<Data::Kramerius>,
377             L<English>,
378             L<Error::Pure>,
379             L<Getopt::Std>,
380             L<HTTP::Request>,
381             L<IO::Barf>,
382             L<JSON::XS>,
383             L<LWP::UserAgent>,
384             L<METS::Files>,
385             L<Perl6::Slurp>.
386              
387             =head1 SEE ALSO
388              
389             =over
390              
391             =item L<Task::Kramerius>
392              
393             Install modules for Kramerius system.
394              
395             =item L<App::Images::To::DjVu>
396              
397             Base class for images2djvu script.
398              
399             =back
400              
401             =head1 REPOSITORY
402              
403             L<https://github.com/michal-josef-spacek/App-Kramerius-To-Images>
404              
405             =head1 AUTHOR
406              
407             Michal Josef Špaček L<mailto:skim@cpan.org>
408              
409             L<http://skim.cz>
410              
411             =head1 LICENSE AND COPYRIGHT
412              
413             © 2021 Michal Josef Špaček
414              
415             BSD 2-Clause License
416              
417             =head1 VERSION
418              
419             0.04
420              
421             =cut