diff --git a/.gitignore b/.gitignore index ba48f9d..3669789 100644 --- a/.gitignore +++ b/.gitignore @@ -23,5 +23,6 @@ lost* bin/rtsp-simple-server/rtsp* bin/rtsp-simple-server/*.yml -# Ignore Custom Config for Intsaller +# Ignore Config for Intsaller tools/config.local +tools/.config diff --git a/Makefile b/Makefile index a85bea0..b86f977 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,13 @@ #### webcamd - A webcam Service for multiple Cams and Stream Services. #### #### Written by Stephan Wendel aka KwadFan -#### Copyright 2021 +#### Copyright 2021 - 2022 #### https://github.com/mainsail-crew/crowsnest #### #### This File is distributed under GPLv3 #### -.PHONY: help install unsinstall build buildclean +.PHONY: build buildclean config help install unsinstall # Setup USER = $(shell whoami) @@ -25,18 +25,17 @@ help: @echo "" @echo " Available actions:" @echo "" - @echo " install Installs crowsnest" - @echo " uninstall Uninstalls crowsnest" + @echo " config Configures Installer" + @echo " install Installs crowsnest (needs sudo)" + @echo " uninstall Uninstalls crowsnest (needs sudo)" @echo " build builds binaries" @echo " buildclean cleans binaries (for recompile)" + @echo " clean Removes Installer config" @echo "" install: @bash -c 'tools/install.sh' -unattended: - @bash -c 'tools/install.sh -z' - uninstall: @bash -c 'tools/uninstall.sh' @@ -46,4 +45,16 @@ build: buildclean: $(MAKE) -C $(BIN_FOLDER) clean +clean: + @if [ -f tools/.config ]; then rm -f tools/.config; fi + @echo "Removed installer config file ..." + +config: + @bash -c 'tools/configure.sh' + +report: + @if [ -f ~/report.txt ]; then rm -f ~/report.txt; fi + @bash -c 'tools/dev-helper.sh -a >> ~/report.txt' + @sed -ri 's/\x1B\[([0-9]{1,3}(;[0-9]{1,2})?)?[mGK]//g' ~/report.txt + diff --git a/README.md b/README.md index 0a4860a..bf7a392 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,8 @@ So, this will be the 'lookout point' for your Printer. cd ~ git clone https://github.com/mainsail-crew/crowsnest.git cd ~/crowsnest - make install + make config + sudo make install _This is not tested on other Distributions. If you test that on other Distributions,\ feel free to open a Pull Request to enhance Documentation._ @@ -37,6 +38,7 @@ After successful Instalation you should consider to add type: git_repo path: ~/crowsnest origin: https://github.com/mainsail-crew/crowsnest.git + install_script: tools/install.sh to your moonraker.conf, to get latest and possibly greatest Features. diff --git a/custompios/crowsnest/config b/custompios/crowsnest/config index d12c02d..0de72b8 100644 --- a/custompios/crowsnest/config +++ b/custompios/crowsnest/config @@ -2,27 +2,33 @@ #### crowsnest - A webcam Service for multiple Cams and Stream Services. #### #### Written by Stephan Wendel aka KwadFan -#### Copyright 2021 +#### Copyright 2021 - 2022 #### https://github.com/mainsail-crew/crowsnest #### #### This File is distributed under GPLv3 #### # shellcheck disable=all -# crowsnest -[ -n "$CROWSNEST_CROWSNEST_REPO_SHIP" ] || CROWSNEST_CROWSNEST_REPO_SHIP=https://github.com/mainsail-crew/crowsnest.git -[ -n "$CROWSNEST_CROWSNEST_REPO_BRANCH" ] || CROWSNEST_CROWSNEST_REPO_BRANCH=master -[ -n "$CROWSNEST_CROWSNEST_DEPS" ] || CROWSNEST_CROWSNEST_DEPS="git crudini bsdutils findutils v4l-utils ffmpeg" -[ -n "$CROWSNEST_DEFAULT_CONF" ] || CROWSNEST_DEFAULT_CONF="mainsail_default.conf" -[ -n "$CROWSNEST_DEFAULT_CONF_DIR" ] || CROWSNEST_DEFAULT_CONF_DIR="/home/${BASE_USER}/klipper_config" -# Force Raspicam fix bool (1:yes / 0:no) -[ -n "$CROWSNEST_FORCE_RASPICAMFIX" ] || CROWSNEST_FORCE_RASPICAMFIX=1 -# Add Crowsnest to moonraker.conf (update manager) bool (1:yes / 0:no) -[ -n "$CROWSNEST_ADD_CROWSNEST_MOONRAKER" ] || CROWSNEST_ADD_CROWSNEST_MOONRAKER=1 +# crowsnest repo +[[ -n "$CROWSNEST_REPO_SHIP" ]] || CROWSNEST_REPO_SHIP=https://github.com/mainsail-crew/crowsnest.git +[[ -n "$CROWSNEST_REPO_BRANCH" ]] || CROWSNEST_REPO_BRANCH=master + +# crowsnest setup +[[ -n "$CROWSNEST_DEFAULT_CONF" ]] || CROWSNEST_DEFAULT_CONF="resources/crowsnest.conf" +[[ -n "$CROWSNEST_CONFIG_PATH" ]] || CROWSNEST_CONFIG_PATH="/home/pi/printer_data/config" +[[ -n "$CROWSNEST_LOG_PATH" ]] || CROWSNEST_LOG_PATH="/home/pi/printer_data/logs" +[[ -n "$CROWSNEST_ENV_PATH" ]] || CROWSNEST_ENV_PATH="/home/pi/printer_data/systemd" +[[ -n "$CROWSNEST_RASPICAMFIX" ]] || CROWSNEST_RASPICAMFIX="1" +[[ -n "$CROWSNEST_ADD_CROWSNEST_MOONRAKER" ]] || CROWSNEST_ADD_CROWSNEST_MOONRAKER="1" +[[ -n "$CROWSNEST_MOONRAKER_CONF_PATH" ]] || CROWSNEST_MOONRAKER_CONF_PATH="/home/pi/printer_data/config/moonraker.conf" # ustreamer -[ -n "$CROWSNEST_USTREAMER_DEPS" ] || CROWSNEST_USTREAMER_DEPS="git build-essential libevent-dev libjpeg-dev \ -libbsd-dev libraspberrypi-dev libgpiod-dev" -[ -n "$CROWSNEST_USTREAMER_WITH_OMX" ] || CROWSNEST_USTREAMER_WITH_OMX="y" -[ -n "$CROWSNEST_USTREAMER_WITH_GPIO" ] || CROWSNEST_USTREAMER_WITH_GPIO="n" +[[ -n "$CROWSNEST_USTREAMER_REPO_SHIP" ]] || CROWSNEST_USTREAMER_REPO_SHIP="https://github.com/pikvm/ustreamer.git" +[[ -n "$CROWSNEST_USTREAMER_REPO_BRANCH" ]] || CROWSNEST_USTREAMER_REPO_BRANCH="master" + +########################################################################### +### DO NOT EDIT BELOW THIS LINE, UNLESS YOU KNOW EXACTLY WHAT HAPPENDS! ### +########################################################################### + +CROWSNEST_UNATTENDED="1" diff --git a/custompios/crowsnest/start_chroot_script b/custompios/crowsnest/start_chroot_script index 9f75b2c..9631f7e 100644 --- a/custompios/crowsnest/start_chroot_script +++ b/custompios/crowsnest/start_chroot_script @@ -9,41 +9,72 @@ #### This File is distributed under GPLv3 #### -# shellcheck disable=all +# shellcheck enable=requires-variable-braces # Error handling set -Ee +# shellcheck disable=SC1091 source /common.sh install_cleanup_trap -echo_green "Installing crowsnest and enable webcam Service ..." -# install dependencies -# force apt update -apt update -# It could use inbuilt dependencie check, but should speed up if preinstalled. -# shellcheck disable=SC2086 -check_install_pkgs ${CROWSNEST_CROWSNEST_DEPS} ${CROWSNEST_USTREAMER_DEPS} -# Move to $HOME dir +# Module only Variables +CN_BUILD_PACKAGE_FILE="/tmp/cn_packages.lst" +CN_BUILD_INSTALL_SH="/home/${BASE_USER}/crowsnest/tools/install.sh" + +echo_green "Installing crowsnest ..." + +## Force apt update +apt-get update +## Make sure 'git' is installed! +check_install_pkgs git + +## Step 1: Move to Home Dir as WorkingDirectoy pushd "/home/${BASE_USER}" &> /dev/null || exit 1 - # make sure config folder exist - if [ ! -d "${CROWSNEST_DEFAULT_CONF_DIR}" ]; then - sudo -u "${BASE_USER}" mkdir -p "${CROWSNEST_DEFAULT_CONF_DIR}" - fi - # clone Repo - echo_green "Clone crowsnest repository ..." - gitclone CROWSNEST_CROWSNEST_REPO crowsnest - # install crowsnest - use crowsnest's make unattended - pushd "/home/${BASE_USER}/crowsnest" &> /dev/null || exit 1 - echo_green "Launch crowsnest install routine ..." - pushd "/home/${BASE_USER}/crowsnest" &> /dev/null || exit 1 - sudo -u "${BASE_USER}" make unattended - # Apply Raspicam fix if enabled. - if [ "${CROWSNEST_FORCE_RASPICAMFIX}" == "1" ]; then - echo -en "Applying Raspicam Fix ... \r" - sudo sh -c 'echo "bcm2835-v4l2" >> /etc/modules' - sudo cp file_templates/bcm2835-v4l2.conf /etc/modprobe.d/ - echo -e "Applying Raspicam Fix ... [OK]" - fi - popd &> /dev/null || exit 1 + +## Step 2: clone crowsnest repo +echo_green "Clone crowsnest repository ..." +gitclone CROWSNEST_REPO crowsnest + +## Step 3: grep PKGLIST from install.sh for dependencies +echo_green "Generating packages file ..." +grep "PKGLIST=" "${CN_BUILD_INSTALL_SH}" >> "${CN_BUILD_PACKAGE_FILE}" + +## Step 4: Rename PKGLIST to Module usable Var +echo_green "Rename variable PKGLIST to CROWSNEST_DEPS ..." +sed -i 's/PKGLIST/CROWSNEST_DEPS/g' "${CN_BUILD_PACKAGE_FILE}" + +## Step 5: Source cn_package.lst file +# shellcheck disable=SC1090 +# Shellcheck has to be disabled here, +# because it is an dynamic generated file and not checkable +. "${CN_BUILD_PACKAGE_FILE}" + +## Step 6: Install packages +echo_green "Install crowsnest dependencies ..." +# shellcheck disable=SC2086 +# disabled because we need 'wordsplitting' +check_install_pkgs ${CROWSNEST_DEPS} + +## Step 7: Move to crowsnest as working directory +pushd "/home/${BASE_USER}/crowsnest" &> /dev/null || exit 1 + +## Step 8: Run crowsnest install routine +echo_green "Launch crowsnest install routine ..." +make install + +## Step 9: Leave crowsnest popd &> /dev/null || exit 1 + +## Step 10: clean packages.lst file +rm -f "${CN_BUILD_PACKAGE_FILE}" + +## Step 11: leave home dir +popd &> /dev/null || exit 1 + +## Step 12: +echo_green "Enable crowsnest.service ..." +systemctl_if_exists enable crowsnest.service + +## Finish +echo_green "Installing crowsnest ... DONE!" diff --git a/file_templates/bcm2835-v4l2.conf b/resources/bcm2835-v4l2.conf similarity index 100% rename from file_templates/bcm2835-v4l2.conf rename to resources/bcm2835-v4l2.conf diff --git a/file_templates/crowsnest-rtsp.yml b/resources/crowsnest-rtsp.yml similarity index 100% rename from file_templates/crowsnest-rtsp.yml rename to resources/crowsnest-rtsp.yml diff --git a/sample_configs/mainsail_default.conf b/resources/crowsnest.conf similarity index 92% rename from sample_configs/mainsail_default.conf rename to resources/crowsnest.conf index 19cb7d5..f58f5b3 100644 --- a/sample_configs/mainsail_default.conf +++ b/resources/crowsnest.conf @@ -1,5 +1,6 @@ #### crowsnest.conf -#### This is mainsail / MainsailOS default config. +#### This is a typical default config. +#### Also used as default in mainsail / MainsailOS #### See: #### https://github.com/mainsail-crew/crowsnest/blob/master/README.md #### for details to configure to your needs. @@ -20,7 +21,7 @@ [crowsnest] -log_path: ~/klipper_logs/crowsnest.log # Default logfile in ~/klipper_logs/crowsnest.log +log_path: %LOGPATH% log_level: verbose # Valid Options are quiet/verbose/debug delete_log: false # Deletes log on every restart, if set to true diff --git a/file_templates/crowsnest.service b/resources/crowsnest.service similarity index 79% rename from file_templates/crowsnest.service rename to resources/crowsnest.service index 2973af1..57263fd 100644 --- a/file_templates/crowsnest.service +++ b/resources/crowsnest.service @@ -1,7 +1,7 @@ #### crowsnest - A webcam Service for multiple Cams and Stream Services. #### #### Written by Stephan Wendel aka KwadFan -#### Copyright 2021 +#### Copyright 2021 - 2022 #### https://github.com/mainsail-crew/crowsnest #### #### This File is distributed under GPLv3 @@ -20,10 +20,11 @@ StartLimitIntervalSec=180 WantedBy=multi-user.target [Service] -Environment=CROWSNEST_CONFIG=/home/pi/klipper_config/crowsnest.conf -Type=exec -User=pi +Type=simple +User=%USER% RemainAfterExit=Yes -ExecStart= /usr/local/bin/crowsnest -c ${CROWSNEST_CONFIG} +WorkingDirectory=/home/%USER%/crowsnest +EnvironmentFile=%ENV% +ExecStart= /usr/local/bin/crowsnest $CROWSNEST_ARGS Restart=on-failure RestartSec=5 diff --git a/file_templates/logrotate_crowsnest b/resources/logrotate_crowsnest similarity index 60% rename from file_templates/logrotate_crowsnest rename to resources/logrotate_crowsnest index eb0e8ee..805a36c 100644 --- a/file_templates/logrotate_crowsnest +++ b/resources/logrotate_crowsnest @@ -1,22 +1,20 @@ # crowsnest logrotate file - #### crowsnest - A webcam Service for multiple Cams and Stream Services. #### #### Written by Stephan Wendel aka KwadFan -#### Copyright 2021 +#### Copyright 2021 - 2022 #### https://github.com/mainsail-crew/crowsnest #### #### This File is distributed under GPLv3 #### - -/home/pi/klipper_logs/crowsnest.log { - rotate 3 - missingok - notifempty - copy - daily - dateext - dateformat .%Y-%m-%d - maxsize 4M +%LOGPATH% { +rotate 3 +missingok +notifempty +copy +daily +dateext +dateformat .%Y-%m-%d +maxsize 4M } diff --git a/file_templates/moonraker_update.txt b/resources/moonraker_update.txt similarity index 84% rename from file_templates/moonraker_update.txt rename to resources/moonraker_update.txt index 97d612f..97e32f3 100644 --- a/file_templates/moonraker_update.txt +++ b/resources/moonraker_update.txt @@ -5,3 +5,4 @@ type: git_repo path: ~/crowsnest origin: https://github.com/mainsail-crew/crowsnest.git managed_services: crowsnest +install_script: tools/install.sh diff --git a/sample_configs/minimal.conf b/sample_configs/minimal.conf deleted file mode 100644 index f37b10e..0000000 --- a/sample_configs/minimal.conf +++ /dev/null @@ -1,27 +0,0 @@ - - -##################################################################### -#### ##### -#### Information about ports and according URL's ##### -#### ##### -##################################################################### -#### ##### -#### Port 8080 equals /webcam/?action=[stream/snapshot] ##### -#### Port 8081 equals /webcam2/?action=[stream/snapshot] ##### -#### Port 8082 equals /webcam3/?action=[stream/snapshot] ##### -#### Port 8083 equals /webcam4/?action=[stream/snapshot] ##### -#### ##### -##################################################################### - - -[crowsnest] -log_path: ~/klipper_logs/crowsnest.log # Default logfile in ~/klipper_logs/crowsnest.log -log_level: quiet # Valid Options are quiet/verbose/debug -delete_log: true # Deletes log on every restart, if set to true - -[cam 1] -mode: mjpg # mjpg/rtsp -port: 8080 # Port -device: /dev/video0 # See Log for available ... -resolution: 640x480 # widthxheight format -max_fps: 15 # If Hardware Supports this it will be forced, ohterwise ignored/coerced. diff --git a/tools/config.armbian-bullseye b/tools/config.armbian-bullseye deleted file mode 100644 index 3395c7b..0000000 --- a/tools/config.armbian-bullseye +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -#### crowsnest - A webcam Service for multiple Cams and Stream Services. -#### -#### Written by Stephan Wendel aka KwadFan -#### Copyright 2021 -#### https://github.com/mainsail-crew/crowsnest -#### -#### This File is distributed under GPLv3 -#### -# shellcheck disable=all - - -[ -n "$CROWSNEST_CROWSNEST_DEPS" ] || CROWSNEST_CROWSNEST_DEPS="git crudini bsdutils findutils v4l-utils ffmpeg" -[ -n "$CROWSNEST_DEFAULT_CONF" ] || CROWSNEST_DEFAULT_CONF="mainsail_default.conf" -[ -n "$CROWSNEST_DEFAULT_CONF_DIR" ] || CROWSNEST_DEFAULT_CONF_DIR="/home/${BASE_USER}/klipper_config" -# Force Raspicam fix bool (1:yes / 0:no) -[ -n "$CROWSNEST_FORCE_RASPICAMFIX" ] || CROWSNEST_FORCE_RASPICAMFIX=0 -# Add Crowsnest to moonraker.conf (update manager) bool (1:yes / 0:no) -[ -n "$CROWSNEST_ADD_CROWSNEST_MOONRAKER" ] || CROWSNEST_ADD_CROWSNEST_MOONRAKER=1 - - -# ustreamer -[ -n "$CROWSNEST_USTREAMER_REPO_SHIP" ] || CROWSNEST_USTREAMER_REPO_SHIP=https://github.com/pikvm/ustreamer -[ -n "$CROWSNEST_USTREAMER_REPO_BRANCH" ] || CROWSNEST_USTREAMER_REPO_BRANCH=master -[ -n "$CROWSNEST_USTREAMER_DEPS" ] || CROWSNEST_USTREAMER_DEPS="git build-essential libevent-dev libjpeg-dev \ -libbsd-dev" -[ -n "$CROWSNEST_USTREAMER_WITH_OMX" ] || CROWSNEST_USTREAMER_WITH_OMX="n" -[ -n "$CROWSNEST_USTREAMER_WITH_GPIO" ] || CROWSNEST_USTREAMER_WITH_GPIO="n" diff --git a/tools/config.armbian-buster b/tools/config.armbian-buster deleted file mode 100644 index 3395c7b..0000000 --- a/tools/config.armbian-buster +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -#### crowsnest - A webcam Service for multiple Cams and Stream Services. -#### -#### Written by Stephan Wendel aka KwadFan -#### Copyright 2021 -#### https://github.com/mainsail-crew/crowsnest -#### -#### This File is distributed under GPLv3 -#### -# shellcheck disable=all - - -[ -n "$CROWSNEST_CROWSNEST_DEPS" ] || CROWSNEST_CROWSNEST_DEPS="git crudini bsdutils findutils v4l-utils ffmpeg" -[ -n "$CROWSNEST_DEFAULT_CONF" ] || CROWSNEST_DEFAULT_CONF="mainsail_default.conf" -[ -n "$CROWSNEST_DEFAULT_CONF_DIR" ] || CROWSNEST_DEFAULT_CONF_DIR="/home/${BASE_USER}/klipper_config" -# Force Raspicam fix bool (1:yes / 0:no) -[ -n "$CROWSNEST_FORCE_RASPICAMFIX" ] || CROWSNEST_FORCE_RASPICAMFIX=0 -# Add Crowsnest to moonraker.conf (update manager) bool (1:yes / 0:no) -[ -n "$CROWSNEST_ADD_CROWSNEST_MOONRAKER" ] || CROWSNEST_ADD_CROWSNEST_MOONRAKER=1 - - -# ustreamer -[ -n "$CROWSNEST_USTREAMER_REPO_SHIP" ] || CROWSNEST_USTREAMER_REPO_SHIP=https://github.com/pikvm/ustreamer -[ -n "$CROWSNEST_USTREAMER_REPO_BRANCH" ] || CROWSNEST_USTREAMER_REPO_BRANCH=master -[ -n "$CROWSNEST_USTREAMER_DEPS" ] || CROWSNEST_USTREAMER_DEPS="git build-essential libevent-dev libjpeg-dev \ -libbsd-dev" -[ -n "$CROWSNEST_USTREAMER_WITH_OMX" ] || CROWSNEST_USTREAMER_WITH_OMX="n" -[ -n "$CROWSNEST_USTREAMER_WITH_GPIO" ] || CROWSNEST_USTREAMER_WITH_GPIO="n" diff --git a/tools/config.bullseye b/tools/config.bullseye deleted file mode 100644 index d9adb56..0000000 --- a/tools/config.bullseye +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -#### crowsnest - A webcam Service for multiple Cams and Stream Services. -#### -#### Written by Stephan Wendel aka KwadFan -#### Copyright 2021 -#### https://github.com/mainsail-crew/crowsnest -#### -#### This File is distributed under GPLv3 -#### -# shellcheck disable=all - - -[ -n "$CROWSNEST_CROWSNEST_DEPS" ] || CROWSNEST_CROWSNEST_DEPS="git crudini bsdutils findutils v4l-utils ffmpeg" -[ -n "$CROWSNEST_DEFAULT_CONF" ] || CROWSNEST_DEFAULT_CONF="mainsail_default.conf" -[ -n "$CROWSNEST_DEFAULT_CONF_DIR" ] || CROWSNEST_DEFAULT_CONF_DIR="/home/${BASE_USER}/klipper_config" -# Force Raspicam fix bool (1:yes / 0:no) -[ -n "$CROWSNEST_FORCE_RASPICAMFIX" ] || CROWSNEST_FORCE_RASPICAMFIX=1 -# Add Crowsnest to moonraker.conf (update manager) bool (1:yes / 0:no) -[ -n "$CROWSNEST_ADD_CROWSNEST_MOONRAKER" ] || CROWSNEST_ADD_CROWSNEST_MOONRAKER=1 - - -# ustreamer -[ -n "$CROWSNEST_USTREAMER_REPO_SHIP" ] || CROWSNEST_USTREAMER_REPO_SHIP=https://github.com/pikvm/ustreamer.git -[ -n "$CROWSNEST_USTREAMER_REPO_BRANCH" ] || CROWSNEST_USTREAMER_REPO_BRANCH=master -[ -n "$CROWSNEST_USTREAMER_DEPS" ] || CROWSNEST_USTREAMER_DEPS="git build-essential libevent-dev libjpeg62-turbo-dev \ -libbsd-dev libgpiod-dev" -[ -n "$CROWSNEST_USTREAMER_WITH_OMX" ] || CROWSNEST_USTREAMER_WITH_OMX="n" -[ -n "$CROWSNEST_USTREAMER_WITH_GPIO" ] || CROWSNEST_USTREAMER_WITH_GPIO="n" diff --git a/tools/config.buntu64 b/tools/config.buntu64 deleted file mode 100644 index d254c4d..0000000 --- a/tools/config.buntu64 +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -#### crowsnest - A webcam Service for multiple Cams and Stream Services. -#### -#### Written by Stephan Wendel aka KwadFan -#### Copyright 2021 -#### https://github.com/mainsail-crew/crowsnest -#### -#### This File is distributed under GPLv3 -#### -# shellcheck disable=all - - -[ -n "$CROWSNEST_CROWSNEST_DEPS" ] || CROWSNEST_CROWSNEST_DEPS="git crudini bsdutils findutils v4l-utils ffmpeg" -[ -n "$CROWSNEST_DEFAULT_CONF" ] || CROWSNEST_DEFAULT_CONF="mainsail_default.conf" -[ -n "$CROWSNEST_DEFAULT_CONF_DIR" ] || CROWSNEST_DEFAULT_CONF_DIR="/home/${BASE_USER}/klipper_config" -# Force Raspicam fix bool (1:yes / 0:no) -[ -n "$CROWSNEST_FORCE_RASPICAMFIX" ] || CROWSNEST_FORCE_RASPICAMFIX=1 -# Add Crowsnest to moonraker.conf (update manager) bool (1:yes / 0:no) -[ -n "$CROWSNEST_ADD_CROWSNEST_MOONRAKER" ] || CROWSNEST_ADD_CROWSNEST_MOONRAKER=1 - - -# ustreamer -[ -n "$CROWSNEST_USTREAMER_REPO_SHIP" ] || CROWSNEST_USTREAMER_REPO_SHIP=https://github.com/pikvm/ustreamer.git -[ -n "$CROWSNEST_USTREAMER_REPO_BRANCH" ] || CROWSNEST_USTREAMER_REPO_BRANCH=master -[ -n "$CROWSNEST_USTREAMER_DEPS" ] || CROWSNEST_USTREAMER_DEPS="git build-essential libevent-dev libjpeg-dev \ -libbsd-dev libgpiod-dev" -[ -n "$CROWSNEST_USTREAMER_WITH_OMX" ] || CROWSNEST_USTREAMER_WITH_OMX="n" -[ -n "$CROWSNEST_USTREAMER_WITH_GPIO" ] || CROWSNEST_USTREAMER_WITH_GPIO="n" diff --git a/tools/config.buster b/tools/config.buster deleted file mode 100644 index 9d85a8f..0000000 --- a/tools/config.buster +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -#### crowsnest - A webcam Service for multiple Cams and Stream Services. -#### -#### Written by Stephan Wendel aka KwadFan -#### Copyright 2021 -#### https://github.com/mainsail-crew/crowsnest -#### -#### This File is distributed under GPLv3 -#### -# shellcheck disable=all - - -[ -n "$CROWSNEST_CROWSNEST_DEPS" ] || CROWSNEST_CROWSNEST_DEPS="git crudini bsdutils findutils v4l-utils ffmpeg" -[ -n "$CROWSNEST_DEFAULT_CONF" ] || CROWSNEST_DEFAULT_CONF="mainsail_default.conf" -[ -n "$CROWSNEST_DEFAULT_CONF_DIR" ] || CROWSNEST_DEFAULT_CONF_DIR="/home/${BASE_USER}/klipper_config" -# Force Raspicam fix bool (1:yes / 0:no) -[ -n "$CROWSNEST_FORCE_RASPICAMFIX" ] || CROWSNEST_FORCE_RASPICAMFIX=1 -# Add Crowsnest to moonraker.conf (update manager) bool (1:yes / 0:no) -[ -n "$CROWSNEST_ADD_CROWSNEST_MOONRAKER" ] || CROWSNEST_ADD_CROWSNEST_MOONRAKER=1 - - -# ustreamer -[ -n "$CROWSNEST_USTREAMER_REPO_SHIP" ] || CROWSNEST_USTREAMER_REPO_SHIP=https://github.com/pikvm/ustreamer -[ -n "$CROWSNEST_USTREAMER_REPO_BRANCH" ] || CROWSNEST_USTREAMER_REPO_BRANCH=master -[ -n "$CROWSNEST_USTREAMER_DEPS" ] || CROWSNEST_USTREAMER_DEPS="git build-essential libevent-dev libjpeg8-dev \ -libbsd-dev libraspberrypi-dev libgpiod-dev" -[ -n "$CROWSNEST_USTREAMER_WITH_OMX" ] || CROWSNEST_USTREAMER_WITH_OMX="y" -[ -n "$CROWSNEST_USTREAMER_WITH_GPIO" ] || CROWSNEST_USTREAMER_WITH_GPIO="n" diff --git a/tools/config.local.example b/tools/config.local.example deleted file mode 100644 index c29c34b..0000000 --- a/tools/config.local.example +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -#### crowsnest - A webcam Service for multiple Cams and Stream Services. -#### -#### Written by Stephan Wendel aka KwadFan -#### Copyright 2021 -#### https://github.com/mainsail-crew/crowsnest -#### -#### This File is distributed under GPLv3 -#### -# shellcheck disable=all - - -[ -n "$CROWSNEST_CROWSNEST_DEPS" ] || CROWSNEST_CROWSNEST_DEPS="git crudini bsdutils findutils v4l-utils ffmpeg" -[ -n "$CROWSNEST_DEFAULT_CONF" ] || CROWSNEST_DEFAULT_CONF="mainsail_default.conf" -[ -n "$CROWSNEST_DEFAULT_CONF_DIR" ] || CROWSNEST_DEFAULT_CONF_DIR="/home/${BASE_USER}/klipper_config" -# Force Raspicam fix bool (1:yes / 0:no) -[ -n "$CROWSNEST_FORCE_RASPICAMFIX" ] || CROWSNEST_FORCE_RASPICAMFIX=0 -# Add Crowsnest to moonraker.conf (update manager) bool (1:yes / 0:no) -[ -n "$CROWSNEST_ADD_CROWSNEST_MOONRAKER" ] || CROWSNEST_ADD_CROWSNEST_MOONRAKER=0 - - -# ustreamer -[ -n "$CROWSNEST_USTREAMER_REPO_SHIP" ] || CROWSNEST_USTREAMER_REPO_SHIP=https://github.com/pikvm/ustreamer.git -[ -n "$CROWSNEST_USTREAMER_REPO_BRANCH" ] || CROWSNEST_USTREAMER_REPO_BRANCH=master -[ -n "$CROWSNEST_USTREAMER_DEPS" ] || CROWSNEST_USTREAMER_DEPS="git build-essential libevent-dev libjpeg62-turbo-dev \ -libbsd-dev libgpiod-dev" -[ -n "$CROWSNEST_USTREAMER_WITH_OMX" ] || CROWSNEST_USTREAMER_WITH_OMX="n" -[ -n "$CROWSNEST_USTREAMER_WITH_GPIO" ] || CROWSNEST_USTREAMER_WITH_GPIO="n" diff --git a/tools/config.x86 b/tools/config.x86 deleted file mode 100644 index bee2d44..0000000 --- a/tools/config.x86 +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -#### crowsnest - A webcam Service for multiple Cams and Stream Services. -#### -#### Written by Stephan Wendel aka KwadFan -#### Copyright 2021 -#### https://github.com/mainsail-crew/crowsnest -#### -#### This File is distributed under GPLv3 -#### -# shellcheck disable=all - -# crowsnest -[ -n "$CROWSNEST_CROWSNEST_DEPS" ] || CROWSNEST_CROWSNEST_DEPS="git crudini bsdutils findutils v4l-utils ffmpeg curl \ -libxcomposite1 libxtst6" -[ -n "$CROWSNEST_DEFAULT_CONF" ] || CROWSNEST_DEFAULT_CONF="mainsail_default.conf" -[ -n "$CROWSNEST_DEFAULT_CONF_DIR" ] || CROWSNEST_DEFAULT_CONF_DIR="/home/${BASE_USER}/klipper_config" -[ -n "$CROWSNEST_MOONRAKER_SUPPORT" ] || CROWSNEST_MOONRAKER_SUPPORT="y" - -# ustreamer -[ -n "$CROWSNEST_USTREAMER_REPO_SHIP" ] || CROWSNEST_USTREAMER_REPO_SHIP=https://github.com/pikvm/ustreamer.git -[ -n "$CROWSNEST_USTREAMER_REPO_BRANCH" ] || CROWSNEST_USTREAMER_REPO_BRANCH=master -[ -n "$CROWSNEST_USTREAMER_DEPS" ] || CROWSNEST_USTREAMER_DEPS="git build-essential libevent-dev libjpeg-dev \ -libbsd-dev" -[ -n "$CROWSNEST_USTREAMER_WITH_OMX" ] || CROWSNEST_USTREAMER_WITH_OMX="n" -[ -n "$CROWSNEST_USTREAMER_WITH_GPIO" ] || CROWSNEST_USTREAMER_WITH_GPIO="n" diff --git a/tools/configure.sh b/tools/configure.sh new file mode 100755 index 0000000..0216c49 --- /dev/null +++ b/tools/configure.sh @@ -0,0 +1,278 @@ +#!/usr/bin/env bash + +#### crowsnest - A webcam Service for multiple Cams and Stream Services. +#### +#### Written by Stephan Wendel aka KwadFan +#### Copyright 2021 - 2022 +#### https://github.com/mainsail-crew/crowsnest +#### +#### This File is distributed under GPLv3 +#### + +# shellcheck enable=require-variable-braces + +# Exit on errors +set -Ee + +# Global Vars +CN_CONFIG_USER=$(whoami) +CN_CONFIG_CONFIGFILE="tools/.config" +CN_CONFIG_ROOTPATH="/home/${CN_CONFIG_USER}/printer_data" +CN_CONFIG_CONFIGPATH="${CN_CONFIG_ROOTPATH}/config" +CN_CONFIG_LOGPATH="${CN_CONFIG_ROOTPATH}/logs" +CN_CONFIG_ENVPATH="${CN_CONFIG_ROOTPATH}/systemd" +CN_MOONRAKER_CONFIG_PATH="${CN_CONFIG_CONFIGPATH}/moonraker.conf" +CN_USTREAMER_REPO="https://github.com/pikvm/ustreamer.git" +CN_USTREAMER_BRANCH="master" + +### Messages +header_msg() { + clear + echo -e "\e[34m\n #### Crowsnest Install Configurator ####\e[0m\n" +} + +welcome_msg() { + header_msg + echo -e "This will guide you through install configuration" + echo -e "After successful configuration use\n" + echo -e "\t\e[32msudo make install\e[0m\n" + echo -e "to install crowsnest ..." +} + +abort_msg() { + header_msg + echo -e "Configuration aborted by user ... \e[31mExiting!\e[0m" +} + +check_config_file_msg() { + header_msg + echo -e "\n\t\e[33mWarning:\e[0m Found an existing .config!\n" +} + + +default_path_msg() { + echo -e "Hit ENTER to use default." +} + +config_path_msg() { + header_msg + echo -e "Please specify path to config file (crowsnest.conf)\n" + echo -e "\t\e[34mNOTE:\e[0m File names are hardcoded! Also skip trailing backslash!" + echo -e "\tDefault: \e[32m${CN_CONFIG_CONFIGPATH}\e[0m\n" +} + +log_path_msg() { + header_msg + echo -e "Please specify path to log file (crowsnest.log)\n" + echo -e "\t\e[34mNOTE:\e[0m File names are hardcoded! Also skip trailing backslash!" + echo -e "\tDefault: \e[32m${CN_CONFIG_LOGPATH}\e[0m\n" +} + +env_path_msg() { + header_msg + echo -e "Please specify path to service environment file (crowsnest.env)\n" + echo -e "\t\e[34mNOTE:\e[0m File names are hardcoded! Also skip trailing backslash!" + echo -e "\tDefault: \e[32m${CN_CONFIG_ENVPATH}\e[0m\n" +} + +apply_raspicamfix_msg() { + header_msg + echo -e "Should the Raspicam Fix be applied?\n" + echo -e "\t\e[34mNOTE:\e[0m\n\tThis should be only applied if you are" + echo -e "\tusing a Raspberry Pi! This will force Raspicams" + echo -e "\tusing the device path '/dev/video0'\n" + echo -e "Available are:\n Yes [y or Y]\n No [n or N]\n Hit ENTER for auto\n" + echo -e "In 'auto' mode Installer try to detect device and applies fix if SBC is a Pi!\n" +} + +add_moonraker_entry_msg() { + header_msg + echo -e "Should the update_manager entry added to your moonraker.conf?\n" + echo -e "\t\e[34mNOTE:\e[0m\n\tThis will only work if your moonraker.conf" + echo -e "\tshares the same path as your crowsnest.conf!!!\n" + echo -e "If you want/have to do that manually,\nplease see 'resources/moonraker_update.txt'" + echo -e "Copy the content in your moonraker.conf\n" +} + +goodbye_msg() { + header_msg + echo -e "\t\e[32mSuccessful\e[0m configuration." + echo -e "\tIn order to install crowsnest, please run:\n" + echo -e "\t\t\e[32msudo make install\e[0m\n" + echo -e "Goodbye ..." +} + +### funcs +continue_config() { + local reply + while true; do + read -erp "Continue? [Y/n]: " -i "Y" reply + case "${reply}" in + [Yy]* ) + break + ;; + [Nn]* ) + abort_msg + exit 0 + ;; + * ) + echo -e "\e[31mERROR: Please type Y or N !\e[0m" + ;; + esac + done +} + +check_config_file() { + local reply + if [[ -f "${CN_CONFIG_CONFIGFILE}" ]]; then + check_config_file_msg + while true; do + read -erp "Overwrite? [y/N]: " -i "N" reply + case "${reply}" in + [Yy]* ) + rm -f tools/.config + break + ;; + [Nn]* ) + abort_msg + exit 0 + ;; + * ) + echo -e "\e[31mERROR:\e[0m Please type Y or N !" + ;; + esac + done + return 0 + fi + return 0 +} + +create_config_header() { + { + echo -e "BASE_USER=\"${CN_CONFIG_USER}\""; + echo -e "CROWSNEST_USTREAMER_REPO_SHIP=\"${CN_USTREAMER_REPO}\""; + echo -e "CROWSNEST_USTREAMER_REPO_BRANCH=\"${CN_USTREAMER_BRANCH}\"" + } >> "${CN_CONFIG_CONFIGFILE}" +} + +specify_config_path() { + local reply + config_path_msg + default_path_msg + read -erp "Please enter path: " reply + if [[ -z "${reply}" ]]; then + echo -e "CROWSNEST_CONFIG_PATH=\"${CN_CONFIG_CONFIGPATH}\"" >> \ + "${CN_CONFIG_CONFIGFILE}" + return 0 + fi + if [[ -n "${reply}" ]]; then + echo -e "CROWSNEST_CONFIG_PATH=\"${reply}\"" >> "${CN_CONFIG_CONFIGFILE}" + CN_MOONRAKER_CONFIG_PATH="${reply}/moonraker.conf" + return 0 + fi +} + +specify_log_path() { + local reply + log_path_msg + default_path_msg + read -erp "Please enter path: " reply + if [[ -z "${reply}" ]]; then + echo -e "CROWSNEST_LOG_PATH=\"${CN_CONFIG_LOGPATH}\"" >> \ + "${CN_CONFIG_CONFIGFILE}" + return 0 + fi + if [[ -n "${reply}" ]]; then + echo -e "CROWSNEST_LOG_PATH=\"${reply}\"" >> "${CN_CONFIG_CONFIGFILE}" + return 0 + fi +} + +specify_env_path() { + local reply + env_path_msg + default_path_msg + read -erp "Please enter path: " reply + if [[ -z "${reply}" ]]; then + echo -e "CROWSNEST_ENV_PATH=\"${CN_CONFIG_ENVPATH}\"" >> \ + "${CN_CONFIG_CONFIGFILE}" + return 0 + fi + if [[ -n "${reply}" ]]; then + echo -e "CROWSNEST_ENV_PATH=\"${reply}\"" >> "${CN_CONFIG_CONFIGFILE}" + return 0 + fi +} + +apply_raspicamfix() { + local reply + apply_raspicamfix_msg + read -erp "Enable Raspicamfix?: " reply + if [[ -z "${reply}" ]]; then + echo -e "CROWSNEST_RASPICAMFIX=\"auto\"" >> \ + "${CN_CONFIG_CONFIGFILE}" + return 0 + fi + while true; do + case "${reply}" in + [yY]*) + echo -e "CROWSNEST_RASPICAMFIX=\"1\"" >> "${CN_CONFIG_CONFIGFILE}" + break + ;; + [nN]*) + echo -e "CROWSNEST_RASPICAMFIX=\"0\"" >> "${CN_CONFIG_CONFIGFILE}" + break + ;; + esac + done +} + +add_moonraker_entry() { + local reply + add_moonraker_entry_msg + while true; do + read -erp "Add update_manager entry? [Y/n]: " -i "Y" reply + case "${reply}" in + [yY]*) + echo -e "CROWSNEST_ADD_CROWSNEST_MOONRAKER=\"1\"" >> "${CN_CONFIG_CONFIGFILE}" + echo "CROWSNEST_MOONRAKER_CONF_PATH=\"${CN_MOONRAKER_CONFIG_PATH}\"" \ + >> "${CN_CONFIG_CONFIGFILE}" + break + ;; + [nN]*) + echo -e "CROWSNEST_ADD_CROWSNEST_MOONRAKER=\"0\"" >> "${CN_CONFIG_CONFIGFILE}" + break + ;; + * ) + echo -e "\e[31mERROR:\e[0m Please type Y or N !" + ;; + esac + done +} + +### Main func +main() { + # Step 1: Welcome Message + welcome_msg + continue_config + # Step 2: Check for existing file + check_config_file + # Step 3: Create config header + create_config_header + # Step 4: Specify config file path. + specify_config_path + # Step 5: Specify log file path. + specify_log_path + # Step 6: Specify env path. + specify_env_path + # Step 7: Raspicam fix + apply_raspicamfix + # Step 8: Moonraker entry + add_moonraker_entry + # Step 9: Display finished message + goodbye_msg +} + +### MAIN +main +exit 0 diff --git a/tools/dev-helper.sh b/tools/dev-helper.sh new file mode 100755 index 0000000..a97d10d --- /dev/null +++ b/tools/dev-helper.sh @@ -0,0 +1,352 @@ +#!/usr/bin/env bash + +#### crowsnest - A webcam Service for multiple Cams and Stream Services. +#### +#### Written by Stephan Wendel aka KwadFan +#### Copyright 2021 - 2022 +#### https://github.com/mainsail-crew/crowsnest +#### +#### This File is distributed under GPLv3 +#### + +# shellcheck enable=require-variable-braces + +# Exit on errors +set -Ee + +# Debug +# set -x + +# Global Vars +TITLE="\e[31mcrowsnest\e[0m - $(basename "${0}")" +DH_VERSION="v0.0.0" +[[ -n "${BASE_USER}" ]] || BASE_USER="$(whoami)" + +# Set fallback lang +export LC_ALL=C + +# Message Vars +CN_OK="\e[32mOK\e[0m" +CN_FL="\e[31mFAILED\e[0m" +# leave in place for later use +# CN_SK="\e[33mSKIPPED\e[0m" + +CN_G="\e[32m" +CN_R="\e[31m" +CN_B="\e[34m" +CN_N="\e[0m" + + +# Message funcs +echo_green() { + echo -e "\e[32m${1}\e[0m" +} + +echo_red() { + echo -e "\e[31m${1}\e[0m" +} + +echo_yellow() { + echo -e "\e[33m${1}\e[0m" +} + +echo_blue() { + echo -e "\e[34m${1}\e[0m" +} + +echo_blank() { + echo -e "\n" +} + +help_msg() { + echo -e "\n\t $(basename "${0}") [Options]\n" + echo -e "\t\t-h\tPrints this help." + echo -e "\t\t-V\tShows Version of $(basename "${0}")" + echo -e "\t\t-a\tShows all available informations gathered" + echo -e "\t\t-c\tShows informations about cameras" + echo -e "\t\t-o\tShows informations about used OS" + echo -e "\t\t-s\tShows informations about host system" + echo -e "\t\t-x\tPerforms tests to ensure successful install of crowsnest" + echo -e "\t\t-d\tDecolorize file (if output is redirected to file)" + echo_blank + exit 1 +} + +# Global functions + +## call get_os_version +get_os_info() { + local osrel adrel + # Dirty Hack to not fail script :P + adrel="$(find /etc -name "*-release" -type f -print 2> /dev/null || echo "" )" + if [[ -f /etc/os-release ]]; then + osrel="$(grep "PRETTY_NAME=" /etc/os-release | cut -d'=' -f2 | sed 's/\"//g')" + echo_blue "OS Info:\n" + echo -e "Distribution: ${CN_G}\t${osrel}${CN_N}\n" + fi + ## Find additional informations + if [[ -n "${adrel}" ]]; then + for i in ${adrel}; do + if [[ -f "${i}" ]]; then + echo_blue "Additional Release Info:\n" + echo -e "From ${i}:\n" + echo -e "${CN_G}$(cat "${i}")${CN_N}\n" + fi + done + fi +} + +### Import config +import_config() { + ## Source config if present + if [[ -s tools/.config ]]; then + # shellcheck disable=SC1091 + source tools/.config + return 0 + else + echo -e "\[31mNo .config found!\e[0m" + return 0 + fi +} + +is_raspberry_pi() { + if [[ -f /proc/device-tree/model ]] && + grep -q "Raspberry" /proc/device-tree/model; then + echo "1" + else + echo "0" + fi +} + +# get_val
+# spits out value +get_val() { + crudini --get "${1}" "${2}" "${3}" 2> /dev/null +} + +host_info() { + grep "model name" /proc/cpuinfo | head -1 | awk -F': ' '{print $2}' +} + +load_avg() { + local load_avg + load_avg=$(uptime | rev | cut -d":" -f1 | rev | sed 's/ //1' ) + echo " ${load_avg} (load in last 1m/5m/15m)" +} + +cpu_info() { + if [[ -n "$(command -v lscpu)" ]]; then + echo_blue "CPU Details:\n" + lscpu + echo_blank + fi +} + +mem_info() { + echo_blue "Mem Info:" + free -m + echo -e "\n" +} + +disk_info() { + echo_blue "Disk Info:" + df -h + echo -e "\n" +} + +get_host_info() { + local kernel model + kernel="$(uname -srmp)" + echo_blue "Host Informations:\n" + if [[ -f /proc/device-tree/model ]]; then + model="$(tr -d '\0' < /proc/device-tree/model)" + fi + if [[ ! -f /proc/device-tree/model ]]; then + model="${CN_R}Unknown ($(host_info))${CN_N}" + fi + echo -e "Running on: ${CN_G}${model}${CN_N}\n" + echo -e "Kernel: ${CN_G}${kernel}${CN_N}\n" + echo -e "Load Average: $(load_avg)\n" + cpu_info + mem_info + disk_info +} + +get_cam_info() { + local cam ctrls vid_dev + vid_dev="$(find /dev/v4l/by-path -name "*video*index0" -print | sed '/isp/d;/codec/d' )" + if [[ -z "$(command -v v4l2-ctl)" ]]; then + echo_red "Command: v4l2-ctl not found!" + echo_red "Can not grab appropriate informations ..." + return 0 + fi + ## helper func + sym_lnk() { + local dev + dev="$(basename "$(readlink -f "${1}")")" + find /dev/v4l -type l -ls | grep -i "${dev}$" | awk '{print $11}' + } + + echo_blue "v4l2-ctl supported camera(s):\n" + for dev in ${vid_dev}; do + cam="$(v4l2-ctl -d "${dev}" --list-formats-ext | sed '1,3d')" + ctrls="$(v4l2-ctl -d "${dev}" --list-ctrls-menus || echo "")" + echo_blue "Device $(readlink -f "${dev}"):\n" + echo_green "Symbolic links to $(readlink -f "${dev}"):\n" + sym_lnk "${dev}" + echo_blank + echo -e "Supported formats:\n" + echo -e "${cam}\n" + if [[ -n "${ctrls}" ]]; then + echo -e "Supported Controls:\n" + echo -e "${ctrls}\n" + fi + done +} + +get_crowsnest() { + local cn_bin cn_svc_file + cn_bin="$(command -v crowsnest)" + cn_svc_file="$(find /etc/systemd/system -maxdepth 1 -name "crowsnest*.service")" + echo_blue "Testing install of crowsnest:\n" + echo_green "Some tests need 'sudo' rights!\nPlease enter password if prompted!\n" + sudo sh -c 'echo "" > /dev/null' + echo -e "Searching for crowsnest ..." + if [[ -n "${cn_bin}" ]]; then + echo -e "crowsnest found in ${cn_bin} [${CN_OK}]" + echo -e "\t${CN_B}==>${CN_N} $(readlink -f "${cn_bin}")\n" + echo_blue "Version:" + crowsnest -v + echo_blank + else + echo -e "crowsnest not found! [${CN_FL}]\n" + echo_red "Further test will be aborted...\n" + exit 1 + fi + echo_blue "Service tests:\n" + for svc in ${cn_svc_file}; do + if [[ ! -f "${svc}" ]]; then + echo -e "${svc} not found! [${CN_FL}]\n" + fi + if [[ -f "${svc}" ]]; then + echo -e "${svc} found! [${CN_OK}]\n" + ## Print service file + echo_blue "Print service file:\n" + cat -n "${svc}" + echo_blank + fi + ## Check is-active + echo -e "Service Status: ${CN_G}$(sudo systemctl is-active "$(basename "${svc}")")${CN_N}\n" + ## Check for env file + cn_env_path="$(grep -i "EnvironmentFile" "${svc}" | cut -d"=" -f2)" + echo_blue "Environment file ($(basename "${cn_env_path}")):" + if [[ ! -f "${cn_env_path}" ]]; then + echo -e "${cn_env_path} not found! [${CN_FL}]\n" + fi + if [[ -f "${cn_env_path}" ]]; then + echo -e "${cn_env_path} found! [${CN_OK}]\n" + echo_blue "Print environment file:\n" + cat -n "${cn_env_path}" + echo_blank + fi + ## Check config file + ### Import path from env file + # shellcheck disable=SC1090 + . "${cn_env_path}" + cn_cnf_path="${CROWSNEST_ARGS/-c /}" + echo_blue "Config file ($(basename "${cn_cnf_path}")):" + if [[ ! -f "${cn_cnf_path}" ]]; then + echo -e "${cn_cnf_path} not found! [${CN_FL}]\n" + fi + if [[ -f "${cn_cnf_path}" ]]; then + echo -e "${cn_cnf_path} found! [${CN_OK}]\n" + echo_blue "Print config file:\n" + cat -n "${cn_cnf_path}" + echo_blank + fi + ## Check log file + ### Clean path + cn_log_path="$(grep -i "crowsnest.log" "${cn_cnf_path}" | sed 's#log_path: ~#'"${HOME}"'#')" + echo_blue "Log file ($(basename "${cn_log_path}")):" + if [[ ! -f "${cn_log_path}" ]]; then + echo -e "${cn_log_path} not found! [${CN_FL}]\n" + fi + if [[ -f "${cn_log_path}" ]]; then + echo -e "${cn_log_path} found! [${CN_OK}]\n" + echo_blue "Print config file (last 10 lines):\n" + tail -n10 "${cn_log_path}" + echo_blank + fi + done +} + +get_config() { + echo_blue "Installer .config file ($(basename "${cn_cnf_file}")):" + cn_cnf_file="${PWD}/tools/.config" + if [[ ! -f "${cn_cnf_file}" ]]; then + echo -e "${cn_cnf_file} not found! [${CN_FL}]\n" + fi + if [[ -f "${cn_cnf_file}" ]]; then + echo -e "${cn_cnf_file} found! [${CN_OK}]\n" + echo_blue "Print .config file:\n" + cat -n "${cn_cnf_file}" + echo_blank + fi +} + +decolorize() { + echo -en "Decolorizing ${1} ...\r" + sed -r -i 's/\x1B\[([0-9]{1,3}(;[0-9]{1,2})?)?[mGK]//g' "${1}" + echo -e "Decolorizing ${1} ...[${CN_OK}]\r" + echo_blank +} + +#### MAIN +echo -e "${TITLE}\n" +[[ "${#}" -eq 0 ]] && help_msg +while getopts ":acd:hosxzV" arg; do + case "${arg}" in + a ) + get_os_info + get_host_info + get_cam_info + get_crowsnest + get_config + break + ;; + c ) + get_cam_info + break + ;; + d ) + decolorize "${OPTARG}" + break + ;; + o ) + get_os_info + break + ;; + s ) + get_host_info + break + ;; + x ) + get_crowsnest + break + ;; + z ) + get_config + break + ;; + V ) + echo -e "${CN_B}$(basename "${0}")${CN_N} Version: ${CN_G}${DH_VERSION}${CN_N}\n" + break + ;; + h | \? ) + echo -e "Invalid option: -${OPTARG}" + help_msg + ;; + esac + done + +exit 0 diff --git a/tools/install.sh b/tools/install.sh index 7e16472..4944c34 100755 --- a/tools/install.sh +++ b/tools/install.sh @@ -1,187 +1,133 @@ #!/usr/bin/env bash -# Crow's Nest -# A multiple Cam and Stream Service for mainsailOS -# Written by Stephan Wendel aka KwadFan -# Copyright 2021 - 2022 -# https://github.com/mainsail-crew/crowsnest -# GPL V3 -######## + +#### crowsnest - A webcam Service for multiple Cams and Stream Services. +#### +#### Written by Stephan Wendel aka KwadFan +#### Copyright 2021 - 2022 +#### https://github.com/mainsail-crew/crowsnest +#### +#### This File is distributed under GPLv3 +#### # shellcheck enable=require-variable-braces -## disabled SC2086 for some lines because there we want 'word splitting' - # Exit on errors set -Ee +# Debug +# set -x + # Global Vars -BASE_USER=$(whoami) -TITLE="crowsnest - A Webcam Daemon for Raspberry Pi OS" +TITLE="\e[31mcrowsnest\e[0m - A webcam daemon for multiple Cams and stream services." +[[ -n "${BASE_USER}" ]] || BASE_USER="$(whoami)" +[[ -n "${CROWSNEST_UNATTENDED}" ]] || CROWSNEST_UNATTENDED="0" +[[ -n "${CROWSNEST_DEFAULT_CONF}" ]] || CROWSNEST_DEFAULT_CONF="resources/crowsnest.conf" -### Non root -if [ ${UID} == '0' ]; then - echo -e "DO NOT RUN THIS SCRIPT AS ROOT!\nExiting..." - exit 1 -fi +# Message Vars +CN_OK="\e[32mOK\e[0m" +CN_SK="\e[33mSKIPPED\e[0m" +### Global setup ### noninteractive Check -if [ "${DEBIAN_FRONTEND}" != "noninteractive" ]; then +if [[ "${DEBIAN_FRONTEND}" != "noninteractive" ]]; then export DEBIAN_FRONTEND=noninteractive fi -### Functions +### Check non-root +if [[ ${UID} != '0' ]]; then + echo -e "\n\tYOU NEED TO RUN INSTALLER AS ROOT!" + echo -e "\tPlease try '\e[32msudo make install\e[0m'\n\nExiting..." + exit 1 +fi + +### Global functions ### Messages ### Welcome Message -function welcome_msg { +welcome_msg() { echo -e "${TITLE}\n" - echo -e "\tSome Parts of the Installer requires 'root' privileges." - echo -e "\tYou will be prompted for your 'sudo' password, if needed.\n" + echo -e "\t\e[34mAhoi!\e[0m" + echo -e "\tThank you for installing crowsnest ;)" + echo -e "\tThis will take a while ... " + echo -e "\tPlease reboot after installation has finished.\n" + sleep 1 } -function detect_msg { - echo -e "Found an existing 'crowsnest'. This will be removed." - echo -e "Since we dont use mjpg-streamer it will also removed." +### Config Message +config_msg() { + echo -e "\nConfig file not found!\n\tYOU NEED TO CREATE A CONFIGURATION!" + echo -e "\tPlease use 'make config' first!\nExiting..." + exit 1 +} + +### Detect Message +detect_msg() { + echo -e "Found an existing 'crowsnest' or mjpg-streamer" + echo -e "This has to be removed..." echo -e "You can use KIAUH for example to reinstall.\n" } -function goodbye_msg { - echo -e "\nInstallation complete.\n\tPlease reboot your machine!" - echo -e "I hope you enjoy crowsnest, GoodBye ..." +### Goodbye Message +goodbye_msg() { + echo -e "\nInstallation \e[32msuccessful\e[0m.\n" + echo -e "\t\e[33mTo take changes effect, you need to reboot your machine!\e[0m\n" } -### Installer - -### General ## These two functions are reused from custompios common.sh ## Credits to guysoft! ## https://github.com/guysoft/CustomPiOS -function install_cleanup_trap() { +install_cleanup_trap() { # kills all child processes of the current process on SIGINT or SIGTERM trap 'cleanup' SIGINT SIGTERM } -function cleanup() { +cleanup() { # make sure that all child processed die when we die echo -e "Killed by user ...\r\nGoodBye ...\r" - # shellcheck disable=2046 - [ -n "$(jobs -pr)" ] && kill $(jobs -pr) && sleep 5 && kill -9 $(jobs -pr) + [[ -n "$(jobs -pr)" ]] && kill "$(jobs -pr)" && sleep 5 && kill -9 "$(jobs -pr)" } -## -function err_exit { - if [ "${1}" != "0" ]; then +err_exit() { + if [[ "${1}" != "0" ]]; then echo -e "ERROR: Error ${1} occured on line ${2}" echo -e "ERROR: Stopping $(basename "$0")." echo -e "Goodbye..." fi - # shellcheck disable=2046 - [ -n "$(jobs -pr)" ] && kill $(jobs -pr) && sleep 5 && kill -9 $(jobs -pr) + [[ -n "$(jobs -pr)" ]] && kill "$(jobs -pr)" && sleep 5 && kill -9 "$(jobs -pr)" exit 1 } -### Init ERR Trap -trap 'err_exit $? $LINENO' ERR - -## helper func ## call get_os_version -function get_os_version { - if [ -n "${1}" ]; then +get_os_version() { + if [[ -n "${1}" ]]; then grep -c "${1}" /etc/os-release fi } -### Import config from custompios. -function import_config { - ## Source Custom config if present - if [ -s tools/config.local ]; then +### Import config +import_config() { + ## Source config if present + if [[ -s tools/.config ]]; then # shellcheck disable=SC1091 - source tools/config.local + source tools/.config return 0 - fi - - ## X86 machines - if [ "$(uname -m)" == "x86_64" ] && - [ -f tools/config.x86 ]; then - # shellcheck disable=SC1091 - source tools/config.x86 - return 0 - fi - - ## rpi os buster - if [ "$(uname -m)" != "x86_64" ] && - [ "$(get_os_version buster)" != "0" ] && - [ -f "tools/config.buster" ]; then - # shellcheck disable=SC1091 - source tools/config.buster - return 0 - fi - - ## bullseye - if [ "$(uname -m)" != "x86_64" ] && - [ "$(get_os_version bullseye)" != "0" ] && - [ -f "tools/config.bullseye" ]; then - # shellcheck disable=SC1091 - source tools/config.bullseye - return 0 - fi - - ## Ubuntu ARM (armv7l) tested on v20.04 - # Thanks to https://github.com/gdachs - # To my sadness he didnt make wanted changes in - # https://github.com/mainsail-crew/crowsnest/pull/32 - # But I appriciate your work, thx gdachs! - if [ "$(uname -m)" == "armv7l" ] && - [ "$(get_os_version ubuntu)" != "0" ] && - [ -f "tools/config.buntu64" ]; then - # shellcheck disable=SC1091 - source tools/config.buntu64 - return 0 - fi - - ## Ubuntu ARM (aarch64) tested on v22.04 - if [ "$(uname -m)" == "aarch64" ] && - [ "$(get_os_version ubuntu)" != "0" ] && - [ -f "tools/config.buntu64" ]; then - # shellcheck disable=SC1091 - source tools/config.buntu64 - return 0 - fi - - ## armbian buster - if [ "$(uname -m)" != "x86_64" ] && - [ -f "/etc/armbian-release" ] && - [ "$(get_os_version buster)" != "0" ] && - [ -f "tools/config.armbian-buster" ]; then - # shellcheck disable=SC1091 - source tools/config.armbian-buster - return 0 - fi - - ## armbian bullseye - if [ "$(uname -m)" != "x86_64" ] && - [ -f "/etc/armbian-release" ] && - [ "$(get_os_version bullseye)" != "0" ] && - [ -f "tools/config.armbian-bullseye" ]; then - # shellcheck disable=SC1091 - source tools/config.armbian-bullseye - return 0 - fi - - ## armbian jammy - if [ "$(uname -m)" != "x86_64" ] && - [ -f "/etc/armbian-release" ] && - [ "$(get_os_version ubuntu)" != "0" ] && - [ -f "tools/config.buntu64" ]; then - # shellcheck disable=SC1091 - source tools/config.buntu64 + else + config_msg return 0 fi } +create_filestructure() { + for i in "${CROWSNEST_CONFIG_PATH}" "${CROWSNEST_LOG_PATH%/*.*}" "${CROWSNEST_ENV_PATH}"; do + if [[ ! -d "${i}" ]]; then + mkdir -p "${i}" + fi + done +} + ### Detect legacy webcamd. -function detect_existing_webcamd { +detect_existing_webcamd() { local remove if [ -x "/usr/local/bin/webcamd" ] && [ -d "${HOME}/mjpg-streamer" ]; then detect_msg @@ -190,7 +136,7 @@ function detect_existing_webcamd { y|Y|yes|Yes|YES) echo -en "\nStopping webcamd.service ...\r" sudo systemctl stop webcamd.service &> /dev/null - echo -e "Stopping webcamd.service ... \t[OK]\r" + echo -e "Stopping webcamd.service ... \t[${CN_OK}]\r" remove_existing_webcamd ;; @@ -210,163 +156,178 @@ function detect_existing_webcamd { } ### Remove existing webcamd -function remove_existing_webcamd { - if [ -x "/usr/local/bin/webcamd" ]; then +remove_existing_webcamd() { + if [[ -x "/usr/local/bin/webcamd" ]]; then echo -en "Removing 'webcamd' ...\r" sudo rm -f /usr/local/bin/webcamd > /dev/null - echo -e "Removing 'webcamd' ... \t\t[OK]\r" + echo -e "Removing 'webcamd' ... \t\t[${CN_OK}]\r" fi - if [ -d "${HOME}/mjpg-streamer" ]; then + if [[ -d "${HOME}/mjpg-streamer" ]]; then echo -en "Removing 'mjpg-streamer' ...\r" sudo rm -rf "${HOME}"/mjpg-streamer > /dev/null - echo -e "Removing 'mjpg-streamer' ... \t[OK]\r" + echo -e "Removing 'mjpg-streamer' ... \t[${CN_OK}]\r" fi - if [ -f "/etc/systemd/system/webcamd.service" ]; then + if [[ -f "/etc/systemd/system/webcamd.service" ]]; then echo -en "Removing 'webcamd.service' ...\r" sudo systemctl disable webcamd.service &> /dev/null sudo rm -f /etc/systemd/system/webcamd.service > /dev/null - echo -e "Removing 'webcamd.service' ... \t[OK]\r" + echo -e "Removing 'webcamd.service' ... \t[${CN_OK}]\r" fi - if [ -f "/var/log/webcamd.log" ]; then + if [[ -f "/var/log/webcamd.log" ]]; then echo -en "Removing 'webcamd.log' ...\r" sudo rm -f /var/log/webcamd.log > /dev/null + if [[ -f "${HOME}/klipper_logs/webcamd.log" ]]; then sudo rm -f "${HOME}"/klipper_logs/webcamd.log > /dev/null - echo -e "Removing 'webcamd.log' ... \t[OK]\r" + fi + if [[ -f "${HOME}/printer_data/logs/webcamd.log" ]]; then + sudo rm -f "${HOME}"/printer_data/logs/webcamd.log > /dev/null + fi + echo -e "Removing 'webcamd.log' ... \t[${CN_OK}]\r" fi - if [ -f "/etc/logrotate.d/webcamd" ]; then + if [[ -f "/etc/logrotate.d/webcamd" ]]; then echo -en "Removing 'webcamd' logrotate...\r" sudo rm -f /etc/logrotate.d/webcamd > /dev/null - echo -e "Removing 'webcamd' logrotate ... \t[OK]\r" + echo -e "Removing 'webcamd' logrotate ... \t[${CN_OK}]\r" fi echo -e "\nOld 'webcamd' completly removed." echo -e "webcam.txt kept,but no longer necessary ..." } +install_packages() { + ### Crowsnest Dependencies + PKGLIST="git crudini bsdutils findutils v4l-utils curl" + ### Ustreamer Dependencies + PKGLIST="${PKGLIST} build-essential libevent-dev libjpeg-dev libbsd-dev" + ### simple-rtsp-server Dependencies + PKGLIST="${PKGLIST} libxcomposite1 libxtst6 ffmpeg" + + echo -e "Running apt update first ..." + ### Run apt update + sudo apt-get -q --allow-releaseinfo-change update -function install_crowsnest { - local addconf bin_path logrotatefile moonraker_conf moonraker_update - local crowsnest_bin servicefile template - bin_path="/usr/local/bin" - crowsnest_bin="${HOME}/crowsnest/crowsnest" - template="${PWD}/sample_configs/${CROWSNEST_DEFAULT_CONF}" - servicefile="${PWD}/file_templates/crowsnest.service" - logrotatefile="${HOME}/crowsnest/file_templates/logrotate_crowsnest" - moonraker_conf="${HOME}/klipper_config/moonraker.conf" - moonraker_update="${PWD}/file_templates/moonraker_update.txt" - ## helper func moonraker update_manager - function add_update_entry { - if [ -f "${moonraker_conf}" ]; then - # make sure no file exist - if [ -f "/tmp/moonraker.conf" ]; then - sudo rm -f /tmp/moonraker.conf - fi - echo -e "Adding [update_manager] entry ..." - sudo -u "${BASE_USER}" \ - cp "${moonraker_conf}" "${moonraker_conf}.backup" && - cat "${moonraker_conf}" "${moonraker_update}" > /tmp/moonraker.conf && - cp -rf /tmp/moonraker.conf "${moonraker_conf}" - if [ "${UNATTENDED}" == "true" ]; then - sudo rm -f "${moonraker_conf}.backup" - fi - else - echo -e "moonraker.conf is missing ... [SKIPPED]" - fi - } - echo -e "\nInstall crowsnest Service ..." - ## Install Dependencies echo -e "Installing 'crowsnest' Dependencies ..." - # shellcheck disable=2086 - sudo apt install --yes --no-install-recommends ${CROWSNEST_CROWSNEST_DEPS} > /dev/null - echo -e "Installing 'crowsnest' Dependencies ... [OK]" - ## Link crowsnest to $PATH + # shellcheck disable=SC2086 + # disable because we want 'wordsplitting' + sudo apt-get install -q -y --no-install-recommends ${PKGLIST} + + if [[ "$(get_os_version buster)" != "0" ]]; then + sudo apt-get install -q -y --no-install-recommends libraspberrypi-dev + fi + echo -e "Installing 'crowsnest' Dependencies ... [${CN_OK}]" +} + +install_crowsnest() { + local bin_path config config_log_path crowsnest_bin + bin_path="/usr/local/bin" + config="${CROWSNEST_CONFIG_PATH}/crowsnest.conf" + crowsnest_bin="/home/${BASE_USER}/crowsnest/crowsnest" + # Link crowsnest to $PATH echo -en "Linking crowsnest ...\r" + # Remove if exist! + if [[ -f /usr/local/bin/crowsnest ]]; then + rm -f /usr/local/bin/crowsnest + fi sudo ln -sf "${crowsnest_bin}" "${bin_path}" > /dev/null - echo -e "Linking crowsnest ... [OK]\r" - ## Copy crowsnest.conf - # Make sure config directory exists! - if [ ! -d "${CROWSNEST_DEFAULT_CONF_DIR}" ]; then - sudo -u "${BASE_USER}" mkdir -p "${CROWSNEST_DEFAULT_CONF_DIR}" + echo -e "Linking crowsnest ... [${CN_OK}]\r" + # Install base line config + if [[ -f "${config}" ]]; then + echo -e "Found existing 'crowsnest.conf' in ${CROWSNEST_CONFIG_PATH}" + echo -e "Checking log_path ..." + config_log_path="$(crudini --get "${config}" crowsnest log_path)" + # strip out file name (crowsnest.log) + if [[ "${config_log_path%/*.*}" != "${CROWSNEST_LOG_PATH}" ]]; then + echo -e "Setup new log_path: ${CROWSNEST_LOG_PATH}" + sed -i 's|'"${config_log_path}"'|'"${CROWSNEST_LOG_PATH}/crowsnest.log"'|' "${config}" + # Strip full path to tilde + sed -i 's|'"/home/${BASE_USER}"'|~|g' "${config}" + fi + if [[ "${config_log_path%/*.*}" = "${CROWSNEST_LOG_PATH}" ]]; then + echo -e "Entry matching ... [${CN_OK}]" + # Strip full path to tilde + sed -i 's|'"/home/${BASE_USER}"'|~|g' "${config}" + fi fi - # Make sure not to overwrite existing! - if [ ! -f "${CROWSNEST_DEFAULT_CONF_DIR}/crowsnest.conf" ]; then + # Make sure not overwrite existing! + if [[ ! -f "${config}" ]]; then echo -en "Copying crowsnest.conf ...\r" - sudo -u "${BASE_USER}" cp -rf "${template}" "${CROWSNEST_DEFAULT_CONF_DIR}"/crowsnest.conf - echo -e "Copying crowsnest.conf ... [OK]\r" + sudo -u "${BASE_USER}" \ + cp -f "${CROWSNEST_DEFAULT_CONF}" "${config}" &> /dev/null + sed -i 's|%LOGPATH%|'"${CROWSNEST_LOG_PATH}"'|g' "${config}" + # Strip full path to tilde + sed -i 's|'"/home/${BASE_USER}"'|~|g' "${config}" + echo -e "Copying crowsnest.conf ... [${CN_OK}]\r" fi - ## Copy crowsnest.service - echo -en "Copying crowsnest.service file ...\r" - sudo cp -rf "${servicefile}" /etc/systemd/system/crowsnest.service > /dev/null - if [ ! "${BASE_USER}" == "pi" ]; then - sudo sed -i 's|pi|'"${BASE_USER}"'|g' /etc/systemd/system/crowsnest.service - fi - echo -e "Copying crowsnest.service file ... [OK]\r" - ## Copy logrotate - echo -en "Linking logrotate file ...\r" - sudo cp -rf "${logrotatefile}" /etc/logrotate.d/crowsnest - if [ ! "${BASE_USER}" == "pi" ]; then - sudo sed -i 's|pi|'"${BASE_USER}"'|g' /etc/logrotate.d/crowsnest - fi - echo -e "Linking logrotate file ... [OK]\r" - ## update systemd if not unattended - if [ "${UNATTENDED}" == "false" ] && [ "$(stat -c %i /)" == "2" ]; then - echo -en "Reload systemd to enable new deamon ...\r" - sudo systemctl daemon-reload - echo -e "Reload systemd to enable new daemon ... [OK]" - fi - ## enable crowsnest.service - echo -en "Enable crowsnest.service on boot ...\r" - sudo systemctl enable crowsnest.service &> /dev/null - echo -e "Enable crowsnest.service on boot ... [OK]\r" - ## Add moonraker update manager entry - ## Unattended - if [ "${UNATTENDED}" == "true" ] && - [ "${CROWSNEST_ADD_CROWSNEST_MOONRAKER}" == "1" ] && - [ -f "${moonraker_conf}" ]; then - echo -en "Adding Crowsnest Update Manager entry to moonraker.conf ...\r" - add_update_entry - echo -e "Adding Crowsnest Update Manager entry to moonraker.conf ... [OK]" - fi - ## Manual install - if [ "${UNATTENDED}" != "true" ] && - [ "${CROWSNEST_ADD_CROWSNEST_MOONRAKER}" != "0" ]; then - while true; do - read -erp "Do you want to add [update_manager] entry? (y/N) " -i "N" addconf - case "${addconf}" in - y|Y|yes|Yes|YES) - if [ "$(grep -c "crowsnest" "${moonraker_conf}")" == "0" ]; then - add_update_entry - else - echo -e "Update Manager entry already exists moonraker.conf ... [SKIPPED]" - fi - break - ;; + return 0 +} - n|N|no|No|NO) - echo -e "Adding Crowsnest Update Manager entry to moonraker.conf ... [SKIPPED]" - break - ;; +install_service_file() { + local servicefile systemd_dir + servicefile="${PWD}/resources/crowsnest.service" + systemd_dir="/etc/systemd/system" + echo -en "Install crowsnest.service file ...\r" + # Install Service file + cp -f "${servicefile}" "${systemd_dir}" + sed -i 's|%USER%|'"${BASE_USER}"'|g;s|%ENV%|'"${CROWSNEST_ENV_PATH}/crowsnest.env"'|g' \ + "${systemd_dir}/crowsnest.service" + # create and install env file + echo -e "CROWSNEST_ARGS=\"-c ${CROWSNEST_CONFIG_PATH}/crowsnest.conf\"\n" > "${CROWSNEST_ENV_PATH}/crowsnest.env" + chown -f "${BASE_USER}":"${BASE_USER}" "${CROWSNEST_ENV_PATH}/crowsnest.env" + echo -e "Install crowsnest.service file ... [${CN_OK}]\r" +} - *) - echo -e "\nInvalid input, please try again." - ;; - esac - done - fi +install_logrotate() { + local logrotatefile logpath + logrotatefile="resources/logrotate_crowsnest" + logpath="${CROWSNEST_LOG_PATH}/crowsnest.log" + # install logrotate + echo -en "Install logrotate file ...\r" + cp -rf "${logrotatefile}" /etc/logrotate.d/crowsnest + sed -i 's|%LOGPATH%|'"${logpath}"'|g' /etc/logrotate.d/crowsnest + echo -e "Install logrotate file ... [${CN_OK}]\r" +} - ## add $USER to group video - echo -en "Add User ${BASE_USER} to group 'video' ...\r" - if [ "$(groups | grep -c video)" == "0" ]; then - sudo usermod -aG video "${BASE_USER}" > /dev/null - echo -e "Add User ${BASE_USER} to group 'video' ... [OK]" +add_update_entry() { + local moonraker_conf + moonraker_conf="${CROWSNEST_CONFIG_PATH}/moonraker.conf" + moonraker_update="${PWD}/resources/moonraker_update.txt" + echo -en "Adding Crowsnest Update Manager entry to moonraker.conf ...\r" + if [[ -f "${moonraker_conf}" ]]; then + if [[ "$(grep -c "crowsnest" "${moonraker_conf}")" != "0" ]]; then + echo -e "Update Manager entry already exists moonraker.conf ... [${CN_SK}]" + return 0 + fi + # make sure no file exist + if [[ -f "/tmp/moonraker.conf" ]]; then + sudo rm -f /tmp/moonraker.conf + fi + sudo -u "${BASE_USER}" \ + cp "${moonraker_conf}" "${moonraker_conf}.backup" && + cat "${moonraker_conf}" "${moonraker_update}" > /tmp/moonraker.conf && + cp -rf /tmp/moonraker.conf "${moonraker_conf}" + if [[ "${CROWSNEST_UNATTENDED}" = "1" ]]; then + sudo rm -f "${moonraker_conf}.backup" + fi + echo -e "Adding Crowsnest Update Manager entry to moonraker.conf ... [${CN_OK}]" else - echo -e "Add User ${BASE_USER} to group 'video' ... [SKIPPED]" + echo -e "moonraker.conf is missing ... [${CN_SK}]" + fi +} + +## add $USER to group video +add_group_video() { + echo -en "Add User ${BASE_USER} to group 'video' ...\r" + if [[ "$(groups "${BASE_USER}" | grep -c video)" == "0" ]]; then + usermod -aG video "${BASE_USER}" > /dev/null + echo -e "Add User ${BASE_USER} to group 'video' ... [${CN_OK}]" + else + echo -e "Add User ${BASE_USER} to group 'video' ... [${CN_SK}]" echo -e "==> User ${BASE_USER} is already in group 'video'" fi } -function clone_ustreamer { +clone_ustreamer() { ## remove bin/ustreamer if exist - if [ -d bin/ustreamer ]; then + if [[ -d bin/ustreamer ]]; then rm -rf bin/ustreamer fi git clone "${CROWSNEST_USTREAMER_REPO_SHIP}" \ @@ -374,85 +335,188 @@ function clone_ustreamer { ## Buster workaround ## ustreamer support omx only till version 4.13 ## so stick to that version - if [ "$(get_os_version buster)" != "0" ]; then + if [[ "$(get_os_version buster)" != "0" ]]; then pushd bin/ustreamer &> /dev/null || exit 1 git reset --hard 61ab2a8 popd &> /dev/null || exit 1 fi } -function build_apps { +build_apps() { echo -e "Build dependend Stream Apps ..." echo -e "Cloning ustreamer repository ..." clone_ustreamer - echo -e "Installing 'ustreamer' Dependencies ..." - # shellcheck disable=2086 - sudo apt install --yes --no-install-recommends ${CROWSNEST_USTREAMER_DEPS} > /dev/null - echo -e "Installing 'ustreamer' Dependencies ... [OK]" pushd bin > /dev/null make all popd > /dev/null } -function install_raspicam_fix { - if [ -f /proc/device-tree/model ] && - grep -q "Raspberry" /proc/device-tree/model ; then - echo -en "Applying Raspicam Fix ... \r" - sudo sh -c 'echo "bcm2835-v4l2" >> /etc/modules' - sudo cp file_templates/bcm2835-v4l2.conf /etc/modprobe.d/ - echo -e "Applying Raspicam Fix ... [OK]" +is_raspberry_pi() { + if [[ -f /proc/device-tree/model ]] && + grep -q "Raspberry" /proc/device-tree/model; then + echo "1" else - echo -e "This is not a Raspberry Pi!" - echo -e "Applying Raspicam Fix ... [SKIPPED]" + echo "0" fi } -function enable_legacy_cam { +install_raspicam_fix() { + if [[ "${CROWSNEST_RASPICAMFIX}" == "auto" ]]; then + if [[ "$(is_raspberry_pi)" = "1" ]]; then + echo -e "Device is a Raspberry Pi" + CROWSNEST_RASPICAMFIX="1" + fi + if [[ "$(is_raspberry_pi)" = "0" ]]; then + echo -e "Device is \e[31mNOT\e[0m a Raspberry Pi ... [${CN_SK}]" + CROWSNEST_RASPICAMFIX="0" + fi + fi + if [[ "${CROWSNEST_RASPICAMFIX}" == "1" ]]; then + echo -en "Applying Raspicam Fix ... \r" + bash -c 'echo "bcm2835-v4l2" >> /etc/modules' + cp resources/bcm2835-v4l2.conf /etc/modprobe.d/ + echo -e "Applying Raspicam Fix ... [${CN_OK}]" + fi +} + +enable_legacy_cam() { local cfg + local -a model cfg="/boot/config.txt" - echo -en "Enable legacy camera stack ... \r" - sudo sed -i "s/camera_auto_detect=1/#camera_auto_detect=1/" "${cfg}" - if [ "$(grep -c "start_x" "${cfg}")" == "0" ]; then - sudo crudini --set --inplace "${cfg}" all start_x 1 &> /dev/null + model=(pi3 pi4) + if [[ -f "${cfg}" ]] && [[ "$(is_raspberry_pi)" = "1" ]]; then + + # Helper func + get_val() { + crudini --get "${cfg}" "${1}" gpu_mem 2> /dev/null + } + + echo -en "Enable legacy camera stack ... \r" + sed -i "s/camera_auto_detect=1/#camera_auto_detect=1/" "${cfg}" + if [[ "$(grep -c "start_x" "${cfg}")" = "0" ]]; then + crudini --set --inplace "${cfg}" all start_x 1 &> /dev/null + fi + + for d in "${model[@]}"; do + if [[ "$(get_val "${d}")" -lt "129" ]]; then + crudini --set --inplace "${cfg}" "${d}" gpu_mem 256 &> /dev/null + fi + done + if [[ "$(get_val pi0)" -lt "129" ]]; then + sudo crudini --set --inplace "${cfg}" pi0 gpu_mem 160 &> /dev/null + fi + echo -e "Enable legacy camera stack ... [${CN_OK}]" fi - if [ "$(grep -c "gpu_mem" "${cfg}")" == "0" ]; then - sudo crudini --set --inplace "${cfg}" pi4 gpu_mem 256 &> /dev/null - sudo crudini --set --inplace "${cfg}" all gpu_mem 128 &> /dev/null - fi - echo -e "Enable legacy camera stack ... [OK]" } -#### MAIN -while getopts "z" arg; do - case ${arg} in - z) - echo "WARN: Running in UNATTENDED Mode ..." - set -x - UNATTENDED="true" - ;; - *) - UNATTENDED="false" - ;; - esac -done -install_cleanup_trap -import_config -welcome_msg -if [ "${UNATTENDED}" != "true" ]; then - detect_existing_webcamd -fi -echo -e "Running apt update first ..." -sudo apt update -install_crowsnest -build_apps -if [ "${UNATTENDED}" != "true" ] && -[ "${CROWSNEST_FORCE_RASPICAMFIX}" != "0" ]; then - install_raspicam_fix -fi -if [ "$(get_os_version bullseye)" != "0" ] && -[ -f "/boot/config.txt" ]; then - enable_legacy_cam -fi -goodbye_msg +## enable service +enable_service() { + echo -en "Enable crowsnest.service on boot ...\r" + sudo systemctl enable crowsnest.service &> /dev/null + echo -e "Enable crowsnest.service on boot ... [${CN_OK}]\r" +} +## start systemd service +start_service() { + sudo systemctl daemon-reload &> /dev/null + sudo systemctl start crowsnest.service &> /dev/null +} + +## ask reboot +ask_reboot() { + local reply + while true; do + read -erp "Reboot NOW? [y/N]: " -i "N" reply + case "${reply}" in + [yY]*) + echo -e "Going to reboot in 5 seconds!" + sleep 5 + reboot + ;; + [nN]*) + echo -e "\n\e[31mNot to reboot may cause issues!" + echo -e "Reboot as soon as possible!\e[0m\n" + echo -e "Goodbye ..." + break + ;; + * ) + echo -e "\e[31mERROR:\e[0m Please choose Y or N !" + ;; + esac + done +} + +## Main func +main() { + ## Initialize traps + install_cleanup_trap + + ## Welcome message + welcome_msg + + ## Step 1: import .config file + if [[ "${CROWSNEST_UNATTENDED}" = "0" ]]; then + import_config + fi + + ## Make sure folders exist + create_filestructure + + ## Step 2: Detect existing webcamd + if [[ "${CROWSNEST_UNATTENDED}" = "0" ]]; then + detect_existing_webcamd + fi + + ## Step 3: Install dependencies + install_packages + + ## Step 4: Install crowsnest + install_crowsnest + + ## Step 5: Build Applications + build_apps + + ## Step 6: Add $USER to group 'video' + add_group_video + + ## Step 7: Enable Legacy Camera Stack + if [[ "$(get_os_version bullseye)" != "0" ]] && + [[ -f "/boot/config.txt" ]]; then + enable_legacy_cam + fi + + ## Step 8: Install service File + install_service_file + + ## Step 9: Enable service + ## If unattended skip enable and start service + if [[ -f /etc/systemd/system/crowsnest.service ]] && + [[ "${CROWSNEST_UNATTENDED}" = "0" ]]; then + enable_service + fi + if [[ "${CROWSNEST_UNATTENDED}" = "0" ]]; then + start_service + fi + + ## Step 10: Install logrotate file + install_logrotate + + ## Step 11: Install raspicamfix + install_raspicam_fix + + ## Step 12: Add moonraker update_manager entry + if [[ "${CROWSNEST_UNATTENDED}" = "1" ]] || + [[ "${CROWSNEST_ADD_CROWSNEST_MOONRAKER}" = "1" ]]; then + add_update_entry + fi + + ## Step 13: Ask for reboot + ## Skip if UNATTENDED + goodbye_msg + if [[ "${CROWSNEST_UNATTENDED}" = "0" ]]; then + ask_reboot + fi +} + +main exit 0 diff --git a/tools/uninstall.sh b/tools/uninstall.sh index b821d01..29c5c63 100755 --- a/tools/uninstall.sh +++ b/tools/uninstall.sh @@ -2,7 +2,7 @@ #### crowsnest - A webcam Service for multiple Cams and Stream Services. #### #### Written by Stephan Wendel aka KwadFan -#### Copyright 2021 +#### Copyright 2021 - 2022 #### https://github.com/mainsail-crew/crowsnest #### #### This File is distributed under GPLv3 @@ -17,21 +17,36 @@ set -Ee # set -x # Global Vars -TITLE="crowsnest - A Webcam Daemon for Raspberry Pi OS" +TITLE="\e[31mcrowsnest\e[0m - A webcam daemon for multiple Cams and stream services." +CN_CONFIG_ENVPATH="$(find "${HOME}" -name "crowsnest.env")" + +# Message Vars +CN_OK="\e[32mOK\e[0m" +CN_SK="\e[33mSKIPPED\e[0m" + +### Check non-root +if [[ ${UID} = '0' ]]; then + echo -e "\n\tYOU DONT NEED TO RUN UNINSTALLER AS ROOT!" + echo -e "\tYou will be prompted for 'sudo' passwd" + exit 1 +fi ### Functions ### Messages ### Welcome Message -function welcome_msg { +welcome_msg() { echo -e "${TITLE}\n" - echo -e "\tSome Parts of the Uninstaller requires 'root' privileges." - echo -e "\tYou will be prompted for your 'sudo' password, if needed.\n" + echo -e "\t\e[34mAhoi!\e[0m" + echo -e "\tTo sad that you want to uninstall crowsnest :(" + echo -e "\tThis will take a while ... " + echo -e "\tPlease reboot after installation has finished.\n" + sleep 1 } -function goodbye_msg { - echo -e "Please remove manually the 'crowsnest' folder in ${HOME}" - echo -e "Remove [update manager crowsnest] section from moonraker.conf!" +goodbye_msg() { + echo -e "Please remove manually the 'crowsnest' folder in ${HOME}\n" + echo -e "\tRemove [update manager crowsnest] section from moonraker.conf,before reboot!\n" echo -e "After that is done, please reboot!\nGoodBye...\n" } @@ -40,12 +55,12 @@ function goodbye_msg { ## Credits to guysoft! ## https://github.com/guysoft/CustomPiOS -function install_cleanup_trap() { +install_cleanup_trap() { # kills all child processes of the current process on SIGINT or SIGTERM trap 'cleanup' SIGINT SIGTERM } -function cleanup() { +cleanup() { # make sure that all child processed die when we die echo -e "Killed by user ...\r\nGoodBye ...\r" # shellcheck disable=2046 @@ -53,7 +68,7 @@ function cleanup() { } ## -function err_exit { +err_exit() { if [ "${1}" != "0" ]; then echo -e "ERROR: Error ${1} occured on line ${2}" echo -e "ERROR: Stopping $(basename "$0")." @@ -69,16 +84,18 @@ trap 'err_exit $? $LINENO' ERR ### Uninstall crowsnest -function ask_uninstall { +ask_uninstall() { local remove if [ -x "/usr/local/bin/crowsnest" ] && [ -d "${HOME}/crowsnest" ]; then while true; do read -erp "Do you REALLY want to remove existing 'crowsnest'? (y/N) " -i "N" remove case "${remove}" in y|Y|yes|Yes|YES) + source_env_file uninstall_crowsnest remove_raspicam_fix remove_logrotate + ask_remove_config goodbye_msg break ;; @@ -98,44 +115,81 @@ function ask_uninstall { fi } -function uninstall_crowsnest { +source_env_file() { + # shellcheck disable=SC1090 + . "${CN_CONFIG_ENVPATH}" +} + +uninstall_crowsnest() { local servicefile bin_path servicefile="/etc/systemd/system/crowsnest.service" bin_path="/usr/local/bin/crowsnest" + # Dirty hack to grant sudo priviledges + # and not overwriting next \r line + sudo sh -c 'echo "" > /dev/null' echo -en "\nStopping crowsnest.service ...\r" sudo systemctl stop crowsnest.service &> /dev/null - echo -e "Stopping crowsnest.service ... \t[OK]\r" + echo -e "Stopping crowsnest.service ... \t[${CN_OK}]\r" echo -en "\nDisable crowsnest.service ...\r" sudo systemctl disable crowsnest.service &> /dev/null - echo -e "Disable crowsnest.service ... \t[OK]\r" + echo -e "Disable crowsnest.service ... \t[${CN_OK}]\r" echo -en "Uninstalling crowsnest.service...\r" - if [ -f "${servicefile}" ]; then + if [[ -f "${servicefile}" ]]; then sudo rm -f "${servicefile}" fi - if [ -x "${bin_path}" ]; then + if [[ -x "${bin_path}" ]]; then sudo rm -f "${bin_path}" fi - echo -e "Uninstalling crowsnest.service...[OK]\r" + echo -e "Uninstalling crowsnest.service...[${CN_OK}]\r" + if [[ -n "${CN_CONFIG_ENVPATH}" ]]; then + echo -en "Removing crowsnest.env ...\r" + sudo rm -f "${CN_CONFIG_ENVPATH}" + echo -e "Removing crowsnest.env ... [${CN_OK}]\r" + fi } -function remove_raspicam_fix { - if [ -f /etc/modprobe.d/bcm2835-v4l2.conf ] && - [ -f /proc/device-tree/model ] && +ask_remove_config() { + local config reply + config="${CROWSNEST_ARGS/-c /}" + while true; do + read -erp "Do you want to remove crowsnest.conf? [y/N]: " -i "N" reply + case "${reply}" in + [yY]* ) + sudo rm -f "${config}" + echo -e "Removing 'crowsnest.conf' ... [${CN_OK}]\r" + break + ;; + [nN]* ) + echo -e "Removing 'crowsnest.conf' ... [${CN_SK}]\r" + break + ;; + * ) + echo -e "\e[31mERROR: Not a valid choice, try again ...\e[0m" + ;; + esac + done + return 0 +} + +remove_raspicam_fix() { + if [[ -f /etc/modprobe.d/bcm2835-v4l2.conf ]] && + [[ -f /proc/device-tree/model ]] && grep -q "Raspberry" /proc/device-tree/model ; then echo -en "Removing Raspicam Fix ...\r" sudo sed -i '/bcm2835/d' /etc/modules sudo rm -f /etc/modprobe.d/bcm2835-v4l2.conf - echo -e "Removing Raspicam Fix ... [OK]" + echo -e "Removing Raspicam Fix ... [${CN_OK}]" else - echo -e "This is not a Raspberry Pi!" - echo -e "Removing Raspicam Fix ... [SKIPPED]" + echo -e "Removing Raspicam Fix ... [${CN_SK}]" + echo -e "\tThis is not a Raspberry Pi" + echo -e "\tor Raspicamfix not installed ... \n" fi } function remove_logrotate { echo -en "Removing Logrotate Rule ...\r" sudo rm -f /etc/logrotate.d/crowsnest - echo -e "Removing Logrotate Rule ... [OK]" + echo -e "Removing Logrotate Rule ... [${CN_OK}]" } #### MAIN