summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Dockerfile73
-rw-r--r--README.md107
-rw-r--r--cpanfile12
-rw-r--r--index.pl166
-rw-r--r--public/static/502.html20
-rw-r--r--public/static/504.html20
-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)bin139372 -> 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/v11
-rw-r--r--templates/display.html.ep5
-rw-r--r--templates/exception.html.ep3
-rw-r--r--templates/infoscreen.html.ep20
-rw-r--r--templates/main.html.ep41
-rw-r--r--templates/not_found.html.ep3
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"]
diff --git a/README.md b/README.md
index 67579d1..06637f8 100644
--- a/README.md
+++ b/README.md
@@ -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';
diff --git a/index.pl b/index.pl
index 504803a..676bb19 100644
--- a/index.pl
+++ b/index.pl
@@ -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
index e532b93..e532b93 100644
--- a/public/static/VRRR.ttf
+++ b/public/static/fonts/VRRR.ttf
Binary files differ
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>