Commit graph

175 commits

Author SHA1 Message Date
Romain Vimont
80fe12a95f Require libavcodec >= 57.37
In ffmpeg/doc/APIchanges:

> 2016-04-21 - 7fc329e - lavc 57.37.100 - avcodec.h
>   Add a new audio/video encoding and decoding API with decoupled input
>   and output -- avcodec_send_packet(), avcodec_receive_frame(),
>   avcodec_send_frame() and avcodec_receive_packet().

Refs de9b79ec2d

Refs #2862 <https://github.com/Genymobile/scrcpy/issues/2862>
2021-12-07 00:04:35 +01:00
Romain Vimont
099c546580 Require libavformat >= 57.33
In ffmpeg/doc/APIchanges:

> 2016-04-11 - 6f69f7a / 9200514 - lavf 57.33.100 / 57.5.0 - avformat.h
>   Add AVStream.codecpar, deprecate AVStream.codec.

Refs 5d9e96dc4e

Refs #2862 <https://github.com/Genymobile/scrcpy/issues/2862>
2021-12-07 00:04:27 +01:00
Romain Vimont
dca2c5f94f Require SDL >= 2.0.5
Icon loading uses SDL_CreateRGBSurfaceWithFormatFrom(), available since
SDL 2.0.5 (in 2016).

Refs #2862 <https://github.com/Genymobile/scrcpy/issues/2862>
2021-12-06 23:49:55 +01:00
Romain Vimont
0c0f62e4ab Use static maps to convert input events
This improves readability (hopefully).

PR #2831 <https://github.com/Genymobile/scrcpy/pull/2831>
2021-11-29 21:15:07 +01:00
Romain Vimont
f609b406c9 Add function to find the device IP address
Parse the result of "adb shell ip route" to find the device IP address.

PR #2827 <https://github.com/Genymobile/scrcpy/pull/2827>
2021-11-29 20:39:03 +01:00
Romain Vimont
b90c89766b Set CLOEXEC flag on sockets
If SOCK_CLOEXEC exists, then set the flag on socket creation.

Otherwise, use fcntl() (or SetHandleInformation() on Windows) to set the
flag afterwards.

This avoids the sockets to be inherited in child processes.

Refs #2783 <https://github.com/Genymobile/scrcpy/pull/2783>
2021-11-26 09:40:39 +01:00
Romain Vimont
d5f6697f3a Add (v)asprintf compatibility functions
In case they are not available on the platform.
2021-11-24 19:55:00 +01:00
Romain Vimont
d6c0054545 Move check_functions in meson script
Move the variable to the place it is actually used.
2021-11-24 19:38:33 +01:00
Romain Vimont
dc0ac01e00 Define common feature test macros for all systems
_POSIX_C_SOURCE, _XOPEN_SOURCE and _GNU_SOURCE are also used on Windows.

Fix regression introduced by ba547e3895.
2021-11-24 19:36:33 +01:00
Romain Vimont
aba1fc03c3 Add acksync helper to wait for acks
This will allow to send requests with sequence numbers to the server
and wait for acknowledgements.

PR #2814 <https://github.com/Genymobile/scrcpy/pull/2814>
2021-11-23 21:15:05 +01:00
RipleyTom
7bdbde7363 Add options to configure tunnel host and port
In "adb forward" mode, by default, scrcpy connects to localhost:PORT,
where PORT is the local port passed to "adb forward". This assumes that
the tunnel is established on the local host with a local adb server
(which is the common case).

For advanced usage, add --tunnel-host and --tunnel-port to force the
connection to a different destination.

Fixes #2801 <https://github.com/Genymobile/scrcpy/issues/2801>
PR #2807 <https://github.com/Genymobile/scrcpy/pull/2807>

Signed-off-by: Romain Vimont <rom@rom1v.com>
2021-11-21 22:37:52 +01:00
Romain Vimont
ba547e3895 Configure feature test macros in meson
Refs #2807 <https://github.com/Genymobile/scrcpy/pull/2807>

