@@ -0,0 +1,4 @@
|
||||
*.jpg filter=lfs diff=lfs merge=lfs -text
|
||||
*.png filter=lfs diff=lfs merge=lfs -text
|
||||
*.mp4 filter=lfs diff=lfs merge=lfs -text
|
||||
*.ttf filter=lfs diff=lfs merge=lfs -text
|
||||
@@ -1,4 +1,7 @@
|
||||
*.deb
|
||||
*.zip
|
||||
.DS_Store
|
||||
\#*
|
||||
\#*
|
||||
|
||||
# Non open source packages
|
||||
kiosk-browser
|
||||
@@ -0,0 +1,19 @@
|
||||
Package: tooloop-compositor
|
||||
Version: 1.0.0
|
||||
Maintainer: Tooloop Multimedia
|
||||
Homepage: https://www.tooloop.de
|
||||
Section: tooloop/addon
|
||||
Architecture: all
|
||||
Name: picom Compositor
|
||||
Depends: picom
|
||||
Recommends: picom-conf
|
||||
Thumbnail: picom-thumbnail.png
|
||||
Description: Installs the picom compositor to eliminate screen tearing.
|
||||
[picom](https://github.com/yshui/picom) is a compositor for X, and a fork of Compton.
|
||||
It has many features but we are primarily using it to fight screen tearing.
|
||||
.
|
||||
There is a graphical tool to configure picom:
|
||||
.
|
||||
```bash
|
||||
picom-conf /home/tooloop/.config/picom.conf
|
||||
```
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
picom &
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
rm -f /assets/logs/picom.log
|
||||
@@ -0,0 +1,54 @@
|
||||
# Example with all options at
|
||||
# /usr/share/picom-conf/picom.conf.example
|
||||
|
||||
|
||||
#################################
|
||||
# General Settings #
|
||||
#################################
|
||||
|
||||
# Specify the backend to use: `xrender`, `glx`, or `xr_glx_hybrid`.
|
||||
# `xrender` is the default one.
|
||||
#
|
||||
backend = "glx";
|
||||
# backend = "xrender";
|
||||
|
||||
# Enable/disable VSync.
|
||||
# vsync = false
|
||||
vsync = true;
|
||||
|
||||
# GLX backend: Avoid using stencil buffer, useful if you don't have a stencil buffer.
|
||||
# Might cause incorrect opacity when rendering transparent content (but never
|
||||
# practically happened) and may not work with blur-background.
|
||||
# My tests show a 15% performance boost. Recommended.
|
||||
#
|
||||
glx-no-stencil = true;
|
||||
|
||||
# GLX backend: Avoid rebinding pixmap on window damage.
|
||||
# Probably could improve performance on rapid window content changes,
|
||||
# but is known to break things on some drivers (LLVMpipe, xf86-video-intel, etc.).
|
||||
# Recommended if it works.
|
||||
#
|
||||
glx-no-rebind-pixmap = false;
|
||||
|
||||
# Use X Sync fence to sync clients' draw calls, to make sure all draw
|
||||
# calls are finished before picom starts drawing. Needed on nvidia-drivers
|
||||
# with GLX backend for some users.
|
||||
#
|
||||
# xrender-sync-fence = false;
|
||||
|
||||
# Set the log level. Possible values are:
|
||||
# "trace", "debug", "info", "warn", "error"
|
||||
# in increasing level of importance. Case doesn't matter.
|
||||
# If using the "TRACE" log level, it's better to log into a file
|
||||
# using *--log-file*, since it can generate a huge stream of logs.
|
||||
#
|
||||
# log-level = "debug"
|
||||
log-level = "warn";
|
||||
|
||||
# Set the log file.
|
||||
# If *--log-file* is never specified, logs will be written to stderr.
|
||||
# Otherwise, logs will to written to the given file, though some of the early
|
||||
# logs might still be written to the stderr.
|
||||
# When setting this option from the config file, it is recommended to use an absolute path.
|
||||
#
|
||||
log-file = "/assets/logs/picom.log";
|
||||
@@ -1,4 +1,7 @@
|
||||
#!/bin/bash
|
||||
echo "-------------------------------------------------------------------------"
|
||||
echo "Copying packages to local repository"
|
||||
echo ""
|
||||
|
||||
# move them to the repository
|
||||
for archive in *; do
|
||||
@@ -13,9 +16,4 @@ done
|
||||
# update local package repository
|
||||
/opt/tooloop/scripts/tooloop-update-packages
|
||||
|
||||
sudo systemctl restart tooloop-control.service
|
||||
|
||||
# list available packages
|
||||
#apt list tooloop*
|
||||
|
||||
tree /assets/packages/
|
||||
sudo systemctl restart tooloop-control.service
|
||||
|
Before Width: | Height: | Size: 341 KiB |
|
Before Width: | Height: | Size: 160 KiB |
|
Before Width: | Height: | Size: 152 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 29 KiB |
@@ -1,12 +1,12 @@
|
||||
Package: tooloop-glmark2
|
||||
Package: tooloop-gpu-benchmark
|
||||
Version: 1.0.0
|
||||
Maintainer: Tooloop Multimedia
|
||||
Homepage: https://www.tooloop.de
|
||||
Bugs: https://github.com/glmark2/glmark2
|
||||
Section: tooloop/presentation
|
||||
Depends: glmark2
|
||||
Architecture: amd64
|
||||
Name: glmark2
|
||||
Architecture: all
|
||||
Name: GPU Benchmark
|
||||
Thumbnail: glmark2-thumbnail.jpg
|
||||
Media: glmark2-jellyfish.jpg, glmark2-buffer.jpg, glmark2-refract.jpg, glmark2-shadow.jpg
|
||||
Description: OpenGL 2.0 and ES 2.0 benchmark
|
||||
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 899 KiB |
|
Before Width: | Height: | Size: 281 KiB |
|
Before Width: | Height: | Size: 535 KiB |
|
Before Width: | Height: | Size: 140 KiB |
|
Before Width: | Height: | Size: 466 KiB |
|
Before Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 212 KiB |
|
Before Width: | Height: | Size: 323 KiB |
|
Before Width: | Height: | Size: 451 KiB |
|
Before Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 262 KiB |
|
Before Width: | Height: | Size: 592 KiB |
@@ -1,83 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Slideshow</title>
|
||||
<style media="screen">
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: black;
|
||||
}
|
||||
|
||||
.slide {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
opacity: 0;
|
||||
transition: opacity 1s;
|
||||
}
|
||||
|
||||
.active {
|
||||
opacity: 1;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.next {
|
||||
z-index: 3;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="slideshow">
|
||||
<div class="slide active" style="background-image: url(/media/assets/data/image1.jpg)"></div>
|
||||
<div class="slide" style="background-image: url(/media/assets/data/image2.jpg)"></div>
|
||||
<div class="slide" style="background-image: url(/media/assets/data/image3.jpg)"></div>
|
||||
<div class="slide" style="background-image: url(/media/assets/data/image4.jpg)"></div>
|
||||
<div class="slide" style="background-image: url(/media/assets/data/image5.jpg)"></div>
|
||||
<div class="slide" style="background-image: url(/media/assets/data/image6.jpg)"></div>
|
||||
<div class="slide" style="background-image: url(/media/assets/data/image7.jpg)"></div>
|
||||
<div class="slide" style="background-image: url(/media/assets/data/image8.jpg)"></div>
|
||||
<div class="slide" style="background-image: url(/media/assets/data/image9.jpg)"></div>
|
||||
<div class="slide" style="background-image: url(/media/assets/data/image10.jpg)"></div>
|
||||
<div class="slide" style="background-image: url(/media/assets/data/image11.jpg)"></div>
|
||||
<div class="slide" style="background-image: url(/media/assets/data/image12.jpg)"></div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var active, next;
|
||||
|
||||
function nextImage() {
|
||||
active = document.querySelector("#slideshow .slide.active");
|
||||
active.classList.remove("active");
|
||||
|
||||
active = getNextSlide(active);
|
||||
active.classList.add("active");
|
||||
active.classList.remove("next");
|
||||
|
||||
next = getNextSlide(active)
|
||||
next.classList.add("next")
|
||||
}
|
||||
|
||||
function getNextSlide(slide) {
|
||||
return slide.nextElementSibling ? slide.nextElementSibling : document.querySelectorAll("#slideshow .slide")[0];
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
setInterval("nextImage()", 7000);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
COMMAND="chromium-browser --noerrdialogs --kiosk --incognito /media/assets/presentation/slideshow.html"
|
||||
|
||||
if [ $EUID == 0 ]; then
|
||||
su tooloop -c "$COMMAND" &
|
||||
else
|
||||
$COMMAND &
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
killall chrome
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,20 @@
|
||||
Package: tooloop-intel-media-va-driver-non-free
|
||||
Version: 1.0.0
|
||||
Maintainer: Tooloop Multimedia
|
||||
Homepage: https://www.tooloop.de
|
||||
Bugs: https://www.github.com/Tooloop/Tooloop-Packages
|
||||
Section: tooloop/addon
|
||||
Architecture: amd64
|
||||
Depends: intel-media-va-driver-non-free
|
||||
Name: Intel Hardware Video Acceleration
|
||||
Thumbnail: intel-media-va-driver.png
|
||||
Description: Installs the Intel Media Driver for VAAPI
|
||||
The [Intel Media Driver for VAAPI](https://github.com/intel/media-driver) is a
|
||||
new VA-API (Video Acceleration API) user mode driver supporting hardware
|
||||
accelerated decoding, encoding, and video post processing for GEN based
|
||||
graphics hardware.
|
||||
.
|
||||
Installing this will reduce CPU load when decoding e. g. h.264 video if
|
||||
supported by the playback software. As result your video will run smoother and
|
||||
your device produces less heat.
|
||||
|
||||
|
Before Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,13 @@
|
||||
Package: tooloop-media-player
|
||||
Version: 1.0.0
|
||||
Maintainer: Tooloop Multimedia
|
||||
Homepage: https://www.tooloop.de
|
||||
Bugs: https://github.com/Tooloop/Tooloop-Packages
|
||||
Section: tooloop/presentation
|
||||
Architecture: all
|
||||
Depends: mpv
|
||||
Name: Media Player
|
||||
Description: A simple image and video player
|
||||
The tooloop media player is using [mpv](https://mpv.io/) to loop over all images and videos in `/assets/data`.
|
||||
Thumbnail: video-player-thumbnail.jpg
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
# mpv
|
||||
|
||||
mpv is a fork of mplayer2, which is a fork of MPlayer.
|
||||
|
||||
mpv as a whole is licensed under the GNU General Public License GPL version 2
|
||||
or later (called GPLv2+ in this document, see LICENSE.GPL for full license
|
||||
text) by default, or the GNU Lesser General Public License LGPL version 2 or
|
||||
later (LGPLv2.1+ in this document, see LICENSE.LGPL for full license text) if
|
||||
built with the --enable-lgpl configure switch.
|
||||
|
||||
Most source files are LGPLv2.1+ or GPLv2+, but some files are available under
|
||||
more liberal licenses, such as BSD, MIT, ISC, and possibly others. Look at the
|
||||
copyright header of each source file, and grep the sources for "Copyright" if
|
||||
you need to know details. C source files without Copyright notice are usually
|
||||
licensed as LGPLv2.1+. Also see the list of files with specific licenses below
|
||||
(not all files can have a standard license header).
|
||||
|
||||
All new contributions must be LGPLv2.1+ licensed. Using a more liberal license
|
||||
compatible to LGPLv2.1+ is also ok.
|
||||
|
||||
Changes done to GPL code must come with the implicit/explicit agreement that the
|
||||
project can relicense the changes to LGPLv2.1+ at a later point without asking
|
||||
the contributor. This is a safeguard for making potential relicensing of
|
||||
remaining GPL code to LGPLv2.1+ easier.
|
||||
|
||||
See DOCS/contribute.md for binding rules wrt. licensing for contributions.
|
||||
|
||||
For information about authors and contributors, consult the git log, which
|
||||
contains the complete SVN and CVS history as well.
|
||||
|
||||
"v2.1+" in this context means "version 2.1 or later".
|
||||
|
||||
Some libraries are GPLv2+ or GPLv3+ only. Building mpv with Samba support makes
|
||||
it GPLv3+.
|
||||
|
||||
mpv can be built as LGPLv2.1+ with the --enable-lgpl configure option. To add
|
||||
a LGPL mode to mpv, MPlayer code had to be relicensed from GPLv2+ to LGPLv2.1+
|
||||
by asking the MPlayer authors for permission. Since permission could not be
|
||||
obtained from everyone, LGPL mode disables the following features, some of
|
||||
them quite central:
|
||||
- Linux X11 video output
|
||||
- BSD audio output via OSS
|
||||
- NVIDIA/Linux hardware decoding (vdpau, although nvdec usually works)
|
||||
- Linux TV input
|
||||
- minor features: jack, DVD, CDDA, SMB, CACA, legacy direct3d VO
|
||||
Some of these will be fixed in the future. The intended use for LGPL mode is
|
||||
with libmpv, and currently it's not recommended to build mpv CLI in LGPL mode
|
||||
at all.
|
||||
|
||||
The following files are still GPL only (--enable-lgpl disables them):
|
||||
|
||||
audio/out/ao_jack.c will stay GPL
|
||||
audio/out/ao_oss.c will stay GPL
|
||||
stream/dvb* must stay GPL
|
||||
stream/stream_cdda.c unknown
|
||||
stream/stream_dvb.* must stay GPL
|
||||
stream/stream_dvdnav.c unknown
|
||||
video/out/vo_caca.c unknown
|
||||
video/out/vo_direct3d.c unknown
|
||||
video/out/vo_vaapi.c probably impossible (some company's code)
|
||||
video/out/vo_vdpau.c probably impossible (nVidia's code)
|
||||
video/out/vo_x11.c probably impossible
|
||||
video/out/vo_xv.c probably impossible
|
||||
video/out/x11_common.* probably impossible
|
||||
video/vdpau.c hard (GPL-only parts must be ifdefed)
|
||||
video/vdpau.h unknown
|
||||
video/vdpau_mixer.* actual code must be rewritten
|
||||
DOCS/man/ GPLv2+
|
||||
bootstrap.py unknown license, probably GPLv2+ or LGPLv2+
|
||||
etc/mplayer-input.conf unknown license, probably GPLv2+
|
||||
mpv.desktop unknown license, probably GPLv2+
|
||||
etc/restore-old-bindings.conf unknown license, probably GPLv2+
|
||||
|
||||
None of the cases listed above affect the final binary if it's built as
|
||||
LGPL. Linked libraries still can affect the final license (for example if
|
||||
FFmpeg was built as GPL).
|
||||
@@ -0,0 +1,7 @@
|
||||
# A simple image and video player
|
||||
|
||||
The tooloop media player is using [mpv](https://mpv.io/) to loop over all images and videos in `/assets/data`.
|
||||
|
||||
## Customizing
|
||||
|
||||
Check out the start script if you want to fiddle with some mpv options. [Here's the reference manual](https://mpv.io/manual/).
|
||||
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
mpv \
|
||||
--fullscreen \
|
||||
--image-display-duration=5 \
|
||||
--loop-playlist \
|
||||
--no-osc \
|
||||
--no-osd-bar \
|
||||
--video-sync=display-resample \
|
||||
/assets/data &
|
||||
|
||||
exit 0
|
||||
@@ -3,6 +3,6 @@
|
||||
# here comes everything, you need to stop the running presentation
|
||||
# basically kill or stop everything you started in `start-presentation.sh`
|
||||
|
||||
kill $(pidof mplayer)
|
||||
killall mpv
|
||||
|
||||
exit 0
|
||||
@@ -3,7 +3,7 @@ Version: 1.0.0
|
||||
Maintainer: Tooloop Multimedia
|
||||
Homepage: https://www.tooloop.de
|
||||
Section: tooloop/addon
|
||||
Architecture: amd64
|
||||
Architecture: all
|
||||
Name: nginx Webserver
|
||||
Depends: nginx, php-fpm, php-mbstring, php-curl, php-xml, php-gd
|
||||
Recommends: tooloop-transparent-cursor
|
||||
@@ -21,7 +21,7 @@ server {
|
||||
|
||||
location ~* \.php$ {
|
||||
try_files $uri =404;
|
||||
fastcgi_pass unix:/var/run/php/php8.1-fpm-tooloop.sock;
|
||||
fastcgi_pass unix:/var/run/php/php8.3-fpm-tooloop.sock;
|
||||
include fastcgi.conf;
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
@@ -33,7 +33,7 @@ group = tooloop
|
||||
; (IPv6 and IPv4-mapped) on a specific port;
|
||||
; '/path/to/unix/socket' - to listen on a unix socket.
|
||||
; Note: This value is mandatory.
|
||||
listen = /var/run/php/php8.1-fpm-tooloop.sock
|
||||
listen = /var/run/php/php8.3-fpm-tooloop.sock
|
||||
|
||||
; Set listen(2) backlog.
|
||||
; Default Value: 511 (-1 on FreeBSD and OpenBSD)
|
||||
@@ -238,7 +238,7 @@ pm.max_spare_servers = 3
|
||||
; last request memory: 0
|
||||
;
|
||||
; Note: There is a real-time FPM status monitoring sample web page available
|
||||
; It's available in: /usr/share/php/8.1/fpm/status.html
|
||||
; It's available in: /usr/share/php/8.3/fpm/status.html
|
||||
;
|
||||
; Note: The value must start with a leading slash (/). The value can be
|
||||
; anything, but it may not be a good idea to use the .php extension or it
|
||||
@@ -0,0 +1,13 @@
|
||||
Package: tooloop-onboarding
|
||||
Version: 1.0.0
|
||||
Maintainer: Tooloop Multimedia
|
||||
Homepage: https://www.tooloop.de
|
||||
Bugs: https://github.com/Tooloop/Tooloop-Packages
|
||||
Section: tooloop/presentation
|
||||
Architecture: all
|
||||
Depends: chromium-browser
|
||||
Name: Onboarding
|
||||
Description: Tipps and first steps
|
||||
Learn how to find your way in Tooloop OS.
|
||||
Thumbnail: onboarding-thumbnail.png
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
:root {
|
||||
--font-size: 18px;
|
||||
--light-grey: #f2f2f2;
|
||||
--medium-grey: #999999;
|
||||
--dark-grey: #333333;
|
||||
--pink: #E6004C;
|
||||
--width: 800px;
|
||||
--height: 600px;
|
||||
--scale: 1.0;
|
||||
--slide-duration: 10s;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Clear Sans";
|
||||
src: url("../fonts/ClearSans-Regular.ttf");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Clear Sans";
|
||||
src: url("../fonts/ClearSans-Italic.ttf");
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Clear Sans";
|
||||
src: url("../fonts/ClearSans-Bold.ttf");
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Clear Sans";
|
||||
src: url("../fonts/ClearSans-BoldItalic.ttf");
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
html {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
body {
|
||||
width: var(--width);
|
||||
height: var(--height);
|
||||
transform: scale(var(--scale));
|
||||
transform-origin: 0 0;
|
||||
|
||||
background-color: black;
|
||||
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: var(--font-size);
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
|
||||
font-family: "Clear Sans", system-ui, sans-serif;
|
||||
}
|
||||
|
||||
nav {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
button {
|
||||
pointer-events: all;
|
||||
position: absolute;
|
||||
padding: 0;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
border: none;
|
||||
background: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background: var(--light-grey);
|
||||
}
|
||||
|
||||
button:active {
|
||||
background: var(--medium-grey);
|
||||
}
|
||||
|
||||
button.close-button {
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
}
|
||||
button.close-button:hover {
|
||||
background-color: rgba(255,255,255, 0.1);
|
||||
}
|
||||
|
||||
button.close-button svg {
|
||||
stroke: white;
|
||||
}
|
||||
|
||||
button.slide-button {
|
||||
bottom: calc((var(--height) / 4 - 2rem) / 2);
|
||||
}
|
||||
|
||||
button.slide-button svg {
|
||||
stroke: var(--pink);
|
||||
}
|
||||
|
||||
button.slide-button.previous {
|
||||
left: 1rem;
|
||||
}
|
||||
|
||||
button.slide-button.next {
|
||||
right: 1rem;
|
||||
}
|
||||
|
||||
#slider {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow-x: auto;
|
||||
overflow-y: none;
|
||||
scroll-snap-type: x mandatory;
|
||||
scroll-behavior: smooth;
|
||||
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
#slider::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.slide {
|
||||
scroll-snap-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
width: var(--width);
|
||||
height: var(--height);
|
||||
}
|
||||
|
||||
.slide .image {
|
||||
background-color: var(--light-grey);
|
||||
height: calc(var(--height) * 3 / 4);
|
||||
}
|
||||
.slide.no-text .image {
|
||||
height: var(--height);
|
||||
}
|
||||
|
||||
.slide .image img,
|
||||
.slide .image video {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.slide.no-text .description {
|
||||
display: none;
|
||||
}
|
||||
.slide .description {
|
||||
position: relative;
|
||||
padding: 0.5rem 8rem 1rem;
|
||||
height: calc(var(--height) / 4);
|
||||
background-color: white;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.slide .description h1,
|
||||
.slide .description p {
|
||||
margin: 0 0 0.5rem 0;
|
||||
}
|
||||
.slide .description p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.slide .description h1 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
|
||||
.slide .description h1:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.slide .description code {
|
||||
background-color: #ddd;
|
||||
padding: 0.1rem 0.3rem;
|
||||
color: var(--dark-grey);
|
||||
font-size: 0.888rem;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.progressBar {
|
||||
position: fixed;
|
||||
height: .333rem;
|
||||
width: 0%;
|
||||
background-color: #ccc;
|
||||
mix-blend-mode: multiply;
|
||||
/* opacity: 0.5; */
|
||||
bottom: 0px;
|
||||
|
||||
transition: width;
|
||||
transition-duration: 0s;
|
||||
transition-timing-function: linear;
|
||||
}
|
||||
|
||||
.progressBar.playing {
|
||||
width: 100%;
|
||||
transition-duration: var(--slide-duration);
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Welcome to Tooloop OS</title>
|
||||
<link rel="stylesheet" href="css/styles.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="slider"></div>
|
||||
|
||||
<template id="slide-template">
|
||||
<div class="slide">
|
||||
<section class="image"></section>
|
||||
<section class="description"></section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<nav>
|
||||
<button class="slide-button previous" onclick="slider.previous();">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-chevron-left" width="24"
|
||||
height="24" viewBox="0 0 24 24" stroke-width="1.5" fill="none" stroke-linecap="miter"
|
||||
stroke-linejoin="miter">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M15 6l-6 6l6 6" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<button class="slide-button next" onclick="slider.next();">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-chevron-right" width="24"
|
||||
height="24" viewBox="0 0 24 24" stroke-width="1.5" fill="none" stroke-linecap="miter"
|
||||
stroke-linejoin="miter">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M9 6l6 6l-6 6" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<button class="close-button" onclick="window.close();">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-x" width="24" height="24"
|
||||
viewBox="0 0 24 24" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M18 6l-12 12" />
|
||||
<path d="M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<script src="js/marked.min.js"></script>
|
||||
<script src="slides/slides.js"></script>
|
||||
<script src="js/Slider.js"></script>
|
||||
|
||||
<script>
|
||||
var slider = new Slider("#slider", "#slide-template", slides, 10000);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,155 @@
|
||||
class Slider {
|
||||
|
||||
imageTypes = ["png", "gif", "webp", "jpg"];
|
||||
videoTypes = ["mp4", "webm"];
|
||||
|
||||
data;
|
||||
element;
|
||||
progressBar;
|
||||
template;
|
||||
slides = [];
|
||||
activeSlide = 0;
|
||||
slideDuration;
|
||||
slideTimeout;
|
||||
|
||||
constructor(element, template, data, slideDuration = 10000) {
|
||||
this.element = document.querySelector(element);
|
||||
this.template = document.querySelector(template);
|
||||
this.data = data;
|
||||
this.slideDuration = slideDuration;
|
||||
this.ip = location.host;
|
||||
|
||||
// append slides
|
||||
for (let i = 0; i < this.data.length; i++) {
|
||||
let slide = this.template.content.cloneNode(true);
|
||||
let type = this.getType(i);
|
||||
|
||||
switch (type) {
|
||||
// image
|
||||
case "image":
|
||||
let img = document.createElement("img");
|
||||
img.src = "./slides/" + this.data[i].image;
|
||||
slide.querySelector(".image").appendChild(img);
|
||||
break;
|
||||
|
||||
case "video":
|
||||
let video = document.createElement("video");
|
||||
video.autoplay = true;
|
||||
video.loop = true;
|
||||
video.muted = true;
|
||||
video.src = "./slides/" + this.data[i].image;
|
||||
slide.querySelector(".image").appendChild(video);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// texts
|
||||
let hasText = this.data[i].title || this.data[i].description;
|
||||
if (hasText) {
|
||||
// let title = slide.querySelector(".description h1");
|
||||
// title.textContent = this.data[i].title;
|
||||
let description = slide.querySelector(".description");
|
||||
description.innerHTML = marked.parse(this.data[i].description);
|
||||
|
||||
let title = document.createElement("h1");
|
||||
title.textContent = this.data[i].title;
|
||||
description.prepend(title);
|
||||
}
|
||||
|
||||
// slide
|
||||
this.element.appendChild(slide);
|
||||
|
||||
let slideNode = document.querySelector(element + " .slide:last-child");
|
||||
slideNode.id = "slide-" + i;
|
||||
slideNode.classList.toggle("no-text", !hasText);
|
||||
this.slides.push(slideNode);
|
||||
}
|
||||
|
||||
// append progress bar
|
||||
let progressBar = document.createElement("div");
|
||||
progressBar.classList.add("progressBar");
|
||||
this.progressBar = this.element.appendChild(progressBar);
|
||||
document.querySelector(":root").style.setProperty("--slide-duration", this.slideDuration / 1000 + "s");
|
||||
|
||||
|
||||
// observe scroll position
|
||||
this.element.onscroll = e => this.onScroll(e);
|
||||
|
||||
// keyboard shortcuts
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if (e.code === "ArrowLeft" || e.code === "ArrowRight")
|
||||
e.preventDefault();
|
||||
});
|
||||
document.addEventListener("keyup", (e) => {
|
||||
if (e.code === "ArrowLeft") this.previous();
|
||||
if (e.code === "ArrowRight") this.next();
|
||||
});
|
||||
|
||||
// start auto play
|
||||
this.startTimeout();
|
||||
}
|
||||
|
||||
onScroll(e) {
|
||||
let newSlide = Math.round(e.target.scrollLeft / 800);
|
||||
if (this.activeSlide != newSlide) {
|
||||
this.handleVideoPlayback(this.activeSlide, newSlide);
|
||||
this.activeSlide = newSlide;
|
||||
this.startTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
next() {
|
||||
// scroll to next slide
|
||||
let targetSlide = this.activeSlide >= (this.data.length - 1) ? 0 : this.activeSlide + 1;
|
||||
this.element.scrollTo(targetSlide * 800, 0);
|
||||
|
||||
this.handleVideoPlayback(this.activeSlide, targetSlide);
|
||||
|
||||
}
|
||||
|
||||
handleVideoPlayback(oldSlideIndex, newSlideIndex) {
|
||||
|
||||
// stop old video
|
||||
if (this.getType(oldSlideIndex) == "video") {
|
||||
this.slides[oldSlideIndex].querySelector("video").pause();
|
||||
}
|
||||
|
||||
// start new video and timeout
|
||||
if (this.getType(newSlideIndex) == "video") {
|
||||
let video = this.slides[newSlideIndex].querySelector("video");
|
||||
video.currentTime = 0
|
||||
video.play();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
previous() {
|
||||
let targetSlide = this.activeSlide <= 0 ? (this.data.length - 1) : this.activeSlide - 1
|
||||
this.element.scrollTo(targetSlide * 800, 0);
|
||||
|
||||
this.handleVideoPlayback(this.activeSlide, targetSlide);
|
||||
}
|
||||
|
||||
startTimeout(timeout = this.slideDuration) {
|
||||
clearTimeout(this.slideTimeout);
|
||||
this.slideTimeout = setTimeout(() => { this.next(); }, timeout);
|
||||
|
||||
// restart progress animation
|
||||
// https://css-tricks.com/restart-css-animation/
|
||||
this.progressBar.classList.remove("playing");
|
||||
void this.progressBar.offsetWidth;
|
||||
this.progressBar.classList.add("playing");
|
||||
}
|
||||
|
||||
getType(slideIndex) {
|
||||
let type = this.data[slideIndex].image.split('.').pop().toLowerCase();
|
||||
|
||||
if (this.imageTypes.includes(type)) return "image";
|
||||
if (this.videoTypes.includes(type)) return "video";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
var slides = [
|
||||
{
|
||||
image: "Hello world.mp4",
|
||||
},
|
||||
{
|
||||
image: "System menu.mp4",
|
||||
title: "The system menu",
|
||||
description: `Your mouse cursor is hidden. It will only show up if you move it.
|
||||
Click on the desktop to open the menu.`
|
||||
},
|
||||
{
|
||||
image: "System settings.mp4",
|
||||
title: "System settings",
|
||||
description: `Reach for the settings app to configure and monitor this computer.
|
||||
It’s browser-based so you can use it remotely.`
|
||||
},
|
||||
{
|
||||
image: "File management.mp4",
|
||||
title: "File management",
|
||||
description: `Tooloop OS is designed to be maintained over network.
|
||||
Administrate over \`SSH\` and manage files using \`SFTP\` or \`AFP\`.
|
||||
You can of course also use a USB flash drive.`
|
||||
},
|
||||
{
|
||||
image: "Automation.mp4",
|
||||
title: "Automation",
|
||||
description: `Integrate Tooloop Boxes with your automation system.
|
||||
Almost everything Tooloop OS can do can also be done via REST.`,
|
||||
},
|
||||
{
|
||||
image: "Shortcuts.mp4",
|
||||
title: "Shortcuts for your convenience",
|
||||
description: `There are some handy keyboard shortcuts and terminal commands starting with _tooloop_, e. g. \`tooloop-presentation-start\`.`,
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
# List of Chromium Command Line Switches
|
||||
# https://peter.sh/experiments/chromium-command-line-switches/
|
||||
|
||||
COMMAND="chromium-browser \
|
||||
--disable-features=Translate,Infobars \
|
||||
--no-default-browser-check \
|
||||
--no-first-run \
|
||||
--noerrdialogs \
|
||||
--class=TooloopOnboarding \
|
||||
--app=file:///media/assets/data/index.html"
|
||||
|
||||
if [ $EUID == 0 ]; then
|
||||
/bin/bash /assets/presentation/stop-presentation.sh
|
||||
sleep 0.1
|
||||
su tooloop -c "$COMMAND" &
|
||||
else
|
||||
/bin/bash /assets/presentation/stop-presentation.sh
|
||||
sleep 0.1
|
||||
$COMMAND &
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
pids=$(xdotool search --class "TooloopOnboarding")
|
||||
for pid in $pids; do
|
||||
xkill -id $pid
|
||||
break
|
||||
done
|
||||
|
||||
exit 0
|
||||
@@ -1,15 +1,15 @@
|
||||
Package: tooloop-kiosk-browser
|
||||
Package: tooloop-simple-kiosk-browser
|
||||
Version: 1.0.0
|
||||
Maintainer: Tooloop Multimedia
|
||||
Homepage: https://www.tooloop.de
|
||||
Bugs: https://github.com/Tooloop/Tooloop-Packages
|
||||
Section: tooloop/presentation
|
||||
Architecture: amd64
|
||||
Architecture: all
|
||||
Depends: chromium-browser
|
||||
Recommends: tooloop-transparent-cursor
|
||||
Suggests: tooloop-nginx
|
||||
Name: Kiosk Browser
|
||||
Description: Full-screen browser for touch kiosks
|
||||
Name: Simple Kiosk Browser
|
||||
Description: Simple fullscreen browser for touch kiosks
|
||||
A simple full-screen kiosk browser based on chromium.
|
||||
You can define its’ homepage in the settings.
|
||||
Thumbnail: kiosk-browser-thumbnail.jpg
|
||||
@@ -4,7 +4,7 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Simple Kiosk</title>
|
||||
<title>Kiosk Browser</title>
|
||||
|
||||
<style type="text/css">
|
||||
canvas {
|
||||
@@ -23,14 +23,13 @@
|
||||
}
|
||||
|
||||
#box {
|
||||
width: 50%;
|
||||
width: 640px;
|
||||
position: absolute;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
left: 25%;
|
||||
left: calc(50% - 320px);
|
||||
top: 25%;
|
||||
border-radius: 2px;
|
||||
padding: 20px;
|
||||
max-width: 640px;
|
||||
box-sizing: border-box;
|
||||
padding: 50px 40px 50px 40px;
|
||||
-webkit-user-select: none;
|
||||
@@ -88,12 +87,11 @@
|
||||
<div id="particles"></div>
|
||||
|
||||
<div id="box">
|
||||
<h1>Simple Kiosk</h1>
|
||||
<p>This is a simple browser for your show room or trade fair booth.</p>
|
||||
<h1>Kiosk Browser</h1>
|
||||
<p>This is a simple fullscreen browser for your show room or trade fair booth.</p>
|
||||
<p>It has very few features but works for simple things.</p>
|
||||
<p>By default it loads <span style="font-family: monospace;">/assets/data/index.html</span> but you can choose
|
||||
any page you like.</p>
|
||||
<p>Simple Kiosk comes with a plugin for the Tooloop Settings Server so you can configure it in there.</p>
|
||||
any page you like by editing <span style="font-family: monospace;">/assets/presentation/start-presentation.sh</span>.</p>
|
||||
</div>
|
||||
|
||||
<div id="credits"><a href="http://vincentgarreau.com/particles.js/">particles.js</a> by Vincent Garreau</div>
|
||||
@@ -11,6 +11,7 @@ COMMAND="chromium-browser \
|
||||
--overscroll-history-navigation=1 \
|
||||
--incognito \
|
||||
--disable-features=Translate,Infobars \
|
||||
--disable-pinch \
|
||||
--no-default-browser-check \
|
||||
--no-first-run \
|
||||
--noerrdialogs \
|
||||
|
Before Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 130 B |
|
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 128 B |