diff options
-rw-r--r-- | Dockerfile | 73 | ||||
-rw-r--r-- | README.md | 107 | ||||
-rw-r--r-- | cpanfile | 12 | ||||
-rw-r--r-- | index.pl | 166 | ||||
-rw-r--r-- | public/static/502.html | 20 | ||||
-rw-r--r-- | public/static/504.html | 20 | ||||
-rw-r--r-- | public/static/css/display.css (renamed from public/static/display.css) | 2 | ||||
-rw-r--r-- | public/static/css/infoscreen.css (renamed from public/static/infoscreen.css) | 0 | ||||
-rw-r--r-- | public/static/css/main.css (renamed from public/static/main.css) | 0 | ||||
-rw-r--r-- | public/static/css/mobile.css (renamed from public/static/mobile.css) | 0 | ||||
-rw-r--r-- | public/static/fonts/VRRR.ttf (renamed from public/static/VRRR.ttf) | bin | 139372 -> 139372 bytes | |||
-rw-r--r-- | public/static/js/collapse.js (renamed from public/static/collapse.js) | 0 | ||||
-rw-r--r-- | public/static/js/image.js (renamed from public/static/image.js) | 0 | ||||
-rw-r--r-- | public/static/js/jquery-2.1.1.min.js (renamed from public/static/jquery-2.1.1.min.js) | 0 | ||||
l--------- | public/static/v1 | 1 | ||||
-rw-r--r-- | templates/display.html.ep | 5 | ||||
-rw-r--r-- | templates/exception.html.ep | 3 | ||||
-rw-r--r-- | templates/infoscreen.html.ep | 20 | ||||
-rw-r--r-- | templates/main.html.ep | 41 | ||||
-rw-r--r-- | templates/not_found.html.ep | 3 |
20 files changed, 362 insertions, 111 deletions
diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b208156 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,73 @@ +# docker build -t vrr-fakedisplay:latest --build-arg=vrrf_version=$(git describe --dirty) . + +FROM debian:buster-slim AS files + +ARG vrrf_version=git + +COPY Build.PL cpanfile index.pl /app/ +COPY lib/ /app/lib/ +COPY public/ /app/public/ +COPY share/ /app/share/ +COPY templates/ /app/templates/ + +WORKDIR /app + +RUN ln -sf ../ext-templates/imprint.html.ep templates/imprint.html.ep \ + && ln -sf ../ext-templates/privacy.html.ep templates/privacy.html.ep + +RUN find lib -name '*.pm' -or -name '*.PL' | xargs sed -i \ + -e "s/VERSION *= *.*;/VERSION = '${vrrf_version}';/" + +RUN sed -i -e "s/VERSION *= *.*;/VERSION = '${vrrf_version}';/" \ + index.pl + + +FROM perl:5.30-slim + +ARG DEBIAN_FRONTEND=noninteractive +ARG APT_LISTCHANGES_FRONTEND=none + +COPY --from=files /app/ /app/ + +WORKDIR /app + +RUN apt-get update \ + && apt-get -y --no-install-recommends install \ + ca-certificates \ + curl \ + gcc \ + libc6-dev \ + libdb5.3 \ + libdb5.3-dev \ + libgd3 \ + libgd-dev \ + libssl1.1 \ + libssl-dev \ + libxml2 \ + libxml2-dev \ + make \ + zlib1g-dev \ + && cpanm -n --no-man-pages --installdeps . \ + && mv public / \ + && perl Build.PL \ + && perl Build \ + && perl Build manifest \ + && perl Build install \ + && rm -rf ~/.cpanm _build blib MANIFEST* META* MYMETA* \ + && mv /public . \ + && apt-get -y purge \ + curl \ + gcc \ + libc6-dev \ + libdb5.3-dev -\ + libgd-dev \ + libssl-dev \ + libxml2-dev \ + make \ + zlib1g-dev \ + && apt-get -y autoremove \ + && rm -rf /var/cache/apt/* /var/lib/apt/lists/* + +EXPOSE 8091 + +CMD ["hypnotoad", "-f", "index.pl"] @@ -9,36 +9,105 @@ It supports most german local transit networks and also some austrian ones. There's a public [vrr-infoscreen service on finalrewind.org](https://vrrf.finalrewind.org/). You can also host your own -instance, see the Setup notes below. +instance via carton/cpanminus or Docker, see the Setup notes below. + +**Legacy Warning**. As of 2017, vrr-infoscreen is not under active development +anymore. Maintenance and bugfixes may not occur in a timely manner. ## Dependencies - * perl ≥ 5.10 - * Cache::File (part of the Cache module) - * DateTime - * DateTime::Format::Strptime - * File::ShareDir - * GD - * Mojolicious - * Mojolicious::Plugin::BrowserDetect - * Travel::Status::DE::EFA ≥ 1.15 - * Travel::Status::DE::HAFAS ≥ 2.03 - * Travel::Status::DE::URA ≥ 2.01 + * perl ≥ 5.20 + * carton or cpanminus + * build-essential (gcc/clang, make) + * libdb (Berkeley Database Libraries) + * libgd (GD Graphics Library) + * libxml2 + * zlib -## Setup +## Installation + +After installing the dependencies, clone the repository using git, e.g. + +``` +git clone https://git.finalrewind.org/vrr-fakedisplay +``` + +Make sure that all files (including `.git`, which is used to determine the +software version) are readable by your www user, and follow the steps in the +next sections. + +## Perl Dependencies + +vrr-infoscreen depends on a set of Perl modules which are documented in +`cpanfile`. After installing the dependencies mentioned above, you can use +carton or cpanminus to install Perl depenencies locally. + +In the project root directory (where `cpanfile` resides), run either + +``` +carton install +``` + +or + +``` +cpanm -n --installdeps . +``` + +Next, you need to build App::VRR::Fakedisplay, which is required for the LED +frontend and shipped with vrr-fakedisplay. -First, build App::VRR::Fakedisplay which is required for the LED frontend: +``` +export PERL5LIB=local/lib/perl5 +perl Build.PL +./Build +./Build manifest +sudo ./Build install +``` -* perl Build.PL -* ./Build -* ./Build manifest -* sudo ./Build install +## Running + +You are now ready to start the web service. If you used carton, it boils +down to + +``` +carton exec hypnotoad index.pl +``` + +Otherwise, you need to make the perl dependencies available by setting the +PERL5LIB environment variable: + +``` +PERL5LIB=local/lib/perl5 local/bin/hypnotoad index.pl +``` + +Note that you should provide imprint and privacy policy pages. Depending on +traffic volume, you may also want to increase the amount of worker processes. +See the Setup notes below. + +## Installation with Docker + +A vrr-infoscreen image is available on Docker Hub. You can install and run it +as follows: + +``` +docker pull derfnull/vrr-fakedisplay:latest +docker run --rm -p 8000:8091 -v "$(pwd)/templates:/app/ext-templates:ro" vrr-fakedisplay:latest +``` + +This will make the web service available on port 8000. Note that you should +provide imprint and privacy policy pages, see the Setup notes below. + +Use `docker run -e VRRFAKEDISPLAY_WORKERS=4 ...` and similar to pass +environment variables to the vrr-infoscreen service. + +## Setup vrr-infoscreen is configured via environment variables: | Variable | Default | Description | | :------- | :------ | :---------- | -| VRRFAKEDISPLAY\_LISTEN | `http://127.0.0.1:8091` | IP and Port for web service | +| VRRFAKEDISPLAY\_LISTEN | `http://*:8091` | IP and Port for web service | | VRRFAKEDISPLAY\_STATS | _None_ | File in which the total count of (non-cached) backend API requests is written | | VRRFAKEDISPLAY\_CACHE | `/tmp/vrr-fakedisplay` | Cache directory | | VRRFAKEDISPLAY\_WORKERS | 2 | Number of concurrent worker processes | diff --git a/cpanfile b/cpanfile new file mode 100644 index 0000000..49198e0 --- /dev/null +++ b/cpanfile @@ -0,0 +1,12 @@ +requires 'Cache'; +requires 'DateTime'; +requires 'DateTime::Format::Strptime'; +requires 'File::ShareDir'; +requires 'File::Slurp'; +requires 'GD'; +requires 'Module::Build'; +requires 'Mojolicious'; +requires 'Mojolicious::Plugin::BrowserDetect'; +requires 'Travel::Status::DE::EFA'; +requires 'Travel::Status::DE::HAFAS'; +requires 'Travel::Status::DE::URA'; @@ -46,7 +46,10 @@ sub log_api_access { } sub get_results { - my ( $backend, $city, $stop ) = @_; + my %opt = @_; + my $backend = $opt{backend}; + my $city = $opt{city}; + my $stop = $opt{stop}; my $sub_backend; my $expiry = 200; @@ -130,9 +133,6 @@ sub get_results { } else { my $efa_url = 'http://efa.vrr.de/vrr/XSLT_DM_REQUEST'; - if ( not $city ) { - return { errstr => 'City must be specified for this backend' }; - } if ($sub_backend) { my $service = first { lc( $_->{shortname} ) eq lc($sub_backend) } @@ -142,11 +142,12 @@ sub get_results { } } $status = Travel::Status::DE::EFA->new( - efa_url => $efa_url, - place => $city, - name => $stop, - timeout => 3, - full_routes => 0, + efa_url => $efa_url, + place => $city, + name => $stop, + timeout => 3, + full_routes => 0, + proximity_search => $opt{proximity_search} ); } if ( not $status->errstr ) { @@ -192,8 +193,11 @@ sub handle_request { my $data; if ($stop) { - $data = get_results( $self->param('backend') // $default{backend}, - $city, $stop ); + $data = get_results( + backend => $self->param('backend') // $default{backend}, + city => $city, + stop => $stop + ); } if ( not $no_lines or $no_lines < 1 or $no_lines > 40 ) { @@ -273,7 +277,12 @@ sub get_filtered_departures { my ( @grep_line, @grep_platform, @filtered_results ); - my $data = get_results( $opt{backend}, $opt{city}, $opt{stop} ); + my $data = get_results( + backend => $opt{backend}, + city => $opt{city}, + stop => $opt{stop}, + proximity_search => $opt{proximity_search} + ); my $results = $data->{results}; @@ -303,9 +312,9 @@ sub get_filtered_departures { @grep_line and not( List::MoreUtils::any { $line =~ $_ } @grep_line ) ) - or ( @grep_platform and not( $platform ~~ \@grep_platform ) ) + or ( @grep_platform and not( $platform ~~ \@grep_platform ) ) or ( $opt{hide_regional} and $line =~ m{ ^ (RB | RE | IC | EC) }x ) - or ( $opt{offset} and $d->countdown < $opt{offset} ) + or ( $opt{offset} and $d->countdown < $opt{offset} ) ) { next; @@ -323,10 +332,11 @@ sub make_infoboard_lines { my (%opt) = @_; my ( @grep_line, @grep_platform ); - my $no_lines = $opt{no_lines} // $default{no_lines}; - my $max_lines = $opt{max_lines} // 40; - my $offset = $opt{offset} // 0; - my $results = $opt{data}; + my $no_lines = $opt{no_lines} // $default{no_lines}; + my $max_lines = $opt{max_lines} // 40; + my $offset = $opt{offset} // 0; + my $time_format = $opt{time_format} // 'countdown'; + my $results = $opt{data}; my $displayed_lines = 0; my $want_crop = $opt{want_crop}; my @fmt_departures; @@ -390,6 +400,9 @@ sub make_infoboard_lines { { next; } + elsif ( $time_format eq 'hhmm' ) { + $etr = $dt->strftime('%H:%M'); + } elsif ( $duration->in_units('minutes') == 0 ) { $etr = 'sofort'; } @@ -426,23 +439,25 @@ sub render_html { my $template = $frontend eq 'html' ? 'display' : 'infoscreen'; my $data = get_filtered_departures( - city => $self->stash('city') // q{}, - stop => $self->stash('stop'), - backend => scalar $self->param('backend'), - filter_line => scalar $self->param('line'), - filter_platform => scalar $self->param('platform'), - hide_regional => ( $template eq 'infoscreen' ? 0 : 1 ), - offset => scalar $self->param('offset'), + city => $self->stash('city') // q{}, + stop => $self->stash('stop'), + backend => scalar $self->param('backend'), + filter_line => scalar $self->param('line'), + filter_platform => scalar $self->param('platform'), + hide_regional => ( $template eq 'infoscreen' ? 0 : 1 ), + offset => scalar $self->param('offset'), + proximity_search => scalar $self->param('proximity_search'), ); my @departures = make_infoboard_lines( - city => $self->stash('city') // q{}, - stop => $self->stash('stop'), - backend => scalar $self->param('backend'), - no_lines => scalar $self->param('no_lines'), - offset => scalar $self->param('offset'), - want_crop => scalar $self->param('want_crop'), - data => $data->{filtered_results}, + city => $self->stash('city') // q{}, + stop => $self->stash('stop'), + backend => scalar $self->param('backend'), + no_lines => scalar $self->param('no_lines'), + offset => scalar $self->param('offset'), + time_format => scalar $self->param('time_format'), + want_crop => scalar $self->param('want_crop'), + data => $data->{filtered_results}, ); for my $d (@departures) { @@ -470,26 +485,30 @@ sub render_html { sub render_json { my $self = shift; + my $time_format = $self->param('time_format') // 'countdown'; + my $data = get_filtered_departures( - city => $self->stash('city') // q{}, - stop => $self->stash('stop'), - backend => scalar $self->param('backend'), - filter_line => scalar $self->param('line'), - filter_platform => scalar $self->param('platform'), - hide_regional => 0, - offset => scalar $self->param('offset'), + city => $self->stash('city') // q{}, + stop => $self->stash('stop'), + backend => scalar $self->param('backend'), + filter_line => scalar $self->param('line'), + filter_platform => scalar $self->param('platform'), + hide_regional => 0, + offset => scalar $self->param('offset'), + proximity_search => scalar $self->param('proximity_search'), ); my $raw_departures = $data->{filtered_results}; my $errstr = $data->{errstr}; my @departures = make_infoboard_lines( - no_lines => scalar $self->param('no_lines'), - offset => scalar $self->param('offset'), - want_crop => scalar $self->param('want_crop'), - data => $raw_departures, + no_lines => scalar $self->param('no_lines'), + offset => scalar $self->param('offset'), + time_format => $time_format, + want_crop => scalar $self->param('want_crop'), + data => $raw_departures, ); for my $d (@departures) { - if ( $d->[2] and $d->[2] ne 'sofort' ) { + if ( $d->[2] and $d->[2] ne 'sofort' and $time_format eq 'countdown' ) { $d->[2] .= ' min'; } } @@ -510,29 +529,32 @@ sub render_json { sub render_image { my $self = shift; - my $color = $self->param('color') || '255,208,0'; - my $scale = $self->param('scale'); + my $color = $self->param('color') || '255,208,0'; + my $scale = $self->param('scale'); + my $time_format = $self->param('time_format') // 'countdown'; my $data = get_filtered_departures( - city => $self->stash('city') // q{}, - stop => $self->stash('stop'), - backend => scalar $self->param('backend'), - filter_line => scalar $self->param('line'), - filter_platform => scalar $self->param('platform'), - hide_regional => 0, - offset => scalar $self->param('offset'), + city => $self->stash('city') // q{}, + stop => $self->stash('stop'), + backend => scalar $self->param('backend'), + filter_line => scalar $self->param('line'), + filter_platform => scalar $self->param('platform'), + hide_regional => 0, + offset => scalar $self->param('offset'), + proximity_search => scalar $self->param('proximity_search'), ); my $raw_departures = $data->{filtered_results}; my $errstr = $data->{errstr}; my @departures = make_infoboard_lines( - city => $self->stash('city') // q{}, - stop => $self->stash('stop'), - backend => scalar $self->param('backend'), - no_lines => scalar $self->param('no_lines'), - offset => scalar $self->param('offset'), - want_crop => scalar $self->param('want_crop'), - data => $raw_departures + city => $self->stash('city') // q{}, + stop => $self->stash('stop'), + backend => scalar $self->param('backend'), + no_lines => scalar $self->param('no_lines'), + offset => scalar $self->param('offset'), + time_format => $time_format, + want_crop => scalar $self->param('want_crop'), + data => $raw_departures ); if ( $scale > 30 ) { @@ -567,7 +589,10 @@ sub render_image { $png->draw_at( 0, $line ); $png->draw_at( 25, $destination ); - if ( length($etr) > 2 ) { + if ( $time_format eq 'hhmm' ) { + $png->draw_at( 153, $etr ); + } + elsif ( length($etr) > 2 ) { $png->draw_at( 145, $etr ); } elsif ( length($etr) > 1 ) { @@ -577,7 +602,7 @@ sub render_image { $png->draw_at( 154, $etr ); } - if ( $etr and $etr ne 'sofort' ) { + if ( $etr and $etr ne 'sofort' and $time_format eq 'countdown' ) { $png->draw_at( 161, 'min' ); } @@ -637,8 +662,11 @@ get '/_redirect' => sub { if ( $params->param('frontend') and $params->param('frontend') eq 'infoscreen' ) { - my $data = get_results( $self->param('backend') // $default{backend}, - $city, $stop ); + my $data = get_results( + backend => $self->param('backend') // $default{backend}, + city => $city, + stop => $stop + ); if ( not $data->{errstr} ) { $suffix = '.html'; } @@ -681,14 +709,14 @@ get '/:city/<*stop>.html' => \&render_html; get '/:city/<*stop>.json' => \&render_json; get '/:city/<*stop>.png' => \&render_image; get '/:city/*stop' => \&handle_request; -get '/<:stop>.html' => \&render_html; -get '/<:stop>.json' => \&render_json; -get '/<:stop>.png' => \&render_image; -get '/:stop' => \&handle_request; +get '/<*stop>.html' => \&render_html; +get '/<*stop>.json' => \&render_json; +get '/<*stop>.png' => \&render_image; +get '/*stop' => \&handle_request; app->config( hypnotoad => { - listen => [ $ENV{VRRFAKEDISPLAY_LISTEN} // 'http://127.0.0.1:8091' ], + listen => [ $ENV{VRRFAKEDISPLAY_LISTEN} // 'http://*:8091' ], pid_file => '/tmp/vrr-fakedisplay.pid', workers => $ENV{VRRFAKEDISPLAY_WORKERS} // 2, }, diff --git a/public/static/502.html b/public/static/502.html new file mode 100644 index 0000000..7702a87 --- /dev/null +++ b/public/static/502.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<html> +<head> + <title>vrr-infoscreen: 502 Bad Gateway</title> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link href="/static/main.css" rel="stylesheet"> +</head> +<body> + +<div class="container"> +<div class="error"> +<strong>502 Bad Gateway</strong> +Das Backend konnte die Anfrage nicht bearbeiten.<br/> +Mögliche Gründe dafür sind Programmierfehler oder Nichterreichbarkeit der +Nameserver von <a href="http://vrr.de">vrr.de</a>. +</div> <!-- error --> +</div> <!-- container --> +</body> +</html> diff --git a/public/static/504.html b/public/static/504.html new file mode 100644 index 0000000..2298cd0 --- /dev/null +++ b/public/static/504.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<html> +<head> + <title>vrr-infoscreen: 504 Gateway Timeout</title> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link href="/static/main.css" rel="stylesheet"> +</head> +<body> + +<div class="container"> +<div class="error"> +<strong>504 Gateway Timeout</strong> +Das Backend konnte die Anfrage nicht rechtzeitig bearbeiten.<br/> +Mögliche Gründe dafür sind Programmierfehler oder Nichterreichbarkeit der +Nameserver von <a href="http://vrr.de">vrr.de</a>. +</div> <!-- error --> +</div> <!-- container --> +</body> +</html> diff --git a/public/static/display.css b/public/static/css/display.css index f874bf2..76280c5 100644 --- a/public/static/display.css +++ b/public/static/css/display.css @@ -1,6 +1,6 @@ @font-face { font-family: VRRR; - src: url('/static/VRRR.ttf'); + src: url('/static/v1/fonts/VRRR.ttf'); } body { diff --git a/public/static/infoscreen.css b/public/static/css/infoscreen.css index c2415be..c2415be 100644 --- a/public/static/infoscreen.css +++ b/public/static/css/infoscreen.css diff --git a/public/static/main.css b/public/static/css/main.css index 7eee1f3..7eee1f3 100644 --- a/public/static/main.css +++ b/public/static/css/main.css diff --git a/public/static/mobile.css b/public/static/css/mobile.css index efa6023..efa6023 100644 --- a/public/static/mobile.css +++ b/public/static/css/mobile.css diff --git a/public/static/VRRR.ttf b/public/static/fonts/VRRR.ttf Binary files differindex e532b93..e532b93 100644 --- a/public/static/VRRR.ttf +++ b/public/static/fonts/VRRR.ttf diff --git a/public/static/collapse.js b/public/static/js/collapse.js index d38b30a..d38b30a 100644 --- a/public/static/collapse.js +++ b/public/static/js/collapse.js diff --git a/public/static/image.js b/public/static/js/image.js index 40bc37d..40bc37d 100644 --- a/public/static/image.js +++ b/public/static/js/image.js diff --git a/public/static/jquery-2.1.1.min.js b/public/static/js/jquery-2.1.1.min.js index e5ace11..e5ace11 100644 --- a/public/static/jquery-2.1.1.min.js +++ b/public/static/js/jquery-2.1.1.min.js diff --git a/public/static/v1 b/public/static/v1 new file mode 120000 index 0000000..945c9b4 --- /dev/null +++ b/public/static/v1 @@ -0,0 +1 @@ +.
\ No newline at end of file diff --git a/templates/display.html.ep b/templates/display.html.ep index 4cf52a2..5a98e1a 100644 --- a/templates/display.html.ep +++ b/templates/display.html.ep @@ -3,8 +3,9 @@ <head> <title><%= $title %></title> <meta charset="utf-8"> - %= stylesheet '/static/display.css' - %= javascript '/static/jquery-2.1.1.min.js' + % my $av = 'v1'; # asset version + %= stylesheet "/static/${av}/css/display.css" + %= javascript '/static/js/jquery-2.1.1.min.js' </head> <body style="color: #<%= join(q{}, map { sprintf('%02x', $_) } @{$color} ) %>; font-size: <%= $scale * 100 %>%;"> diff --git a/templates/exception.html.ep b/templates/exception.html.ep index 2312586..aea4c40 100644 --- a/templates/exception.html.ep +++ b/templates/exception.html.ep @@ -4,7 +4,8 @@ <title>vrr-infoscreen</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> - %= stylesheet '/static/main.css' + % my $av = 'v1'; # asset version + %= stylesheet "/static/${av}/css/main.css" </head> <body> diff --git a/templates/infoscreen.html.ep b/templates/infoscreen.html.ep index d634a93..62aa56c 100644 --- a/templates/infoscreen.html.ep +++ b/templates/infoscreen.html.ep @@ -8,12 +8,13 @@ <meta http-equiv="refresh" content="<%= $self->stash('refresh_interval') %>"/> % } - %= stylesheet '/static/infoscreen.css' + % my $av = 'v1'; # asset version + %= stylesheet "/static/${av}/css/infoscreen.css" % if ($self->browser->mobile) { - %= stylesheet '/static/mobile.css' + %= stylesheet "/static/${av}/css/mobile.css" % } - %= javascript '/static/jquery-2.1.1.min.js' - %= javascript '/static/collapse.js' + %= javascript '/static/js/jquery-2.1.1.min.js' + %= javascript "/static/${av}/js/collapse.js" </head> <body> @@ -180,6 +181,17 @@ % if ($departure->can('route_interesting') and $departure->route_interesting) { %= join(' - ', map { $_->can('name_suf') ? $_->name_suf : $_->name } ($departure->route_interesting)); % } +% elsif ($departure->can('occupancy') and $departure->occupancy) { +% if ($departure->occupancy eq 'MANY_SEATS') { + ●○○ +% } +% elsif ($departure->occupancy eq 'FEW_SEATS') { + ●●○ +% } +% elsif ($departure->occupancy eq 'STANDING_ONLY') { + <span style="color: red;">●●●</span> +% } +% } </span> <!-- route --> <span class="dest"> %= $departure->destination diff --git a/templates/main.html.ep b/templates/main.html.ep index 1c539fb..8f21978 100644 --- a/templates/main.html.ep +++ b/templates/main.html.ep @@ -4,9 +4,10 @@ <title><%= $title %></title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> - %= stylesheet '/static/main.css' - %= javascript '/static/jquery-2.1.1.min.js' - %= javascript '/static/image.js' + % my $av = 'v1'; # asset version + %= stylesheet "/static/${av}/css/main.css" + %= javascript '/static/js/jquery-2.1.1.min.js' + %= javascript "/static/${av}/js/image.js" </head> <body> @@ -80,10 +81,22 @@ Ankündigung ändern.</p> % else { <div class="container"> <p> -Diese Seite ist ein inoffizielles Frontend für die Abfahrtsmonitore -einiger europäischer Nahverkehrsunternehmen. Sie kannn wahlweise die oft an -Haltestellen montierten LED-Displays nachahmen oder einen Handy- und -Infoscreen-tauglichen Abfahrtsmonitor anzeigen. +vrr-infoscreen ist ein inoffizielles Frontend für die Abfahrtsmonitore einiger +europäischer Nahverkehrsunternehmen. Es kannn wahlweise die oft an Haltestellen +montierten LED-Displays nachahmen oder einen für Infotafeln geeigneten +Abfahrtsmonitor anzeigen. +</p> + +<p> +Diese Seite ist ein privat betriebenes Projekt ohne Verfügbarkeitsgarantie +und wird derzeit nicht aktiv gepflegt oder weiterentwickelt. Alternativen: +<ul> +<li>LED-Tafel: Derzeit keine</li> +<li>HTML/App: <a href="https://nvm.finalrewind.org">nvm.finalrewind.org</a></li> +<li>JSON aus EFA-APIs: <a href="https://finalrewind.org/interblag/entry/efa-json-api/">EFA-APIs mit nativer JSON-Unterstützung</a></li> +<li>JSON aus HAFAS-APIs: <a href="https://transport.rest/">transport.rest</a></li> +<li>JSON aus URA-APIs: Derzeit keine</li> +</ul> </p> <p> @@ -103,7 +116,7 @@ Alle Angaben ohne Gewähr. %= form_for _redirect => begin <div> <div class="field"> - <div class="desc">Stadt (Pflichtfeld für EFA-Backends, sonst optional)</div> + <div class="desc">Stadt (optional, kann auch Teil der Haltestelle sein)</div> <div> % if (stash('place_candidates') and @{ stash('place_candidates') } ) { % my @candidates = map { [ $_, $_ ] } @{ stash('place_candidates') }; @@ -195,8 +208,8 @@ Alle Angaben ohne Gewähr. <span class="notes">Hinweise:</span> <ul> <li><a href="/Essen/Martinstr?no_lines=8">Beispiel</a></li> -<li><a href="http://dbf.finalrewind.org/">db-infoscreen</a> -(für Züge und Bahnhöfe optimiert)</li> +<li><a href="https://dbf.finalrewind.org/">db-infoscreen</a> +(nur S-Bahn, Regional- und Fernverkehr)</li> </ul> </div> <!-- notes --> @@ -204,12 +217,12 @@ Alle Angaben ohne Gewähr. <a href="http://finalrewind.org/projects/vrr-fakedisplay/">vrr-infoscreen</a> v<%= $version %><br/> Backends:<br/> -<a href="http://finalrewind.org/projects/Travel-Status-DE-URA/">Travel::Status::DE::URA</a> -v<%= $Travel::Status::DE::ASEAG::VERSION %><br/> -<a href="http://finalrewind.org/projects/Travel-Status-DE-DeutscheBahn/">Travel::Status::DE::HAFAS</a> -v<%= $Travel::Status::DE::HAFAS::VERSION %><br/> <a href="http://finalrewind.org/projects/Travel-Status-DE-VRR/">Travel::Status::DE::EFA</a> v<%= $Travel::Status::DE::EFA::VERSION %><br/> +<a href="http://finalrewind.org/projects/Travel-Status-DE-DeutscheBahn/">Travel::Status::DE::HAFAS</a> +v<%= $Travel::Status::DE::HAFAS::VERSION %><br/> +<a href="http://finalrewind.org/projects/Travel-Status-DE-URA/">Travel::Status::DE::URA</a> +v<%= $Travel::Status::DE::URA::VERSION %><br/> <a href="/_imprint">Impressum</a><br/> <a href="/_privacy">Datenschutz</a><br/> </div> diff --git a/templates/not_found.html.ep b/templates/not_found.html.ep index 1fada6c..98bb664 100644 --- a/templates/not_found.html.ep +++ b/templates/not_found.html.ep @@ -4,7 +4,8 @@ <title>vrr-infoscreen</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> - %= stylesheet '/static/main.css' + % my $av = 'v1'; # asset version + %= stylesheet "/static/${av}/css/main.css" </head> <body> |