summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Build.PL3
-rw-r--r--Changelog49
-rw-r--r--Dockerfile4
-rwxr-xr-xbin/efa-m33
-rw-r--r--cpanfile1
m---------ext/transport-apis0
-rw-r--r--lib/Travel/Status/DE/EFA.pm68
-rw-r--r--lib/Travel/Status/DE/EFA/Departure.pm14
-rw-r--r--lib/Travel/Status/DE/EFA/Info.pm4
-rw-r--r--lib/Travel/Status/DE/EFA/Line.pm4
-rw-r--r--lib/Travel/Status/DE/EFA/Services.pm.PL25
-rw-r--r--lib/Travel/Status/DE/EFA/Stop.pm4
-rw-r--r--lib/Travel/Status/DE/EFA/Trip.pm50
-rw-r--r--lib/Travel/Status/DE/VRR.pm4
-rwxr-xr-xscripts/makedeb-docker2
-rwxr-xr-xscripts/makedeb-docker-helper2
16 files changed, 202 insertions, 65 deletions
diff --git a/Build.PL b/Build.PL
index a5eeab4..fb74975 100644
--- a/Build.PL
+++ b/Build.PL
@@ -19,7 +19,7 @@ Module::Build->new(
'Cache::File' => 0,
'GIS::Distance' => 0,
},
- requires => {
+ requires => {
'perl' => '5.10.1',
'Carp' => 0,
'Class::Accessor' => 0,
@@ -30,6 +30,7 @@ Module::Build->new(
'List::Util' => 0,
'LWP::UserAgent' => 0,
'LWP::Protocol::https' => 0,
+ 'URI::Escape' => 0,
},
sign => 1,
meta_merge => {
diff --git a/Changelog b/Changelog
index 5d8a9d9..f462e53 100644
--- a/Changelog
+++ b/Changelog
@@ -1,5 +1,52 @@
-git HEAD
+Travel::Status::DE::VRR 3.18 - Sun Dec 07 2025
+ * Services: Fix VVS / update its API URL
+ (patch by amélie: <https://chaos.social/@aamy/115652192750332957>)
+
+Travel::Status::DE::VRR 3.17 - Wed Oct 15 2025
+
+ * New dependency: URI::Escape
+ * URL-Escape umlauts in name/place parameters sent to EFA backends.
+ This fixes umlaut-related issues in LinzAG and VVO requests.
+ * EFA: Detect "invalid stop" backend errors.
+ * EFA(3pm): Remove efa_encoding, which has been unsupported for a long
+ time already.
+
+Travel::Status::DE::VRR 3.16 - Sat Sep 20 2025
+
+ * Add AVV ("AVV Augsburg", not Aachen) service definition
+
+Travel::Status::DE::VRR 3.15 - Sat Aug 30 2025
+
+ * Trip->polyline: improve handling of trips that pass the same stop
+ multiple times
+
+Travel::Status::DE::VRR 3.14 - Mon Jul 14 2025
+
+ * Fix handling of stops with just a single departure
+
+Travel::Status::DE::VRR 3.13 - Thu Jun 19 2025
+
+ * EFA->new_p: Return $self in case of error so that clients can access
+ place_candidates and name_candidates. This behaviour was already
+ documented, but not implemented.
+
+Travel::Status::DE::VRR 3.12 - Wed Jun 18 2025
+
+ * Departure->id: Include the scheduled departure time. This fixes cases
+ where the trip details (stopseq) endpoint would randomly return
+ yesterday's details or no usable data at all.
+ * efa-m: Trip detail mode now only accepts trip IDs obtained from v3.12+
+
+Travel::Status::DE::VRR 3.11 - Mon Jun 16 2025
+
+ * efa-m: Show occupancy in trip details
+ * Trip->route: Provide occupancy data
+
+Travel::Status::DE::VRR 3.10 - Sun Jun 15 2025
+
+ * Stop: Add is_cancelled accessor
+ * Add BEG, RVV service definitions
* Breaking change: $efa->name_candidates and $efa->place_candidates now
return lists of Travel::Status::DE::EFA::Stop objects rather than
just strings.
diff --git a/Dockerfile b/Dockerfile
index 1b1d2c1..bb1d7d6 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM perl:5.30-slim
+FROM perl:5.40-slim
COPY bin/ /app/bin/
COPY ext/ /app/ext/
@@ -10,7 +10,7 @@ WORKDIR /app
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
- && apt-get -y --no-install-recommends install ca-certificates curl gcc libc6-dev libssl1.1 libssl-dev make zlib1g-dev \
+ && apt-get -y --no-install-recommends install ca-certificates curl gcc libc6-dev libssl3 libssl-dev make zlib1g-dev \
&& cpanm -n --no-man-pages --installdeps . \
&& perl Build.PL \
&& perl Build \
diff --git a/bin/efa-m b/bin/efa-m
index 3367a2f..3dc1ca8 100755
--- a/bin/efa-m
+++ b/bin/efa-m
@@ -4,7 +4,7 @@ use warnings;
use 5.010;
use utf8;
-our $VERSION = '3.09';
+our $VERSION = '3.18';
binmode( STDOUT, ':encoding(utf-8)' );
@@ -16,7 +16,6 @@ use Travel::Status::DE::EFA;
my $service = 'VRR';
my $efa_url;
-my $efa_encoding;
my $use_cache = 1;
my $cache;
my ( $json_output, $raw_json_output );
@@ -99,12 +98,15 @@ if ($use_cache) {
my ( $place, $input, $coord, $stopseq, $stopfinder );
if ( @ARGV == 1 ) {
- if ( $ARGV[0] =~ m{ ^ ([^@]*) @ ([^@]*) [(] ([^)]*) [)] (.*) $ }x ) {
+ if ( $ARGV[0]
+ =~ m{ ^ ([^@]*) @ ([^@]*) [(] ([^T]*) T ([^)]*) [)] (.*) $ }x )
+ {
$stopseq = {
stateless => $1,
stop_id => $2,
date => $3,
- key => $4
+ time => $4,
+ key => $5
};
}
elsif ( $ARGV[0] =~ m{ ^ [?] (?<name> .*) $ }x ) {
@@ -156,8 +158,7 @@ elsif ($service) {
);
exit 1;
}
- $efa_encoding = $service_ref->{encoding};
- $efa_url = undef;
+ $efa_url = undef;
}
sub new_efa {
@@ -168,7 +169,6 @@ sub new_efa {
cache => $cache,
date => $date,
developer_mode => $developer_mode,
- efa_encoding => $efa_encoding,
full_routes => $full_routes,
place => $place,
name => $input,
@@ -353,6 +353,7 @@ sub show_stopseq {
);
say q{};
+ my $occupancy_len = 0;
my $delay_len = 0;
my $inner_delay_len = 0;
my $max_delay = max map { abs( $_->delay // 0 ) } $trip->route;
@@ -360,6 +361,9 @@ sub show_stopseq {
$inner_delay_len = length($max_delay) + 1;
$delay_len = length( sprintf( '(%+d)', $max_delay ) ) + 1;
}
+ if ( first { $_->occupancy } $trip->route ) {
+ $occupancy_len = 2;
+ }
if ( first { $_->is_cancelled } $trip->route and $delay_len < 3 ) {
$delay_len = 3;
@@ -367,7 +371,7 @@ sub show_stopseq {
for my $stop ( $trip->route ) {
printf(
- "%s → %s%${delay_len}s %s (%s) %s\n",
+ "%s → %s%${delay_len}s %-${occupancy_len}s%s (%s) %s\n",
$stop->arr ? $stop->arr->strftime('%H:%M')
: q{ },
$stop->dep ? $stop->dep->strftime('%H:%M')
@@ -378,9 +382,10 @@ sub show_stopseq {
? sprintf( " (%+${inner_delay_len}d)", $stop->delay )
: q{}
),
+ $stop->occupancy ? format_occupancy( $stop->occupancy ) : q{},
$stop->full_name,
- $stop->niveau,
- $stop->platform
+ $stop->niveau // q{?},
+ $stop->platform // q{}
);
}
}
@@ -585,14 +590,14 @@ if ( my $err = $efa->errstr ) {
if ($json_output) {
if ($stopseq) {
- say JSON->new->convert_blessed->encode( $efa->result );
+ say JSON->new->canonical->convert_blessed->encode( $efa->result );
}
else {
- say JSON->new->convert_blessed->encode( [ $efa->results ] );
+ say JSON->new->canonical->convert_blessed->encode( [ $efa->results ] );
}
}
elsif ($raw_json_output) {
- say JSON->new->convert_blessed->encode( $efa->{response} );
+ say JSON->new->canonical->convert_blessed->encode( $efa->{response} );
}
elsif ($coord) {
show_coord();
@@ -628,7 +633,7 @@ B<efa-m> [B<-s> I<service>] I<tripid>
=head1 VERSION
-version 3.09
+version 3.18
=head1 DESCRIPTION
diff --git a/cpanfile b/cpanfile
index c88d11b..d3c5113 100644
--- a/cpanfile
+++ b/cpanfile
@@ -7,6 +7,7 @@ requires 'JSON';
requires 'List::Util';
requires 'LWP::UserAgent';
requires 'LWP::Protocol::https';
+requires 'URI::Escape';
on test => sub {
requires 'File::Slurp';
diff --git a/ext/transport-apis b/ext/transport-apis
-Subproject ef57e8b8158653b4f5f400fff109a417e9117c5
+Subproject a8cd43ae408009920a62e2c3b8c6ca0d89c3a81
diff --git a/lib/Travel/Status/DE/EFA.pm b/lib/Travel/Status/DE/EFA.pm
index 29dbf5b..7edb8e8 100644
--- a/lib/Travel/Status/DE/EFA.pm
+++ b/lib/Travel/Status/DE/EFA.pm
@@ -5,12 +5,13 @@ use warnings;
use 5.010;
use utf8;
-our $VERSION = '3.09';
+our $VERSION = '3.18';
use Carp qw(confess cluck);
use DateTime;
use DateTime::Format::Strptime;
use Encode qw(encode);
+use IO::Socket::SSL;
use JSON;
use Travel::Status::DE::EFA::Departure;
use Travel::Status::DE::EFA::Info;
@@ -19,6 +20,7 @@ use Travel::Status::DE::EFA::Services;
use Travel::Status::DE::EFA::Stop;
use Travel::Status::DE::EFA::Trip;
use LWP::UserAgent;
+use URI::Escape qw(uri_escape);
sub new_p {
my ( $class, %opt ) = @_;
@@ -42,7 +44,8 @@ sub new_p {
say $self->{json}->pretty->encode( $self->{response} );
}
- $self->check_for_ambiguous();
+ $self->check_for_ambiguous;
+ $self->check_for_error;
if ( $self->{errstr} ) {
$promise->reject( $self->{errstr}, $self );
@@ -54,7 +57,7 @@ sub new_p {
}
)->catch(
sub {
- my ($err) = @_;
+ my ( $err, $self ) = @_;
$promise->reject($err);
return;
}
@@ -66,6 +69,8 @@ sub new_p {
sub new {
my ( $class, %opt ) = @_;
+ my $encoding = 'UTF-8';
+ my $tls_insecure = 0;
$opt{timeout} //= 10;
if ( $opt{timeout} <= 0 ) {
delete $opt{timeout};
@@ -105,6 +110,12 @@ sub new {
$opt{efa_url} .= '/XML_DM_REQUEST';
}
$opt{time_zone} //= $service->{time_zone};
+ if ( not $service->{tls_verify} ) {
+ $tls_insecure = 1;
+ }
+ if ( $service->{encoding} ) {
+ $encoding = $service->{encoding};
+ }
}
}
@@ -160,6 +171,7 @@ sub new {
developer_mode => $opt{developer_mode},
efa_url => $opt{efa_url},
service => $opt{service},
+ tls_insecure => $tls_insecure,
strp_stopseq => DateTime::Format::Strptime->new(
pattern => '%Y%m%d %H:%M',
time_zone => $opt{time_zone},
@@ -206,6 +218,7 @@ sub new {
stop => $opt{stopseq}{stop_id},
tripCode => $opt{stopseq}{key},
date => $opt{stopseq}{date},
+ time => $opt{stopseq}{time},
coordOutputFormat => 'WGS84[DD.DDDDD]',
outputFormat => 'rapidJson',
useRealtime => '1',
@@ -224,14 +237,16 @@ sub new {
itdDateYear => $dt->year,
itdTimeHour => $dt->hour,
itdTimeMinute => $dt->minute,
- name_dm => encode( 'UTF-8', $opt{name} ),
+ name_dm =>
+ uri_escape( encode( $encoding, $opt{name} ), '^A-Za-z0-9-._~ ' ),
};
}
if ( $opt{place} ) {
$self->{post}{placeInfo_dm} = 'invalid';
$self->{post}{placeState_dm} = 'empty';
- $self->{post}{place_dm} = encode( 'UTF-8', $opt{place} );
+ $self->{post}{place_dm}
+ = uri_escape( encode( $encoding, $opt{place} ), '^A-Za-z0-9-._~ ' );
}
if ( $opt{full_routes} ) {
@@ -247,6 +262,12 @@ sub new {
}
else {
my %lwp_options = %{ $opt{lwp_options} // { timeout => 10 } };
+ if ($tls_insecure) {
+ $lwp_options{ssl_opts}{SSL_verify_mode}
+ = IO::Socket::SSL::SSL_VERIFY_NONE;
+ $lwp_options{ssl_opts}{verify_hostname} = 0;
+ }
+
$self->{ua} = LWP::UserAgent->new(%lwp_options);
$self->{ua}->env_proxy;
}
@@ -284,7 +305,8 @@ sub new {
say $self->{json}->pretty->encode( $self->{response} );
}
- $self->check_for_ambiguous();
+ $self->check_for_ambiguous;
+ $self->check_for_error;
return $self;
}
@@ -351,6 +373,10 @@ sub post_with_cache_p {
say ' cache miss';
}
+ if ( $self->{tls_insecure} ) {
+ $self->{ua}->insecure(1);
+ }
+
$self->{ua}->post_p( $url, form => $self->{post} )->then(
sub {
my ($tx) = @_;
@@ -401,6 +427,23 @@ sub place_candidates {
return;
}
+sub check_for_error {
+ my ($self) = @_;
+
+ my $json = $self->{response};
+
+ my %kv;
+ for my $m ( @{ $json->{dm}{message} // [] } ) {
+ $kv{ $m->{name} } = $m->{value};
+ }
+
+ if ( $kv{error} ) {
+ $self->{errstr} = "Backend error: $kv{error}";
+ }
+
+ return;
+}
+
sub check_for_ambiguous {
my ($self) = @_;
@@ -627,6 +670,11 @@ sub results_dm {
my ($self) = @_;
my $json = $self->{response};
+ # Oh EFA, you so silly
+ if ( $json->{departureList} and ref( $json->{departureList} ) eq 'HASH' ) {
+ $json->{departureList} = [ $json->{departureList}{departure} ];
+ }
+
my @results;
for my $departure ( @{ $json->{departureList} // [] } ) {
push(
@@ -702,7 +750,7 @@ Travel::Status::DE::EFA - unofficial EFA departure monitor
=head1 VERSION
-version 3.09
+version 3.18
=head1 DESCRIPTION
@@ -766,12 +814,6 @@ B<stop> (stop/station name).
Request departures for the date/time specified by I<DateTime object>.
Default: now.
-=item B<efa_encoding> => I<encoding>
-
-Some EFA servers do not correctly specify their response encoding. If you
-observe encoding issues, you can manually specify it here. Example:
-iso-8859-15.
-
=item B<full_routes> => B<0>|B<1>
If true: Request full routes for all departures from the backend. This
diff --git a/lib/Travel/Status/DE/EFA/Departure.pm b/lib/Travel/Status/DE/EFA/Departure.pm
index 93b8c0c..9527a58 100644
--- a/lib/Travel/Status/DE/EFA/Departure.pm
+++ b/lib/Travel/Status/DE/EFA/Departure.pm
@@ -10,7 +10,7 @@ use Travel::Status::DE::EFA::Stop;
use parent 'Class::Accessor';
-our $VERSION = '3.09';
+our $VERSION = '3.18';
Travel::Status::DE::EFA::Departure->mk_ro_accessors(
qw(countdown datetime delay destination is_cancelled key line lineref mot
@@ -70,7 +70,8 @@ sub new {
key => $departure->{servingLine}{key},
stateless => $departure->{servingLine}{stateless},
stop_id_num => $departure->{stopID},
- line => $departure->{servingLine}{symbol},
+ line => $departure->{servingLine}{symbol}
+ || $departure->{servingLine}{number},
train_type => $departure->{servingLine}{trainType},
train_name => $departure->{servingLine}{trainName},
train_no => $departure->{servingLine}{trainNum},
@@ -177,10 +178,11 @@ sub id {
return $self->{id} = sprintf( '%s@%d(%s)%d',
$self->stateless =~ s{ }{}gr,
- scalar $self->route_pre
- ? ( $self->route_pre )[0]->id_num
+ scalar $self->route_pre ? ( $self->route_pre )[0]->id_num
: $self->stop_id_num,
- $self->sched_datetime->strftime('%Y%m%d'),
+ ( scalar $self->route_pre and ( $self->route_pre )[0]->sched_dep )
+ ? ( $self->route_pre )[0]->sched_dep->strftime('%Y%m%dT%H:%M')
+ : $self->sched_datetime->strftime('%Y%m%dT%H:%M'),
$self->key );
}
@@ -303,7 +305,7 @@ departure received by Travel::Status::DE::EFA
=head1 VERSION
-version 3.09
+version 3.18
=head1 DESCRIPTION
diff --git a/lib/Travel/Status/DE/EFA/Info.pm b/lib/Travel/Status/DE/EFA/Info.pm
index 9c5e009..a2328dd 100644
--- a/lib/Travel/Status/DE/EFA/Info.pm
+++ b/lib/Travel/Status/DE/EFA/Info.pm
@@ -6,7 +6,7 @@ use 5.010;
use parent 'Class::Accessor';
-our $VERSION = '3.09';
+our $VERSION = '3.18';
Travel::Status::DE::EFA::Info->mk_ro_accessors(
qw(link_url link_text subject content subtitle additional_text));
@@ -58,7 +58,7 @@ Travel::Status::DE::EFA::Info - Information about a public transit stop
=head1 VERSION
-version 3.09
+version 3.18
=head1 DESCRIPTION
diff --git a/lib/Travel/Status/DE/EFA/Line.pm b/lib/Travel/Status/DE/EFA/Line.pm
index dff9db0..180e6b5 100644
--- a/lib/Travel/Status/DE/EFA/Line.pm
+++ b/lib/Travel/Status/DE/EFA/Line.pm
@@ -6,7 +6,7 @@ use 5.010;
use parent 'Class::Accessor';
-our $VERSION = '3.09';
+our $VERSION = '3.18';
Travel::Status::DE::EFA::Line->mk_ro_accessors(
qw(direction mot name number operator route type valid));
@@ -57,7 +57,7 @@ requested station
=head1 VERSION
-version 3.09
+version 3.18
=head1 DESCRIPTION
diff --git a/lib/Travel/Status/DE/EFA/Services.pm.PL b/lib/Travel/Status/DE/EFA/Services.pm.PL
index 39e0e6b..84701f5 100644
--- a/lib/Travel/Status/DE/EFA/Services.pm.PL
+++ b/lib/Travel/Status/DE/EFA/Services.pm.PL
@@ -17,12 +17,13 @@ sub load_instance {
my $data = $json->decode(
scalar read_file("ext/transport-apis/data/${path}-efa.json") );
my %ret = (
- name => $opt{name} // $data->{name} =~ s{ *[(][^)]+[)]}{}r,
- homepage => $data->{attribution}{homepage},
- url => $opt{url} // $data->{options}{endpoint} =~ s{ / $ }{}rx,
- time_zone => $data->{timezone},
- languages => $data->{supportedLanguages},
- coverage => {
+ name => $opt{name} // $data->{name} =~ s{ *[(][^)]+[)]}{}r,
+ homepage => $data->{attribution}{homepage},
+ url => $opt{url} // $data->{options}{endpoint} =~ s{ / $ }{}rx,
+ time_zone => $data->{timezone},
+ languages => $data->{supportedLanguages},
+ tls_verify => $opt{tls_verify} // 1,
+ coverage => {
area => $data->{coverage}{realtimeCoverage}{area},
regions => $data->{coverage}{realtimeCoverage}{region} // []
},
@@ -35,6 +36,11 @@ sub load_instance {
# VRT: Encoding issues
# VVSt: NXDOMAIN
my %efa_instance = (
+ AVV => {
+ url => 'https://fahrtauskunft.avv-augsburg.de/efa',
+ name => 'Augsburger Verkehrs- & Tarifverbund',
+ tls_verify => 0,
+ },
BEG => {
url => 'https://bahnland-bayern.de/efa',
name => 'Bayerische Eisenbahngesellschaft',
@@ -50,9 +56,8 @@ my %efa_instance = (
},
KVV => { load_instance('de/kvv') },
LinzAG => {
- url => 'https://www.linzag.at/static',
- name => 'Linz AG',
- encoding => 'iso-8859-15',
+ url => 'https://www.linzag.at/static',
+ name => 'Linz AG',
},
MVV => { load_instance('de/mvv') },
NVBW => {
@@ -108,7 +113,7 @@ use warnings;
use 5.014;
use utf8;
-our $VERSION = '3.09';
+our $VERSION = '3.18';
# Most of these have been adapted from
# <https://github.com/public-transport/transport-apis> and
diff --git a/lib/Travel/Status/DE/EFA/Stop.pm b/lib/Travel/Status/DE/EFA/Stop.pm
index 8cd7186..4111984 100644
--- a/lib/Travel/Status/DE/EFA/Stop.pm
+++ b/lib/Travel/Status/DE/EFA/Stop.pm
@@ -6,7 +6,7 @@ use 5.010;
use parent 'Class::Accessor';
-our $VERSION = '3.09';
+our $VERSION = '3.18';
Travel::Status::DE::EFA::Stop->mk_ro_accessors(
qw(sched_arr rt_arr arr arr_delay
@@ -93,7 +93,7 @@ in a Travel::Status::DE::EFA::Result's route
=head1 VERSION
-version 3.09
+version 3.18
=head1 DESCRIPTION
diff --git a/lib/Travel/Status/DE/EFA/Trip.pm b/lib/Travel/Status/DE/EFA/Trip.pm
index 1e67a07..115d21d 100644
--- a/lib/Travel/Status/DE/EFA/Trip.pm
+++ b/lib/Travel/Status/DE/EFA/Trip.pm
@@ -9,7 +9,7 @@ use Travel::Status::DE::EFA::Stop;
use parent 'Class::Accessor';
-our $VERSION = '3.09';
+our $VERSION = '3.18';
Travel::Status::DE::EFA::Trip->mk_ro_accessors(
qw(operator product product_class name line number type id dest_name dest_id)
@@ -20,13 +20,15 @@ sub new {
my $json = $conf{json}{transportation} // $conf{json}{leg}{transportation};
+ #say $json->{disassembledName} . ' <-> ' . $json->{number};
+
my $ref = {
operator => $json->{operator}{name},
product => $json->{product}{name},
product_class => $json->{product}{class},
polyline_raw => $conf{json}{leg}{coords},
name => $json->{name},
- line => $json->{disassembledName},
+ line => $json->{disassembledName} // $json->{number},
number => $json->{properties}{trainNumber},
type => $json->{properties}{trainType} // $json->{product}{name},
id => $json->{id},
@@ -76,8 +78,19 @@ sub polyline {
$distance = GIS::Distance->new;
};
+ # Ggf. sollte die Abbildung andersrum laufen: Im zweiten Schritt durch die
+ # Polyline iterieren und Stops zuordnen (d.h. polyline_i als Key); bei
+ # Bedarf Polyline-Indexe duplizieren. Lässt sich wunderbar an der Linie
+ # 101/106 in Essen testen (3x Helenenstr, davon 2x am Anfang und 1x
+ # mittendrin).
+
if ($distance) {
my %min_dist;
+
+ # A single trip may pass the same stop multiple times, meaning that
+ # stop IDs alone are not guaranteed to be unique. So we need to use a
+ # stop's index in the trip's route as key in addition to the stop's ID.
+ my $route_i = 0;
for my $stop ( $self->route ) {
for my $polyline_index ( 0 .. $#{ $self->{polyline} } ) {
my $pl = $self->{polyline}[$polyline_index];
@@ -86,21 +99,41 @@ sub polyline {
$stop->{latlon}[1],
$pl->{lat}, $pl->{lon}
);
- if ( not $min_dist{ $stop->{id_code} }
- or $min_dist{ $stop->{id_code} }{dist} > $dist )
+ my $key = $route_i . ';' . $stop->{id_code};
+ if ( not $min_dist{$key}
+ or $min_dist{$key}{dist} > $dist )
{
- $min_dist{ $stop->{id_code} } = {
+ $min_dist{$key} = {
dist => $dist,
index => $polyline_index,
};
}
}
+ $route_i += 1;
}
+ $route_i = 0;
for my $stop ( $self->route ) {
- if ( $min_dist{ $stop->{id_code} } ) {
- $self->{polyline}[ $min_dist{ $stop->{id_code} }{index} ]{stop}
+ my $key = $route_i . ';' . $stop->{id_code};
+ if ( $min_dist{$key} ) {
+ if ( defined $self->{polyline}[ $min_dist{$key}{index} ]{stop} )
+ {
+ warn(
+"$key: overwriting stop ref at $min_dist{$key}{index} with $key"
+ );
+
+ # XXX experimental and untested
+ # one polyline entry maps to multiple stops → duplicate it; insert $stop after the already-present entry
+ #$min_dist{$key}{index} += 1;
+ #splice(
+ # @{ $self->{polyline} },
+ # $min_dist{$key}{index},
+ # 0, { %{ $self->{polyline}[ $min_dist{$key}{index} ] } }
+ #);
+ }
+ $self->{polyline}[ $min_dist{$key}{index} ]{stop}
= $stop;
}
+ $route_i += 1;
}
}
@@ -152,6 +185,7 @@ sub route {
sched_dep => $self->parse_dt( $stop->{departureTimePlanned} ),
rt_arr => $self->parse_dt( $stop->{arrivalTimeEstimated} ),
rt_dep => $self->parse_dt( $stop->{departureTimeEstimated} ),
+ occupancy => $stop->{properties}{occupancy},
is_cancelled => $stop->{isCancelled},
latlon => $stop->{coord},
full_name => $name_full,
@@ -204,7 +238,7 @@ trip
=head1 VERSION
-version 3.09
+version 3.18
=head1 DESCRIPTION
diff --git a/lib/Travel/Status/DE/VRR.pm b/lib/Travel/Status/DE/VRR.pm
index d52944c..3ff2cc6 100644
--- a/lib/Travel/Status/DE/VRR.pm
+++ b/lib/Travel/Status/DE/VRR.pm
@@ -4,7 +4,7 @@ use strict;
use warnings;
use 5.010;
-our $VERSION = '3.09';
+our $VERSION = '3.18';
use parent 'Travel::Status::DE::EFA';
@@ -43,7 +43,7 @@ Travel::Status::DE::VRR - unofficial VRR departure monitor.
=head1 VERSION
-version 3.09
+version 3.18
=head1 DESCRIPTION
diff --git a/scripts/makedeb-docker b/scripts/makedeb-docker
index 6c06971..ceba8f8 100755
--- a/scripts/makedeb-docker
+++ b/scripts/makedeb-docker
@@ -6,6 +6,6 @@ docker run --rm -v "${PWD}:/orig:ro" -v "${PWD}/scripts:/scripts:ro" \
-v "${PWD}/out:/out" -e USER=$(id -u) -e GROUP=$(id -g) \
-e "DEBEMAIL=${DEBEMAIL}" -e "DEBFULLNAME=${DEBFULLNAME}" \
-e "LOGNAME=${LOGNAME}" -e "VERSION=$(git describe --dirty)-1" \
- debian:buster /scripts/makedeb-docker-helper
+ debian:bookworm /scripts/makedeb-docker-helper
echo "Debian package has been written to $(pwd)/out"
diff --git a/scripts/makedeb-docker-helper b/scripts/makedeb-docker-helper
index f6f309d..bbfdd1e 100755
--- a/scripts/makedeb-docker-helper
+++ b/scripts/makedeb-docker-helper
@@ -10,7 +10,7 @@ apt-get -y install \
apt-file dh-make-perl libmodule-build-perl \
libclass-accessor-perl libdatetime-perl libdatetime-format-strptime-perl \
libexception-class-perl libfile-slurp-perl libwww-perl \
- libjson-perl libjson-xs-perl \
+ libjson-perl libjson-xs-perl liburi-perl \
libtest-compile-perl libtest-pod-perl \
libtest-fatal-perl libtest-simple-perl