Co-authored-by: RipleyTom <RipleyTom@users.noreply.github.com>
2021-11-21 00:20:11 +01:00
Romain Vimont
057c7a4df4 Move str_util to str
Simplify naming.
2021-11-14 01:22:22 +01:00
Romain Vimont
c4d008b96a Extract adb tunnel to a separate component
This simplifies the server code.
2021-11-14 01:22:22 +01:00
Romain Vimont
40340509d9 Add interruptor utilities
Expose wrapper functions for interrupting blocking calls, for process
and sockets.
2021-11-13 22:54:18 +01:00
Romain Vimont
e0896142db Introduce interruptor tool
An interruptor instance will help to wake up a blocking call from
another thread (typically to terminate immediately on Ctrl+C).
2021-11-13 22:53:07 +01:00
Romain Vimont
d4c262301f Move functions from process to file
Move filesystem-related functions from process.[ch] to file.[ch].
2021-11-12 22:44:37 +01:00
Romain Vimont
38332f683c Add util function to get terminal size 2021-11-11 15:22:39 +01:00
Romain Vimont
9ec3406568 Add line wrapper
Add a tool to wrap lines at words boundaries (spaces) to fit in a
specified number of columns, left-indented by a specified number of
spaces.
2021-11-11 14:55:53 +01:00
Romain Vimont
6dba1922c1 Add string buffer util
This will help to build strings incrementally.
2021-11-11 14:55:52 +01:00
Romain Vimont
27fa23846d Define default options as const struct
This is more readable than a macro, and we could ifdef some fields.
2021-10-27 18:43:47 +02:00
Alynx Zhou
207082977a Add support for USB HID keyboard over AOAv2
This provides a better input experience, by simulating a physical
keyboard. It converts SDL keyboard events to proper HID events, and send
them over AOAv2.

This is a rewriting and bugfix of the origin code from @amosbird:
<https://github.com/Genymobile/scrcpy/issues/279#issuecomment-453819354>

The feature is enabled the command line option -K or --hid-keyboard,
and is only available on Linux, over USB.

Refs <https://source.android.com/devices/accessories/aoa2#hid-support>
Refs <https://www.usb.org/sites/default/files/hid1_11.pdf>

PR #2632 <https://github.com/Genymobile/scrcpy/pull/2632>

Signed-off-by: Romain Vimont <rom@rom1v.com>
2021-10-26 21:30:04 +02:00
Romain Vimont
f7d1efdf1d Extract mouse processor trait
Mainly for consistency with the keyboard processor trait.

This could allow to provide alternative mouse processors.
2021-10-26 21:30:04 +02:00
Romain Vimont
bcf5a9750f Extract keyboard processor trait
This will allow to provide alternative key processors.
2021-10-26 21:30:04 +02:00
Romain Vimont
1e340caf76 Remove legacy scrcpy icon
Remove the old icon in XPM format and the code to load it.
2021-10-25 18:08:37 +02:00
Romain Vimont
6004f0b6b0 Use a new scrcpy icon
Use the new icon designed by @varlesh:
<https://github.com/Genymobile/scrcpy/pull/1987#issuecomment-949684080>

Load it from a PNG file (SDL only supports bitmap icons).
2021-10-25 18:08:37 +02:00
Romain Vimont
0e4564da03 Add icon loader
Add helper to load icons from image files via FFmpeg.
2021-10-25 18:08:37 +02:00
Romain Vimont
2f03141e9f Add clock tests
The clock rolling sum is not trivial. Test it.
2021-07-14 14:54:22 +02:00
Romain Vimont
79278961b9 Implement buffering
To minimize latency (at the cost of jitter), scrcpy always displays a
frame as soon as it available, without waiting.

However, when recording (--record), it still writes the captured
timestamps to the output file, so that the recorded file can be played
correctly without jitter.

Some real-time use cases might benefit from adding a small latency to
compensate for jitter too. For example, few tens of seconds of latency
for live-streaming are not important, but jitter is noticeable.

Therefore, implement a buffering mechanism (disabled by default) to add
a configurable latency delay.

PR #2417 <https://github.com/Genymobile/scrcpy/issues/2417>
2021-07-14 14:27:33 +02:00
Romain Vimont
4d8bcfc68a Extract current video_buffer to frame_buffer
The current video buffer only stores one pending frame.

