summaryrefslogtreecommitdiff
path: root/bin/db-iris
diff options
context:
space:
mode:
Diffstat (limited to 'bin/db-iris')
-rwxr-xr-xbin/db-iris189
1 files changed, 142 insertions, 47 deletions
diff --git a/bin/db-iris b/bin/db-iris
index 870c0ca..08906e2 100755
--- a/bin/db-iris
+++ b/bin/db-iris
@@ -1,19 +1,18 @@
-#!/usr/bin/env perl
+#!perl
use strict;
use warnings;
use 5.014;
use utf8;
-no if $] >= 5.018, warnings => 'experimental::smartmatch';
-
-our $VERSION = '1.28';
+our $VERSION = '1.96';
use DateTime;
use DateTime::Format::Strptime;
-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::MoreUtils qw(none);
+use JSON;
+use List::Util qw(first max);
+use List::MoreUtils qw(any none);
use Travel::Status::DE::IRIS;
use Travel::Status::DE::IRIS::Stations;
@@ -23,9 +22,12 @@ my $developer_mode = 0;
my $lookahead = 2 * 60;
my $realtime = 0;
my $with_related = 1;
-my ( $filter_via, $track_via, $status_via );
-my ( @grep_class, @grep_type, @grep_platform );
-my ( %edata, @edata_pre );
+my $json_output = 0;
+my $use_cache = 1;
+my ( $schedule_cache, $realtime_cache );
+my ( $filter_via, $track_via, $status_via );
+my ( @grep_class, @grep_type, @grep_platform );
+my ( %edata, @edata_pre );
my @output;
@@ -46,7 +48,9 @@ GetOptions(
'v|via=s' => \$filter_via,
'V|track-via=s' => \$track_via,
'x|exact|no-related' => sub { $with_related = 0 },
+ 'cache!' => \$use_cache,
'devmode' => \$developer_mode,
+ 'json' => \$json_output,
'version' => \&show_version,
) or show_help(1);
@@ -115,19 +119,40 @@ if ($time) {
}
for my $efield (@edata_pre) {
- given ($efield) {
- when ('a') { $edata{additional} = 1 }
- when ('c') { $edata{canceled} = 1 }
- when ('d') { $edata{delay} = 1 }
- when ('D') { $edata{delays} = 1 }
- when ('f') { $edata{fullroute} = 1 }
- when ('m') { $edata{messages} = 1 }
- when ('q') { $edata{qos} = 1 }
- when ('r') { $edata{route} = 1 }
- when ('R') { $edata{replacements} = 1 }
- when ('t') { $edata{times} = 1 }
- when ('!') { $edata{debug} = 1 }
- default { $edata{$efield} = 1 }
+ if ( $efield eq 'a' ) { $edata{additional} = 1 }
+ elsif ( $efield eq 'c' ) { $edata{canceled} = 1 }
+ elsif ( $efield eq 'd' ) { $edata{delay} = 1 }
+ elsif ( $efield eq 'D' ) { $edata{delays} = 1 }
+ elsif ( $efield eq 'f' ) { $edata{fullroute} = 1 }
+ elsif ( $efield eq 'm' ) { $edata{messages} = 1 }
+ elsif ( $efield eq 'q' ) { $edata{qos} = 1 }
+ elsif ( $efield eq 'r' ) { $edata{route} = 1 }
+ elsif ( $efield eq 'R' ) { $edata{replacements} = 1 }
+ elsif ( $efield eq 't' ) { $edata{times} = 1 }
+ elsif ( $efield eq '!' ) { $edata{debug} = 1 }
+ else { $edata{$efield} = 1 }
+}
+
+if ($use_cache) {
+ my $cache_path = $ENV{XDG_CACHE_HOME} // "$ENV{HOME}/.cache";
+ my $schedule_cache_path = "${cache_path}/db-iris-schedule";
+ my $realtime_cache_path = "${cache_path}/db-iris-realtime";
+ eval {
+ use Cache::File;
+ $schedule_cache = Cache::File->new(
+ cache_root => $schedule_cache_path,
+ default_expires => '6 hours',
+ lock_level => Cache::File::LOCK_LOCAL(),
+ );
+ $realtime_cache = Cache::File->new(
+ cache_root => $realtime_cache_path,
+ default_expires => '180 seconds',
+ lock_level => Cache::File::LOCK_LOCAL(),
+ );
+ };
+ if ($@) {
+ $schedule_cache = undef;
+ $realtime_cache = undef;
}
}
@@ -135,14 +160,18 @@ my $status = Travel::Status::DE::IRIS->new(
datetime => $datetime,
developer_mode => $developer_mode,
lookahead => $lookahead,
+ main_cache => $schedule_cache,
+ realtime_cache => $realtime_cache,
station => $station,
with_related => $with_related,
);
if ($track_via) {
$status_via = Travel::Status::DE::IRIS->new(
- datetime => $datetime,
- station => $track_via,
- lookahead => $lookahead + 3 * 60,
+ datetime => $datetime,
+ lookahead => $lookahead + 3 * 60,
+ main_cache => $schedule_cache,
+ realtime_cache => $realtime_cache,
+ station => $track_via,
);
}
@@ -206,7 +235,7 @@ sub get_station {
exit(1);
}
elsif ( @stations == 1 ) {
- return $stations[0][0];
+ return $stations[0][2];
}
else {
say STDERR "The input '$input_name' is ambiguous. Please choose one "
@@ -260,6 +289,9 @@ sub format_delay {
elsif ( $d->departure_is_cancelled ) {
$delay .= ' ⊖';
}
+ elsif ( $d->start < $datetime and not $d->has_realtime ) {
+ $delay = ' ?';
+ }
return $delay;
}
@@ -413,6 +445,11 @@ if ( $status_via and $status_via->warnstr ) {
sanitize_options();
+if ($json_output) {
+ say JSON->new->convert_blessed->encode( [ $status->results ] );
+ exit 0;
+}
+
for my $d ( $status->results() ) {
my @via;
@@ -420,15 +457,33 @@ for my $d ( $status->results() ) {
# route may be incomplete, so check route_end as well
@via = ( $d->route_post, $d->route_end );
- if ( ( $filter_via and not( first { $_ =~ m{$filter_via}io } @via ) )
- or ( @grep_class and none { $_ ~~ \@grep_class } $d->classes )
- or ( @grep_platform and not( $d->platform ~~ \@grep_platform ) )
- or ( @grep_type and not( $d->type ~~ \@grep_type ) )
+ if ( ( $filter_via and not( first { $_ =~ m{$filter_via}io } @via ) )
or $d->is_wing )
{
next;
}
+ if ( @grep_platform and none { $d->platform eq $_ } @grep_platform ) {
+ next;
+ }
+
+ if ( @grep_type and none { $d->type eq $_ } @grep_type ) {
+ next;
+ }
+
+ if (@grep_class) {
+ my $skip = 1;
+ for my $class ( $d->classes ) {
+ if ( any { $class eq $_ } @grep_class ) {
+ $skip = 0;
+ last;
+ }
+ }
+ if ($skip) {
+ next;
+ }
+ }
+
my $delay = format_delay($d);
my $platformstr = $d->platform // q{};
@@ -441,8 +496,7 @@ for my $d ( $status->results() ) {
my $d_via = first {
$_->train_id eq $d->train_id
or ( $_->old_train_id and $_->old_train_id eq $d->train_id );
- }
- $status_via->results;
+ } $status_via->results;
if ( not $d_via
or not $d_via->sched_arrival
or $d_via->sched_arrival < $d->departure )
@@ -494,7 +548,7 @@ for my $d ( $status->results() ) {
push( @processed_wings, $wing->wing_id );
}
for my $wing ( $d->arrival_wings ) {
- if ( not $wing->wing_id ~~ \@processed_wings ) {
+ if ( none { $wing->wing_id eq $_ } @processed_wings ) {
my $wingdelay = format_delay($wing);
push(
@output,
@@ -533,24 +587,38 @@ B<db-iris> [B<-rx>] [B<-d> I<date>] [B<-o> I<output-flags>]
=head1 VERSION
-version 1.28
+version 1.96
=head1 DESCRIPTION
db-iris is an interface to the DeutscheBahn departure monitor
available at L<https://iris.noncd.db.de/wbt/js/index.html>.
-It requests all departures at I<station> and lists them on stdout, similar to
-the big departure screens installed at most main stations. I<station> can be
-a DS100 station code (such as "EE"), a normal station name
-(such as "Essen Hbf" or "Dortmund UniversitE<auml>t"), or an IBNR / european station
-number (such as 8000098). If no exact match is found, B<db-iris> will try to
-find station names similar to I<station>.
+It requests all trains departing from (or arriving at) I<station> in the next
+two hours and lists them on stdout. I<station> can be a DS100 station code
+(such as "EE"), a normal station name (such as "Essen Hbf" or "Dortmund
+UniversitE<auml>t"), or an IBNR / european station number (such as 8000098). If
+no exact match is found, B<db-iris> will try to find station names similar to
+I<station>.
+
+By default, db-iris shows the following data for each train:
+
+=over
+
+=item * scheduled departure time (see also B<-ot>, B<-r>).
+
+=item * delay in minutes, cancellation, or a question mark (C<< ? >>)
+indicating that no real-time data is available.
-An exclamation mark (C<< ! >>) next to a destination indicates that at least
-one stop on the train's route has been canceled. Use B<-oc> to see the canceled
-stops. An exclamation mark next to a platform indicates that it is not the
-scheduled one.
+=item * train line or number.
+
+=item * destination (see also B<-or>). An exclamation mark (C<< ! >>)
+indicates that at least one stop has been cancelled (see B<-oc>).
+
+=item * platform. An exclamation mark (C<< ! >>) indicates that it is not
+the scheduled one.
+
+=back
=head1 OPTIONS
@@ -575,16 +643,35 @@ or I<dd>.I<mm>.I<YYYY> format, or C<< tomorrow >>. Note that typically only
slight (a few hours max) deviations from the current time are supported by the
IRIS backend, larger ones will not return data.
+=item B<--json>
+
+List results as JSON, see Travel::Status::DE::IRIS::Result(3pm) for a partial
+documentation of arrival/departure keys. The B<--output> option has no effect
+when using B<--json>.
+
+Note that JSON entries not mentioned in Travel::Status::DE::IRIS::Result(3pm)
+are NOT guaranteed to be compatible between releases. Their structure is not
+part of the db-iris / Travel::Status::DE::IRIS versioning scheme; it may change
+in backwards-incompatible ways anytime.
+
=item B<-l>, B<--lookahead> I<int>
Do not return results which are more than I<int> minutes in the future.
-Defaults to 240 (4 hours).
+Defaults to 120 (2 hours).
Note that this is only an upper limit, not a guarantee to get every train
with a departure in less than I<int> minutes. This guarantee holds only for
I<int> below 120. However, any non-negative number is accepted for this
option.
+=item B<--no-cache>
+
+If the Cache::File module is available, server replies are cached in
+F<~/.cache/db-iris-schedule> and F<~/.cache/db-iris-realtime> (or paths
+relative to C<$XDG_CACHE_HOME>, if set). Use this option to disable caching
+altogether. Note that this will significantly decrease db-iris responsiveness,
+especially on mobile networks such as WifiOnICE.
+
=item B<-o>, B<--output> I<outputtypes>
For each result, output I<outputtypes> in addition to the normal time, delay,
@@ -757,13 +844,21 @@ None.
=back
+=head1 RECOMMENDS
+
+=over
+
+=item * Cache::File(3pm)
+
+=back
+
=head1 BUGS AND LIMITATIONS
There are no known bugs at the moment.
=head1 AUTHOR
-Copyright (C) 2013-2019 by Daniel Friesel E<lt>derf@finalrewind.orgE<gt>
+Copyright (C) 2013-2024 by Birte Kristina Friesel E<lt>derf@finalrewind.orgE<gt>
The station data used by this script is provided by DB
Station&Service AG, Europaplatz 1, 10557 Berlin, Germany and available