diff options
Diffstat (limited to 'bin/efa')
-rwxr-xr-x | bin/efa | 163 |
1 files changed, 117 insertions, 46 deletions
@@ -4,20 +4,18 @@ use warnings; use 5.010; use utf8; -no if $] >= 5.018, warnings => 'experimental::smartmatch'; - use utf8; use Encode qw(decode); use Travel::Routing::DE::EFA; use Exception::Class; use Getopt::Long qw/:config no_ignore_case/; -use List::Util qw(first); +use List::Util qw(first max); -our $VERSION = '2.19'; +our $VERSION = '2.24'; my $ignore_info; my $efa; -my $efa_url = 'http://efa.vrr.de/vrr/XSLT_TRIP_REQUEST2'; +my $efa_url = 'https://app.vrr.de/vrrstd/XML_TRIP_REQUEST2'; my ( @from, @to, @via, $from_type, $to_type, $via_type ); my $opt = { 'efa-url' => \$efa_url, @@ -32,6 +30,9 @@ my $opt = { binmode( STDOUT, ':encoding(utf-8)' ); binmode( STDERR, ':encoding(utf-8)' ); +my $output_bold = -t STDOUT ? "\033[1m" : q{}; +my $output_reset = -t STDOUT ? "\033[0m" : q{}; + sub show_help { my ($exit_status) = @_; @@ -49,7 +50,7 @@ sub new_efa_by_url { origin => [ @from, $from_type ], destination => [ @to, $to_type ], - via => ( @via ? [ @via, $via_type ] : undef ), + via => ( @via ? [ @via, $via_type ] : undef ), arrival_time => $opt->{arrive}, departure_time => $opt->{depart}, @@ -172,6 +173,22 @@ sub format_footpath { return $str; } +sub format_delay_incl { + my ( $delay, $len ) = @_; + if ( $delay and $len ) { + return sprintf( "(%+${len}d)", $delay ); + } + return q{}; +} + +sub format_delay_excl { + my ( $delay, $len ) = @_; + if ( $delay and $len ) { + return sprintf( " %+${len}d ", $delay ); + } + return q{}; +} + sub display_routes { my (@routes) = @_; @@ -191,8 +208,19 @@ sub display_routes { } } + my $delay_len = 0; for my $c ( $route->parts ) { - display_connection($c); + if ( $c->departure_delay ) { + $delay_len + = max( $delay_len, length( $c->departure_delay ) + 1 ); + } + if ( $c->arrival_delay ) { + $delay_len = max( $delay_len, length( $c->arrival_delay ) + 1 ); + } + } + + for my $c ( $route->parts ) { + display_connection( $c, $delay_len ); } # last one needs to be shown separately @@ -211,29 +239,25 @@ sub display_routes { } sub display_connection { - my ($c) = @_; + my ( $c, $delay_len ) = @_; + + my $delay_fmt = $delay_len ? $delay_len + 2 : 0; if ( $c->is_cancelled ) { say '# FAHRT FÄLLT AUS'; } - elsif ( $c->delay ) { - printf( "# +%d, Plan: %s -> %s\n", - $c->delay, $c->departure_stime, $c->arrival_stime ); - } - for my $note ( $c->regular_notes ) { - my $text = $note->summary; - if ( not( length $ignore_info and $text =~ /$ignore_info/i ) ) { - say "# $text"; - } - } + my $occupancy = q{}; - for my $notice ( $c->current_notes ) { - if ( $notice->subtitle ne $notice->subject ) { - printf( "# %s - %s\n", $notice->subtitle, $notice->subject ); + if ( $c->occupancy ) { + if ( $c->occupancy == 1 ) { + $occupancy = '[ ]'; } - else { - printf( "# %s\n", $notice->subtitle ); + elsif ( $c->occupancy == 2 ) { + $occupancy = '[* ]'; + } + elsif ( $c->occupancy == 3 ) { + $occupancy = '[!!]'; } } @@ -244,21 +268,52 @@ sub display_connection { } printf( - "%-5s ab %-30s %-20s %s\n", + "${output_bold}%s${output_reset} %s %s\n", + $c->train_line || $c->train_product, + $c->train_destination ? q{→} : q{ }, + $c->train_destination + ); + + printf( + "%-5s %-${delay_fmt}s ab %-30s\n", $c->departure_time, + format_delay_incl( $c->departure_delay, $delay_len ), $c->departure_stop_and_platform, - $c->train_line || $c->train_product, - $c->train_destination, ); if ( $opt->{'full-route'} ) { for my $via_stop ( $c->via ) { - printf( "%-5s %-30s %s\n", - $via_stop->[1], $via_stop->[2], $via_stop->[3] ); + printf( + "%-5s %-${delay_fmt}s %-30s %s\n", + $via_stop->[1], format_delay_excl( $via_stop->[4], $delay_len ), + $via_stop->[2], $via_stop->[3] + ); + } + } + + printf( + "%-5s %-${delay_fmt}s an %-30s %s\n", + $c->arrival_time, + format_delay_incl( $c->arrival_delay, $delay_len ), + $c->arrival_stop_and_platform, $occupancy + ); + + for my $notice ( $c->current_notes ) { + if ( $notice->subtitle ne $notice->subject ) { + printf( "# %s - %s\n", $notice->subtitle, $notice->subject ); + } + else { + printf( "# %s\n", $notice->subtitle ); + } + } + + for my $note ( $c->regular_notes ) { + my $text = $note->summary; + if ( not( length $ignore_info and $text =~ /$ignore_info/i ) ) { + say "# $text"; } } - printf( "%-5s an %s\n", $c->arrival_time, $c->arrival_stop_and_platform, ); print "\n"; if ( $opt->{'extended-info'} @@ -325,14 +380,23 @@ if ( $opt->{exclude} ) { @{ $opt->{exclude} } = split( qr{,}, join( q{,}, @{ $opt->{exclude} } ) ); } +my %accessibility_map = ( + s => 'without_solid_stairs', + 'no-stairs' => 'without_solid_stairs', + e => 'without_escalators', + 'no-escalators' => 'without_escalators', + E => 'without_elevators', + 'no-elevators' => 'without_elevators', + l => 'with_low_platform', + nf => 'with_low_platform', + 'low-platform' => 'with_low_platform', + w => 'with_wheelchair', + wheelchair => 'with_wheelchair', +); + for my $field ( @{ $opt->{accessibility} } ) { - given ($field) { - when ( [qw[s no-stairs]] ) { $opt->{without_solid_stairs} = 1 } - when ( [qw[e no-escalators]] ) { $opt->{without_escalators} = 1 } - when ( [qw[E no-elevators]] ) { $opt->{without_elevators} = 1 } - when ( [qw[l nf low-platform]] ) { $opt->{with_low_platform} = 1 } - when ( [qw[w wheelchair]] ) { $opt->{with_wheelchair} = 1 } - when ( [qw[i info]] ) { } # used for ignore_info default + if ( $accessibility_map{$field} ) { + $opt->{ $accessibility_map{$field} } = 1; } } @@ -390,16 +454,18 @@ for my $pair ( [ \@from, \$from_type ], [ \@via, \$via_type ], {$+{target}}x ) { - given ( $+{type} ) { - when ('addr') { ${ $pair->[1] } = 'address' } - default { ${ $pair->[1] } = $+{type} } + if ( $+{type} eq 'addr' ) { + ${ $pair->[1] } = 'address'; + } + else { + ${ $pair->[1] } = $+{type}; } } } if ( $opt->{service} ) { my $service = first { lc( $_->{shortname} ) eq lc( $opt->{service} ) } - Travel::Routing::DE::EFA::get_efa_urls(); + Travel::Routing::DE::EFA::get_efa_urls(); if ( not $service ) { printf STDERR ( "Error: Unknown service '%s'. See 'efa -l' for a " @@ -457,7 +523,7 @@ efa - Command line client for EFA-based public transit routing services =head1 VERSION -version 2.19 +version 2.24 =head1 DESCRIPTION @@ -472,6 +538,11 @@ instance can be selected using B<-s> I<service> or B<-u> I<url>. It is also possible to probe all known EFA services for a specific connection using the B<-A> and B<-D> options. +If available, B<efa> shows the expected occupancy of each route part. +It ranges from C<< [ ] >> (low occupancy) to C<< [!!] >> (very high +occupancy). Occupation data appears to be limited to certain VRR trains +at the moment. + =head1 OPTIONS =over @@ -531,7 +602,7 @@ entry points which did not return an error. =item B<-u>|B<--efa-url> I<url> URL to the EFA entry point, defaults to -L<http://efa.vrr.de/vrr/XSLT_TRIP_REQUEST2>. Depending on your location, some +L<https://app.vrr.de/vrrstd/XML_TRIP_REQUEST2>. Depending on your location, some I<url>s may contain more specific data than others. See Travel::Routing::DE::EFA(3pm) and the B<-l> option for alternatives. @@ -708,9 +779,9 @@ All vehicles must be wheelchair accessible. 0 Everything went well 1 Invalid arguments, see error message 2 Network error, unable to send request - 3 efa.vrr.de did not return any parsable data - 4 efa.vrr.de error: ambiguous input - 5 efa.vrr.de error: no connections found + 3 EFA did not return any parsable data + 4 EFA error: ambiguous input + 5 EFA error: no connections found 10 Unknown Travel::Routing::DE::EFA error 255 Other internal error @@ -769,7 +840,7 @@ to to request via -> to. =head1 AUTHOR -Copyright (C) 2009-2020 by Daniel Friesel E<lt>derf@finalrewind.orgE<gt> +Copyright (C) 2009-2023 by Birte Kristina Friesel E<lt>derf@finalrewind.orgE<gt> =head1 LICENSE |