[DOCKER] Simplify cron (#1184)
Drastically simplifies setting up cron within ytdl-sub. Below is the documentation which is available in readthedocs, and a section on how to migrate from the old way to this.
## New Cron Documentation
Cron is preconfigured in every ytdl-sub docker container. Enable by adding the following ENV variables to your docker setup.
```
services:
ytdl-sub:
environment:
- CRON_SCHEDULE="0 */6 * * *"
- CRON_RUN_ON_START=false
```
- CRON_SCHEDULE follows the standard [cron scheduling syntax](https://crontab.guru/#0_*/6_*_*_*). The above value will run the script once every 6 hours.
- CRON_RUN_ON_START toggles whether to run your cron script on container start.
The cron script will reside in the main directory with the file name `cron`. Cron logs should show when viewing the Docker logs.
## Migrating Existing Cron Setup
Containers' cron files will remain intact until you add the `CRON_SCHEDULE` variable. Once you add that with your preferred schedule, it will write that value to /config/crontabs/abc and create a new file `cron` within your working directory. Simply copy everything from your existing `run_cron` script into `cron`.
If you have the ENV variable `DOCKER_MODS` in your docker-compose, remove it. It is now included by default. Not removing this will prevent cron logs from showing in your docker container logs.
This commit is contained in:
parent
bb2bc49a49
commit
51c134a036
12 changed files with 150 additions and 155 deletions
|
|
@ -57,6 +57,12 @@ RUN mkdir -p /config && \
|
||||||
# CONTAINER CONFIGS
|
# CONTAINER CONFIGS
|
||||||
|
|
||||||
ENV EDITOR="nano" \
|
ENV EDITOR="nano" \
|
||||||
HOME="/config"
|
HOME="/config" \
|
||||||
|
DOCKER_MODS=linuxserver/mods:universal-stdout-logs|linuxserver/mods:universal-cron \
|
||||||
|
DEFAULT_WORKSPACE=/config \
|
||||||
|
CRON_SCRIPT="/config/cron" \
|
||||||
|
CRON_WRAPPER_SCRIPT="/config/.cron_wrapper" \
|
||||||
|
LOGS_TO_STDOUT=/config/.cron.log \
|
||||||
|
LSIO_FIRST_PARTY=false
|
||||||
|
|
||||||
VOLUME /config
|
VOLUME /config
|
||||||
|
|
@ -79,11 +79,13 @@ RUN mkdir -p /config && \
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# CONTAINER CONFIGS
|
# CONTAINER CONFIGS
|
||||||
|
|
||||||
|
ENV EDITOR="nano" \
|
||||||
ENV YTDL_SUB_TYPE="gui" \
|
|
||||||
EDITOR="nano" \
|
|
||||||
HOME="/config" \
|
HOME="/config" \
|
||||||
DOCKER_MODS=linuxserver/mods:universal-cron \
|
DOCKER_MODS=linuxserver/mods:universal-stdout-logs|linuxserver/mods:universal-cron \
|
||||||
DEFAULT_WORKSPACE=/config/ytdl-sub-configs
|
DEFAULT_WORKSPACE=/config/ytdl-sub-configs \
|
||||||
|
CRON_SCRIPT="/config/ytdl-sub-configs/cron" \
|
||||||
|
CRON_WRAPPER_SCRIPT="/config/ytdl-sub-configs/.cron_wrapper" \
|
||||||
|
LOGS_TO_STDOUT=/config/ytdl-sub-configs/.cron.log \
|
||||||
|
LSIO_FIRST_PARTY=false
|
||||||
|
|
||||||
VOLUME /config
|
VOLUME /config
|
||||||
|
|
@ -83,6 +83,12 @@ RUN mkdir -p /config && \
|
||||||
# CONTAINER CONFIGS
|
# CONTAINER CONFIGS
|
||||||
|
|
||||||
ENV EDITOR="nano" \
|
ENV EDITOR="nano" \
|
||||||
HOME="/config"
|
HOME="/config" \
|
||||||
|
DOCKER_MODS=linuxserver/mods:universal-stdout-logs|linuxserver/mods:universal-cron \
|
||||||
|
DEFAULT_WORKSPACE=/config \
|
||||||
|
CRON_SCRIPT="/config/cron" \
|
||||||
|
CRON_WRAPPER_SCRIPT="/config/.cron_wrapper" \
|
||||||
|
LOGS_TO_STDOUT=/config/.cron.log \
|
||||||
|
LSIO_FIRST_PARTY=false
|
||||||
|
|
||||||
VOLUME /config
|
VOLUME /config
|
||||||
69
docker/root/custom-cont-init.d/defaults
Normal file
69
docker/root/custom-cont-init.d/defaults
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
#!/usr/bin/with-contenv bash
|
||||||
|
|
||||||
|
echo "Starting ytdl-sub..."
|
||||||
|
|
||||||
|
# copy config
|
||||||
|
[[ ! -e "$DEFAULT_WORKSPACE/config.yaml" ]] && \
|
||||||
|
mkdir -p "$DEFAULT_WORKSPACE" && \
|
||||||
|
cp /defaults/config.yaml "$DEFAULT_WORKSPACE/config.yaml"
|
||||||
|
[[ ! -e "$DEFAULT_WORKSPACE/subscriptions.yaml" ]] && \
|
||||||
|
mkdir -p "$DEFAULT_WORKSPACE" && \
|
||||||
|
cp /defaults/subscriptions.yaml "$DEFAULT_WORKSPACE/subscriptions.yaml"
|
||||||
|
[[ ! -d "$DEFAULT_WORKSPACE/examples" ]] && \
|
||||||
|
mkdir -p "$DEFAULT_WORKSPACE/examples" && \
|
||||||
|
cp -r /defaults/examples/* "$DEFAULT_WORKSPACE/examples"
|
||||||
|
|
||||||
|
[[ ! -e "/config/.bashrc" ]] && \
|
||||||
|
echo "alias ls='ls --color=auto'" > /config/.bashrc && \
|
||||||
|
echo "cd ." >> /config/.bashrc
|
||||||
|
|
||||||
|
# permissions
|
||||||
|
chown -R ${PUID:-abc}:${PGID:-abc} \
|
||||||
|
/config
|
||||||
|
|
||||||
|
# set up cron
|
||||||
|
if [ "$CRON_SCHEDULE" != "" ] ; then
|
||||||
|
[[ ! -e "$CRON_SCRIPT" ]] && \
|
||||||
|
cp /defaults/cron "$CRON_SCRIPT"
|
||||||
|
|
||||||
|
# create cron script wrapper
|
||||||
|
echo '#!/bin/bash' > "$CRON_WRAPPER_SCRIPT"
|
||||||
|
echo "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" >> "$CRON_WRAPPER_SCRIPT"
|
||||||
|
echo "cd \"$DEFAULT_WORKSPACE\"" >> "$CRON_WRAPPER_SCRIPT"
|
||||||
|
echo ". \"$CRON_SCRIPT\" | tee -a \"$LOGS_TO_STDOUT\"" >> "$CRON_WRAPPER_SCRIPT"
|
||||||
|
chmod +x "$CRON_WRAPPER_SCRIPT"
|
||||||
|
chown abc:abc "$CRON_WRAPPER_SCRIPT"
|
||||||
|
|
||||||
|
# Set the crontab file to the schedule, cleanly
|
||||||
|
CRON_SCHEDULE_CLEAN="${CRON_SCHEDULE//\"/}"
|
||||||
|
CRON_SCHEDULE_CLEAN="${CRON_SCHEDULE_CLEAN//\'/}"
|
||||||
|
|
||||||
|
echo "# min hour day month weekday command" > /config/crontabs/abc
|
||||||
|
echo "$CRON_SCHEDULE_CLEAN $DEFAULT_WORKSPACE/.cron_wrapper" >> /config/crontabs/abc
|
||||||
|
|
||||||
|
chmod +x "$CRON_SCRIPT"
|
||||||
|
chown abc:abc "$CRON_SCRIPT"
|
||||||
|
|
||||||
|
crontab -u abc /config/crontabs/abc
|
||||||
|
|
||||||
|
CRON_SUCCESS=$?
|
||||||
|
if [ $CRON_SUCCESS -eq 0 ] ; then
|
||||||
|
echo "Cron enabled with schedule $CRON_SCHEDULE_CLEAN"
|
||||||
|
|
||||||
|
if [ "$CRON_RUN_ON_START" = true ] ; then
|
||||||
|
echo "Running cron script on start"
|
||||||
|
. "$CRON_WRAPPER_SCRIPT"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Error in CRON_SCHEDULE definition, disabling cron."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "CRON_SCHEDULE not specified, disabling cron."
|
||||||
|
echo "# min hour day month weekday command" > /config/crontabs/abc
|
||||||
|
echo "" >> /config/crontabs/abc
|
||||||
|
fi
|
||||||
|
|
||||||
|
# always create cron log file, after cron runs
|
||||||
|
# on start to not tail it again
|
||||||
|
echo "" > "$LOGS_TO_STDOUT"
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
#!/usr/bin/with-contenv bash
|
|
||||||
|
|
||||||
# Exit if not gui
|
|
||||||
if [ "$YTDL_SUB_TYPE" != "gui" ] ; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Checking ytdl-sub-gui defaults..."
|
|
||||||
|
|
||||||
# copy config
|
|
||||||
[[ ! -e /config/ytdl-sub-configs/config.yaml ]] && \
|
|
||||||
mkdir -p /config/ytdl-sub-configs && \
|
|
||||||
cp /defaults/config.yaml /config/ytdl-sub-configs/config.yaml
|
|
||||||
[[ ! -e /config/ytdl-sub-configs/subscriptions.yaml ]] && \
|
|
||||||
mkdir -p /config/ytdl-sub-configs && \
|
|
||||||
cp /defaults/subscriptions.yaml /config/ytdl-sub-configs/subscriptions.yaml
|
|
||||||
[[ ! -d /config/ytdl-sub-configs/examples ]] && \
|
|
||||||
mkdir -p /config/ytdl-sub-configs/examples && \
|
|
||||||
cp /defaults/examples/* /config/ytdl-sub-configs/examples
|
|
||||||
|
|
||||||
# permissions
|
|
||||||
chown -R ${PUID:-abc}:${PGID:-abc} \
|
|
||||||
/config
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
#!/usr/bin/with-contenv bash
|
|
||||||
|
|
||||||
# Exit if gui
|
|
||||||
if [ "$YTDL_SUB_TYPE" == "gui" ] ; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Checking ytdl-sub defaults..."
|
|
||||||
|
|
||||||
# copy config
|
|
||||||
[[ ! -e /config/config.yaml ]] && \
|
|
||||||
cp /defaults/config.yaml /config/config.yaml
|
|
||||||
[[ ! -e /config/subscriptions.yaml ]] && \
|
|
||||||
cp /defaults/subscriptions.yaml /config/subscriptions.yaml
|
|
||||||
[[ ! -d /config/examples ]] && \
|
|
||||||
cp -R /defaults/examples /config/
|
|
||||||
|
|
||||||
# permissions
|
|
||||||
chown -R ${PUID:-abc}:${PGID:-abc} \
|
|
||||||
/config
|
|
||||||
4
docker/root/defaults/cron
Normal file
4
docker/root/defaults/cron
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
echo "Beginning cron job..."
|
||||||
|
|
||||||
|
# Place your ytdl-sub command(s) here.
|
||||||
|
# This script is executed in the same relative path as this file.
|
||||||
15
docker/root/etc/s6-overlay/s6-rc.d/init-adduser/branding
Normal file
15
docker/root/etc/s6-overlay/s6-rc.d/init-adduser/branding
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
――――――――――――――――――――――――――――――――――――
|
||||||
|
██╗ ██╗████████╗██████╗ ██╗
|
||||||
|
╚██╗ ██╔╝╚══██╔══╝██╔══██╗██║
|
||||||
|
╚████╔╝ ██║ ██║ ██║██║
|
||||||
|
╚██╔╝ ██║ ██║ ██║██║
|
||||||
|
██║ ██║ ██████╔╝███████╗
|
||||||
|
╚═╝ ╚═╝ ╚═════╝ ╚══════╝
|
||||||
|
|
||||||
|
███████╗██╗ ██╗██████╗
|
||||||
|
██╔════╝██║ ██║██╔══██╗
|
||||||
|
███████╗██║ ██║██████╔╝
|
||||||
|
╚════██║██║ ██║██╔══██╗
|
||||||
|
███████║╚██████╔╝██████╔╝
|
||||||
|
╚══════╝ ╚═════╝ ╚═════╝
|
||||||
|
――――――――――――――――――――――――――――――――――――
|
||||||
1
docker/root/etc/s6-overlay/s6-rc.d/init-adduser/test.txt
Normal file
1
docker/root/etc/s6-overlay/s6-rc.d/init-adduser/test.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
hi
|
||||||
|
|
@ -6,8 +6,34 @@ services:
|
||||||
- PUID=1000
|
- PUID=1000
|
||||||
- PGID=1000
|
- PGID=1000
|
||||||
- TZ=America/Los_Angeles
|
- TZ=America/Los_Angeles
|
||||||
|
- CRON_SCHEDULE="*/1 * * * *"
|
||||||
|
- CRON_RUN_ON_START=true
|
||||||
volumes:
|
volumes:
|
||||||
- ./volumes/ytdl-sub-gui:/config
|
- ./volumes/ytdl-sub-gui:/config
|
||||||
ports:
|
ports:
|
||||||
- 8443:8443
|
- 8443:8443
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
ytdl-sub:
|
||||||
|
image: ytdl-sub:local
|
||||||
|
container_name: ytdl-sub
|
||||||
|
environment:
|
||||||
|
- PUID=1000
|
||||||
|
- PGID=1000
|
||||||
|
- TZ=America/Los_Angeles
|
||||||
|
- CRON_SCHEDULE="*/1 * * * *"
|
||||||
|
- CRON_RUN_ON_START=true
|
||||||
|
volumes:
|
||||||
|
- ./volumes/ytdl-sub:/config
|
||||||
|
restart: unless-stopped
|
||||||
|
ytdl-sub-ubuntu:
|
||||||
|
image: ytdl-sub-ubuntu:local
|
||||||
|
container_name: ytdl-sub-ubuntu
|
||||||
|
environment:
|
||||||
|
- PUID=1000
|
||||||
|
- PGID=1000
|
||||||
|
- TZ=America/Los_Angeles
|
||||||
|
- CRON_SCHEDULE="*/1 * * * *"
|
||||||
|
- CRON_RUN_ON_START=true
|
||||||
|
volumes:
|
||||||
|
- ./volumes/ytdl-sub:/config
|
||||||
|
restart: unless-stopped
|
||||||
|
|
|
||||||
|
|
@ -1,133 +1,43 @@
|
||||||
Automating Downloads
|
Automating Downloads
|
||||||
====================
|
====================
|
||||||
|
|
||||||
One of the key capabilities of ``ytdl-sub`` automating new downloads.
|
|
||||||
To take advantage of this, you must set up scheduling to execute the commands at some interval.
|
|
||||||
How you set up this scheduling depends on which version of ``ytdl-sub`` you downloaded.
|
|
||||||
|
|
||||||
|
|
||||||
:ref:`Guide for Docker and Unraid Containers <guides/getting_started/automating_downloads:docker and unraid>`
|
:ref:`Guide for Docker and Unraid Containers <guides/getting_started/automating_downloads:docker and unraid>`
|
||||||
|
|
||||||
:ref:`Guide for Linux <guides/getting_started/automating_downloads:linux>`
|
:ref:`Guide for Linux <guides/getting_started/automating_downloads:linux>`
|
||||||
|
|
||||||
:ref:`Guide for Windows <guides/getting_started/automating_downloads:windows>`
|
:ref:`Guide for Windows <guides/getting_started/automating_downloads:windows>`
|
||||||
|
|
||||||
.. _cron tab manpage: https://man7.org/linux/man-pages/man5/crontab.5.html#EXAMPLE_CRON_FILE
|
.. _cron scheduling syntax: https://crontab.guru/#0_*/6_*_*_*
|
||||||
|
|
||||||
.. _docker-unraid-setup:
|
.. _docker-unraid-setup:
|
||||||
|
|
||||||
Docker and Unraid
|
Docker and Unraid
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
.. tab-set::
|
Cron is preconfigured in every ytdl-sub docker container. Enable by adding the following
|
||||||
|
ENV variables to your docker setup.
|
||||||
.. tab-item:: GUI Image
|
|
||||||
|
|
||||||
The script that will execute automatically is located at ``/config/ytdl-sub-configs/run_cron``.
|
|
||||||
|
|
||||||
Access your container at http://localhost:8443/, then in the GUI terminal run these commands:
|
.. code-block:: yaml
|
||||||
|
|
||||||
.. code-block:: shell
|
services:
|
||||||
|
ytdl-sub:
|
||||||
|
environment:
|
||||||
|
- CRON_SCHEDULE="0 */6 * * *"
|
||||||
|
- CRON_RUN_ON_START=false
|
||||||
|
|
||||||
echo '#!/bin/bash' > /config/ytdl-sub-configs/run_cron
|
|
||||||
echo "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" >> /config/ytdl-sub-configs/run_cron
|
|
||||||
echo "echo 'Cron started, running ytdl-sub...'" >> /config/ytdl-sub-configs/run_cron
|
|
||||||
echo "cd /config/ytdl-sub-configs" >> /config/ytdl-sub-configs/run_cron
|
|
||||||
echo "ytdl-sub --config=config.yaml sub subscriptions.yaml" >> /config/ytdl-sub-configs/run_cron
|
|
||||||
chmod +x /config/ytdl-sub-configs/run_cron
|
|
||||||
chown abc:abc /config/ytdl-sub-configs/run_cron
|
|
||||||
|
|
||||||
You can test the newly created script by running:
|
- ``CRON_SCHEDULE`` follows the standard `cron scheduling syntax`_. The above value will run the script once every 6 hours.
|
||||||
|
- ``CRON_RUN_ON_START`` toggles whether to run your cron script on container start.
|
||||||
|
|
||||||
.. code-block:: shell
|
The cron script will reside in the main directory with the file name ``cron``.
|
||||||
|
Cron logs should show when viewing the Docker logs.
|
||||||
|
|
||||||
/config/ytdl-sub-configs/run_cron
|
|
||||||
|
|
||||||
To create the cron definition, run the following command:
|
|
||||||
|
|
||||||
.. code-block:: shell
|
|
||||||
|
|
||||||
echo "# min hour day month weekday command" > /config/crontabs/abc
|
|
||||||
echo " 0 */6 * * * /config/ytdl-sub-configs/run_cron" >> /config/crontabs/abc
|
|
||||||
|
|
||||||
This will run the script every 6 hours. To run every hour, change ``*/6`` to ``*/1``, or to run once a day, change the same value to the hour (in 24hr format) that you want it to run at. See the `cron tab manpage`_ for more options.
|
|
||||||
|
|
||||||
.. attention::
|
|
||||||
The Docker container needs to be restarted for changes to take effect. Run `crontab -e` after to verify settings are correct.
|
|
||||||
|
|
||||||
.. tab-item:: Headless Image
|
|
||||||
|
|
||||||
.. _LinuxServer's Universal Cron mod: https://github.com/linuxserver/docker-mods/tree/universal-cron
|
|
||||||
|
|
||||||
The first step is to ensure you have `LinuxServer's Universal Cron mod`_ enabled via the environment variable. For the GUI image, this is already included (no need to add it).
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
|
||||||
|
|
||||||
services:
|
|
||||||
ytdl-sub:
|
|
||||||
image: ghcr.io/jmbannon/ytdl-sub:latest
|
|
||||||
container_name: ytdl-sub
|
|
||||||
environment:
|
|
||||||
- PUID=1000
|
|
||||||
- PGID=1000
|
|
||||||
- TZ=America/Los_Angeles
|
|
||||||
- DOCKER_MODS=linuxserver/mods:universal-cron # <-- Make sure you have this!
|
|
||||||
volumes:
|
|
||||||
# ensure directories have user permissions
|
|
||||||
- </path/to/ytdl-sub/config>:/config
|
|
||||||
- </path/to/ytdl-sub/tv_shows>:/tv_shows
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
This line will tell your container to install and enable cron on start.
|
|
||||||
|
|
||||||
If you had to add this line, you will need to restart your container.
|
|
||||||
|
|
||||||
.. code-block:: shell
|
|
||||||
|
|
||||||
docker compose restart
|
|
||||||
|
|
||||||
The script that will execute automatically is located at ``/config/run_cron``.
|
|
||||||
|
|
||||||
Access your container from the terminal by running:
|
|
||||||
|
|
||||||
.. code-block:: shell
|
|
||||||
|
|
||||||
docker exec -itu abc ytdl-sub /bin/bash
|
|
||||||
|
|
||||||
then in the terminal run these commands:
|
|
||||||
|
|
||||||
.. code-block:: shell
|
|
||||||
|
|
||||||
echo '#!/bin/bash' > /config/run_cron
|
|
||||||
echo "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" >> /config/run_cron
|
|
||||||
echo "echo 'Cron started, running ytdl-sub...'" >> /config/run_cron
|
|
||||||
echo "cd /config" >> /config/run_cron
|
|
||||||
echo "ytdl-sub --config=config.yaml sub subscriptions.yaml" >> /config/run_cron
|
|
||||||
chmod +x /config/run_cron
|
|
||||||
chown abc:abc /config/run_cron
|
|
||||||
|
|
||||||
You can test the newly created script by running:
|
|
||||||
|
|
||||||
.. code-block::
|
|
||||||
|
|
||||||
/config/run_cron
|
|
||||||
|
|
||||||
To create the cron definition, run the following command:
|
|
||||||
|
|
||||||
.. code-block:: shell
|
|
||||||
|
|
||||||
echo "# min hour day month weekday command" > /config/crontabs/abc
|
|
||||||
echo " 0 */6 * * * /config/run_cron" >> /config/crontabs/abc
|
|
||||||
|
|
||||||
This will run the script every 6 hours. To run every hour, change ``*/6`` to ``*/1``, or to run once a day, change the same value to the hour (in 24hr format) that you want it to run at. See the `cron tab manpage`_ for more options.
|
|
||||||
|
|
||||||
.. attention::
|
|
||||||
The Docker container needs to be restarted for changes to take effect. Run `crontab -e` after to verify settings are correct.
|
|
||||||
|
|
||||||
.. _linux-setup:
|
.. _linux-setup:
|
||||||
|
|
||||||
Linux
|
Linux
|
||||||
-----
|
-----
|
||||||
|
Must configure crontab manually, like so:
|
||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,6 @@ Docker Compose is an easy "set it and forget it" install method. Follow the inst
|
||||||
- PUID=1000
|
- PUID=1000
|
||||||
- PGID=1000
|
- PGID=1000
|
||||||
- TZ=America/Los_Angeles
|
- TZ=America/Los_Angeles
|
||||||
- DOCKER_MODS=linuxserver/mods:universal-cron
|
|
||||||
volumes:
|
volumes:
|
||||||
- <path/to/ytdl-sub/config>:/config
|
- <path/to/ytdl-sub/config>:/config
|
||||||
- <path/to/tv_shows>:/tv_shows # optional
|
- <path/to/tv_shows>:/tv_shows # optional
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue