From 62296e112efa5fbe40135f4fdee517e622044f37 Mon Sep 17 00:00:00 2001 From: Alessandro Maggi <59124971+DicyRoll@users.noreply.github.com> Date: Tue, 25 Jun 2024 20:10:14 +0200 Subject: [PATCH] feat: add Spoolman support (#477) --- scripts/backup.sh | 20 ++- scripts/globals.sh | 5 + scripts/spoolman.sh | 277 +++++++++++++++++++++++++++++++++++++ scripts/ui/backup_menu.sh | 3 + scripts/ui/install_menu.sh | 28 ++-- scripts/ui/main_menu.sh | 1 + scripts/ui/remove_menu.sh | 30 ++-- scripts/ui/update_menu.sh | 14 +- 8 files changed, 345 insertions(+), 33 deletions(-) create mode 100644 scripts/spoolman.sh diff --git a/scripts/backup.sh b/scripts/backup.sh index 091d99f..1716963 100755 --- a/scripts/backup.sh +++ b/scripts/backup.sh @@ -45,13 +45,13 @@ function backup_config_dir() { for folder in ${config_pathes}; do if [[ -d ${folder} ]]; then status_msg "Create backup of ${folder} ..." - + folder_name=$(echo "${folder}" | rev | cut -d"/" -f2 | rev) target_dir="${BACKUP_DIR}/configs/${current_date}/${folder_name}" mkdir -p "${target_dir}" cp -r "${folder}" "${target_dir}" i=$(( i + 1 )) - + ok_msg "Backup created in:\n${target_dir}" fi done @@ -213,3 +213,19 @@ function backup_octoeverywhere() { print_error "Can't back up OctoEverywhere directory!\n Not found!" fi } + +function backup_spoolman() { + local current_date + + if [[ -d ${SPOOLMAN_DIR} ]] ; then + status_msg "Creating Spoolman backup ..." + check_for_backup_dir + current_date=$(get_date) + status_msg "Timestamp: ${current_date}" + mkdir -p "${BACKUP_DIR}/Spoolman-backups/${current_date}" + cp -r "${SPOOLMAN_DIR}" "${_}" && cp -r "${SPOOLMAN_DB_DIR}/spoolman.db" "${_}" + print_confirm "Spoolman backup complete!" + else + print_error "Can't back up Spoolman directory!\n Not found!" + fi +} diff --git a/scripts/globals.sh b/scripts/globals.sh index 9504911..991cec7 100644 --- a/scripts/globals.sh +++ b/scripts/globals.sh @@ -87,4 +87,9 @@ function set_globals() { OCTOAPP_ENV="${HOME}/octoapp-env" OCTOAPP_DIR="${HOME}/octoapp" OCTOAPP_REPO="https://github.com/crysxd/OctoApp-Plugin.git" + + #=============== Spoolman ================# + SPOOLMAN_DIR="${HOME}/spoolman" + SPOOLMAN_DB_DIR="${HOME}/.local/share/spoolman" + SPOOLMAN_REPO="https://api.github.com/repos/Donkie/Spoolman/releases/latest" } diff --git a/scripts/spoolman.sh b/scripts/spoolman.sh new file mode 100644 index 0000000..dabae09 --- /dev/null +++ b/scripts/spoolman.sh @@ -0,0 +1,277 @@ +#!/usr/bin/env bash + +#=======================================================================# +# Copyright (C) 2020 - 2024 Dominik Willner # +# # +# This file is part of KIAUH - Klipper Installation And Update Helper # +# https://github.com/dw-0/kiauh # +# # +# This file may be distributed under the terms of the GNU GPLv3 license # +#=======================================================================# + +# Error Handling +set -e + +function install_spoolman() { + + pushd "${HOME}" &> /dev/null || exit 1 + + dependency_check curl jq + + if [[ ! -d "${SPOOLMAN_DIR}" && -z "$(ls -A "${SPOOLMAN_DIR}" 2> /dev/null)" ]]; then + status_msg "Downloading spoolman..." + setup_spoolman_folder + status_msg "Downloading complete" + start_install_script + advanced_config_prompt + else + ### In case spoolman is "incomplete" rerun install script + if get_spoolman_status | grep -q "Incomplete!"; then + start_install_script + exit 1 + fi + + ok_msg "Spoolman already installed" + exit 1 + fi + + enable_moonraker_integration_prompt + patch_spoolman_update_manager + + do_action_service "restart" "moonraker" +} + +function update_spoolman() { + ### stop and disable old spoolman service + do_action_service "stop" "Spoolman" + do_action_service "disable" "Spoolman" + + mv "${SPOOLMAN_DIR}" "${SPOOLMAN_DIR}_old" + + setup_spoolman_folder + cp "${SPOOLMAN_DIR}_old/.env" "${SPOOLMAN_DIR}/.env" + + start_install_script + + rm -rf "${SPOOLMAN_DIR}_old" +} + +function remove_spoolman(){ + if [[ -d "${SPOOLMAN_DIR}" ]]; then + status_msg "Removing spoolman service..." + do_action_service "stop" "Spoolman" + do_action_service "disable" "Spoolman" + sudo rm -f "${SYSTEMD}/Spoolman.service" + sudo systemctl daemon-reload + sudo systemctl reset-failed + ok_msg "Spoolman service removed!" + + status_msg "Removing spoolman directory..." + rm -rf "${SPOOLMAN_DIR}" + ok_msg "Spoolman directory removed!" + fi + + print_confirm "Spoolman successfully removed!" +} + +function update_moonraker_configs() { + local moonraker_configs regex + regex="${HOME//\//\\/}\/([A-Za-z0-9_]+)\/config\/moonraker\.conf" + moonraker_configs=$(find "${HOME}" -maxdepth 3 -type f -regextype posix-extended -regex "${regex}" | sort) + + for conf in ${moonraker_configs}; do + if ! grep -Eq "^\[update_manager Spoolman\]\s*$" "${conf}"; then + ### add new line to conf if it doesn't end with one + [[ $(tail -c1 "${conf}" | wc -l) -eq 0 ]] && echo "" >> "${conf}" + /bin/sh -c "cat >> ${conf}" << MOONRAKER_CONF +${1} +MOONRAKER_CONF + fi + done +} + +function enable_moonraker_integration() { + local integration_str env_port + # get spoolman port from .env + env_port=$(grep "^SPOOLMAN_PORT=" "${SPOOLMAN_DIR}/.env" | cut -d"=" -f2) + + integration_str=" +[spoolman] +server: http://$(hostname -I | cut -d" " -f1):${env_port} +" + + status_msg "Adding Spoolman integration..." + update_moonraker_configs "${integration_str}" +} + +function patch_spoolman_update_manager() { + local updater_str + updater_str=" +[update_manager Spoolman] +type: zip +channel: stable +repo: Donkie/Spoolman +path: ${SPOOLMAN_DIR} +virtualenv: .venv +requirements: requirements.txt +persistent_files: + .venv + .env +managed_services: Spoolman +" + + update_moonraker_configs "${updater_str}" + + # add spoolman service to moonraker.asvc + local moonraker_asvc regex + regex="${HOME//\//\\/}\/([A-Za-z0-9_]+)\/moonraker\.asvc" + moonraker_asvc=$(find "${HOME}" -maxdepth 2 -type f -regextype posix-extended -regex "${regex}" | sort) + + if [[ -n ${moonraker_asvc} ]]; then + status_msg "Adding Spoolman service to moonraker.asvc..." + /bin/sh -c "echo 'Spoolman' >> ${moonraker_asvc}" + fi +} + +function advanced_config_prompt() { + local reply + while true; do + read -erp "${cyan}###### Continue with default configuration? (Y/n):${white} " reply + case "${reply}" in + Y|y|Yes|yes|"") + select_msg "Yes" + break;; + N|n|No|no) + select_msg "No" + advanced_config + break;; + *) + error_msg "Invalid Input!\n";; + esac + done + return 0 +} + +function enable_moonraker_integration_prompt() { + local reply + while true; do + read -erp "${cyan}###### Enable Moonraker integration? (Y/n):${white} " reply + case "${reply}" in + Y|y|Yes|yes|"") + select_msg "Yes" + enable_moonraker_integration + break;; + N|n|No|no) + select_msg "No" + break;; + *) + error_msg "Invalid Input!\n";; + esac + done + return 0 +} + +function advanced_config() { + status_msg "###### Advanced configuration" + + local reply + while true; do + read -erp "${cyan}###### Select spoolman port (7912):${white} " reply + ### set default + if [[ -z "${reply}" ]]; then + reply="7912" + fi + + select_msg "${reply}" + ### check if port is valid + if ! [[ "${reply}" =~ ^[0-9]+$ && "${reply}" -ge 1024 && "${reply}" -le 65535 ]]; then + error_msg "Invalid port number!\n" + continue + fi + + ### update .env + sed -i "s/^SPOOLMAN_PORT=.*$/SPOOLMAN_PORT=${reply}/" "${SPOOLMAN_DIR}/.env" + do_action_service "restart" "Spoolman" + break + done + return 0 +} + +function setup_spoolman_folder() { + local source_url + ### get latest spoolman release url + source_url="$(curl -s "${SPOOLMAN_REPO}" | jq -r '.assets[] | select(.name == "spoolman.zip").browser_download_url')" + + mkdir -p "${SPOOLMAN_DIR}" + curl -sSL "${source_url}" -o /tmp/temp.zip + unzip /tmp/temp.zip -d "${SPOOLMAN_DIR}" &> /dev/null + rm /tmp/temp.zip + + chmod +x "${SPOOLMAN_DIR}"/scripts/install.sh +} + +function start_install_script() { + + pushd "${SPOOLMAN_DIR}" &> /dev/null || exit 1 + + if bash ./scripts/install.sh; then + ok_msg "Spoolman successfully installed!" + else + print_error "Spoolman installation failed!" + exit 1 + fi +} + +function get_spoolman_status() { + local -a files + files=( + "${SPOOLMAN_DIR}" + "${SYSTEMD}/Spoolman.service" + "${SPOOLMAN_DB_DIR}" + ) + + local count + count=0 + + for file in "${files[@]}"; do + [[ -e "${file}" ]] && count=$(( count +1 )) + done + + if [[ "${count}" -eq "${#files[*]}" ]]; then + echo "Installed" + elif [[ "${count}" -gt 0 ]]; then + echo "Incomplete!" + else + echo "Not installed!" + fi +} + +function get_local_spoolman_version() { + local version + version=$(jq -r '.version' "${SPOOLMAN_DIR}"/release_info.json) + echo "${version}" +} + +function get_remote_spoolman_version() { + local version + version=$(curl -s "${SPOOLMAN_REPO}" | jq -r '.tag_name') + echo "${version}" +} + +function compare_spoolman_versions() { + local local_ver remote_ver + local_ver="$(get_local_spoolman_version)" + remote_ver="$(get_remote_spoolman_version)" + + if [[ ${local_ver} != "${remote_ver}" ]]; then + versions="${yellow}$(printf " %-14s" "${local_ver}")${white}" + versions+="|${green}$(printf " %-13s" "${remote_ver}")${white}" + # add spoolman to application_updates_available in kiauh.ini + add_to_application_updates "spoolman" + else + versions="${green}$(printf " %-14s" "${local_ver}")${white}" + versions+="|${green}$(printf " %-13s" "${remote_ver}")${white}" + fi + + echo "${versions}" +} diff --git a/scripts/ui/backup_menu.sh b/scripts/ui/backup_menu.sh index c56ed02..783476c 100755 --- a/scripts/ui/backup_menu.sh +++ b/scripts/ui/backup_menu.sh @@ -26,6 +26,7 @@ function backup_ui() { echo -e "| Klipper Webinterface: | Other: |" echo -e "| 5) [Mainsail] | 9) [Telegram Bot] |" echo -e "| 6) [Fluidd] | 10) [OctoEverywhere] |" + echo -e "| | 11) [Spoolman] |" back_footer } @@ -56,6 +57,8 @@ function backup_menu() { do_action "backup_telegram_bot" "backup_ui";; 10) do_action "backup_octoeverywhere" "backup_ui";; + 11) + do_action "backup_spoolman" "backup_ui";; B|b) clear; main_menu; break;; *) diff --git a/scripts/ui/install_menu.sh b/scripts/ui/install_menu.sh index 8ed0410..3501e0a 100755 --- a/scripts/ui/install_menu.sh +++ b/scripts/ui/install_menu.sh @@ -19,19 +19,19 @@ function install_ui() { echo -e "| all necessary dependencies for the various |" echo -e "| functions on a completely fresh system. |" hr - echo -e "| Firmware & API: | 3rd Party Webinterface: |" - echo -e "| 1) [Klipper] | 6) [OctoPrint] |" - echo -e "| 2) [Moonraker] | |" - echo -e "| | Other: |" - echo -e "| Klipper Webinterface: | 7) [PrettyGCode] |" - echo -e "| 3) [Mainsail] | 8) [Telegram Bot] |" - echo -e "| 4) [Fluidd] | 9) $(obico_install_title) |" - echo -e "| | 10) [OctoEverywhere] |" - echo -e "| | 11) [Mobileraker] |" - echo -e "| Touchscreen GUI: | 12) [OctoApp for Klipper] |" - echo -e "| 5) [KlipperScreen] | |" - echo -e "| | Webcam Streamer: |" - echo -e "| | 13) [Crowsnest] |" + echo -e "| Firmware & API: | Other: |" + echo -e "| 1) [Klipper] | 7) [PrettyGCode] |" + echo -e "| 2) [Moonraker] | 8) [Telegram Bot] |" + echo -e "| | 9) $(obico_install_title) |" + echo -e "| Klipper Webinterface: | 10) [OctoEverywhere] |" + echo -e "| 3) [Mainsail] | 11) [Mobileraker] |" + echo -e "| 4) [Fluidd] | 12) [OctoApp for Klipper] |" + echo -e "| | 13) [Spoolman] |" + echo -e "| Touchscreen GUI: | |" + echo -e "| 5) [KlipperScreen] | Webcam Streamer: |" + echo -e "| | 14) [Crowsnest] |" + echo -e "| 3rd Party Webinterface: | |" + echo -e "| 6) [OctoPrint] | |" back_footer } @@ -75,6 +75,8 @@ function install_menu() { 12) do_action "octoapp_setup_dialog" "install_ui";; 13) + do_action "install_spoolman" "install_ui";; + 14) do_action "install_crowsnest" "install_ui";; B|b) clear; main_menu; break;; diff --git a/scripts/ui/main_menu.sh b/scripts/ui/main_menu.sh index f950f27..011a9ae 100755 --- a/scripts/ui/main_menu.sh +++ b/scripts/ui/main_menu.sh @@ -29,6 +29,7 @@ function main_ui() { echo -e "| | OctoEverywhere: $(print_status "octoeverywhere")|" echo -e "| | Mobileraker: $(print_status "mobileraker")|" echo -e "| | OctoApp: $(print_status "octoapp")|" + echo -e "| | Spoolman: $(print_status "spoolman")|" echo -e "| | |" echo -e "| | Octoprint: $(print_status "octoprint")|" hr diff --git a/scripts/ui/remove_menu.sh b/scripts/ui/remove_menu.sh index f9824b1..9f4d755 100755 --- a/scripts/ui/remove_menu.sh +++ b/scripts/ui/remove_menu.sh @@ -17,21 +17,21 @@ function remove_ui() { hr echo -e "| ${yellow}INFO: Configurations and/or any backups will be kept!${white} |" hr - echo -e "| Firmware & API: | 3rd Party Webinterface: |" - echo -e "| 1) [Klipper] | 8) [OctoPrint] |" - echo -e "| 2) [Moonraker] | |" - echo -e "| | Webcam Streamer: |" - echo -e "| Klipper Webinterface: | 9) [Crowsnest] |" - echo -e "| 3) [Mainsail] | 10) [MJPG-Streamer] |" - echo -e "| 4) [Mainsail-Config] | |" - echo -e "| 5) [Fluidd] | Other: |" - echo -e "| 6) [Fluidd-Config] | 11) [PrettyGCode] |" - echo -e "| | 12) [Telegram Bot] |" - echo -e "| Touchscreen GUI: | 13) [Obico for Klipper] |" - echo -e "| 7) [KlipperScreen] | 14) [OctoEverywhere] |" + echo -e "| Firmware & API: | Webcam Streamer: |" + echo -e "| 1) [Klipper] | 9) [Crowsnest] |" + echo -e "| 2) [Moonraker] | 10) [MJPG-Streamer] |" + echo -e "| | |" + echo -e "| Klipper Webinterface: | Other: |" + echo -e "| 3) [Mainsail] | 11) [PrettyGCode] |" + echo -e "| 4) [Mainsail-Config] | 12) [Telegram Bot] |" + echo -e "| 5) [Fluidd] | 13) [Obico for Klipper] |" + echo -e "| 6) [Fluidd-Config] | 14) [OctoEverywhere] |" echo -e "| | 15) [Mobileraker] |" - echo -e "| | 16) [NGINX] |" - echo -e "| | 17) [OctoApp] |" + echo -e "| Touchscreen GUI: | 16) [NGINX] |" + echo -e "| 7) [KlipperScreen] | 17) [OctoApp] |" + echo -e "| | 18) [Spoolman] |" + echo -e "| 3rd Party Webinterface: | |" + echo -e "| 8) [OctoPrint] | |" back_footer } @@ -76,6 +76,8 @@ function remove_menu() { do_action "remove_nginx" "remove_ui";; 17) do_action "remove_octoapp" "remove_ui";; + 18) + do_action "remove_spoolman" "remove_ui";; B|b) clear; main_menu; break;; *) diff --git a/scripts/ui/update_menu.sh b/scripts/ui/update_menu.sh index 26a3f11..8e85599 100755 --- a/scripts/ui/update_menu.sh +++ b/scripts/ui/update_menu.sh @@ -36,15 +36,16 @@ function update_ui() { echo -e "| 10) [Mobileraker] |$(compare_mobileraker_versions)|" echo -e "| 11) [Crowsnest] |$(compare_crowsnest_versions)|" echo -e "| 12) [OctoApp] |$(compare_octoapp_versions)|" + echo -e "| 13) [Spoolman] |$(compare_spoolman_versions)|" echo -e "| |------------------------------|" - echo -e "| 13) [System] | $(check_system_updates) |" + echo -e "| 14) [System] | $(check_system_updates) |" back_footer } function update_menu() { clear -x && sudo true && clear -x # (re)cache sudo credentials so password prompt doesn't bork ui do_action "" "update_ui" - + local action while true; do read -p "${cyan}####### Perform action:${white} " action @@ -76,6 +77,8 @@ function update_menu() { 12) do_action "update_octoapp" "update_ui";; 13) + do_action "update_spoolman" "update_ui";; + 14) do_action "upgrade_system_packages" "update_ui";; a) do_action "update_all" "update_ui";; @@ -101,7 +104,7 @@ function update_all() { print_confirm "Everything is already up-to-date!" echo; break fi - + echo top_border echo -e "| The following installations will be updated: |" @@ -121,6 +124,9 @@ function update_all() { [[ "${update_arr[*]}" =~ "klipperscreen" ]] && \ echo -e "| ${cyan}● KlipperScreen${white} |" + [[ "${update_arr[*]}" =~ "spoolman" ]] && \ + echo -e "| ${cyan}● SpoolMan${white} |" + [[ "${update_arr[*]}" =~ "pgc_for_klipper" ]] && \ echo -e "| ${cyan}● PrettyGCode for Klipper${white} |" @@ -140,7 +146,7 @@ function update_all() { echo -e "| ${cyan}● System${white} |" bottom_border - + local yn read -p "${cyan}###### Do you want to proceed? (Y/n):${white} " yn case "${yn}" in