Skip to content
hafas-m 5.52 KiB
Newer Older
Birte Kristina Friesel's avatar
Birte Kristina Friesel committed
#!/usr/bin/env perl
use strict;
use warnings;
use 5.010;

use Getopt::Long qw(:config no_ignore_case);
use List::MoreUtils qw(uniq);
use Travel::Status::DE::HAFAS;
my $arrivals    = 0;
my $ignore_late = 0;
my $types       = q{};
my $developer_mode;
my ( $list_services, $service, $hafas_url );
my ( @excluded_mots, @exclusive_mots );

binmode( STDOUT, ':encoding(utf-8)' );
	'a|arrivals'    => \$arrivals,
	'd|date=s'      => \$date,
	'h|help'        => sub { show_help(0) },
	'L|ignore-late' => \$ignore_late,
	'm|mot=s'       => \$types,
	's|service=s'   => \$service,
	't|time=s'      => \$time,
	'u|url=s'       => \$hafas_url,
	'V|version'     => \&show_version,
	'devmode'       => \$developer_mode,
Birte Kristina Friesel's avatar
Birte Kristina Friesel committed
	'list'          => \$list_services,
Birte Kristina Friesel's avatar
Birte Kristina Friesel committed
if ($list_services) {
	printf( "%-40s %-14s %s\n\n", 'operator', 'abbr. (-s)', 'url (-u)' );
	for my $service ( Travel::Status::DE::HAFAS::get_services() ) {
		printf( "%-40s %-14s %s\n", @{$service}{qw(name shortname url)} );
	}
	exit 0;
}

parse_mot_options();
my $status = Travel::Status::DE::HAFAS->new(
	date           => $date,
	language       => $language,
	excluded_mots  => \@excluded_mots,
	exclusive_mots => \@exclusive_mots,
	station        => shift || show_help(1),
	time           => $time,
	mode           => $arrivals ? 'arr' : 'dep',
	developer_mode => $developer_mode,
	service        => $service,
	url            => $hafas_url,
sub show_help {
	my ($code) = @_;

	print 'Usage: hafas-m [-d <dd.mm.yyyy>] [-m <motlist>] [-t <time>] '
	  . "<station>\n"
	  . "See also: man hafas-m\n";
	say "hafas-m version ${VERSION}";
sub parse_mot_options {

	my $default_yes = 1;
	my $help;

	for my $type ( split( qr{,}, $types ) ) {
		if ( $type eq 'help' or $type eq 'list' or $type eq '?' ) {
			my @mots
			  = @{ Travel::Status::DE::HAFAS::get_service($service)
				  ->{productbits} };
			@mots = grep { $_ ne 'x' } @mots;
			@mots = uniq @mots;
			@mots = sort @mots;
			say join( "\n", @mots );
			exit 0;
		}
		elsif ( substr( $type, 0, 1 ) eq q{!} ) {
			push( @excluded_mots, substr( $type, 1 ) );
		}
		else {
			push( @exclusive_mots, $type );
		}
	}
}

sub display_result {
	my (@lines) = @_;

	my @line_length;

	if ( not @lines ) {
		die("Nothing to show\n");
	}

	for my $i ( 0 .. 4 ) {
		$line_length[$i] = max map { length( $_->[$i] ) } @lines;
	}

	for my $line (@lines) {
		my $d = $line->[6];
		if ( $d->messages ) {
			print "\n";
			for my $msg ( $d->messages ) {
				printf( "# %s\n", $msg );
			}
		printf(
			join( q{  }, ( map { "%-${_}s" } @line_length ) ),
			@{$line}[ 0 .. 4 ]
		);
		if ( $line->[5] ) {
			print $line->[5];
	say STDERR "Request error: ${err}";
for my $d ( $status->results() ) {

	if ( $ignore_late and $d->delay ) {
			$d->is_cancelled
			? 'CANCELED'
			: ( $d->delay ? sprintf( '%+d', $d->delay ) : q{} ),
			$d->route_end,
			( $d->platform // q{} ) . ( $d->is_changed_platform ? ' !' : q{} ),
Birte Kristina Friesel's avatar
Birte Kristina Friesel committed
__END__

=head1 NAME

hafas-m - Interface to the DeutscheBahn/HAFAS online departure monitor
Birte Kristina Friesel's avatar
Birte Kristina Friesel committed
=head1 SYNOPSIS

B<hafas-m> [B<-a>] [B<-d> I<date>] [B<-L>] [B<-m> I<motlist>] [B<-t> I<time>]
I<station>
Birte Kristina Friesel's avatar
Birte Kristina Friesel committed
=head1 DESCRIPTION

hafas-m is an interface to HAFAS-based departure monitors, for instance the
one available at L<http://reiseauskunft.bahn.de/bin/bhftafel.exe/dn>.

It requests all departures at I<station> (optionally filtered by date, time,
route and means of transport) and lists them on stdout, similar to the big
departure screens installed at most main stations.
Birte Kristina Friesel's avatar
Birte Kristina Friesel committed
=head1 OPTIONS

=item B<-a>, B<--arrivals>

Show arrivals instead of departures, including trains ending at the specified
station. Note that this causes the output to display the start instead of
the end station and B<-f> to list all stops between start end
I<station>, not I<station> and end.

=item B<-d>, B<--date> I<dd>.I<mm>.I<yyyy>

Date to list departures for.  Default: today.

=item B<-l>, B<--lang> B<d>|B<e>|B<i>|B<n>

Set language used for additional information. Supports B<d>eutsch (default),
B<e>nglish, B<i>talian and dutch (B<n>).

=item B<-L>, B<--ignore-late>

Do not display delayed trains.

=item B<-m>, B<--mot> I<motlist>

Comma-separated list of modes of transport to show/hide.  Accepts the following

	ice    InterCity Express trains
	ic_ec  InterCity / EuroCity trains
	d      InterRegio and similar
	nv     "Nahverkehr", RegionalExpress and such
	s      S-Bahn
	bus
	ferry
	u      U-Bahn
	tram

You can prefix an argument with "!" to hide it.  The default is C<<
ice,ic_ec,d,nv,s >>.  Note that B<-m> does not replace the default, so if you
only want to see S-Bahn and U-Bahn departures, you'd have to use C<< -m
!ice,!ic_ec,!d,!nv,u >>.

=item B<-t>, B<--time> I<hh>:I<mm>

Time to list departures for.  Default: now.
=item B<-V>, B<--version>

Show version information.
Birte Kristina Friesel's avatar
Birte Kristina Friesel committed
=head1 EXIT STATUS

Zero unless things went wrong.

Birte Kristina Friesel's avatar
Birte Kristina Friesel committed
=head1 CONFIGURATION

Birte Kristina Friesel's avatar
Birte Kristina Friesel committed
=head1 DEPENDENCIES

=over

=item * Class::Accessor(3pm)

=item * LWP::UserAgent(3pm)

=item * XML::LibXML(3pm)

=back

Birte Kristina Friesel's avatar
Birte Kristina Friesel committed
=head1 BUGS AND LIMITATIONS

Birte Kristina Friesel's avatar
Birte Kristina Friesel committed
=head1 AUTHOR

Copyright (C) 2015 by Daniel Friesel E<lt>derf@finalrewind.orgE<gt>
Birte Kristina Friesel's avatar
Birte Kristina Friesel committed

=head1 LICENSE

This program is licensed under the same terms as Perl itself.