File Coverage

blib/lib/WebService/Vichan.pm
Criterion Covered Total %
statement 83 88 94.3
branch 22 38 57.8
condition 5 6 83.3
subroutine 18 18 100.0
pod 7 9 77.7
total 135 159 84.9


line stmt bran cond sub pod time code
1             package WebService::Vichan;
2              
3 1     1   102505 use 5.014000;
  1         3  
4 1     1   5 use strict;
  1         2  
  1         20  
5 1     1   4 use warnings;
  1         3  
  1         45  
6 1     1   293 use parent qw/Exporter/;
  1         266  
  1         4  
7              
8 1     1   505 use HTTP::Tiny;
  1         43643  
  1         38  
9 1     1   389 use Hash::Inflator;
  1         555  
  1         38  
10 1     1   364 use JSON::MaybeXS;
  1         8683  
  1         96  
11 1     1   457 use Time::HiRes qw/time sleep/;
  1         1295  
  1         8  
12              
13             our $VERSION = '0.001001';
14              
15             our %cache;
16             our $last_request = 0;
17             our $ht = HTTP::Tiny->new(
18             agent => 'WebService-Vichan/'.$VERSION,
19             verify_SSL => 1
20             );
21              
22             use constant +{
23 1         1168 API_4CHAN => 'https://a.4cdn.org',
24             API_8CHAN => 'https://8ch.net',
25 1     1   314 };
  1         4  
26              
27             our @EXPORT_OK = qw/API_4CHAN API_8CHAN/;
28             our %EXPORT_TAGS = ( all => \@EXPORT_OK );
29              
30             sub new {
31 2     2 1 47809 my ($class, $url) = @_;
32 2         15 bless { url => $url }, $class
33             }
34              
35             sub do_request {
36 8     8 0 36 my ($url, $cached_result, $cached_timestamp) = @_;
37 8         27 my %options;
38 8 50       54 if ($cached_timestamp) {
39 0         0 $options{headers}{'If-Modified-Since'} = $cached_timestamp
40             }
41 8         52 my $time_since_last_request = time - $last_request;
42 8 100       6524394 sleep 1 - $time_since_last_request if $time_since_last_request < 1;
43 8         631 my $result = $ht->get($url, \%options);
44 8         7876421 $last_request = time;
45 8 50       83 if ($result->{status} == 304) {
    50          
46 0         0 [$cached_result, $cached_timestamp]
47             } elsif (!$result->{success}) {
48 0         0 my $diestr = sprintf "Error requesting %s: %s\n", $url, $result->{reason};
49 0 0       0 die $diestr unless $result->{success};
50             } else {
51 8         2783 [$result->{content}, $last_request]
52             }
53             }
54              
55             sub requestf {
56 12     12 0 63 my ($self, $format, @args) = @_;
57 12         97 my $what = sprintf $format, @args;
58 12         78 my $url = $self->{url} . '/' . $what;
59 12         54 my $result = $cache{$url};
60 12 100       91 if (!defined $result) {
    50          
61 8         39 $cache{$url} = do_request $url
62             } elsif (time - $result->[1] > 10) {
63 0         0 $cache{$url} = do_request $url, @$result
64             }
65 12         60550 decode_json $cache{$url}->[0]
66             }
67              
68             sub boards {
69 2     2 1 16 my ($self) = @_;
70 2         11 my $result = $self->requestf('boards.json');
71 2 100       30 $result = $result->{boards} if ref $result eq 'HASH';
72             my @results = map {
73 2   100     35 $_->{board} //= $_->{uri};
  2731         161875  
74 2731         7457 Hash::Inflator->new($_)
75             } @$result;
76 2 50       5654 wantarray ? @results : \@results;
77             }
78              
79             sub threads {
80 4     4 1 939 my ($self, $board) = @_;
81 4 50       28 $board = $board->{board} if ref $board;
82 4         31 my $result = $self->requestf('%s/threads.json', $board);
83 4         25 my @pages = map { Hash::Inflator->new($_) } @$result;
  72         28757  
84 4 50       1262 wantarray ? @pages : \@pages
85             }
86              
87             sub threads_flat {
88 2     2 1 28 my @pages = shift->threads(@_);
89 2         13 my @flat = map { @{$_->{threads}} } @pages;
  36         75  
  36         396  
90 2 50       107 wantarray ? @flat : \@flat
91             }
92              
93             sub catalog {
94 4     4 1 3544 my ($self, $board) = @_;
95 4 50       33 $board = $board->{board} if ref $board;
96 4         26 my $result = $self->requestf('%s/catalog.json', $board);
97 4         54 my @pages = map { Hash::Inflator->new($_) } @$result;
  72         169026  
98 4 50       5132 wantarray ? @pages : \@pages
99             }
100              
101             sub catalog_flat {
102 2     2 1 25 my @pages = shift->catalog(@_);
103 2         11 my @flat = map { @{$_->{threads}} } @pages;
  36         65  
  36         290  
104 2 50       87 wantarray ? @flat : \@flat
105             }
106              
107             sub thread {
108 2     2 1 3696 my ($self, $board, $threadno, $is_4chan) = @_;
109 2 50       18 $board = $board->{board} if ref $board;
110 2 50       14 $threadno = $threadno->{no} if ref $threadno;
111 2   66     25 $is_4chan //= (index $self->{url}, '4cdn.org') >= 0;
112 2 100       10 my $res_or_thread = $is_4chan ? 'thread' : 'res';
113 2         12 my $result =
114             $self->requestf('%s/%s/%s.json', $board, $res_or_thread, $threadno);
115 2         16 my @posts = map { Hash::Inflator->new($_) } @{$result->{posts}};
  779         68133  
  2         13  
116 2 50       3835 wantarray ? @posts : \@posts
117             }
118              
119             1;
120             __END__