line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package XML::OPDS::Acquisition; |
2
|
|
|
|
|
|
|
|
3
|
5
|
|
|
5
|
|
33
|
use strict; |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
147
|
|
4
|
5
|
|
|
5
|
|
24
|
use warnings FATAL => 'all'; |
|
5
|
|
|
|
|
39
|
|
|
5
|
|
|
|
|
196
|
|
5
|
5
|
|
|
5
|
|
27
|
use Types::Standard qw/Str ArrayRef InstanceOf Object/; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
34
|
|
6
|
5
|
|
|
5
|
|
4181
|
use Moo; |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
28
|
|
7
|
5
|
|
|
5
|
|
1645
|
use DateTime; |
|
5
|
|
|
|
|
12
|
|
|
5
|
|
|
|
|
140
|
|
8
|
5
|
|
|
5
|
|
25
|
use XML::Atom; |
|
5
|
|
|
|
|
7
|
|
|
5
|
|
|
|
|
292
|
|
9
|
5
|
|
|
5
|
|
36
|
use XML::Atom::Person; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
116
|
|
10
|
5
|
|
|
5
|
|
41
|
use XML::Atom::Entry; |
|
5
|
|
|
|
|
18
|
|
|
5
|
|
|
|
|
4679
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=head1 NAME |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
XML::OPDS::Acquisition - Acquisition elements for OPDS feeds |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=head1 SETTERS/ACCESSORS |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
The following accessors are read-only and are meant to be passed as an |
19
|
|
|
|
|
|
|
hash to the C<new> constructor. |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
=head2 id |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
Optional. The example specification uses uuid like |
24
|
|
|
|
|
|
|
C<urn:uuid:2853dacf-ed79-42f5-8e8a-a7bb3d1ae6a2>. If not provided, the |
25
|
|
|
|
|
|
|
C<href> (with the prefix if provided) will be used instead. |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
=head2 prefix |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
If provided, every uri will have this string prepended, so you can |
30
|
|
|
|
|
|
|
just pass URIs like '/path/to/file' and have them consistently turned |
31
|
|
|
|
|
|
|
to 'http://myserver.org/path/to/file' if you set this to |
32
|
|
|
|
|
|
|
'http://myserver.org'. See also L<XML::OPDS> C<prefix> method. |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
=cut |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
has id => (is => 'ro', isa => Str); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
has prefix => (is => 'ro', isa => Str, default => sub { '' }); |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=head2 href |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
The URI of the resource. Required. |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=cut |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
has href => (is => 'ro', isa => Str, required => 1); |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=head2 title |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
The title. Required. |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
=cut |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
has title => (is => 'ro', isa => Str, required => 1); |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=head2 files |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
An arrayref with the download files. The prefix is added if set. |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
=head1 OPTIONAL ATTRIBUTES |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
The following attributes are optional and describe the publication. |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=head2 authors |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
An arrayref of either scalars with names, or hashrefs with C<name> and |
67
|
|
|
|
|
|
|
C<uri> as keys. C<uri> is optional. |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
=head2 summary |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
Plain text. |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
=head2 description |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
HTML allowed. |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
=head2 language |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=head2 issued |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
The publication date. |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=head2 publisher |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
=head2 updated |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
A DateTime object with the time of the last update of the resource. |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=cut |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
has authors => (is => 'ro', isa => ArrayRef); |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
has summary => (is => 'ro', isa => Str); |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
has description => (is => 'ro', isa => Str); |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
has language => (is => 'ro', isa => Str); |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
has issued => (is => 'ro', isa => Str); |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
has publisher => (is => 'ro', isa => Str); |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
has updated => (is => 'rw', isa => InstanceOf['DateTime'], |
104
|
|
|
|
|
|
|
default => sub { return DateTime->now }); |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
has files => (is => 'ro', isa => ArrayRef[Str], default => sub { [] }); |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
has _dt_formatter => (is => 'ro', isa => Object, default => sub { DateTime::Format::RFC3339->new }); |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=head2 thumbnail |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
The uri of the thumbnail |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
=head2 image |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
The uri of the image |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
=head1 METHODS |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
Usually they are for internal usage. |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=head2 identifier |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
=head2 authors_as_links |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
Return a list of L<XML::Atom::Person> objects from the C<authors> |
127
|
|
|
|
|
|
|
value. |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
=head2 files_as_links |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
Return a list of L<XML::Atom::Link> objects constructed from C<files>, |
132
|
|
|
|
|
|
|
C<image>, C<thumbnail>, with the appropriate C<rel> and C<type>. |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=head2 as_entry |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
Return the acquisition L<XML::Atom::Entry> object. |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
=cut |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
has thumbnail => (is => 'ro', isa => Str); |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
has image => (is => 'ro', isa => Str); |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
has _dc => (is => 'lazy', |
145
|
|
|
|
|
|
|
isa => Object, |
146
|
|
|
|
|
|
|
default => sub { |
147
|
|
|
|
|
|
|
XML::Atom::Namespace->new(dc => 'http://purl.org/dc/elements/1.1/'); |
148
|
|
|
|
|
|
|
}); |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
sub identifier { |
151
|
18
|
|
|
18
|
1
|
30
|
my $self = shift; |
152
|
18
|
|
33
|
|
|
160
|
return $self->id || $self->prefix . $self->href; |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
sub authors_as_links { |
156
|
18
|
|
|
18
|
1
|
29
|
my $self = shift; |
157
|
18
|
|
|
|
|
32
|
my @out; |
158
|
18
|
100
|
|
|
|
50
|
if (my $authors = $self->authors) { |
159
|
1
|
|
|
|
|
13
|
foreach my $author (@$authors) { |
160
|
2
|
100
|
|
|
|
9
|
my $hash = ref($author) ? $author : { name => $author }; |
161
|
2
|
50
|
|
|
|
6
|
if (my $name = $hash->{name}) { |
162
|
2
|
|
|
|
|
7
|
my $author_obj = XML::Atom::Person->new(Version => 1.0); |
163
|
2
|
|
|
|
|
113
|
$author_obj->name($hash->{name}); |
164
|
2
|
100
|
|
|
|
205
|
if (my $uri = $hash->{uri}) { |
165
|
1
|
|
|
|
|
6
|
$author_obj->uri($self->prefix . $uri); |
166
|
|
|
|
|
|
|
} |
167
|
2
|
|
|
|
|
79
|
push @out, $author_obj; |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
} |
171
|
18
|
|
|
|
|
45
|
return @out; |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
sub files_as_links { |
175
|
18
|
|
|
18
|
1
|
31
|
my $self = shift; |
176
|
18
|
|
|
|
|
27
|
my @out; |
177
|
18
|
|
|
|
|
141
|
my %mime = ( |
178
|
|
|
|
|
|
|
tex => 'application/x-tex', |
179
|
|
|
|
|
|
|
pdf => 'application/pdf', |
180
|
|
|
|
|
|
|
html => 'text/html', |
181
|
|
|
|
|
|
|
epub => 'application/epub+zip', |
182
|
|
|
|
|
|
|
muse => 'text/plain', |
183
|
|
|
|
|
|
|
txt => 'text/plain', |
184
|
|
|
|
|
|
|
zip => 'application/zip', |
185
|
|
|
|
|
|
|
png => 'image/png', |
186
|
|
|
|
|
|
|
jpg => 'image/jpeg', |
187
|
|
|
|
|
|
|
jpeg => 'image/jpeg', |
188
|
|
|
|
|
|
|
gif => 'image/gif', |
189
|
|
|
|
|
|
|
mobi => 'application/x-mobipocket-ebook', |
190
|
|
|
|
|
|
|
); |
191
|
|
|
|
|
|
|
# maybe support open-access, borrow, buy, sample, subscribe ? 8.4.1 |
192
|
18
|
|
|
|
|
28
|
my @all = map { +{ rel => 'acquisition', href => $_ } } @{$self->files}; |
|
20
|
|
|
|
|
77
|
|
|
18
|
|
|
|
|
56
|
|
193
|
18
|
50
|
|
|
|
66
|
die "Missing acquisition links" unless @all; |
194
|
|
|
|
|
|
|
|
195
|
18
|
100
|
|
|
|
58
|
if (my $thumb = $self->thumbnail) { |
196
|
5
|
|
|
|
|
12
|
push @all, { rel => 'image/thumbnail', href => $thumb }; |
197
|
|
|
|
|
|
|
} |
198
|
18
|
100
|
|
|
|
51
|
if (my $image = $self->image) { |
199
|
5
|
|
|
|
|
13
|
push @all, { rel => 'image', href => $image }; |
200
|
|
|
|
|
|
|
} |
201
|
18
|
|
|
|
|
37
|
foreach my $file (@all) { |
202
|
30
|
|
|
|
|
38
|
my $mime_type; |
203
|
30
|
100
|
|
|
|
151
|
if ($file->{href} =~ m/\.(\w+)\z/) { |
204
|
28
|
|
|
|
|
67
|
my $ext = $1; |
205
|
28
|
|
|
|
|
47
|
$mime_type = $mime{$ext}; |
206
|
|
|
|
|
|
|
} |
207
|
30
|
100
|
|
|
|
55
|
next unless $mime_type; |
208
|
28
|
|
|
|
|
78
|
my $link = XML::Atom::Link->new(Version => 1.0); |
209
|
28
|
|
|
|
|
1754
|
$link->rel("http://opds-spec.org/$file->{rel}"); |
210
|
28
|
|
|
|
|
615
|
$link->href($self->prefix . $file->{href}); |
211
|
28
|
|
|
|
|
463
|
$link->type($mime_type); |
212
|
28
|
|
|
|
|
480
|
push @out, $link; |
213
|
|
|
|
|
|
|
} |
214
|
18
|
50
|
|
|
|
44
|
if (@out) { |
215
|
18
|
|
|
|
|
98
|
return @out; |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
else { |
218
|
0
|
|
|
|
|
0
|
die "Links are required" |
219
|
|
|
|
|
|
|
}; |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
sub as_entry { |
223
|
18
|
|
|
18
|
1
|
42
|
my $self = shift; |
224
|
18
|
|
|
|
|
65
|
my $entry = XML::Atom::Entry->new(Version => 1.0); |
225
|
18
|
|
|
|
|
1620
|
$entry->id($self->identifier); |
226
|
18
|
|
|
|
|
1801
|
$entry->title($self->title); |
227
|
18
|
|
|
|
|
1882
|
$entry->updated($self->_dt_formatter->format_datetime($self->updated)); |
228
|
18
|
100
|
|
|
|
4181
|
if (my $lang = $self->language) { |
229
|
1
|
|
|
|
|
21
|
$entry->set($self->_dc, language => $lang); |
230
|
|
|
|
|
|
|
} |
231
|
18
|
|
|
|
|
173
|
foreach my $author ($self->authors_as_links) { |
232
|
2
|
|
|
|
|
35
|
$entry->add_author($author); |
233
|
|
|
|
|
|
|
} |
234
|
18
|
100
|
|
|
|
82
|
if (my $summary = $self->summary) { |
235
|
1
|
|
|
|
|
20
|
$entry->summary($summary); |
236
|
|
|
|
|
|
|
} |
237
|
18
|
100
|
|
|
|
144
|
if (my $desc = $self->description) { |
238
|
5
|
|
|
|
|
17
|
$entry->content($desc); |
239
|
|
|
|
|
|
|
} |
240
|
18
|
|
|
|
|
3845
|
foreach my $link ($self->files_as_links) { |
241
|
28
|
|
|
|
|
301
|
$entry->add_link($link); |
242
|
|
|
|
|
|
|
} |
243
|
18
|
|
|
|
|
570
|
return $entry; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
1; |