Initial commit
[www-oxontime.git] / lib / WWW / Oxontime.pm
1 package WWW::Oxontime;
2
3 use 5.014000;
4 use strict;
5 use warnings;
6 use parent qw/Exporter/;
7
8 our $VERSION = '0.001';
9 our @EXPORT_OK = qw/stops_for_route departures_for_stop/;
10 our @EXPORT = '';
11
12 use HTML::TreeBuilder;
13 use HTTP::Tiny;
14 use JSON::MaybeXS;
15 use Time::Piece;
16
17 our $STOPS_URL = 'http://www.buscms.com/Nimbus/operatorpages/widgets/departureboard/ssi.aspx?method=updateRouteStops&routeid=%d&callback=cb&_=%d';
18 our $DEPARTS_URL = 'http://www.buscms.com/api/REST/html/departureboard.aspx?clientid=Nimbus&stopid=%d&format=jsonp&cachebust=123&sourcetype=siri&requestor=Netescape&includeTimestamp=true&_=%d';
19 our $DEPART_TIME_FORMAT = '%d/%m/%Y %T';
20
21 our $ht = HTTP::Tiny->new(agent => "WWW-Oxontime/$VERSION");
22
23 sub stops_for_route {
24 my ($route_id) = @_;
25 my $url = sprintf $STOPS_URL, int $route_id, time;
26 my $result = $ht->get($url);
27 die $result->{reason} unless $result->{success};
28 my $json = $result->{content};
29 $json = substr $json, 3, (length $json) - 5;
30 my $stops = decode_json($json)->{stops};
31 wantarray ? @$stops : $stops
32 }
33
34 sub departures_for_stop {
35 my ($stop_id) = @_;
36 my $url = sprintf $DEPARTS_URL, int $stop_id, time;
37 my $result = $ht->get($url);
38 die $result->{reason} unless $result->{success};
39 my $content = $result->{content};
40 $content =~ s/\s/ /g; # replaces tabs with spaces
41 $content = JSON->new->allow_nonref(1)->decode(qq/"$content"/);
42 my $html = HTML::TreeBuilder->new_from_content($content);
43
44 my @lines = $html->look_down(class => qr/\browServiceDeparture\b/);
45 my @result = map {
46 my @cells = $_->find('td');
47 my $departs = $cells[2]->attr('data-departureTime');
48 +{
49 service => $cells[0]->as_trimmed_text,
50 destination => $cells[1]->as_trimmed_text,
51 departs => Time::Piece->strptime($departs, $DEPART_TIME_FORMAT),
52 }
53 } @lines;
54 wantarray ? @result : \@result
55 }
56
57 1;
58 __END__
59
60 =encoding utf-8
61
62 =head1 NAME
63
64 WWW::Oxontime - live Oxford bus departures from Oxontime
65
66 =head1 SYNOPSIS
67
68 use WWW::Oxontime qw/stops_for_route departures_for_stop/;
69 my @stops_on_8_outbound = stops_for_route 15957;
70 my $queens_lane = $stops_on_8_outbound[2]->{stopId};
71 my @from_queens_lane = departures_for_stop $queens_lane;
72 for my $entry (@from_queens_lane) {
73 say $entry->{service}, ' towards ', $entry->{destination}, ' departs at ', $entry->{departs};
74 }
75
76 =head1 DESCRIPTION
77
78 This module wraps L<http://www.oxontime.com> to provide live bus
79 departures in Oxford.
80
81 Two methods can be exported (none by default):
82
83 =over
84
85 =item B<stops_for_route>(I<$route_id>)
86
87 Given a route ID (these can be obtained by inspecting the homepage of
88 Oxontime), returns in list context a list of hashrefs having the keys
89 C<stopName> (name of stop) and C<stopId> (ID of stop, suitable for
90 passing to C<departures_for_stop>). In scalar context, an arrayref
91 containing this list is returned.
92
93 =item B<departures_for_stop>(I<$stop_id>)
94
95 Given a stop ID (these can be obtained by inspecting the homepage of
96 Oxontime or by calling C<stops_for_route>), returns in list context a
97 list of hashrefs having the keys C<service> (name of service and
98 company that runs it), C<destination> (where the service is finishing)
99 and C<departs> (L<Time::Piece> object representing the time when the
100 service departs). In scalar context, an arrayref containing the list
101 is returned.
102
103 Note that C<departs> is in the time zone of Oxford, but Time::Piece
104 interprets it as being in local time. If local time is different from
105 time in Oxford, this needs to be taken into account.
106
107 =back
108
109 =head1 AUTHOR
110
111 Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
112
113 =head1 COPYRIGHT AND LICENSE
114
115 Copyright (C) 2017 by Marius Gavrilescu
116
117 This library is free software; you can redistribute it and/or modify
118 it under the same terms as Perl itself, either Perl version 5.26.1 or,
119 at your option, any later version of Perl 5 you may have available.
120
121
122 =cut
This page took 0.028542 seconds and 4 git commands to generate.