]>
Commit | Line | Data |
---|---|---|
1 | package WWW::Search::Torrentz::Result; | |
2 | ||
3 | use 5.014000; | |
4 | use strict; | |
5 | use warnings; | |
6 | use parent qw/WWW::SearchResult/; | |
7 | ||
8 | our $VERSION = '0.001'; | |
9 | ||
10 | use HTML::TreeBuilder; | |
11 | use URI::Escape qw/uri_escape/; | |
12 | ||
13 | sub new{ | |
14 | my ($class, %args) = @_; | |
15 | my $self = $class->SUPER::new(@_); | |
16 | $self->{parsed} = 0; | |
17 | ||
18 | no strict 'refs'; | |
19 | $self->$_($args{$_}) for qw/title verified age size seeders leechers infohash/; | |
20 | $self->{ua} = $args{ua}; | |
21 | $self->add_url("https://torrentz.eu/$args{infohash}"); | |
22 | $self | |
23 | } | |
24 | ||
25 | sub infohash { shift->_elem(infohash => @_) } | |
26 | sub verified { shift->_elem(verified => @_) } | |
27 | sub age { shift->_elem(age => @_) } | |
28 | sub size { shift->_elem(size => @_) } | |
29 | sub seeders { shift->_elem(seeders => @_) } | |
30 | sub leechers { shift->_elem(leechers => @_) } | |
31 | ||
32 | sub magnet{ | |
33 | my ($self, $full) = @_; | |
34 | my $infohash = $self->infohash; | |
35 | my $title = uri_escape $self->title; | |
36 | my $uri = "magnet:?xt=urn:btih:$infohash&dn=$title"; | |
37 | ||
38 | $uri .= join '', map { "&tr=$_"} map { uri_escape $_ } $self->trackers if $full; | |
39 | ||
40 | $uri | |
41 | } | |
42 | ||
43 | sub parse_page { | |
44 | my $self = $_[0]; | |
45 | my $tree = HTML::TreeBuilder->new; | |
46 | $tree->utf8_mode(1); | |
47 | $tree->parse($self->{ua}->get($self->url)->content); | |
48 | $tree->eof; | |
49 | ||
50 | my $trackers = $tree->look_down(class => 'trackers'); | |
51 | $self->{trackers} //= []; | |
52 | for my $tracker ($trackers->find('dl')) { | |
53 | push $self->{trackers}, $tracker->find('a')->as_text; | |
54 | } | |
55 | ||
56 | my $files = $tree->look_down(class => 'files'); | |
57 | $self->{files} //= []; | |
58 | $self->parse_directory(scalar $files->find('li'), ''); | |
59 | ||
60 | $self->{parsed} = 1; | |
61 | } | |
62 | ||
63 | sub parse_directory{ | |
64 | my ($self, $directory, $prefix) = @_; | |
65 | $prefix .= $directory->as_text . '/'; | |
66 | my $contents_ul = $directory->right->find('ul'); | |
67 | return unless defined $contents_ul; # Empty directory | |
68 | my @children = $contents_ul->content_list; | |
69 | my $skip = 0; | |
70 | for my $child (@children) { | |
71 | if ($skip) { | |
72 | $skip = 0; | |
73 | next; | |
74 | } | |
75 | ||
76 | if (defined $child->attr('class') && $child->attr('class') eq 't') { | |
77 | $self->parse_directory($child, $prefix); | |
78 | $skip = 1; | |
79 | } else { | |
80 | $child->objectify_text; | |
81 | my ($filename, $size) = $child->find('~text'); | |
82 | push $self->{files}, +{ | |
83 | path => $prefix.$filename->attr('text'), | |
84 | size => $size->attr('text') | |
85 | } | |
86 | } | |
87 | } | |
88 | } | |
89 | ||
90 | sub trackers{ | |
91 | my $self = $_[0]; | |
92 | $self->parse_page unless $self->{parsed}; | |
93 | @{$self->{trackers}} | |
94 | } | |
95 | ||
96 | sub files{ | |
97 | my $self = $_[0]; | |
98 | $self->parse_page unless $self->{parsed}; | |
99 | @{$self->{files}} | |
100 | } | |
101 | ||
102 | sub torrent{ | |
103 | my $self = $_[0]; | |
104 | my $torrage = 'http://torrage.com/torrent/' . uc $self->infohash . '.torrent'; | |
105 | my $torrent = $self->{ua}->get($torrage)->content; | |
106 | ||
107 | $torrent; # TODO: if this is undef, download metadata with magnet link | |
108 | } | |
109 | ||
110 | 1; | |
111 | __END__ | |
112 | ||
113 | =encoding utf-8 | |
114 | ||
115 | =head1 NAME | |
116 | ||
117 | WWW::Search::Torrentz::Result - a result of a WWW::Search::Torrentz search | |
118 | ||
119 | =head1 SYNOPSIS | |
120 | ||
121 | my $result = $search->next_result; | |
122 | say 'URL: ' . $result->url; | |
123 | say 'Title: ' . $result->title; | |
124 | say 'Infohash: ' . $result->infohash; | |
125 | say 'Verified: ' . $result->verified; | |
126 | say 'Age: ' . $result->age; | |
127 | say 'Size: ' . $result->size; | |
128 | say 'Seeders: ' . $result->seeders; | |
129 | say 'Leechers: ' . $result->leechers; | |
130 | say 'Magnet link: ' . $result->magnet; | |
131 | say 'Magnet link with trackers: ' . $result->magnet(1); | |
132 | my @tracker_list = $result->trackers; | |
133 | my @file_list = $result->files; | |
134 | my $torrent_file = $result->torrent; | |
135 | ||
136 | =head1 DESCRIPTION | |
137 | ||
138 | WWW::Search::Torrentz::Result is the result of a WWW::Search::Torrentz search. | |
139 | ||
140 | Useful methods: | |
141 | ||
142 | =over | |
143 | ||
144 | =item B<url> | |
145 | ||
146 | Returns a link to the torrent details page. | |
147 | ||
148 | =item B<title> | |
149 | ||
150 | Returns the torrent's title. | |
151 | ||
152 | =item B<infohash> | |
153 | ||
154 | Returns the infohash of the torrent, a 40 character hex string. | |
155 | ||
156 | =item B<verified> | |
157 | ||
158 | Returns the verification level of this torrent, or 0 if the torrent not verified. Higher is better. | |
159 | ||
160 | =item B<age> | |
161 | ||
162 | Returns the torrent's age, as returned by Torrentz. Usually a string such as '4 days', 'yesterday', 'today', '2 months'. | |
163 | ||
164 | =item B<size> | |
165 | ||
166 | Returns the torrent's size, as returned by Torrentz. A string such as '151 MB', '25 GB'. | |
167 | ||
168 | =item B<seeders> | |
169 | ||
170 | Returns the number of seeders this torrent has, as returned by Torrentz. | |
171 | ||
172 | =item B<leechers> | |
173 | ||
174 | Returns the number of leechers this torrent has, as returned by Torrentz. | |
175 | ||
176 | =item B<magnet>([I<include_trackers>]) | |
177 | ||
178 | Returns a magnet link that describes this torrent. | |
179 | ||
180 | If I<include_trackers> is true, the magnet link will include the tracker list. This calls B<parse_page> if not called already. | |
181 | ||
182 | =item B<trackers> | |
183 | ||
184 | Returns a list of trackers for this torrent. Calls B<parse_page> if not called already. | |
185 | ||
186 | =item B<files> | |
187 | ||
188 | Returns a list of files this torrent includes. Calls B<parse_page> if not called already. | |
189 | ||
190 | Each element is a hashref with two keys. C<path> is the file path and C<size> is the file size, as returned by Torrentz. | |
191 | ||
192 | =item B<parse_page> | |
193 | ||
194 | Downloads the details page for this torrent and extracts the tracker and file list. It is called automatically by other methods when necessary, you shouldn't have to call it yourself. | |
195 | ||
196 | =item B<torrent> | |
197 | ||
198 | Downloads this torrent file from Torrage. If found, it returns the contents of the torrent file. Otherwise it returns undef. | |
199 | ||
200 | =back | |
201 | ||
202 | =head1 SEE ALSO | |
203 | ||
204 | =head1 AUTHOR | |
205 | ||
206 | Marius Gavrilescu, E<lt>marius@ieval.roE<gt> | |
207 | ||
208 | =head1 COPYRIGHT AND LICENSE | |
209 | ||
210 | Copyright (C) 2013 by Marius Gavrilescu | |
211 | ||
212 | This library is free software; you can redistribute it and/or modify | |
213 | it under the same terms as Perl itself, either Perl version 5.18.1 or, | |
214 | at your option, any later version of Perl 5 you may have available. | |
215 | ||
216 | ||
217 | =cut |