In order to add a new buffering feature, move this part to a separate
"frame buffer". Keep the video_buffer, which currently delegates all its
calls to the frame_buffer.
2021-07-14 14:22:32 +02:00
Romain Vimont
ec871dd3f5 Wrap tick API
This avoids to use the SDL timer API directly, and will allow to handle
generic ticks (possibly negative).
2021-07-14 14:22:32 +02:00
Romain Vimont
5c95d18beb Move log level conversion to log API 2021-06-20 16:04:18 +02:00
Romain Vimont
6adc97198b Provide device info directly on server connection
This avoids to retrieve them in a separate step.
2021-05-17 08:52:08 +02:00
Marco Martinelli
d39161f753 Add support for v4l2loopback
It allows to send the video stream to /dev/videoN, so that it can be
captured (like a webcam) by any v4l2-capable tool.

PR #2232 <https://github.com/Genymobile/scrcpy/pull/2232>
PR #2233 <https://github.com/Genymobile/scrcpy/pull/2233>
PR #2268 <https://github.com/Genymobile/scrcpy/pull/2268>

Co-authored-by: Romain Vimont <rom@rom1v.com>
2021-04-25 14:59:10 +02:00
Romain Vimont
9826c5c4a4 Remove HiDPI compilation flag
Always enable HiDPI support, there is no reason to expose a compilation
flag.
2021-04-04 15:00:13 +02:00
Romain Vimont
b16b65a715 Simplify default values
It makes sense to extract default values for bitrate and port range
(which are arbitrary and might be changed in the future).

However, the default values for "max size" and "lock video orientation"
are naturally unlimited/unlocked, and will never be changed. Extracting
these options just added complexity for no benefit, so hardcode them.
2021-02-25 22:19:05 +01:00
Romain Vimont
9cd1a7380d Enable NDEBUG via Meson built-in option 2021-02-25 22:19:05 +01:00
Romain Vimont
f6320c7e31 Wrap SDL thread functions into scrcpy-specific API
The goal is to expose a consistent API for system tools, and paves the
way to make the "core" independant of SDL in the future.
2021-02-17 09:54:03 +01:00
Romain Vimont
c0dde0fade Provide strdup() compat
Make strdup() available on all platforms.
2021-02-17 09:53:25 +01:00
Romain Vimont
8dbb1676b7 Factorize meson compiler variable initialization 2021-01-17 19:44:23 +01:00
Romain Vimont
cc6f5020d8 Move conditional src files in meson.build
Declare all the source files (including the platform-specific ones) at
the beginning.
2021-01-08 16:44:21 +01:00
Romain Vimont
4bd9da4c93 Split command into process and adb
The process API provides the system-specific implementation, the adb API
uses it to expose adb commands.
2021-01-08 16:44:21 +01:00
Romain Vimont
a46733906a Replace noconsole binary by a wrapper script
This simplifies the build system.

Refs <https://github.com/Genymobile/scrcpy/issues/1975#issuecomment-745314161>
2020-12-22 18:51:59 +01:00
Romain Vimont
1b76d9fd78 Customize shortcut modifier
Add --shortcut-mod, and use Alt as default modifier.

This paves the way to forward the Ctrl key to the device.
2020-08-01 16:31:27 +02:00
Romain Vimont
08c0c64af6 Rename test names from "event" to "msg"
The meson test names had not been changed when "event" had been renamed
to "message".

Ref: 28980bbc90
2020-06-11 23:06:02 +02:00
Romain Vimont
bea7658807 Enable trilinear filtering for OpenGL
Improve downscaling quality if mipmapping is available.

Suggested-by: Giumo Clanjor (哆啦比猫/兰威举) <cjxgm2@gmail.com>

Fixes #40 <https://github.com/Genymobile/scrcpy/issues/40>
Ref: <https://github.com/Genymobile/scrcpy/issues/40#issuecomment-591917787>
2020-04-15 17:39:51 +02:00
Romain Vimont
902b99174d Fix server debugger for Android >= 9
Add a compilation flag to select the debugger method to use:
 - old: Android < 9
 - new: Android >= 9

See <https://github.com/Genymobile/scrcpy/issues/1187#issuecomment-599075661>
2020-03-19 19:15:43 +01:00
George Stamoulis
1982bc439b Add option to lock video orientation
PR #1151 <https://github.com/Genymobile/scrcpy/pull/1151>

Signed-off-by: Romain Vimont <rom@rom1v.com>
2020-02-27 21:24:37 +01:00
Romain Vimont
dc7fcf3c7a Accept port range
Accept a range of ports to listen to, so that it does not fail if
another instance of scrcpy is currently starting.

