summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBirte Kristina Friesel <derf@finalrewind.org>2024-10-18 19:17:10 +0200
committerBirte Kristina Friesel <derf@finalrewind.org>2024-10-18 19:17:10 +0200
commit4dda0fd251e6c82c73cf7ae280caf1ae94d3012e (patch)
treef0301daaac4af07af8e5507d08cce8f1f05c0397
parentd8ffb5163a0f4bf543e5b026879cfff8ada0ab52 (diff)
Add preliminary EFA support
-rw-r--r--lib/DBInfoscreen/Controller/Map.pm8
-rw-r--r--lib/DBInfoscreen/Controller/Stationboard.pm260
-rw-r--r--lib/DBInfoscreen/Helper/EFA.pm13
-rw-r--r--public/static/js/geostop.js9
-rw-r--r--public/static/js/map-refresh.js2
-rw-r--r--templates/_train_details.html.ep8
-rw-r--r--templates/layouts/app.html.ep3
-rw-r--r--templates/select_backend.html.ep11
8 files changed, 299 insertions, 15 deletions
diff --git a/lib/DBInfoscreen/Controller/Map.pm b/lib/DBInfoscreen/Controller/Map.pm
index f3f3f16..ba63d92 100644
--- a/lib/DBInfoscreen/Controller/Map.pm
+++ b/lib/DBInfoscreen/Controller/Map.pm
@@ -12,6 +12,7 @@ use DateTime;
use DateTime::Format::Strptime;
use GIS::Distance;
use List::Util qw();
+use Travel::Status::DE::EFA;
my $strp = DateTime::Format::Strptime->new(
pattern => '%Y-%m-%dT%H:%M:%S%z',
@@ -537,12 +538,15 @@ sub ajax_route {
sub coverage {
my ($self) = @_;
- my $backend = $self->stash('backend');
+ my $backend = lc( $self->stash('backend') );
my $service = $self->stash('service');
my $coverage = {};
- if ( $backend eq 'HAFAS' ) {
+ if ( $backend eq 'efa' ) {
+ $coverage = $self->efa->get_coverage($service);
+ }
+ elsif ( $backend eq 'hafas' ) {
$coverage = $self->hafas->get_coverage($service);
}
diff --git a/lib/DBInfoscreen/Controller/Stationboard.pm b/lib/DBInfoscreen/Controller/Stationboard.pm
index 34a9efd..653c914 100644
--- a/lib/DBInfoscreen/Controller/Stationboard.pm
+++ b/lib/DBInfoscreen/Controller/Stationboard.pm
@@ -1220,11 +1220,202 @@ sub station_train_details {
)->wait;
}
+sub train_details_efa {
+ my ($self) = @_;
+ my $trip_id = $self->stash('train');
+
+ my $stopseq;
+ if ( $trip_id =~ m{ ^ ([^@]*) @ ([^@]*) [(] ([^)]*) [)] (.*) $ }x ) {
+ $stopseq = {
+ stateless => $1,
+ stop_id => $2,
+ date => $3,
+ key => $4
+ };
+ }
+ else {
+ $self->render( 'not_found', status => 404 );
+ return;
+ }
+
+ $self->render_later;
+
+ Travel::Status::DE::EFA->new_p(
+ service => $self->param('efa'),
+ stopseq => $stopseq,
+ cache => $self->app->cache_iris_rt,
+ lwp_options => {
+ timeout => 10,
+ agent => 'dbf.finalrewind.org/2'
+ },
+ promise => 'Mojo::Promise',
+ user_agent => Mojo::UserAgent->new,
+ )->then(
+ sub {
+ my ($efa) = @_;
+ my $trip = $efa->result;
+
+ my $now = DateTime->now( time_zone => 'Europe/Berlin' );
+ my $res = {
+ trip_id => $trip_id,
+ train_type => $trip->type,
+ train_line => $trip->line,
+ train_no => $trip->number,
+ origin => ( $trip->route )[0]->full_name,
+ destination => ( $trip->route )[-1]->full_name,
+ operators => [ $trip->operator ],
+ linetype => lc( $trip->product ) =~ tr{a-z}{}cdr,
+ route_pre_diff => [],
+ route_post_diff => [],
+ moreinfo => [],
+ replaced_by => [],
+ replacement_for => [],
+ };
+
+ if ( $res->{linetype} =~ m{strab|stra.?enbahn} ) {
+ $res->{linetype} = 'tram';
+ }
+ elsif ( $res->{linetype} =~ m{bus} ) {
+ $res->{linetype} = 'bus';
+ }
+
+ my $station_is_past = 1;
+ for my $stop ( $trip->route ) {
+
+ push(
+ @{ $res->{route_post_diff} },
+ {
+ name => $stop->full_name,
+ id => $stop->stop_id,
+ sched_arr => $stop->sched_arr,
+ sched_dep => $stop->sched_dep,
+ rt_arr => $stop->rt_arr,
+ rt_dep => $stop->rt_dep,
+ platform => $stop->platform,
+ }
+ );
+ if (
+ $station_is_past
+ and $now->epoch < (
+ $res->{route_post_diff}[-1]{rt_arr}
+ // $res->{route_post_diff}[-1]{rt_dep}
+ // $res->{route_post_diff}[-1]{sched_arr}
+ // $res->{route_post_diff}[-1]{sched_dep} // $now
+ )->epoch
+ )
+ {
+ $station_is_past = 0;
+ }
+ $res->{route_post_diff}[-1]{isPast} = $station_is_past;
+ }
+
+ if ( my $req_id = $self->param('highlight') ) {
+ my $split;
+ for my $i ( 0 .. $#{ $res->{route_post_diff} } ) {
+ if ( $res->{route_post_diff}[$i]{id} eq $req_id ) {
+ $split = $i;
+ last;
+ }
+ }
+ if ( defined $split ) {
+ $self->stash(
+ station_name => $res->{route_post_diff}[$split]{name} );
+ for my $i ( 0 .. $split - 1 ) {
+ push(
+ @{ $res->{route_pre_diff} },
+ shift( @{ $res->{route_post_diff} } )
+ );
+ }
+ my $station_info = shift( @{ $res->{route_post_diff} } );
+ $res->{eva} = $station_info->{eva};
+ if ( $station_info->{sched_arr} ) {
+ $res->{sched_arrival}
+ = $station_info->{sched_arr}->strftime('%H:%M');
+ }
+ if ( $station_info->{rt_arr} ) {
+ $res->{arrival}
+ = $station_info->{rt_arr}->strftime('%H:%M');
+ }
+ if ( $station_info->{sched_dep} ) {
+ $res->{sched_departure}
+ = $station_info->{sched_dep}->strftime('%H:%M');
+ }
+ if ( $station_info->{rt_dep} ) {
+ $res->{departure}
+ = $station_info->{rt_dep}->strftime('%H:%M');
+ }
+ $res->{arrival_is_cancelled}
+ = $station_info->{arr_cancelled};
+ $res->{departure_is_cancelled}
+ = $station_info->{dep_cancelled};
+ $res->{is_cancelled} = $res->{arrival_is_cancelled}
+ || $res->{arrival_is_cancelled};
+ $res->{tz_offset} = $station_info->{tz_offset};
+ $res->{local_dt_da} = $station_info->{local_dt_da};
+ $res->{local_sched_arr} = $station_info->{local_sched_arr};
+ $res->{local_sched_dep} = $station_info->{local_sched_dep};
+ $res->{is_annotated} = $station_info->{is_annotated};
+ $res->{prod_name} = $station_info->{prod_name};
+ $res->{direction} = $station_info->{direction};
+ $res->{operator} = $station_info->{operator};
+ $res->{platform} = $station_info->{platform};
+ $res->{scheduled_platform}
+ = $station_info->{sched_platform};
+ }
+ }
+
+ $self->respond_to(
+ json => {
+ json => {
+ journey => $trip,
+ },
+ },
+ any => {
+ template => $self->param('ajax')
+ ? '_train_details'
+ : 'train_details',
+ description => sprintf(
+ '%s %s%s%s nach %s',
+ $res->{train_type},
+ $res->{train_line} // $res->{train_no},
+ $res->{origin} ? ' von ' : q{},
+ $res->{origin} // q{},
+ $res->{destination} // 'unbekannt'
+ ),
+ departure => $res,
+ linetype => $res->{linetype},
+ dt_now => DateTime->now( time_zone => 'Europe/Berlin' ),
+ },
+ );
+ }
+ )->catch(
+ sub {
+ my ($e) = @_;
+ $self->respond_to(
+ json => {
+ json => {
+ error => $e,
+ },
+ status => 500,
+ },
+ any => {
+ template => 'exception',
+ message => $e,
+ exception => undef,
+ snapshot => {},
+ status => 500,
+ },
+ );
+ }
+ )->wait;
+}
+
# /z/:train
sub train_details {
my ($self) = @_;
my $train = $self->stash('train');
my $hafas = $self->param('hafas');
+ my $efa = $self->param('efa');
# TODO error handling
@@ -1235,6 +1426,10 @@ sub train_details {
$self->stash( departures => [] );
$self->stash( title => 'DBF' );
+ if ($efa) {
+ return $self->train_details_efa;
+ }
+
my $res = {
train_type => undef,
train_line => undef,
@@ -1570,7 +1765,7 @@ sub handle_efa {
$template,
description => "Abfahrtstafel $station_name",
departures => \@departures,
- station => $efa->stop->name,,
+ station => $efa->stop->name,
version => $self->config->{version},
title => $efa->stop->name // $station_name,
refresh_interval => $template eq 'app' ? 0 : 120,
@@ -2103,6 +2298,7 @@ sub stations_by_coordinates {
my $lon = $self->param('lon');
my $lat = $self->param('lat');
+ my $efa = $self->param('efa');
my $hafas = $self->param('hafas');
if ( not $lon or not $lat ) {
@@ -2120,6 +2316,46 @@ sub stations_by_coordinates {
$self->render_later;
+ if ($efa) {
+ Travel::Status::DE::EFA->new_p(
+ promise => 'Mojo::Promise',
+ user_agent => $self->ua,
+ service => $efa,
+ coord => {
+ lat => $lat,
+ lon => $lon
+ }
+ )->then(
+ sub {
+ my ($efa) = @_;
+ my @efa = map {
+ {
+ name => $_->full_name,
+ eva => $_->id,
+ distance => $_->distance_m / 1000,
+ efa => $efa,
+ }
+ } $efa->results;
+ $self->render(
+ json => {
+ candidates => [@efa],
+ }
+ );
+ }
+ )->catch(
+ sub {
+ my ($err) = @_;
+ $self->render(
+ json => {
+ candidates => [],
+ warning => $err,
+ }
+ );
+ }
+ )->wait;
+ return;
+ }
+
my @iris = map {
{
ds100 => $_->[0][0],
@@ -2219,6 +2455,24 @@ sub backend_list {
}
);
+ for my $backend ( Travel::Status::DE::EFA::get_services() ) {
+ push(
+ @backends,
+ {
+ name => $backend->{name},
+ shortname => $backend->{shortname},
+ homepage => $backend->{homepage},
+ regions => [
+ map { $place_map{$_} // $_ }
+ @{ $backend->{coverage}{regions} }
+ ],
+ has_area => $backend->{coverage}{area} ? 1 : 0,
+ type => 'EFA',
+ efa => 1,
+ }
+ );
+ }
+
for my $backend ( Travel::Status::DE::HAFAS::get_services() ) {
push(
@backends,
@@ -2292,6 +2546,10 @@ sub redirect_to_station {
$params = $params->to_string;
$self->redirect_to("/z/${input}?${params}");
}
+ elsif ( $params->param('efa') ) {
+ $params = $params->to_string;
+ $self->redirect_to("/${input}?${params}");
+ }
elsif ( $params->param('hafas') and $params->param('hafas') ne '1' ) {
$params = $params->to_string;
$self->redirect_to("/${input}?${params}");
diff --git a/lib/DBInfoscreen/Helper/EFA.pm b/lib/DBInfoscreen/Helper/EFA.pm
index 4e81bc3..13944cd 100644
--- a/lib/DBInfoscreen/Helper/EFA.pm
+++ b/lib/DBInfoscreen/Helper/EFA.pm
@@ -13,6 +13,7 @@ use Encode qw(decode encode);
use Mojo::JSON qw(decode_json);
use Mojo::Promise;
use Mojo::Util qw(url_escape);
+use Travel::Status::DE::EFA;
sub new {
my ( $class, %opt ) = @_;
@@ -28,6 +29,18 @@ sub new {
}
+sub get_coverage {
+ my ( $self, $service ) = @_;
+
+ my $service_definition = Travel::Status::DE::EFA::get_service($service);
+
+ if ( not $service_definition ) {
+ return {};
+ }
+
+ return $service_definition->{coverage}{area} // {};
+}
+
sub get_json_p {
my ( $self, $cache, $url ) = @_;
diff --git a/public/static/js/geostop.js b/public/static/js/geostop.js
index fa2d6f1..69bb607 100644
--- a/public/static/js/geostop.js
+++ b/public/static/js/geostop.js
@@ -39,10 +39,13 @@ $(function() {
const eva = candidate.eva,
name = candidate.name,
distance = candidate.distance.toFixed(1),
+ efa = candidate.efa,
hafas = candidate.hafas;
const stationlink = $(document.createElement('a'));
- if (hafas) {
+ if (efa) {
+ stationlink.attr('href', eva + '?efa=' + efa);
+ } else if (hafas) {
stationlink.attr('href', eva + '?hafas=' + hafas);
} else {
stationlink.attr('href', eva);
@@ -55,7 +58,7 @@ $(function() {
const icon = $(document.createElement('i'));
icon.attr('class', 'material-icons');
- icon.text(hafas ? 'directions' : 'train');
+ icon.text((hafas || efa) ? 'directions' : 'train');
stationlink.append(icon);
stationlink.append(distancenode);
@@ -66,7 +69,7 @@ $(function() {
const processLocation = function(loc) {
const param = new URLSearchParams(window.location.search);
- $.post('/_geolocation', {lon: loc.coords.longitude, lat: loc.coords.latitude, hafas: param.get('hafas')}, processResult).fail(function(jqXHR, textStatus, errorThrown) {
+ $.post('/_geolocation', {lon: loc.coords.longitude, lat: loc.coords.latitude, efa: param.get('efa'), hafas: param.get('hafas')}, processResult).fail(function(jqXHR, textStatus, errorThrown) {
removeStatus();
showError("Netzwerkfehler: ", textStatus, errorThrown);
});
diff --git a/public/static/js/map-refresh.js b/public/static/js/map-refresh.js
index 0389323..1d8453a 100644
--- a/public/static/js/map-refresh.js
+++ b/public/static/js/map-refresh.js
@@ -69,7 +69,7 @@ function dbf_anim_fine() {
function dbf_map_reload() {
const param = new URLSearchParams(window.location.search);
- $.get('/_ajax_mapinfo/' + j_reqid + '?hafas=' + param.get('hafas'), function(data) {
+ $.get('/_ajax_mapinfo/' + j_reqid + '?efa=' + param.get('efa') + '&amp;hafas=' + param.get('hafas'), function(data) {
$('#infobox').html(data);
dbf_map_parse();
setTimeout(dbf_map_reload, 61000);
diff --git a/templates/_train_details.html.ep b/templates/_train_details.html.ep
index a02336b..dab05d0 100644
--- a/templates/_train_details.html.ep
+++ b/templates/_train_details.html.ep
@@ -2,8 +2,8 @@
<div>
% if ($departure->{train_no} or $departure->{train_line}) {
<span class="train-line <%= $linetype %>"><%= $departure->{train_type} %>
-
- <%= $departure->{train_line} // $departure->{train_no} %></span>
+ %= $departure->{train_line} // $departure->{train_no}
+ </span>
<span class="train-no"><%= $departure->{train_line} ? $departure->{train_no} : q{} %></span>
% }
</div>
@@ -145,10 +145,10 @@
<div class="verbose">
% if ($departure->{trip_id}) {
% if (stash('station_name')) {
- <a class="smallbutton" href="/map/<%= $departure->{trip_id} =~ s{#}{%23}gr %>/<%= $departure->{train_line} || 0 %>?from=<%= stash('station_name') %>&amp;hafas=<%= param('hafas') // q{} %>"><i class="material-icons" aria-hidden="true">map</i> Karte</a>
+ <a class="smallbutton" href="/map/<%= $departure->{trip_id} =~ s{#}{%23}gr %>/<%= $departure->{train_line} || 0 %>?from=<%= stash('station_name') %>&amp;efa=<%= param('efa') // q{} %>&amp;hafas=<%= param('hafas') // q{} %>"><i class="material-icons" aria-hidden="true">map</i> Karte</a>
% }
% else {
- <a class="smallbutton" href="/map/<%= $departure->{trip_id} =~ s{#}{%23}gr %>/<%= $departure->{train_line} || 0 %>?hafas=<%= param('hafas') // q{} %>"><i class="material-icons" aria-hidden="true">map</i> Karte</a>
+ <a class="smallbutton" href="/map/<%= $departure->{trip_id} =~ s{#}{%23}gr %>/<%= $departure->{train_line} || 0 %>?efa=<%= param('efa') // q{} %>&amp;hafas=<%= param('hafas') // q{} %>"><i class="material-icons" aria-hidden="true">map</i> Karte</a>
% }
% }
% if ($departure->{wr_link}) {
diff --git a/templates/layouts/app.html.ep b/templates/layouts/app.html.ep
index 685f31a..cc13143 100644
--- a/templates/layouts/app.html.ep
+++ b/templates/layouts/app.html.ep
@@ -117,6 +117,7 @@ Bitte eine Station aus der Liste auswählen</div>
%= form_for _redirect => begin
+%= hidden_field efa => param('efa')
%= hidden_field hafas => param('hafas')
<div>
<div class="field">
@@ -142,7 +143,7 @@ Bitte eine Station aus der Liste auswählen</div>
</div>
% }
<div class="backendlink">
- <a class="button button-light" href="<%= url_for('_backend')->query({hafas => param('hafas')}) %>">Backend: <%= param('hafas') ? param('hafas') . ' (HAFAS)' : 'DB (IRIS-TTS)' %></a>
+ <a class="button button-light" href="<%= url_for('_backend')->query({efa => param('efa'), hafas => param('hafas')}) %>">Backend: <%= param('efa') ? param('efa') . ' (EFA)' : param('hafas') ? param('hafas') . ' (HAFAS)' : 'DB (IRIS-TTS)' %></a>
</div>
<div class="break"></div>
<div class="moresettings-header moresettings-header-collapsed button button-light">Weitere Einstellungen</div>
diff --git a/templates/select_backend.html.ep b/templates/select_backend.html.ep
index 836e5c7..2603800 100644
--- a/templates/select_backend.html.ep
+++ b/templates/select_backend.html.ep
@@ -14,17 +14,22 @@
<%= $prev_type %>:<br/>
% }
% my $class = 'button';
- % if (param('hafas')) {
+ % if (param('efa')) {
+ % if ($backend->{efa} and $backend->{shortname} eq param('efa')) {
+ % $class .= ' button-active';
+ % }
+ % }
+ % elsif (param('hafas')) {
% if ($backend->{hafas} and $backend->{shortname} eq param('hafas')) {
% $class .= ' button-active';
% }
% }
% else {
- % if (not $backend->{hafas}) {
+ % if (not ($backend->{efa} or $backend->{hafas})) {
% $class .= ' button-active';
% }
% }
- <a class="<%= $class %>" href="<%= url_for(q{/})->query({ hafas => $backend->{hafas} ? $backend->{shortname} : q{} }) %>"><%= $backend->{shortname} // 'IRIS-TTS' %> – <%= $backend->{name} %></a>
+ <a class="<%= $class %>" href="<%= url_for(q{/})->query({ efa => $backend->{efa} ? $backend->{shortname} : q{}, hafas => $backend->{hafas} ? $backend->{shortname} : q{} }) %>"><%= $backend->{shortname} // 'IRIS-TTS' %> – <%= $backend->{name} %></a>
% if ($backend->{has_area}) {
<a href="/coverage/<%= $backend->{type} %>/<%= $backend->{shortname} %>"><%= join(q{, }, @{$backend->{regions}}) || '[Karte]' %></a>
% }