diff options
Diffstat (limited to 'bin')
-rwxr-xr-x | bin/efa-m | 196 |
1 files changed, 116 insertions, 80 deletions
@@ -4,26 +4,24 @@ use warnings; use 5.010; use utf8; -no if $] >= 5.018, warnings => 'experimental::smartmatch'; - -our $VERSION = '1.20'; +our $VERSION = '2.01'; binmode( STDOUT, ':encoding(utf-8)' ); -use Encode qw(decode); +use Encode qw(decode); use Getopt::Long qw(:config no_ignore_case bundling); -use List::Util qw(first max); +use List::Util qw(first max none); use Travel::Status::DE::EFA; -my $efa_url = 'https://efa.vrr.de/vrr/XSLT_DM_REQUEST'; +my $service = 'VRR'; +my $efa_url; my $efa_encoding; -my ( $date, $time, $input_type, $list_lines, $offset, $relative_times ); -my ($full_routes); -my ( $filter_via, $track_via ); -my ( $timeout, $developer_mode ); -my ( @grep_lines, @grep_platforms, @grep_mots ); -my ( %edata, @edata_pre ); -my ( $list_services, $service, $discover_and_print, $discover ); +my ( $date, $time, $input_type, $list_lines, $offset, $relative_times ); +my ( $full_routes, $filter_via ); +my ( $timeout, $developer_mode ); +my ( @grep_lines, @grep_platforms, @grep_mots ); +my ( %edata, @edata_pre ); +my ( $list_services, $discover_and_print, $discover ); my $efa; @ARGV = map { decode( 'UTF-8', $_ ) } @ARGV; @@ -46,7 +44,7 @@ GetOptions( 'timeout=i' => \$timeout, 'u|efa-url=s' => \$efa_url, 'v|via=s' => \$filter_via, - 'V|track-via=s' => sub { $filter_via = $track_via = $_[1] }, + 'V|track-via=s' => \$filter_via, 'version' => \&show_version, 'devmode' => \$developer_mode, @@ -80,21 +78,22 @@ if ( $input =~ s{ ^ (?<type> address|poi|stop|stopID) : }{}x ) { } for my $efield (@edata_pre) { - given ($efield) { - when ('a') { $edata{route_after} = 1; $full_routes = 1 } - when ('b') { $edata{route_before} = 1; $full_routes = 1 } - when ('f') { $edata{fullroute} = 1; $full_routes = 1 } - when ('r') { $edata{route} = 1; $full_routes = 1 } - default { $edata{$efield} = 1 } - } + if ( $efield eq 'a' ) { $edata{route_after} = 1; $full_routes = 1 } + elsif ( $efield eq 'b' ) { $edata{route_before} = 1; $full_routes = 1 } + elsif ( $efield eq 'f' ) { $edata{fullroute} = 1; $full_routes = 1 } + elsif ( $efield eq 'r' ) { $edata{route} = 1; $full_routes = 1 } + elsif ( $efield eq 'm' ) { $edata{messages} = 1 } + else { $edata{$efield} = 1 } } if ($filter_via) { $full_routes = 1; } -if ($service) { - my $service_ref = first { lc( $_->{shortname} ) eq lc($service) } - Travel::Status::DE::EFA::get_efa_urls(); +if ($efa_url) { + $service = undef; +} +elsif ($service) { + my $service_ref = Travel::Status::DE::EFA::get_service($service); if ( not $service_ref ) { printf STDERR ( "Error: Unknown service '%s'. See 'efa-m --list' for a " @@ -103,16 +102,17 @@ if ($service) { ); exit 1; } - $efa_url = $service_ref->{url}; $efa_encoding = $service_ref->{encoding}; + $efa_url = undef; } -sub new_efa_by_url { - my ($url) = @_; +sub new_efa { + my ( $s, $u ) = @_; my $res = Travel::Status::DE::EFA->new( + service => $s, + efa_url => $u, date => $date, developer_mode => $developer_mode, - efa_url => $url, efa_encoding => $efa_encoding, full_routes => $full_routes, place => $place, @@ -149,6 +149,14 @@ sub show_version { exit 0; } +sub format_delay { + my ( $delay, $len ) = @_; + if ( $delay and $len ) { + return sprintf( "(%+${len}d)", $delay ); + } + return q{}; +} + sub format_route { my (@route) = @_; @@ -159,23 +167,35 @@ sub format_route { say 'BUG'; next; } - if ( not defined $stop->arr_time ) { - $output .= sprintf( " %5s %40s %s\n", - $stop->dep_time, $stop->name, $stop->platform, ); - } - elsif ( not defined $stop->dep_time ) { - $output .= sprintf( "%5s %40s %s\n", - $stop->arr_time, $stop->name, $stop->platform, ); + if ( defined $stop->arr and defined $stop->dep ) { + if ( $stop->arr->epoch == $stop->dep->epoch ) { + $output .= sprintf( + " %5s %40s %s\n", + $stop->arr->strftime('%H:%M'), + $stop->name, $stop->platform, + ); + } + else { + $output .= sprintf( + "%5s → %5s %40s %s\n", + $stop->arr->strftime('%H:%M'), + $stop->dep->strftime('%H:%M'), + $stop->name, $stop->platform, + ); + } } - elsif ( $stop->arr_time eq $stop->dep_time ) { - $output .= sprintf( " %5s %40s %s\n", - $stop->dep_time, $stop->name, $stop->platform, ); + elsif ( defined $stop->arr ) { + $output .= sprintf( + "%5s %40s %s\n", + $stop->arr->strftime('%H:%M'), + $stop->name, $stop->platform, + ); } - else { + elsif ( defined $stop->dep ) { $output .= sprintf( - "%5s → %5s %40s %s\n", - $stop->arr_time, $stop->dep_time, - $stop->name, $stop->platform, + " %5s %40s %s\n", + $stop->dep->strftime('%H:%M'), + $stop->name, $stop->platform, ); } } @@ -197,7 +217,7 @@ sub display_result { for my $line (@lines) { - if ( length( $line->[5] ) ) { + if ( $edata{messages} and length( $line->[5] ) ) { $line->[5] =~ tr{\n\x0d}{ }s; chomp $line->[5]; print "\n"; @@ -224,13 +244,13 @@ sub show_lines { for my $l ( $efa->lines ) { - if ( ( @grep_lines and not( $l->name ~~ \@grep_lines ) ) - or ( @grep_mots and not( $l->mot_name ~~ \@grep_mots ) ) ) + if ( ( @grep_lines and none { $l->name eq $_ } @grep_lines ) + or ( @grep_mots and none { $l->mot_name eq $_ } @grep_mots ) ) { next; } - if ( @grep_mots and not( $l->mot_name ~~ \@grep_mots ) ) { + if ( @grep_mots and none { $l->mot_name eq $_ } @grep_mots ) { next; } @@ -247,6 +267,17 @@ sub show_lines { sub show_results { my @output; + my $delay_len = 0; + my $delay_fmt = 0; + for my $d ( $efa->results ) { + if ( $d->delay ) { + $delay_len = max( $delay_len, length( $d->delay ) + 1 ); + } + } + if ($delay_len) { + $delay_fmt = $delay_len + 3; + } + for my $d ( $efa->results ) { my @output_line; @@ -254,7 +285,7 @@ sub show_results { my $dtime = ( $relative_times ? sprintf( '%2d min', $d->countdown ) - : $d->sched_time + : $d->datetime->strftime('%H:%M') ); if ( $d->platform_db ) { @@ -262,10 +293,10 @@ sub show_results { } if ( - ( @grep_lines and not( $d->line ~~ \@grep_lines ) ) - or ( @grep_mots and not( $d->mot_name ~~ \@grep_mots ) ) + ( @grep_lines and none { $d->line eq $_ } @grep_lines ) + or ( @grep_mots and none { $d->mot_name eq $_ } @grep_mots ) or ( @grep_platforms - and not( $platform ~~ \@grep_platforms ) ) + and none { $platform eq $_ } @grep_platforms ) or ( $offset and $d->countdown < $offset ) or ( $filter_via and @@ -280,24 +311,27 @@ sub show_results { next; } else { - $dtime .= ' CANCELED'; + $dtime = '--:--'; } } - elsif ($track_via) { + elsif ($filter_via) { my $via = first { $_->name =~ m{$filter_via}io } $d->route_post; - $dtime .= ' → ' . $via->arr_time; + $dtime + .= ' → ' + . $via->arr->clone->add( minutes => $d->delay // 0 ) + ->strftime('%H:%M'); } if ( $d->delay ) { - if ($relative_times) { - $dtime .= ' (+' . $d->delay . ')'; - } - else { - $dtime .= ' +' . $d->delay; - } + $dtime .= ' ' . format_delay( $d->delay, $delay_len ); + } + + my $line = $d->line; + if ( length($line) > 10 and $d->train_type and $d->train_no ) { + $line = $d->train_type . ' ' . $d->train_no; } @output_line - = ( $dtime, $platform, $d->line, q{}, $d->destination, $d->info ); + = ( $dtime, $platform, $line, q{}, $d->destination, $d->info ); if ( $edata{route} ) { $output_line[3] @@ -341,7 +375,7 @@ sub show_results { if ( $discover or $discover_and_print ) { for my $service_ref ( Travel::Status::DE::EFA::get_efa_urls() ) { - $efa = new_efa_by_url( $service_ref->{url} ); + $efa = new_efa( $service_ref->{shortname} ); if ( $efa and not $efa->errstr ) { if ($discover_and_print) { last; @@ -358,7 +392,7 @@ if ( $discover or $discover_and_print ) { } } -$efa = new_efa_by_url($efa_url); +$efa = new_efa( $service, $efa_url ); if ( my $err = $efa->errstr ) { say STDERR "Request error: ${err}"; @@ -396,7 +430,7 @@ B<efa-m> [B<-Lr>] [B<-d> I<dd.mm.yyyy>] [B<-t> I<hh:mm>] =head1 VERSION -version 1.20 +version 2.01 =head1 DESCRIPTION @@ -513,6 +547,12 @@ Show up to three stops between the requested station and the departure's destination. B<efa-m> tries to display the three most important stops, however these are heuristically determined and may not be optimal. +=item m / messages + +Show free-text messages associated with individual departures. These can +include generic information such is bicycle transportation options or Wi-Fi +availability, delay reasons, and more. + =back =item B<-p>, B<--platform> I<platforms> @@ -535,13 +575,6 @@ B<--list> option for a list of services. Show departures starting at I<time> instead of now. -=item B<-u>, B<--efa-url> I<url> - -URL to the EFA entry point, defaults to -L<http://efa.vrr.de/vrr/XSLT_DM_REQUEST>. Depending on your location, some -I<url>s may contain more specific data than others. See -Travel::Status::DE::EFA(3pm) and the B<--list> option for alternatives. - =item B<--timeout> I<seconds> Set timeout for HTTP requests. Default: 10 seconds. Set to 0 or a negative @@ -549,15 +582,10 @@ value to disable it. =item B<-v>, B<--via> I<station> -Only show trains serving I<station> after the requseted stop. I<station> -is matched against the "I<city> I<stop>" fields in each line's route. -Regular expressions are also supported. - -=item B<-V>, B<--track-via> I<station> - -Lik B<--via>: Only show trains serving I<station> after the requseted stop. -Also, show the arrival time at I<station> after the departure time at the -current stop. +Only show trains serving I<station> after the requseted stop, and show the +arrival time at I<station> after the departure time at the current stop. +I<station> is matched against the "I<city> I<stop>" fields in each line's +route. Regular expressions are also supported. =item B<--version> @@ -597,9 +625,17 @@ choose the appropriate EFA URL for these by itself. In these cases, you should find an appropriate EFA service using the B<-D>/B<--discover> option and then use B<-s> I<service> when making requests. +=over + +=item * EFA does not provide real-time data for the routes of requested +departures. Hence, B<--via> estimates the arrival time from scheduled +departure and departure delay + +=back + =head1 AUTHOR -Copyright (C) 2011-2020 by Daniel Friesel E<lt>derf@finalrewind.orgE<gt> +Copyright (C) 2011-2023 by Birte Kristina Friesel E<lt>derf@finalrewind.orgE<gt> =head1 LICENSE |