diff options
Diffstat (limited to 'lib/DBInfoscreen/Controller/Stationboard.pm')
-rw-r--r-- | lib/DBInfoscreen/Controller/Stationboard.pm | 416 |
1 files changed, 265 insertions, 151 deletions
diff --git a/lib/DBInfoscreen/Controller/Stationboard.pm b/lib/DBInfoscreen/Controller/Stationboard.pm index e2e5bb5..b64c661 100644 --- a/lib/DBInfoscreen/Controller/Stationboard.pm +++ b/lib/DBInfoscreen/Controller/Stationboard.pm @@ -29,6 +29,20 @@ my %default = ( admode => 'deparr', ); +sub class_to_product { + my ( $self, $hafas ) = @_; + + my $bits = $hafas->get_active_service->{productbits}; + my $ret; + + for my $i ( 0 .. $#{$bits} ) { + $ret->{ 2**$i } + = ref( $bits->[$i] ) eq 'ARRAY' ? $bits->[$i][0] : $bits->[$i]; + } + + return $ret; +} + sub handle_no_results { my ( $self, $station, $data, $hafas ) = @_; @@ -455,7 +469,12 @@ sub handle_request { # (or used by) marudor.de, it was renamed to 'json'. Many clients won't # notice this for year to come, so we make sure mode=marudor still works as # intended. - if ( $template eq 'marudor' ) { + if ( + $template eq 'marudor' + or ( $self->req->headers->accept + and $self->req->headers->accept eq 'application/json' ) + ) + { $template = 'json'; } @@ -490,6 +509,7 @@ sub handle_request { my ($status) = @_; my $data = { results => [ $status->results ], + hafas => $hafas ? $status : undef, station_ds100 => ( $status->station ? $status->station->{ds100} : undef ), station_eva => ( @@ -503,12 +523,6 @@ sub handle_request { ( $status->station ? $status->station->{name} : $station ), }; - if ( $status->station and $status->station->{names} ) { - $data->{station_name} - = List::Util::reduce { length($a) < length($b) ? $a : $b } - @{ $status->station->{names} }; - } - if ( not @{ $data->{results} } and $template eq 'json' ) { $self->handle_no_results_json( $station, $data, $api_version ); return; @@ -735,8 +749,55 @@ sub render_train { from_json => $wr_json ); $departure->{wr} = $wr; $departure->{wr_text} = join( q{ • }, - map { $_->{short} } - grep { $_->{short} } $wr->train_descriptions ); + map { $_->desc_short } + grep { $_->desc_short } $wr->groups ); + my $first = 0; + for my $group ( $wr->groups ) { + my $had_entry = 0; + for my $wagon ( $group->wagons ) { + if ( + not( $wagon->is_locomotive + or $wagon->is_powercar ) + ) + { + my $class; + if ($first) { + push( + @{ $departure->{wr_preview} }, + [ '•', 'meta' ] + ); + $first = 0; + } + my $entry; + if ( $wagon->is_closed ) { + $entry = 'X'; + $class = 'closed'; + } + else { + $entry = $wagon->number + || ( + $wagon->type =~ m{AB} ? '½' + : $wagon->type =~ m{A} ? '1.' + : $wagon->type =~ m{B} ? '2.' + : $wagon->type + ); + } + if ( + $group->train_no ne $departure->{train_no} ) + { + $class = 'otherno'; + } + push( + @{ $departure->{wr_preview} }, + [ $entry, $class ] + ); + $had_entry = 1; + } + } + if ($had_entry) { + $first = 1; + } + } }; $departure->{wr_text} ||= 'Wagen'; return; @@ -812,10 +873,11 @@ sub render_train { } if ($direction) { - $departure->{direction} = $direction; + $departure->{wr_direction} = $direction; + $departure->{wr_direction_num} = $direction eq 'l' ? 0 : 100; } elsif ( $platform_info->{direction} ) { - $departure->{direction} = 'a' . $platform_info->{direction}; + $departure->{wr_direction} = 'a' . $platform_info->{direction}; } return; @@ -833,17 +895,17 @@ sub render_train { my %opt = ( train => $result ); - if ( $self->languages =~ m{^en} ) { - $opt{language} = 'en'; - } + #if ( $self->languages =~ m{^en} ) { + # $opt{language} = 'en'; + #} $self->hafas->get_route_p(%opt)->then( sub { my ( $route, $journey ) = @_; - $departure->{trip_id} = $journey->id; - $departure->{operator} = $journey->operator; - $departure->{date} = $route->[0]{sched_dep} // $route->[0]{dep}; + $departure->{trip_id} = $journey->id; + $departure->{operators} = [ $journey->operators ]; + $departure->{date} = $route->[0]{sched_dep} // $route->[0]{dep}; # Use HAFAS route as source of truth; ignore IRIS data $departure->{route_pre_diff} = []; @@ -859,6 +921,16 @@ sub render_train { = [ $load->{FIRST}, $load->{SECOND} ]; } } + $departure->{tz_offset} = $route->[$i]{tz_offset}; + $departure->{local_dt_da} = $route->[$i]{local_dt_da}; + $departure->{local_sched_arr} + = $route->[$i]{local_sched_arr}; + $departure->{local_sched_dep} + = $route->[$i]{local_sched_dep}; + $departure->{is_annotated} = $route->[$i]{is_annotated}; + $departure->{prod_name} = $route->[$i]{prod_name}; + $departure->{direction} = $route->[$i]{direction}; + $departure->{operator} = $route->[$i]{operator}; last; } } @@ -915,58 +987,39 @@ sub render_train { } )->wait; - $departure->{composition} - = $self->app->train_details_db->{ $departure->{train_no} }; - if ( not $departure->{arrival} - and $departure->{composition}{prepTime} - and $departure->{composition}{prepAt} eq $station_name ) - { - $departure->{prep_time} = $departure->{composition}{prepTime}; - $departure->{arrival_hidden} = 1; - } - if ( $self->param('detailed') ) { - my @cycle_from; - my @cycle_to; - for my $pred ( @{ $departure->{composition}{predecessors} // [] } ) { - push( @cycle_from, $pred->[1] ); - } - for my $succ ( @{ $departure->{composition}{successors} // [] } ) { - push( @cycle_to, $succ->[1] ); - } - $departure->{cycle_from} - = [ map { [ $_, $self->app->train_details_db->{$_} ] } @cycle_from ]; - $departure->{cycle_to} - = [ map { [ $_, $self->app->train_details_db->{$_} ] } @cycle_to ]; - } - # Defer rendering until all requests have completed Mojo::Promise->all(@requests)->then( sub { - $self->render( - $template // '_train_details', - description => sprintf( - '%s %s%s%s nach %s', - $departure->{train_type}, - $departure->{train_line} // $departure->{train_no}, - $departure->{origin} ? ' von ' : q{}, - $departure->{origin} // q{}, - $departure->{destination} // 'unbekannt' - ), - departure => $departure, - linetype => $linetype, - icetype => $self->app->ice_type_map->{ $departure->{train_no} }, - details => $self->param('detailed') - ? $departure->{composition} // {} - : {}, - dt_now => DateTime->now( time_zone => 'Europe/Berlin' ), - station_name => $station_name, - nav_link => - $self->url_for( 'station', station => $station_name )->query( - { - detailed => $self->param('detailed'), - hafas => $self->param('hafas') - } - ), + $self->respond_to( + json => { + json => { + departure => $departure, + station_name => $station_name, + }, + }, + any => { + template => $template // '_train_details', + description => sprintf( + '%s %s%s%s nach %s', + $departure->{train_type}, + $departure->{train_line} // $departure->{train_no}, + $departure->{origin} ? ' von ' : q{}, + $departure->{origin} // q{}, + $departure->{destination} // 'unbekannt' + ), + departure => $departure, + linetype => $linetype, + dt_now => DateTime->now( time_zone => 'Europe/Berlin' ), + station_name => $station_name, + nav_link => + $self->url_for( 'station', station => $station_name ) + ->query( + { + detailed => $self->param('detailed'), + hafas => $self->param('hafas') + } + ), + }, ); } )->wait; @@ -982,6 +1035,10 @@ sub station_train_details { delete $self->stash->{layout}; } + if ( $station =~ s{ [.] json $ }{}x ) { + $self->stash( format => 'json' ); + } + my %opt = ( cache_iris_main => $self->app->cache_iris_main, cache_iris_rt => $self->app->cache_iris_rt, @@ -1057,6 +1114,8 @@ sub station_train_details { arrival_is_cancelled => $result->arrival_is_cancelled, moreinfo => $moreinfo, delay => $result->delay, + arrival_delay => $result->arrival_delay, + departure_delay => $result->departure_delay, route_pre => [ $result->route_pre ], route_post => [ $result->route_post ], replaced_by => [ @@ -1087,11 +1146,20 @@ sub station_train_details { )->catch( sub { my ($errstr) = @_; - $self->render( - 'landingpage', - error => - "Keine Abfahrt von $train_no in $station gefunden: $errstr", - status => 404, + $self->respond_to( + json => { + json => { + error => +"Keine Abfahrt von $train_no in $station gefunden: $errstr", + }, + status => 404, + }, + any => { + template => 'landingpage', + error => +"Keine Abfahrt von $train_no in $station gefunden: $errstr", + status => 404, + }, ); return; } @@ -1101,7 +1169,8 @@ sub station_train_details { # /z/:train sub train_details { my ($self) = @_; - my $train = $self->stash('train'); + my $train = $self->stash('train'); + my $hafas = $self->param('hafas'); # TODO error handling @@ -1109,8 +1178,6 @@ sub train_details { delete $self->stash->{layout}; } - my $api_version = $Travel::Status::DE::IRIS::VERSION; - $self->stash( departures => [] ); $self->stash( title => 'DBF' ); @@ -1139,10 +1206,18 @@ sub train_details { $opt{train_no} = $train_no; } - if ( $self->languages =~ m{^en} ) { - $opt{language} = 'en'; + my $service = 'DB'; + if ( $hafas + and $hafas ne '1' + and Travel::Status::DE::HAFAS::get_service($hafas) ) + { + $opt{service} = $hafas; } + #if ( $self->languages =~ m{^en} ) { + # $opt{language} = 'en'; + #} + if ( my $date = $self->param('date') ) { if ( $date =~ m{ ^ (?<day> \d{1,2} ) [.] (?<month> \d{1,2} ) [.] (?<year> \d{4})? $ }x @@ -1166,43 +1241,52 @@ sub train_details { $self->hafas->get_route_p(%opt)->then( sub { - my ( $route, $journey ) = @_; + my ( $route, $journey, $hafas_obj ) = @_; $res->{trip_id} = $journey->id; $res->{date} = $route->[0]{sched_dep} // $route->[0]{dep}; - if ( not $res->{train_type} ) { - my $train_type = $res->{train_type} = $journey->type // q{}; - my $train_no = $res->{train_no} = $journey->number // q{}; - $res->{train_line} = $journey->line_no // q{}; - $self->stash( title => "${train_type} ${train_no}" ); + my $product = $journey->product; + + if ( my $req_name = $self->param('highlight') ) { + if ( my $p = $journey->product_at($req_name) ) { + $product = $p; + } } - if ( not defined $journey->class ) { + my $train_type = $res->{train_type} = $product->type // q{}; + my $train_no = $res->{train_no} = $product->number // q{}; + $res->{train_line} = $product->line_no // q{}; + $self->stash( title => $train_type . ' ' + . ( $train_no || $res->{train_line} ) ); + + if ( not defined $product->class ) { $linetype = 'ext'; } - elsif ( $journey->class <= 2 ) { - $linetype = 'fern'; - } - elsif ( $journey->class <= 8 ) { - $linetype = 'bahn'; - } - elsif ( $journey->class <= 16 ) { - $linetype = 'sbahn'; - } - elsif ( $journey->class == 32 ) { - $linetype = 'bus'; - } - elsif ( $journey->class == 128 ) { - $linetype = 'ubahn'; - } - elsif ( $journey->class == 256 ) { - $linetype = 'tram'; + else { + my $prod + = $self->class_to_product($hafas_obj)->{ $product->class } + // q{}; + if ( $prod eq 'ice' or $prod eq 'ic_ec' ) { + $linetype = 'fern'; + } + elsif ( $prod eq 's' ) { + $linetype = 'sbahn'; + } + elsif ( $prod eq 'bus' ) { + $linetype = 'bus'; + } + elsif ( $prod eq 'u' ) { + $linetype = 'ubahn'; + } + elsif ( $prod eq 'tram' ) { + $linetype = 'tram'; + } } $res->{origin} = $journey->route_start; $res->{destination} = $journey->route_end; - $res->{operator} = $journey->operator; + $res->{operators} = [ $journey->operators ]; $res->{route_post_diff} = $route; @@ -1246,7 +1330,15 @@ sub train_details { = $station_info->{dep_cancelled}; $res->{is_cancelled} = $res->{arrival_is_cancelled} || $res->{arrival_is_cancelled}; - $res->{platform} = $station_info->{platform}; + $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}; } @@ -1284,55 +1376,52 @@ sub train_details { $res->{details} = [@him_details]; } - if ( $self->param('detailed') ) { - $res->{composition} - = $self->app->train_details_db->{ $res->{train_no} }; - my @cycle_from; - my @cycle_to; - for my $pred ( @{ $res->{composition}{predecessors} // [] } ) { - push( @cycle_from, $pred->[1] ); - } - for my $succ ( @{ $res->{composition}{successors} // [] } ) { - push( @cycle_to, $succ->[1] ); - } - $res->{cycle_from} - = [ map { [ $_, $self->app->train_details_db->{$_} ] } - @cycle_from ]; - $res->{cycle_to} - = [ map { [ $_, $self->app->train_details_db->{$_} ] } - @cycle_to ]; - } - - $self->render( - $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 => $linetype, - icetype => $self->app->ice_type_map->{ $res->{train_no} }, - details => {}, #$departure->{composition} // {}, - dt_now => DateTime->now( time_zone => 'Europe/Berlin' ), + $self->respond_to( + json => { + json => { + journey => $journey, + }, + }, + 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 => $linetype, + dt_now => DateTime->now( time_zone => 'Europe/Berlin' ), + }, ); } )->catch( sub { my ($e) = @_; if ($e) { - $self->render( - 'exception', - message => $e, - exception => undef, - snapshot => {} + $self->respond_to( + json => { + json => { + error => $e, + }, + status => 500, + }, + any => { + template => 'exception', + message => $e, + exception => undef, + snapshot => {}, + status => 500, + }, ); } else { - $self->render('not_found'); + $self->render( 'not_found', status => 404 ); } } )->wait; @@ -1356,6 +1445,7 @@ sub handle_result { my $callback = $self->param('callback'); my $via = $self->param('via'); my $hafas = $self->param('hafas'); + my $hafas_obj = $data->{hafas}; my $now = DateTime->now( time_zone => 'Europe/Berlin' ); @@ -1403,6 +1493,9 @@ sub handle_result { } } + my $class_to_product + = $hafas_obj ? $self->class_to_product($hafas_obj) : {}; + @results = $self->filter_results(@results); for my $result (@results) { @@ -1442,19 +1535,20 @@ sub handle_result { } } elsif ( $result->can('class') ) { - if ( $result->class <= 2 ) { + my $prod = $class_to_product->{ $result->class } // q{}; + if ( $prod eq 'ice' or $prod eq 'ic_ec' ) { $linetype = 'fern'; } - elsif ( $result->class == 16 ) { + elsif ( $prod eq 's' ) { $linetype = 'sbahn'; } - elsif ( $result->class == 32 ) { + elsif ( $prod eq 'bus' ) { $linetype = 'bus'; } - elsif ( $result->class == 128 ) { + elsif ( $prod eq 'u' ) { $linetype = 'ubahn'; } - elsif ( $result->class == 256 ) { + elsif ( $prod eq 'tram' ) { $linetype = 'tram'; } } @@ -1662,6 +1756,8 @@ sub handle_result { station => $result->station, moreinfo => $moreinfo, delay => $delay, + arrival_delay => $result->arrival_delay, + departure_delay => $result->departure_delay, missing_realtime => ( not $result->has_realtime and $result->start < $now ? 1 : 0 @@ -1782,6 +1878,11 @@ sub handle_result { my $params = $self->req->params->clone; $params->param( hafas => not $params->param('hafas') ); if ( $params->param('hafas') ) { + if ( $data->{station_eva} >= 8100000 + and $data->{station_eva} < 8200000 ) + { + $params->param( hafas => 'ÖBB' ); + } $api_link = '/' . $data->{station_eva} . '?' . $params->to_string; $api_text = 'Auf Nahverkehr wechseln'; $api_icon = 'train'; @@ -1803,7 +1904,6 @@ sub handle_result { api_text => $api_text, api_icon => $api_icon, departures => \@departures, - ice_type => $self->app->ice_type_map, station => $station_name, version => $self->config->{version}, title => $via ? "$station_name → $via" : $station_name, @@ -1831,14 +1931,23 @@ sub handle_result { sub stations_by_coordinates { my $self = shift; - my $lon = $self->param('lon'); - my $lat = $self->param('lat'); + my $lon = $self->param('lon'); + my $lat = $self->param('lat'); + my $hafas = $self->param('hafas'); if ( not $lon or not $lat ) { $self->render( json => { error => 'Invalid lon/lat received' } ); return; } + my $service = 'DB'; + if ( $hafas + and $hafas ne '1' + and Travel::Status::DE::HAFAS::get_service($hafas) ) + { + $service = $hafas; + } + $self->render_later; my @iris = map { @@ -1859,6 +1968,7 @@ sub stations_by_coordinates { Travel::Status::DE::HAFAS->new_p( promise => 'Mojo::Promise', user_agent => $self->ua, + service => $service, geoSearch => { lat => $lat, lon => $lon @@ -1871,7 +1981,7 @@ sub stations_by_coordinates { name => $_->name, eva => $_->eva, distance => $_->distance_m / 1000, - hafas => 1 + hafas => $service, } } $hafas->results; if ( @hafas > 10 ) { @@ -1947,6 +2057,10 @@ sub redirect_to_station { $params = $params->to_string; $self->redirect_to("/z/${input}?${params}"); } + elsif ( $params->param('hafas') and $params->param('hafas') ne '1' ) { + $params = $params->to_string; + $self->redirect_to("/${input}?${params}"); + } else { my @candidates = Travel::Status::DE::IRIS::Stations::get_station($input); |