File Coverage

blib/lib/WWW/FetchStory/Fetcher/HPAdultFanfiction.pm
Criterion Covered Total %
statement 9 150 6.0
branch 0 42 0.0
condition 0 3 0.0
subroutine 3 14 21.4
pod 11 11 100.0
total 23 220 10.4


line stmt bran cond sub pod time code
1             package WWW::FetchStory::Fetcher::HPAdultFanfiction;
2             $WWW::FetchStory::Fetcher::HPAdultFanfiction::VERSION = '0.2602';
3 1     1   151005 use strict;
  1         3  
  1         45  
4 1     1   6 use warnings;
  1         2  
  1         112  
5             =head1 NAME
6              
7             WWW::FetchStory::Fetcher::HPAdultFanfiction - fetching module for WWW::FetchStory
8              
9             =head1 VERSION
10              
11             version 0.2602
12              
13             =head1 DESCRIPTION
14              
15             This is the HPAdultFanfiction story-fetching plugin for WWW::FetchStory.
16              
17             =cut
18              
19 1     1   6 use parent qw(WWW::FetchStory::Fetcher);
  1         3  
  1         9  
20              
21             =head1 METHODS
22              
23             =head2 new
24              
25             $obj->WWW::FetchStory::Fetcher->new();
26              
27             =cut
28              
29             sub new {
30 0     0 1   my $class = shift;
31 0           my $self = $class->SUPER::new(@_);
32             # disable the User-Agent for HPAdultFanfiction
33             # because it blocks wget
34 0           $self->{wget} .= " --user-agent=''";
35              
36 0           return ($self);
37             } # new
38              
39             =head2 info
40              
41             Information about the fetcher.
42              
43             $info = $self->info();
44              
45             =cut
46              
47             sub info {
48 0     0 1   my $self = shift;
49            
50 0           my $info = "(http://hp.adultfanfiction.net) An adult Harry Potter fiction archive.";
51              
52 0           return $info;
53             } # info
54              
55             =head2 priority
56              
57             The priority of this fetcher. Fetchers with higher priority
58             get tried first. This is useful where there may be a generic
59             fetcher for a particular site, and then a more specialized fetcher
60             for particular sections of a site. For example, there may be a
61             generic HPAdultFanfiction fetcher, and then refinements for particular
62             HPAdultFanfiction community, such as the sshg_exchange community.
63             This works as either a class function or a method.
64              
65             This must be overridden by the specific fetcher class.
66              
67             $priority = $self->priority();
68              
69             $priority = WWW::FetchStory::Fetcher::priority($class);
70              
71             =cut
72              
73             sub priority {
74 0     0 1   my $class = shift;
75              
76 0           return 2;
77             } # priority
78              
79             =head2 allow
80              
81             If this fetcher can be used for the given URL, then this returns
82             true.
83             This must be overridden by the specific fetcher class.
84              
85             if ($obj->allow($url))
86             {
87             ....
88             }
89              
90             =cut
91              
92             sub allow {
93 0     0 1   my $self = shift;
94 0           my $url = shift;
95              
96 0           return ($url =~ /hp\.adultfanfiction\.net/);
97             } # allow
98              
99             =head1 Private Methods
100              
101             =head2 extract_story
102              
103             Extract the story-content from the fetched content.
104              
105             my ($story, $title) = $self->extract_story(content=>$content,
106             title=>$title);
107              
108             =cut
109              
110             sub extract_story {
111 0     0 1   my $self = shift;
112 0           my %args = (
113             content=>'',
114             title=>'',
115             @_
116             );
117 0           my $content = $args{content};
118              
119 0           my $title = $args{title};
120              
121 0           my $chapter = $self->parse_ch_title(%args);
122 0 0         warn "chapter=$chapter\n" if ($self->{verbose} > 1);
123              
124 0           my $author = $self->parse_author(%args);
125 0 0         warn "author=$author\n" if ($self->{verbose} > 1);
126              
127 0           my $story = '';
128 0 0         if ($content =~ m!<td colspan="3" bgcolor="F4EBCC">\s*<font color="#003333">Disclaimer:[^<]+</font>\s*</td>\s*</tr>\s*<tr>\s*<td colspan="3">\s*<p>&nbsp;</p>\s*</td>\s*</tr>\s*<tr>\s*<td colspan="3" bgcolor="F4EBCC">\s*(.*?)<tr class='catdis'>!s)
129             {
130 0           $story = $1;
131             }
132              
133 0 0         if ($story)
134             {
135 0           $story = $self->tidy_chars($story);
136             }
137             else
138             {
139 0           die "Failed to extract story for $title";
140             }
141              
142 0           my $story_title = "$title: $chapter";
143 0 0         $story_title = $title if ($title eq $chapter);
144 0 0         $story_title = $title if ($chapter eq '');
145              
146 0           my $out = '';
147 0 0         if ($story)
148             {
149 0           $out .= "<h1>$story_title</h1>\n";
150 0           $out .= "<p>by $author</p>\n";
151 0           $out .= "$story";
152             }
153 0           return ($out, $story_title);
154             } # extract_story
155              
156             =head2 parse_toc
157              
158             Parse the table-of-contents file.
159              
160             %info = $self->parse_toc(content=>$content,
161             url=>$url,
162             urls=>\@urls);
163              
164             This should return a hash containing:
165              
166             =over
167              
168             =item chapters
169              
170             An array of URLs for the chapters of the story. In the case where the
171             story only takes one page, that will be the chapter.
172             In the case where multiple URLs have been passed in, it will be those URLs.
173              
174             =item title
175              
176             The title of the story.
177              
178             =back
179              
180             It may also return additional information, such as Summary.
181              
182             =cut
183              
184             sub parse_toc {
185 0     0 1   my $self = shift;
186 0           my %args = (
187             url=>'',
188             content=>'',
189             @_
190             );
191              
192 0           my %info = ();
193 0           my $content = $args{content};
194              
195 0           my @chapters = ();
196 0           $info{url} = $args{url};
197 0           my $sid='';
198 0 0         if ($args{url} =~ m#no=(\d+)#)
199             {
200 0           $sid = $1;
201             }
202             else
203             {
204 0           return $self->SUPER::parse_toc(%args);
205             }
206 0           $info{title} = $self->parse_title(%args);
207 0           $info{author} = $self->parse_author(%args);
208 0           $info{summary} = $self->parse_summary(%args);
209 0           $info{characters} = $self->parse_characters(%args);
210 0           $info{category} = $self->parse_category(%args);
211 0           $info{universe} = 'Harry Potter';
212 0           $info{rating} = 'Adult';
213              
214             # the summary is on the Author page!
215 0           my $auth_id = '';
216 0 0         if ($content =~ m/Author:\s*<a href='authors\.php\?no=(\d+)'>/s)
217             {
218 0           $auth_id = $1;
219             }
220 0 0 0       if ($auth_id and $sid)
221             {
222 0           my $auth_page = $self->get_page("http://hp.adultfanfiction.net/authors.php?no=${auth_id}");
223 0 0         if ($auth_page =~ m#<a href='story\.php\?no=${sid}'>[^<]+</a><br>\s*([^<]+)<br>#s)
224             {
225 0           $info{summary} = $1;
226             }
227             }
228 0 0         if (!$info{summary})
229             {
230 0           $info{summary} = $self->SUPER::parse_summary(%args);
231             }
232 0           $info{chapters} = $self->parse_chapter_urls(%args, sid=>$sid);
233              
234 0           return %info;
235             } # parse_toc
236              
237             =head2 parse_chapter_urls
238              
239             Figure out the URLs for the chapters of this story.
240              
241             =cut
242             sub parse_chapter_urls {
243 0     0 1   my $self = shift;
244 0           my %args = (
245             url=>'',
246             content=>'',
247             @_
248             );
249 0           my $content = $args{content};
250 0           my $sid = $args{sid};
251 0           my @chapters = ();
252 0 0         if (defined $args{urls})
253             {
254 0           @chapters = @{$args{urls}};
  0            
255             }
256 0 0         if (@chapters == 1)
257             {
258 0           @chapters = ();
259 0           my $fmt = 'http://hp.adultfanfiction.net/story.php?no=%d&chapter=%d';
260 0           my $max_chapter = 0;
261 0           while ($content =~ m#<option value='story\.php\?no=${sid}&chapter=(\d+)'#gs)
262             {
263 0           my $a_ch = $1;
264 0 0         if ($a_ch > $max_chapter)
265             {
266 0           $max_chapter = $a_ch;
267             }
268             }
269 0           for (my $ch = 1; $ch <= $max_chapter; $ch++)
270             {
271 0           my $ch_url = sprintf($fmt, $sid, $ch);
272 0 0         warn "chapter=$ch_url\n" if ($self->{verbose} > 1);
273 0           push @chapters, $ch_url;
274             }
275             }
276              
277 0           return \@chapters;
278             } # parse_chapter_urls
279              
280             =head2 parse_title
281              
282             Get the title from the content
283              
284             =cut
285             sub parse_title {
286 0     0 1   my $self = shift;
287 0           my %args = (
288             url=>'',
289             content=>'',
290             @_
291             );
292              
293 0           my $content = $args{content};
294 0           my $title = '';
295 0 0         if ($content =~ m#<title>\s*Story:\s*([^<]+)\s*</title>#is)
296             {
297 0           $title = $1;
298             }
299             else
300             {
301 0           $title = $self->SUPER::parse_title(%args);
302             }
303 0           $title =~ s/\s+$//;
304 0           return $title;
305             } # parse_title
306              
307             =head2 parse_author
308              
309             Get the author from the content
310              
311             =cut
312             sub parse_author {
313 0     0 1   my $self = shift;
314 0           my %args = (
315             url=>'',
316             content=>'',
317             @_
318             );
319              
320 0           my $content = $args{content};
321 0           my $author = '';
322 0 0         if ($content =~ m/Author:\s*<a href='authors\.php\?no=\d+'>\s*([^<]+)\s*<\/a>/s)
323             {
324 0           $author = $1;
325             }
326             else
327             {
328 0           $author = $self->SUPER::parse_author(%args);
329             }
330 0           return $author;
331             } # parse_author
332              
333             =head2 parse_characters
334              
335             Get the characters from the content
336              
337             =cut
338             sub parse_characters {
339 0     0 1   my $self = shift;
340 0           my %args = (
341             url=>'',
342             content=>'',
343             @_
344             );
345              
346 0           my $content = $args{content};
347 0           my $characters = '';
348 0 0         if ($content =~ m#<a href="main\.php\?list=\d+">\s*(\w+)/(\w+)</a>#)
349             {
350 0           $characters = $1 . ', ' . $2;
351 0           $characters =~ s/Arthur/Arthur Weasley/;
352 0           $characters =~ s/Bill/Bill Weasley/;
353 0           $characters =~ s/Charlie/Charlie Weasley/;
354 0           $characters =~ s/Draco/Draco Malfoy/;
355 0           $characters =~ s/Dudley/Dudley Dursley/;
356 0           $characters =~ s/Fred/Fred Weasley/;
357 0           $characters =~ s/George/George Weasley/;
358 0           $characters =~ s/Ginny/Ginny Weasley/;
359 0           $characters =~ s/Harry/Harry Potter/;
360 0           $characters =~ s/Hermione/Hermione Granger/;
361 0           $characters =~ s/James/James Potter/;
362 0           $characters =~ s/Lavender/Lavender Brown/;
363 0           $characters =~ s/Lavendar/Lavender Brown/;
364 0           $characters =~ s/Lily/Lily Evans/;
365 0           $characters =~ s/Lucius/Lucius Malfoy/;
366 0           $characters =~ s/Luna/Luna Lovegood/;
367 0           $characters =~ s/McGonagall/Minerva McGonagall/;
368 0           $characters =~ s/Molly/Molly Weasley/;
369 0           $characters =~ s/Narcissa/Narcissa Malfoy/;
370 0           $characters =~ s/Neville/Neville Longbottom/;
371 0           $characters =~ s/Remus/Remus Lupin/;
372 0           $characters =~ s/Ron/Ron Weasley/;
373 0           $characters =~ s/Snape/Severus Snape/;
374             }
375             else
376             {
377 0           $characters = $self->SUPER::parse_characters(%args);
378             }
379 0           return $characters;
380             } # parse_characters
381              
382             =head2 parse_ch_title
383              
384             Get the chapter title from the content
385              
386             =cut
387             sub parse_ch_title {
388 0     0 1   my $self = shift;
389 0           my %args = (
390             url=>'',
391             content=>'',
392             @_
393             );
394              
395 0           my $content = $args{content};
396 0           my $title = '';
397 0 0         if ($content =~ m#^Chapter\s*(\d+:[^<]+)<br#m)
    0          
398             {
399 0           $title = $1;
400             }
401             elsif ($content =~ m#<option[^>]+selected>([^<]+)</option>#s)
402             {
403 0           $title = $1;
404             }
405             else
406             {
407 0           $title = $self->parse_title(%args);
408             }
409 0           return $title;
410             } # parse_ch_title
411              
412             1; # End of WWW::FetchStory::Fetcher::HPAdultFanfiction
413             __END__