The range can be passed via the command line:

    scrcpy -p 27183:27186
    scrcpy -p 27183  # implicitly 27183:27183, as before

The default is 27183:27199.

Closes #951 <https://github.com/Genymobile/scrcpy/issues/951>
2020-01-18 17:21:00 +01:00
Romain Vimont
db6252e52b Simplify net.c
The platform-specific code for net.c was implemented in sys/*/net.c.

But the differences are quite limited, so use ifdef-blocks in the single
net.c instead.
2019-12-15 22:04:09 +01:00
Romain Vimont
e4cebc8d4c Do not build tests in release mode
Assertions would not be executed.

And as a side effect, it causes "unused variable" warnings.
2019-12-09 23:24:39 +01:00
Romain Vimont
ba1b36758e Define SDL_MAIN_HANDLED in all tests
Each test defines its own main() function. If this flag is not set, then
SDL redefines it to SDL_main(), causing compilation failures.
2019-12-09 23:24:39 +01:00
Romain Vimont
ad92a192b5 Fix meson.build codestyle 2019-12-09 23:00:55 +01:00
Romain Vimont
929bf48c7e Add tests for command-line parsing 2019-12-08 23:19:01 +01:00
Romain Vimont
d950383b72 Move command-line parsing to a separate file 2019-12-08 23:18:57 +01:00
Yu-Chen Lin
b2bf25c52c Add test_buffer_util
Signed-off-by: Yu-Chen Lin <npes87184@gmail.com>
2019-12-04 19:24:59 +01:00
Romain Vimont
b5ebb234dd Replace BUILD_DEBUG by NDEBUG
Use the "standard" NDEBUG definition, which is used by assert().
2019-11-27 21:11:52 +01:00
Romain Vimont
dfd0707a29 Move utilities to util/ 2019-11-24 11:53:23 +01:00
Romain Vimont
18f2e33a8b Fix noconsole.exe
The linker flag "-mwindows" has no effect on my current MinGW.

Instead, passing "-Wl,--subsystem,windows" works.

Fixes <https://github.com/Genymobile/scrcpy/issues/691>
2019-11-19 12:22:11 +01:00
Romain Vimont
683f7ca848 Document how to attach a debugger to the server 2019-11-03 19:42:37 +01:00
Romain Vimont
0415672a75 Merge branch 'master' into dev 2019-11-03 15:56:10 +01:00
yangfl
4696878a97 Add manpage for scrcpy 2019-10-31 18:18:19 +08:00
Romain Vimont
3da95b52bd Rename scrcpy-server.jar to scrcpy-server
The server name ending with .jar has several drawbacks:
 - meson requires the jar executable to attempt to modify it:
     <https://github.com/Genymobile/scrcpy/issues/404#issuecomment-456065923>
     <https://github.com/mesonbuild/meson/issues/4844>
 - meson warns during "ninja install"
     <https://github.com/Genymobile/scrcpy/issues/458>
 - some users try to execute it on the computer as a java executable

Removing the extension solves all these problems.
2019-10-31 10:54:29 +01:00
Romain Vimont
9463850c24 Rename "convert.h" to "event_converter.h"
The filename gave no hint about what was converted.
2019-09-15 17:29:03 +02:00
Romain Vimont
53b6ee2cf4 Add generic intrusive FIFO queue
We need several FIFO queues (a queue of packets, a queue of messages,
etc.).

Some of them are implemented using cbuf, a generic circular buffer. But
for recording, we need to store the packets in an unbounded queue until
they are written, so the queue was implemented manually.

Create a generic implementation (using macros) to avoid reimplementing
it every time.
2019-08-01 23:14:50 +02:00
Romain Vimont
2755bfc255 Improve portable builds
In portable builds, scrcpy-server.jar was supposed to be present in the
current directory, so in practice it worked only if scrcpy was launched
from its own directory.

Instead, find the absolute path of the executable and build a suitable
path to use scrcpy-server.jar from the same directory.
2019-06-11 17:44:07 +02:00
Romain Vimont
eb34098add Simplify portable build configuration
To create a portable build (with scrcpy-server.jar accessible from the
scrcpy directory), replace OVERRIDE_SERVER_PATH by a simple compilation
flag: PORTABLE.

This paves the way to use more complex rules to determine the path of
scrcpy-server.jar in portable builds.
2019-06-11 17:44:07 +02:00
Romain Vimont
b777760bca Simplify scrcpy-server path configuration
The full path of scrcpy-server.jar was partially configured from
meson.build then concatenated by C code.

Instead, directly write the path in C.
2019-06-11 17:44:07 +02:00
Romain Vimont
5d11339259 Inline lock_util functions
They are just tiny wrappers.
2019-06-07 17:19:00 +02:00
Romain Vimont
ebccb9f6cc Add runtime option to render expired frames
Replace the compilation flag SKIP_FRAMES by a runtime flag to force
rendering of expired frames. By default, the expired frames are skipped.
2019-06-05 21:39:42 +02:00
Romain Vimont
28980bbc90 Rename "event" to "message"
After the recent refactorings, a "control event" is not necessarily an
"event" (it may be a "command"). Similarly, the unique "device event"
used to send the device clipboard content is more a "reponse" to the
request from the client than an "event".

Rename both to "message", and rename the message types to better
describe their intent.
2019-05-31 16:18:00 +02:00
Romain Vimont
6112095e75 Add device event receiver
Create a separate component to handle device events, managed by the
controller.
2019-05-30 22:46:52 +02:00
Romain Vimont
f9d2d99166 Add GET_CLIPBOARD device event
Add the first device event, used to forward the device clipboard to the
computer.
2019-05-30 22:36:22 +02:00
Romain Vimont
0a7fe7ad57 Add helpers to truncate UTF-8 at code points
This will help to avoid truncating a UTF-8 string in the middle of a
code point, producing an invalid UTF-8 result.
2019-05-30 22:30:18 +02:00
Romain Vimont
241a3dcba5 Use cbuf for control event queue
Replace the control_event_queue implementation by cbuf.
2019-05-30 22:30:18 +02:00
Romain Vimont
b38292cd69 Add generic circular buffer
Add a circular buffer implementation, to factorize multiple specific
queues implementation.
2019-05-30 22:30:18 +02:00
Romain Vimont
0fbab42f8c Format meson.build for readability 2019-05-30 22:30:18 +02:00
Romain Vimont
e6e011baaf Add stream layer
The decoder initially read from the socket, decoded the video and sent
the decoded frames to the screen:

              +---------+      +----------+
  socket ---> | decoder | ---> |  screen  |
              +---------+      +----------+

The design was simple, but the decoder had several responsabilities.

Then we added the recording feature, so we added a recorder, which
reused the packets received from the socket managed by the decoder:

                                    +----------+
                               ---> |  screen  |
              +---------+     /     +----------+
  socket ---> | decoder | ----
              +---------+     \     +----------+
                               ---> | recorder |
                                    +----------+

This lack of separation of concerns now have concrete implications: we
could not (properly) disable the decoder/display to only record the
video.

Therefore, split the decoder to extract the stream:

                                    +----------+      +----------+
                               ---> | decoder  | ---> |  screen  |
              +---------+     /     +----------+      +----------+
  socket ---> | stream  | ----
              +---------+     \     +----------+
                               ---> | recorder |
                                    +----------+

This will allow to record the stream without decoding the video.
2019-03-02 18:45:45 +01:00
Romain Vimont
fff87095d9 Rename "frames" to "video_buffer"
It better describes the purpose of the structure.
2019-03-02 15:24:33 +01:00
Romain Vimont
6dc6ec05d5 Configure version at meson project level
Make meson aware of the project version, so that it does not print:

    Project version: undefined
2018-11-12 14:10:21 +01:00
Pierre Gordon
a17f1116ce Bump version to 1.5
Signed-off-by: Romain Vimont <rom@rom1v.com>
2018-11-12 08:24:18 +01:00
Romain Vimont
27686e9361 Add recorder
Implement recording in a separate "class".
2018-11-11 16:30:23 +01:00
Romain Vimont
24d107d017 Bump version to 1.4 2018-10-03 23:03:27 +02:00
Romain Vimont
536b31829a Separate multi-words filenames by '_'
Rename foobar.ext to foo_bar.ext.

<https://github.com/Genymobile/scrcpy/pull/226#discussion_r209454865>
2018-08-15 19:30:01 +02:00
npes87184
aa97eed24b installer -> file_handler
Signed-off-by: npes87184 <npes87184@gmail.com>
2018-08-15 17:11:41 +02:00
Romain Vimont
7e42358a7b Bump version to 1.3 2018-08-09 19:14:17 +02:00
Romain Vimont
f705a73149 Use a meson option to crossbuild for Windows
Meson decided to crossbuild for Windows as soon as
meson.is_cross_build() returned true. This made non-Windows crossbuilds
fail.

Instead, add an explicit option "crossbuild_windows".

Fixes <https://github.com/Genymobile/scrcpy/issues/165>.
2018-06-05 20:45:41 +02:00
Romain Vimont
8106bb8215 Bump version to 1.2 2018-05-28 22:32:14 +02:00
Romain Vimont
a63dd47f2d Make CreateProcess() flags depend on "noconsole"
On Windows, display the output of external commands (adb) when a console
is available.
2018-05-28 22:28:20 +02:00
Romain Vimont
aedc2c2da9 Also build "noconsole" binary for Windows
On Windows, an application is either console or gui, it cannot be both.

Scrcpy should be both: it outputs important information to console, but
we still want to be able to ignore the console and launch it without a
visible cmd.exe window.

Therefore, build two binaries:
 - scrcpy.exe
 - scrcpy-noconsole.exe
2018-05-28 20:45:54 +02:00
Romain Vimont
106b87a4d2 Add cross-compilation scripts for Windows
Build the Windows binary from mingw on Linux, using the official
prebuilt binaries for ffmpeg, SDL2 and adb.

MSYS2 and all its packaged dll are not necessary anymore.
2018-05-28 20:45:54 +02:00
Adonis Najimi
e2a2973990 Drag and drop to install apk files from computer
<https://github.com/Genymobile/scrcpy/pull/133>
2018-05-28 20:45:54 +02:00
Romain Vimont
f5cf6c1b2c Include source root directory
All headers and sources are in src/. To avoid using relative includes
from subdirectories ("../../"), include the source root directory.
2018-03-20 21:32:41 +01:00
Romain Vimont
d744837f13 Bump version to 1.1 2018-03-14 09:34:00 +01:00
Romain Vimont
c2ac6fe7bd Upgrade version to 1.0 2018-03-08 09:21:06 +01:00
Romain Vimont
fffeedffda Expose High DPI support configuration flag
The High DPI support is enabled by default, so that the renderer use the
full definition of High DPI screens.

However, there are still mouse coordinates problems on some MacOS having
High DPI support (but not all), so expose a way to disable it.
2018-03-07 18:07:02 +01:00
Romain Vimont
e3f5d3b49b Double the default bitrate
Set the default video bitrate to 8Mbps. This greatly increase quality on
fast motion, without negative side effects.
2018-03-07 18:04:38 +01:00
Romain Vimont
089378926b Rename SCRCPY_SERVER_JAR to SCRCPY_SERVER_PATH
The server is currently a JAR, but it may ba an APK or a DEX, so the
variable name should not contain the type.

Rename the environment variable, the Meson options and the C
definitions.
2018-02-16 15:36:25 +01:00
Romain Vimont
9b056f5091 Replace SDL_net by custom implementation
SDL_net is not very suitable for scrcpy.

For example, SDLNet_TCP_Accept() is non-blocking, so we have to wrap it
by calling many SDL_Net-specific functions to make it blocking.

But above all, SDLNet_TCP_Open() is a server socket only when no IP is
provided; otherwise, it's a client socket. Therefore, it is not possible
to create a server socket bound to localhost, so it accepts connections
from anywhere.

This is a problem for scrcpy, because on start, the application listens
for nearly 1 second until it accepts the first connection, supposedly
from the device. If someone on the local network manages to connect to
the server socket first, then they can stream arbitrary H.264 video.
This may be troublesome, for example during a public presentation ;-)

Provide our own simplified API (net.h) instead, implemented for the
different platforms.
2018-02-16 00:56:58 +01:00
Romain Vimont
000ced9ba8 Refactor screencontrol to inputmanager
The "screen control" handled user input, which happened to be only
used to control the screen.

The controller and screen were passed to every function. Instead, group
them in a struct input_manager.

The purpose is to add a new shortcut to enable/disable FPS counter. This
feature is not related to "screen control", and will require access to
the "frames" instance.
2018-02-15 12:07:47 +01:00