diff --git a/ct/alpine-syncthing.sh b/ct/alpine-syncthing.sh deleted file mode 100644 index 97f2f226..00000000 --- a/ct/alpine-syncthing.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bash -source <(curl -s https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/build.func) -# Copyright (c) 2021-2025 community-scripts ORG -# Author: MickLesk (CanbiZ) -# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE -# Source: https://syncthing.net/ - -APP="Alpine-Syncthing" -var_tags="${var_tags:-alpine;networking}" -var_cpu="${var_cpu:-1}" -var_ram="${var_ram:-256}" -var_disk="${var_disk:-1}" -var_os="${var_os:-alpine}" -var_version="${var_version:-3.21}" -var_unprivileged="${var_unprivileged:-1}" - -header_info "$APP" -variables -color -catch_errors - -function update_script() { - msg_info "Updating Alpine Packages" - $STD apk -U upgrade - msg_ok "Updated Alpine Packages" - - msg_info "Updating Syncthing" - $STD apk upgrade syncthing - msg_ok "Updated Syncthing" - - msg_info "Restarting Syncthing" - $STD rc-service syncthing restart - msg_ok "Restarted Syncthing" - - exit 1 -} - -start -build_container -description - -msg_ok "Completed Successfully!\n" -echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8384${CL}" diff --git a/ct/alpine.sh b/ct/alpine.sh index 8d09d7b6..11972a3c 100644 --- a/ct/alpine.sh +++ b/ct/alpine.sh @@ -11,7 +11,7 @@ var_cpu="${var_cpu:-1}" var_ram="${var_ram:-512}" var_disk="${var_disk:-1}" var_os="${var_os:-alpine}" -var_version="${var_version:-3.21}" +var_version="${var_version:-3.22}" var_unprivileged="${var_unprivileged:-1}" header_info "$APP" diff --git a/ct/debian.sh b/ct/debian.sh index c3816577..c525e5e2 100644 --- a/ct/debian.sh +++ b/ct/debian.sh @@ -40,5 +40,5 @@ start build_container description -msg_ok "Completed Successfully!\n" -echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +msg_ok "Completed Successfully!" +msg_custom "🚀" "${GN}" "${APP} setup has been successfully initialized!" diff --git a/ct/headers/alpine-syncthing b/ct/headers/alpine-syncthing deleted file mode 100644 index 8d684d61..00000000 --- a/ct/headers/alpine-syncthing +++ /dev/null @@ -1,6 +0,0 @@ - ___ __ _ _____ __ __ _ - / | / /___ (_)___ ___ / ___/__ ______ _____/ /_/ /_ (_)___ ____ _ - / /| | / / __ \/ / __ \/ _ \______\__ \/ / / / __ \/ ___/ __/ __ \/ / __ \/ __ `/ - / ___ |/ / /_/ / / / / / __/_____/__/ / /_/ / / / / /__/ /_/ / / / / / / / /_/ / -/_/ |_/_/ .___/_/_/ /_/\___/ /____/\__, /_/ /_/\___/\__/_/ /_/_/_/ /_/\__, / - /_/ /____/ /____/ diff --git a/ct/headers/itsmng b/ct/headers/itsmng deleted file mode 100644 index bbb5bb64..00000000 --- a/ct/headers/itsmng +++ /dev/null @@ -1,6 +0,0 @@ - _ __ - (_) /__________ ___ ____ ____ _ - / / __/ ___/ __ `__ \/ __ \/ __ `/ - / / /_(__ ) / / / / / / / / /_/ / -/_/\__/____/_/ /_/ /_/_/ /_/\__, / - /____/ diff --git a/ct/headers/jellyfin b/ct/headers/jellyfin deleted file mode 100644 index d905c4db..00000000 --- a/ct/headers/jellyfin +++ /dev/null @@ -1,6 +0,0 @@ - __ ____ _____ - / /__ / / /_ __/ __(_)___ - __ / / _ \/ / / / / / /_/ / __ \ -/ /_/ / __/ / / /_/ / __/ / / / / -\____/\___/_/_/\__, /_/ /_/_/ /_/ - /____/ diff --git a/ct/headers/kapowarr b/ct/headers/kapowarr deleted file mode 100644 index e127f364..00000000 --- a/ct/headers/kapowarr +++ /dev/null @@ -1,6 +0,0 @@ - __ __ - / //_/___ _____ ____ _ ______ ___________ - / ,< / __ `/ __ \/ __ \ | /| / / __ `/ ___/ ___/ - / /| / /_/ / /_/ / /_/ / |/ |/ / /_/ / / / / -/_/ |_\__,_/ .___/\____/|__/|__/\__,_/_/ /_/ - /_/ diff --git a/ct/headers/npmplus b/ct/headers/npmplus deleted file mode 100644 index 9920f297..00000000 --- a/ct/headers/npmplus +++ /dev/null @@ -1,6 +0,0 @@ - _ ______ __ ___ __ - / | / / __ \/ |/ /___ / /_ _______ - / |/ / /_/ / /|_/ / __ \/ / / / / ___/ - / /| / ____/ / / / /_/ / / /_/ (__ ) -/_/ |_/_/ /_/ /_/ .___/_/\__,_/____/ - /_/ diff --git a/ct/headers/scraparr b/ct/headers/scraparr new file mode 100644 index 00000000..5e5b3f94 --- /dev/null +++ b/ct/headers/scraparr @@ -0,0 +1,6 @@ + _____ + / ___/______________ _____ ____ ___________ + \__ \/ ___/ ___/ __ `/ __ \/ __ `/ ___/ ___/ + ___/ / /__/ / / /_/ / /_/ / /_/ / / / / +/____/\___/_/ \__,_/ .___/\__,_/_/ /_/ + /_/ diff --git a/ct/headers/zigbee2mqtt b/ct/headers/zigbee2mqtt new file mode 100644 index 00000000..f6925a01 --- /dev/null +++ b/ct/headers/zigbee2mqtt @@ -0,0 +1,6 @@ + _____ _ __ ___ __ _______ ____________ +/__ / (_)___ _/ /_ ___ ___ |__ \ / |/ / __ \/_ __/_ __/ + / / / / __ `/ __ \/ _ \/ _ \__/ // /|_/ / / / / / / / / + / /__/ / /_/ / /_/ / __/ __/ __// / / / /_/ / / / / / +/____/_/\__, /_.___/\___/\___/____/_/ /_/\___\_\/_/ /_/ + /____/ diff --git a/ct/itsmng.sh b/ct/itsmng.sh deleted file mode 100644 index b0117b05..00000000 --- a/ct/itsmng.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env bash -source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func) -# Copyright (c) 2021-2025 community-scripts ORG -# Author: Florianb63 -# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE -# Source: https://itsm-ng.com/ - -APP="itsmng" -var_tags="${var_tags:-asset-management;foss}" -var_cpu="${var_cpu:-2}" -var_ram="${var_ram:-2048}" -var_disk="${var_disk:-10}" -var_os="${var_os:-debian}" -var_version="${var_version:-12}" -var_unprivileged="${var_unprivileged:-1}" - -header_info "$APP" -variables -color -catch_errors - -function update_script() { - header_info - check_container_storage - check_container_resources - - if [[ ! -f /etc/itsm-ng/config_db.php ]]; then - msg_error "No ${APP} Installation Found!" - exit 1 - fi - - msg_info "Updating ${APP} LXC" - $STD apt-get update - $STD apt-get -y upgrade - msg_ok "Updated Successfully" - - exit -} - -start -build_container -description - -msg_ok "Completed Successfully!\n" -echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}" diff --git a/ct/jellyfin.sh b/ct/jellyfin.sh deleted file mode 100644 index a7763ead..00000000 --- a/ct/jellyfin.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bash -source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func) -# Copyright (c) 2021-2025 tteck -# Author: tteck (tteckster) -# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE -# Source: https://jellyfin.org/ - -APP="Jellyfin" -var_tags="${var_tags:-media}" -var_cpu="${var_cpu:-2}" -var_ram="${var_ram:-2048}" -var_disk="${var_disk:-8}" -var_os="${var_os:-ubuntu}" -var_version="${var_version:-24.04}" -var_unprivileged="${var_unprivileged:-1}" - -header_info "$APP" -variables -color -catch_errors - -function update_script() { - header_info - check_container_storage - check_container_resources - if [[ ! -d /usr/lib/jellyfin ]]; then - msg_error "No ${APP} Installation Found!" - exit - fi - msg_info "Updating ${APP} LXC" - $STD apt-get update - $STD apt-get -y upgrade - $STD apt-get -y --with-new-pkgs upgrade jellyfin jellyfin-server - msg_ok "Updated ${APP} LXC" - exit -} - -start -build_container -description - -msg_ok "Completed Successfully!\n" -echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8096${CL}" diff --git a/ct/kapowarr.sh b/ct/kapowarr.sh deleted file mode 100644 index ef1391c7..00000000 --- a/ct/kapowarr.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env bash -source <(curl -s https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/build.func) -# Copyright (c) 2021-2025 community-scripts ORG -# Author: Slaviša Arežina (tremor021) -# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE -# Source: https://github.com/Casvt/Kapowarr - -APP="Kapowarr" -var_tags="${var_tags:-Arr}" -var_cpu="${var_cpu:-1}" -var_ram="${var_ram:-256}" -var_disk="${var_disk:-2}" -var_os="${var_os:-debian}" -var_version="${var_version:-12}" -var_unprivileged="${var_unprivileged:-1}" - -header_info "$APP" -variables -color -catch_errors - -function update_script() { - header_info - check_container_storage - check_container_resources - - if [[ ! -f /etc/systemd/system/kapowarr.service ]]; then - msg_error "No ${APP} Installation Found!" - exit - fi - RELEASE=$(curl -s https://api.github.com/repos/Casvt/Kapowarr/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }') - if [[ "${RELEASE}" != "$(cat $HOME/.kapowarr)" ]] || [[ ! -f $HOME/.kapowarr ]]; then - msg_info "Stopping $APP" - systemctl stop kapowarr - msg_ok "Stopped $APP" - - msg_info "Creating Backup" - mv /opt/kapowarr/db /opt/ - msg_ok "Backup Created" - - msg_info "Updating $APP to ${RELEASE}" - fetch_and_deploy_gh_release "kapowarr" "Casvt/Kapowarr" - mv /opt/db /opt/kapowarr - msg_ok "Updated $APP to ${RELEASE}" - - msg_info "Starting $APP" - systemctl start kapowarr - msg_ok "Started $APP" - - msg_ok "Update Successful" - else - msg_ok "No update required. ${APP} is already at ${RELEASE}" - fi - exit -} - -start -build_container -description - -msg_ok "Completed Successfully!\n" -echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:5656${CL}" diff --git a/ct/npmplus.sh b/ct/npmplus.sh deleted file mode 100644 index 9e3b0917..00000000 --- a/ct/npmplus.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env bash -source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func) -# Copyright (c) 2021-2025 community-scripts ORG -# Author: MickLesk (CanbiZ) -# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE -# Source: https://github.com/ZoeyVid/NPMplus - -APP="NPMplus" -var_tags="${var_tags:-proxy;nginx}" -var_cpu="${var_cpu:-1}" -var_ram="${var_ram:-512}" -var_disk="${var_disk:-3}" -var_os="${var_os:-alpine}" -var_version="${var_version:-3.21}" -var_unprivileged="${var_unprivileged:-1}" - -header_info "$APP" -variables -color -catch_errors - -function update_script() { - UPD=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "UPDATE MODE" --radiolist --cancel-button Exit-Script "Spacebar = Select" 14 60 2 \ - "1" "Check for Alpine Updates" OFF \ - "2" "Update NPMplus Docker Container" ON \ - 3>&1 1>&2 2>&3) - - header_info "$APP" - - case "$UPD" in - "1") - msg_info "Updating Alpine OS" - $STD apk -U upgrade - msg_ok "System updated" - exit - ;; - "2") - msg_info "Updating NPMplus Container" - cd /opt - msg_info "Pulling latest container image" - $STD docker compose pull - msg_info "Recreating container" - $STD docker compose up -d - msg_ok "NPMplus container updated" - exit - ;; - esac - exit 0 -} - -start -build_container -description - -msg_ok "Completed Successfully!\n" -echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" -echo -e "${INFO}${YW} Access it using the following URL:${CL}" -echo -e "${TAB}${GATEWAY}${BGN}https://${IP}:81${CL}" diff --git a/ct/scraparr.sh b/ct/scraparr.sh new file mode 100644 index 00000000..b7eeee7e --- /dev/null +++ b/ct/scraparr.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func) +# Copyright (c) 2021-2025 community-scripts ORG +# Author: JasonGreenC +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/thecfu/scraparr + +APP="Scraparr" +var_tags="${var_tags:-arr;monitoring}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-1024}" +var_disk="${var_disk:-4}" +var_os="${var_os:-debian}" +var_version="${var_version:-12}" +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + + if [[ ! -d /opt/scraparr/ ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + RELEASE=$(curl -fsSL https://api.github.com/repos/thecfu/scraparr/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }') + if [[ ! -f "${HOME}/.scrappar" ]] || [[ "${RELEASE}" != "$(cat "${HOME}"/.scrappar)" ]]; then + msg_info "Stopping Services" + systemctl stop scraparr + msg_ok "Services Stopped" + + PYTHON_VERSION="3.12" setup_uv + fetch_and_deploy_gh_release "scrappar" "thecfu/scraparr" "tarball" "latest" "/opt/scraparr" + + msg_info "Updating ${APP} to ${RELEASE}" + cd /opt/scraparr || exit + $STD uv venv /opt/scraparr/.venv + $STD /opt/scraparr/.venv/bin/python -m ensurepip --upgrade + $STD /opt/scraparr/.venv/bin/python -m pip install --upgrade pip + $STD /opt/scraparr/.venv/bin/python -m pip install -r /opt/scraparr/src/scraparr/requirements.txt + chmod -R 755 /opt/scraparr + msg_ok "Updated ${APP} to v${RELEASE}" + + msg_info "Starting Services" + systemctl start scraparr + msg_ok "Services Started" + else + msg_ok "No update required. ${APP} is already at v${RELEASE}" + fi + exit +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW} Access it using the following URL:${CL}" +echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:7100${CL}" diff --git a/ct/zigbee2mqtt.sh b/ct/zigbee2mqtt.sh new file mode 100644 index 00000000..f087d75b --- /dev/null +++ b/ct/zigbee2mqtt.sh @@ -0,0 +1,90 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func) +# Copyright (c) 2021-2025 tteck +# Author: tteck (tteckster) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://www.zigbee2mqtt.io/ + +APP="Zigbee2MQTT" +var_tags="${var_tags:-smarthome;zigbee;mqtt}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-1024}" +var_disk="${var_disk:-4}" +var_os="${var_os:-debian}" +var_version="${var_version:-12}" +var_unprivileged="${var_unprivileged:-0}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + if [[ ! -d /opt/zigbee2mqtt ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + if [[ -f ~/.zigbee2mqtt ]]; then + CURRENT="$(cat ~/.zigbee2mqtt)" + elif [[ -f /opt/${APP}_version.txt ]]; then + CURRENT="$(cat /opt/${APP}_version.txt)" + rm -f /opt/${APP}_version.txt + else + CURRENT="" + fi + + RELEASE=$(curl -fsSL https://api.github.com/repos/Koenkk/zigbee2mqtt/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }') + if [[ "$RELEASE" != "$CURRENT" ]]; then + if ! command -v jq &>/dev/null; then + $STD apt-get update + $STD apt-get install -y jq + fi + NODE_VERSION=24 NODE_MODULE="pnpm@$(curl -fsSL https://raw.githubusercontent.com/Koenkk/zigbee2mqtt/master/package.json | jq -r '.packageManager | split("@")[1]')" setup_nodejs + + msg_info "Stopping Service" + systemctl stop zigbee2mqtt + msg_ok "Stopped Service" + + msg_info "Creating Backup" + rm -rf /opt/${APP}_backup*.tar.gz + mkdir -p /opt/z2m_backup + $STD tar -czf /opt/z2m_backup/${APP}_backup_$(date +%Y%m%d%H%M%S).tar.gz -C /opt zigbee2mqtt + mv /opt/zigbee2mqtt/data /opt/z2m_backup + msg_ok "Backup Created" + + fetch_and_deploy_gh_release "Zigbee2MQTT" "Koenkk/zigbee2mqtt" "tarball" "latest" "/opt/zigbee2mqtt" + + msg_info "Updating ${APP} to v${RELEASE}" + rm -rf /opt/zigbee2mqtt/data + mv /opt/z2m_backup/data /opt/zigbee2mqtt + cd /opt/zigbee2mqtt + $STD pnpm install --frozen-lockfile + $STD pnpm build + msg_ok "Updated Zigbee2MQTT" + + msg_info "Starting Service" + systemctl start zigbee2mqtt + msg_ok "Started Service" + + msg_info "Cleaning up" + rm -rf /opt/z2m_backup + msg_ok "Cleaned up" + echo "${RELEASE}" >/opt/${APP}_version.txt + else + msg_ok "No update required. ${APP} is already at v${RELEASE}." + fi + exit +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW} Access it using the following URL:${CL}" +echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:9442${CL}" diff --git a/frontend/public/json/docspell.json b/frontend/public/json/docspell.json new file mode 100644 index 00000000..dbf8e95a --- /dev/null +++ b/frontend/public/json/docspell.json @@ -0,0 +1,35 @@ +{ + "name": "Docspell", + "slug": "docspell", + "categories": [ + 12 + ], + "date_created": "2025-07-02", + "type": "ct", + "updateable": true, + "privileged": false, + "config_path": "/opt/docspell/.env", + "interface_port": 3000, + "documentation": "https://docspell.io/", + "website": "https://docspell.io/", + "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/docspell.svg", + "description": "Docspell is an open-source self-hosted application.", + "install_methods": [ + { + "type": "default", + "script": "ct/docspell.sh", + "resources": { + "cpu": 1, + "ram": 1024, + "hdd": 2, + "os": "Debian", + "version": "12" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [] +} \ No newline at end of file diff --git a/frontend/public/json/frigate.json b/frontend/public/json/frigate.json new file mode 100644 index 00000000..b5a8d7d6 --- /dev/null +++ b/frontend/public/json/frigate.json @@ -0,0 +1,35 @@ +{ + "name": "Frigate", + "slug": "frigate", + "categories": [ + 15 + ], + "date_created": "2025-07-02", + "type": "ct", + "updateable": true, + "privileged": false, + "config_path": "/opt/frigate/.env", + "interface_port": 3000, + "documentation": "https://frigate.io/", + "website": "https://frigate.io/", + "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/frigate.svg", + "description": "Frigate is an open-source self-hosted application.", + "install_methods": [ + { + "type": "default", + "script": "ct/frigate.sh", + "resources": { + "cpu": 1, + "ram": 1024, + "hdd": 2, + "os": "Debian", + "version": "12" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [] +} \ No newline at end of file diff --git a/frontend/public/json/hanko.json b/frontend/public/json/hanko.json new file mode 100644 index 00000000..d8628ad8 --- /dev/null +++ b/frontend/public/json/hanko.json @@ -0,0 +1,35 @@ +{ + "name": "Hanko", + "slug": "hanko", + "categories": [ + 21 + ], + "date_created": "2025-07-02", + "type": "ct", + "updateable": true, + "privileged": false, + "config_path": "/opt/hanko/.env", + "interface_port": 3000, + "documentation": "https://docs.hanko.io/", + "website": "https://hanko.io/", + "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/hanko.svg", + "description": "Hanko is an open-source authentication solution providing passkey-first login with support for WebAuthn/FIDO2, biometrics and modern identity flows. Easy to self-host and integrate via API or widget.", + "install_methods": [ + { + "type": "default", + "script": "ct/hanko.sh", + "resources": { + "cpu": 1, + "ram": 1024, + "hdd": 2, + "os": "Debian", + "version": "12" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [] +} diff --git a/frontend/public/json/healthchecks.json b/frontend/public/json/healthchecks.json new file mode 100644 index 00000000..ac5f3fe2 --- /dev/null +++ b/frontend/public/json/healthchecks.json @@ -0,0 +1,35 @@ +{ + "name": "Healthchecks", + "slug": "healthchecks", + "categories": [ + 9 + ], + "date_created": "2025-07-02", + "type": "ct", + "updateable": true, + "privileged": false, + "config_path": "/opt/healthchecks/.env", + "interface_port": 3000, + "documentation": "https://healthchecks.io/", + "website": "https://healthchecks.io/", + "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/healthchecks.svg", + "description": "Healthchecks is an open-source self-hosted application.", + "install_methods": [ + { + "type": "default", + "script": "ct/healthchecks.sh", + "resources": { + "cpu": 1, + "ram": 1024, + "hdd": 2, + "os": "Debian", + "version": "12" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [] +} \ No newline at end of file diff --git a/frontend/public/json/itsmng.json b/frontend/public/json/itsmng.json deleted file mode 100644 index a3bef7af..00000000 --- a/frontend/public/json/itsmng.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "ITSMNG", - "slug": "itsmng", - "categories": [ - 25 - ], - "date_created": "2025-06-20", - "type": "ct", - "updateable": true, - "privileged": false, - "interface_port": 80, - "documentation": "https://wiki.itsm-ng.org/en/home", - "website": "https://itsm-ng.com", - "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/itsm-ng.svg", - "config_path": "/etc/itsm-ng", - "description": "ITSM-NG is a Free Asset and IT Management Software package, Data center management, ITIL Service Desk, licenses tracking and software auditing.", - "install_methods": [ - { - "type": "default", - "script": "ct/itsmng.sh", - "resources": { - "cpu": 2, - "ram": 2048, - "hdd": 10, - "os": "debian", - "version": "12" - } - } - ], - "default_credentials": { - "username": "itsm", - "password": "itsm" - }, - "notes": [] -} diff --git a/frontend/public/json/kapowarr.json b/frontend/public/json/kapowarr.json deleted file mode 100644 index e5d69d07..00000000 --- a/frontend/public/json/kapowarr.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "Kapowarr", - "slug": "kapowarr", - "categories": [ - 14 - ], - "date_created": "2025-06-09", - "type": "ct", - "updateable": true, - "privileged": false, - "interface_port": 5656, - "documentation": "https://casvt.github.io/Kapowarr/general_info/workings/", - "website": "https://casvt.github.io/Kapowarr/", - "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/kapowarr.webp", - "config_path": "", - "description": "Kapowarr allows you to build a digital library of comics. You can add volumes, map them to a folder and start managing! Download, rename, move and convert issues of the volume (including TPB's, One Shots, Hard Covers, and more). The whole process is automated and can be customised in the settings.", - "install_methods": [ - { - "type": "default", - "script": "ct/kapowarr.sh", - "resources": { - "cpu": 1, - "ram": 256, - "hdd": 2, - "os": "debian", - "version": "12" - } - } - ], - "default_credentials": { - "username": null, - "password": null - }, - "notes": [] -} diff --git a/frontend/public/json/maxun.json b/frontend/public/json/maxun.json new file mode 100644 index 00000000..7ed83e0d --- /dev/null +++ b/frontend/public/json/maxun.json @@ -0,0 +1,35 @@ +{ + "name": "Maxun", + "slug": "maxun", + "categories": [ + 0 + ], + "date_created": "2025-07-02", + "type": "ct", + "updateable": true, + "privileged": false, + "config_path": "/opt/maxun/.env", + "interface_port": 3000, + "documentation": "https://maxun.io/", + "website": "https://maxun.io/", + "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/maxun.svg", + "description": "Maxun is an open-source self-hosted application.", + "install_methods": [ + { + "type": "default", + "script": "ct/maxun.sh", + "resources": { + "cpu": 1, + "ram": 1024, + "hdd": 2, + "os": "Debian", + "version": "12" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [] +} \ No newline at end of file diff --git a/frontend/public/json/mealie.json b/frontend/public/json/mealie.json new file mode 100644 index 00000000..dbe8b4c4 --- /dev/null +++ b/frontend/public/json/mealie.json @@ -0,0 +1,35 @@ +{ + "name": "Mealie", + "slug": "mealie", + "categories": [ + 13 + ], + "date_created": "2025-07-02", + "type": "ct", + "updateable": true, + "privileged": false, + "config_path": "/opt/mealie/.env", + "interface_port": 3000, + "documentation": "https://mealie.io/", + "website": "https://mealie.io/", + "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/mealie.svg", + "description": "Mealie is an open-source self-hosted application.", + "install_methods": [ + { + "type": "default", + "script": "ct/mealie.sh", + "resources": { + "cpu": 1, + "ram": 1024, + "hdd": 2, + "os": "Debian", + "version": "12" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [] +} \ No newline at end of file diff --git a/frontend/public/json/postiz.json b/frontend/public/json/postiz.json new file mode 100644 index 00000000..dfcb0f04 --- /dev/null +++ b/frontend/public/json/postiz.json @@ -0,0 +1,35 @@ +{ + "name": "Postiz", + "slug": "postiz", + "categories": [ + 20 + ], + "date_created": "2025-07-02", + "type": "ct", + "updateable": true, + "privileged": false, + "config_path": "/opt/postiz/.env", + "interface_port": 3000, + "documentation": "https://postiz.io/", + "website": "https://postiz.io/", + "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/postiz.svg", + "description": "Postiz is an open-source self-hosted application.", + "install_methods": [ + { + "type": "default", + "script": "ct/postiz.sh", + "resources": { + "cpu": 1, + "ram": 1024, + "hdd": 2, + "os": "Debian", + "version": "12" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [] +} \ No newline at end of file diff --git a/frontend/public/json/saltmaster.json b/frontend/public/json/saltmaster.json new file mode 100644 index 00000000..b538aae1 --- /dev/null +++ b/frontend/public/json/saltmaster.json @@ -0,0 +1,35 @@ +{ + "name": "Saltmaster", + "slug": "saltmaster", + "categories": [ + 1 + ], + "date_created": "2025-07-02", + "type": "ct", + "updateable": true, + "privileged": false, + "config_path": "/opt/saltmaster/.env", + "interface_port": 3000, + "documentation": "https://saltmaster.io/", + "website": "https://saltmaster.io/", + "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/saltmaster.svg", + "description": "Saltmaster is an open-source self-hosted application.", + "install_methods": [ + { + "type": "default", + "script": "ct/saltmaster.sh", + "resources": { + "cpu": 1, + "ram": 1024, + "hdd": 2, + "os": "Debian", + "version": "12" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [] +} \ No newline at end of file diff --git a/frontend/public/json/scraparr.json b/frontend/public/json/scraparr.json new file mode 100644 index 00000000..731618e3 --- /dev/null +++ b/frontend/public/json/scraparr.json @@ -0,0 +1,40 @@ +{ + "name": "Scraparr", + "slug": "scraparr", + "categories": [ + 14 + ], + "date_created": "2024-05-02", + "type": "ct", + "updateable": true, + "privileged": false, + "interface_port": 7100, + "documentation": "https://github.com/thecfu/scraparr/blob/main/README.md", + "website": "https://github.com/thecfu/scraparr", + "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/scraparr-dark.svg", + "config_path": "/scraparr/config/config.yaml", + "description": "Scraparr is a Prometheus exporter for the *arr suite (Sonarr, Radarr, Lidarr, etc.). It provides metrics that can be scraped by Prometheus to monitor and visualize the health and performance of your *arr applications.", + "install_methods": [ + { + "type": "default", + "script": "ct/scraparr.sh", + "resources": { + "cpu": 2, + "ram": 1024, + "hdd": 4, + "os": "debian", + "version": "12" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [ + { + "text": "Edit config file then restart the scraparr service: `systemctl restart scraparr`", + "type": "info" + } + ] +} diff --git a/frontend/public/json/versions.json b/frontend/public/json/versions.json index 4dae1a1d..5cc7311b 100644 --- a/frontend/public/json/versions.json +++ b/frontend/public/json/versions.json @@ -1,19 +1,244 @@ [ + { + "name": "wazuh/wazuh", + "version": "coverity-w27-4.13.0", + "date": "2025-07-01T03:17:32Z" + }, + { + "name": "glpi-project/glpi", + "version": "10.0.18", + "date": "2025-02-12T11:07:02Z" + }, + { + "name": "emqx/emqx", + "version": "e5.9.1", + "date": "2025-07-02T08:11:50Z" + }, + { + "name": "apache/tomcat", + "version": "9.0.107", + "date": "2025-07-02T07:12:09Z" + }, + { + "name": "nzbgetcom/nzbget", + "version": "v25.1", + "date": "2025-06-27T09:14:14Z" + }, + { + "name": "qbittorrent/qBittorrent", + "version": "release-5.1.2", + "date": "2025-07-02T06:13:16Z" + }, + { + "name": "home-assistant/core", + "version": "2025.6.3", + "date": "2025-06-24T13:00:12Z" + }, { "name": "Jackett/Jackett", - "version": "v0.22.2075", - "date": "2025-06-28T10:16:17Z" + "version": "v0.22.2107", + "date": "2025-07-02T05:53:02Z" + }, + { + "name": "firefly-iii/firefly-iii", + "version": "v6.2.20", + "date": "2025-07-02T04:03:37Z" + }, + { + "name": "diced/zipline", + "version": "v4.2.0", + "date": "2025-07-02T00:45:31Z" + }, + { + "name": "sysadminsmedia/homebox", + "version": "v0.20.2", + "date": "2025-07-02T00:37:07Z" + }, + { + "name": "hyperion-project/hyperion.ng", + "version": "2.1.1", + "date": "2025-06-14T17:45:06Z" + }, + { + "name": "mongodb/mongo", + "version": "r8.1.2", + "date": "2025-07-01T22:39:32Z" + }, + { + "name": "Threadfin/Threadfin", + "version": "1.2.35", + "date": "2025-07-01T21:37:20Z" + }, + { + "name": "actualbudget/actual", + "version": "v25.7.0", + "date": "2025-07-01T21:02:27Z" + }, + { + "name": "TwiN/gatus", + "version": "v5.19.0", + "date": "2025-07-01T19:59:32Z" + }, + { + "name": "Koenkk/zigbee2mqtt", + "version": "2.5.0", + "date": "2025-07-01T18:28:01Z" + }, + { + "name": "keycloak/keycloak", + "version": "26.3.0", + "date": "2025-07-01T13:18:12Z" + }, + { + "name": "hivemq/hivemq-community-edition", + "version": "2025.4", + "date": "2025-07-01T18:01:37Z" + }, + { + "name": "HabitRPG/habitica", + "version": "v5.37.1", + "date": "2025-07-01T16:57:43Z" + }, + { + "name": "navidrome/navidrome", + "version": "v0.57.0", + "date": "2025-07-01T16:47:46Z" + }, + { + "name": "jenkinsci/jenkins", + "version": "jenkins-2.517", + "date": "2025-07-01T16:08:23Z" + }, + { + "name": "element-hq/synapse", + "version": "v1.133.0", + "date": "2025-07-01T15:13:42Z" + }, + { + "name": "syncthing/syncthing", + "version": "v1.30.0", + "date": "2025-07-01T11:29:11Z" + }, + { + "name": "Checkmk/checkmk", + "version": "v2.2.0p44-rc1", + "date": "2025-07-01T11:10:25Z" + }, + { + "name": "rcourtman/Pulse", + "version": "v99.99.99", + "date": "2025-07-01T08:26:41Z" + }, + { + "name": "zabbix/zabbix", + "version": "7.4.0", + "date": "2025-07-01T04:36:51Z" + }, + { + "name": "openobserve/openobserve", + "version": "v0.15.0-rc3", + "date": "2025-07-01T04:09:37Z" + }, + { + "name": "NginxProxyManager/nginx-proxy-manager", + "version": "v2.12.4", + "date": "2025-07-01T01:45:42Z" + }, + { + "name": "MagicMirrorOrg/MagicMirror", + "version": "v2.32.0", + "date": "2025-06-30T22:12:48Z" + }, + { + "name": "docker/compose", + "version": "v2.38.1", + "date": "2025-06-30T20:07:35Z" + }, + { + "name": "jhuckaby/Cronicle", + "version": "v0.9.81", + "date": "2025-06-30T16:40:33Z" + }, + { + "name": "ollama/ollama", + "version": "v0.9.4-rc6", + "date": "2025-06-30T15:59:03Z" + }, + { + "name": "prometheus/prometheus", + "version": "v2.53.5", + "date": "2025-06-30T11:01:12Z" + }, + { + "name": "n8n-io/n8n", + "version": "n8n@1.100.0", + "date": "2025-06-23T12:48:35Z" + }, + { + "name": "jupyter/notebook", + "version": "v7.4.4", + "date": "2025-06-30T13:04:22Z" + }, + { + "name": "Graylog2/graylog2-server", + "version": "6.3.0", + "date": "2025-06-30T11:26:45Z" + }, + { + "name": "grokability/snipe-it", + "version": "v8.1.17", + "date": "2025-06-30T11:26:27Z" + }, + { + "name": "documenso/documenso", + "version": "v1.12.0-rc.8", + "date": "2025-06-30T09:47:37Z" + }, + { + "name": "PrivateBin/PrivateBin", + "version": "1.7.8", + "date": "2025-06-30T09:00:54Z" + }, + { + "name": "fuma-nama/fumadocs", + "version": "fumadocs-mdx@11.6.10", + "date": "2025-06-30T07:07:36Z" + }, + { + "name": "mattermost/mattermost", + "version": "preview-v0.1", + "date": "2025-06-27T14:35:47Z" + }, + { + "name": "typesense/typesense", + "version": "v29.0", + "date": "2025-06-30T03:52:33Z" + }, + { + "name": "dgtlmoon/changedetection.io", + "version": "0.50.5", + "date": "2025-06-29T08:54:47Z" + }, + { + "name": "theonedev/onedev", + "version": "v11.11.2", + "date": "2025-06-29T01:40:39Z" + }, + { + "name": "linkwarden/linkwarden", + "version": "v2.11.2", + "date": "2025-06-28T17:33:38Z" + }, + { + "name": "msgbyte/tianji", + "version": "v1.22.5", + "date": "2025-06-28T16:06:19Z" }, { "name": "Luligu/matterbridge", "version": "3.1.0", "date": "2025-06-28T09:02:38Z" }, - { - "name": "firefly-iii/firefly-iii", - "version": "v6.2.19", - "date": "2025-06-28T06:53:45Z" - }, { "name": "esphome/esphome", "version": "2025.6.2", @@ -34,51 +259,21 @@ "version": "v1.5.0", "date": "2025-06-27T22:04:32Z" }, - { - "name": "linkwarden/linkwarden", - "version": "v2.11.1", - "date": "2025-06-27T21:21:59Z" - }, { "name": "homarr-labs/homarr", "version": "v1.26.0", "date": "2025-06-27T19:15:24Z" }, - { - "name": "ollama/ollama", - "version": "v0.9.4-rc1", - "date": "2025-06-27T18:45:33Z" - }, - { - "name": "home-assistant/core", - "version": "2025.6.3", - "date": "2025-06-24T13:00:12Z" - }, - { - "name": "mattermost/mattermost", - "version": "preview-v0.1", - "date": "2025-06-27T14:35:47Z" - }, { "name": "goauthentik/authentik", "version": "version/2025.6.3", "date": "2025-06-27T14:01:06Z" }, - { - "name": "keycloak/keycloak", - "version": "26.2.5", - "date": "2025-05-28T06:49:43Z" - }, { "name": "rclone/rclone", "version": "v1.70.2", "date": "2025-06-27T13:21:17Z" }, - { - "name": "documenso/documenso", - "version": "v1.12.0-rc.7", - "date": "2025-06-27T12:17:45Z" - }, { "name": "sabnzbd/sabnzbd", "version": "4.5.1", @@ -89,31 +284,16 @@ "version": "flowise@3.0.3", "date": "2025-06-27T09:53:57Z" }, - { - "name": "nzbgetcom/nzbget", - "version": "v25.1", - "date": "2025-06-27T09:14:14Z" - }, { "name": "cockpit-project/cockpit", "version": "341.1", "date": "2025-06-27T08:50:16Z" }, - { - "name": "zabbix/zabbix", - "version": "7.2.10", - "date": "2025-06-27T06:40:00Z" - }, { "name": "MediaBrowser/Emby.Releases", "version": "4.9.1.2", "date": "2025-06-26T22:08:00Z" }, - { - "name": "prometheus/prometheus", - "version": "v3.4.2", - "date": "2025-06-26T21:45:21Z" - }, { "name": "home-assistant/operating-system", "version": "15.2", @@ -134,11 +314,6 @@ "version": "v1.84.3", "date": "2025-06-26T16:31:57Z" }, - { - "name": "fuma-nama/fumadocs", - "version": "fumadocs-ui@15.5.5", - "date": "2025-06-26T15:54:17Z" - }, { "name": "traefik/traefik", "version": "v3.5.0-rc1", @@ -164,16 +339,6 @@ "version": "18.0.7", "date": "2025-06-26T09:16:33Z" }, - { - "name": "mongodb/mongo", - "version": "r8.1.2-rc1", - "date": "2025-06-25T22:42:04Z" - }, - { - "name": "rcourtman/Pulse", - "version": "v3.32.0", - "date": "2025-06-25T22:27:01Z" - }, { "name": "gristlabs/grist-core", "version": "v1.6.1", @@ -184,11 +349,6 @@ "version": "v4.101.2", "date": "2025-06-25T21:18:52Z" }, - { - "name": "msgbyte/tianji", - "version": "v1.22.4", - "date": "2025-06-25T20:46:20Z" - }, { "name": "influxdata/influxdb", "version": "v3.2.0", @@ -199,21 +359,11 @@ "version": "2.0.5", "date": "2025-06-25T14:53:31Z" }, - { - "name": "jenkinsci/jenkins", - "version": "jenkins-2.504.3", - "date": "2025-06-25T14:43:01Z" - }, { "name": "bunkerity/bunkerweb", "version": "testing", "date": "2025-06-16T18:10:42Z" }, - { - "name": "n8n-io/n8n", - "version": "n8n@1.100.0", - "date": "2025-06-23T12:48:35Z" - }, { "name": "moghtech/komodo", "version": "v1.18.4", @@ -239,31 +389,11 @@ "version": "v2.18.0", "date": "2025-06-24T08:29:55Z" }, - { - "name": "element-hq/synapse", - "version": "v1.132.0", - "date": "2025-06-17T13:49:30Z" - }, - { - "name": "docker/compose", - "version": "v2.37.3", - "date": "2025-06-24T14:05:33Z" - }, - { - "name": "Checkmk/checkmk", - "version": "v2.4.0p5", - "date": "2025-06-24T13:06:53Z" - }, { "name": "fallenbagel/jellyseerr", "version": "preview-fix-proxy-axios", "date": "2025-06-24T08:50:22Z" }, - { - "name": "wazuh/wazuh", - "version": "coverity-w26-4.13.0", - "date": "2025-06-24T02:02:34Z" - }, { "name": "minio/minio", "version": "RELEASE.2025-06-13T11-33-47Z", @@ -279,11 +409,6 @@ "version": "pmm-6401-v1.120.0", "date": "2025-06-23T15:12:12Z" }, - { - "name": "Graylog2/graylog2-server", - "version": "6.3.0-rc.2", - "date": "2025-06-23T11:31:38Z" - }, { "name": "gotson/komga", "version": "1.22.0", @@ -294,11 +419,6 @@ "version": "2025.6.22", "date": "2025-06-22T22:41:11Z" }, - { - "name": "qbittorrent/qBittorrent", - "version": "release-5.1.1", - "date": "2025-06-22T21:41:17Z" - }, { "name": "clusterzx/paperless-ai", "version": "v3.0.7", @@ -314,31 +434,16 @@ "version": "0.17.14", "date": "2025-06-21T23:43:04Z" }, - { - "name": "HabitRPG/habitica", - "version": "v5.37.0", - "date": "2025-06-21T14:05:12Z" - }, { "name": "rogerfar/rdt-client", "version": "v2.0.114", "date": "2025-06-21T11:20:21Z" }, - { - "name": "theonedev/onedev", - "version": "v11.11.1", - "date": "2025-06-21T09:23:39Z" - }, { "name": "pocketbase/pocketbase", "version": "v0.28.4", "date": "2025-06-21T08:29:04Z" }, - { - "name": "dgtlmoon/changedetection.io", - "version": "0.50.4", - "date": "2025-06-21T07:47:02Z" - }, { "name": "go-gitea/gitea", "version": "v1.24.2", @@ -354,11 +459,6 @@ "version": "v4.0.15.2941", "date": "2025-06-20T17:20:54Z" }, - { - "name": "syncthing/syncthing", - "version": "2.0.0-rc.19", - "date": "2025-06-02T17:56:25Z" - }, { "name": "benzino77/tasmocompiler", "version": "v12.7.0", @@ -389,79 +489,9 @@ "version": "v3.5.5", "date": "2025-06-19T05:43:47Z" }, - { - "name": "docmost/docmost", - "version": "v0.21.0", - "date": "2025-06-18T21:43:27Z" - }, { "name": "ipfs/kubo", "version": "v0.35.0", "date": "2025-05-21T18:00:32Z" - }, - { - "name": "pterodactyl/panel", - "version": "v1.11.11", - "date": "2025-06-18T18:04:50Z" - }, - { - "name": "NodeBB/NodeBB", - "version": "v3.12.7", - "date": "2025-06-18T14:22:53Z" - }, - { - "name": "openhab/openhab-core", - "version": "5.0.0.M3", - "date": "2025-06-18T14:18:12Z" - }, - { - "name": "Bubka/2FAuth", - "version": "v5.6.0", - "date": "2025-06-18T12:19:54Z" - }, - { - "name": "zwave-js/zwave-js-ui", - "version": "v10.7.0", - "date": "2025-06-18T11:57:05Z" - }, - { - "name": "forgejo/forgejo", - "version": "v11.0.2", - "date": "2025-06-18T09:38:19Z" - }, - { - "name": "silverbulletmd/silverbullet", - "version": "2.0.0-pre3", - "date": "2025-06-18T08:01:24Z" - }, - { - "name": "cross-seed/cross-seed", - "version": "v6.12.7", - "date": "2025-06-18T03:44:24Z" - }, - { - "name": "grafana/grafana", - "version": "v11.5.6", - "date": "2025-06-17T22:00:40Z" - }, - { - "name": "project-zot/zot", - "version": "v2.1.5", - "date": "2025-06-17T18:04:11Z" - }, - { - "name": "BookStackApp/BookStack", - "version": "v25.05.1", - "date": "2025-06-17T14:38:04Z" - }, - { - "name": "cloudflare/cloudflared", - "version": "2025.6.1", - "date": "2025-06-17T12:45:39Z" - }, - { - "name": "crowdsecurity/crowdsec", - "version": "v1.6.9", - "date": "2025-06-17T11:54:50Z" } ] diff --git a/frontend/public/json/wallabag.json b/frontend/public/json/wallabag.json new file mode 100644 index 00000000..203595a1 --- /dev/null +++ b/frontend/public/json/wallabag.json @@ -0,0 +1,35 @@ +{ + "name": "Wallabag", + "slug": "wallabag", + "categories": [ + 12 + ], + "date_created": "2025-07-02", + "type": "ct", + "updateable": true, + "privileged": false, + "config_path": "/opt/wallabag/.env", + "interface_port": 3000, + "documentation": "https://wallabag.io/", + "website": "https://wallabag.io/", + "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/wallabag.svg", + "description": "Wallabag is an open-source self-hosted application.", + "install_methods": [ + { + "type": "default", + "script": "ct/wallabag.sh", + "resources": { + "cpu": 1, + "ram": 1024, + "hdd": 2, + "os": "Debian", + "version": "12" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [] +} \ No newline at end of file diff --git a/install/alpine-syncthing-install.sh b/install/alpine-syncthing-install.sh deleted file mode 100644 index 701c052f..00000000 --- a/install/alpine-syncthing-install.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash - -# Copyright (c) 2021-2025 community-scripts ORG -# Author: MickLesk (CanbiZ) -# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE -# Source: https://syncthing.net/ - -source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" -color -verb_ip6 -catch_errors -setting_up_container -network_check -update_os - -msg_info "Setup Syncthing" -$STD apk add --no-cache syncthing -msg_ok "Setup Syncthing" - -msg_info "Enabling Syncthing Service" -$STD rc-update add syncthing default -msg_ok "Enabled Syncthing Service" - -msg_info "Starting Syncthing" -$STD rc-service syncthing start -msg_ok "Started Syncthing" - -motd_ssh -customize diff --git a/install/debian-install.sh b/install/debian-install.sh index 052fd10f..16287231 100644 --- a/install/debian-install.sh +++ b/install/debian-install.sh @@ -17,6 +17,8 @@ msg_info "Installing Dependencies" $STD apt-get install -y gpg msg_ok "Installed Dependencies" +#FFMPEG_VERSION="n7.1.1" FFMPEG_TYPE="full" setup_ffmpeg + #fetch_and_deploy_gh_release "argus" "release-argus/Argus" "singlefile" "latest" "/opt/argus" "Argus-.*linux-amd64" #fetch_and_deploy_gh_release "planka" "plankanban/planka" "prebuild" "latest" "/opt/planka" "planka-prebuild.zip" diff --git a/install/hanko-install.sh b/install/hanko-install.sh index 5ca0d69c..96f2308c 100644 --- a/install/hanko-install.sh +++ b/install/hanko-install.sh @@ -1,9 +1,9 @@ #!/usr/bin/env bash -# Copyright (c) 2021-2025 tteck -# Author: tteck (tteckster) -# License: MIT -# https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# Copyright (c) 2021-2025 community-scripts ORG +# Author: MickLesk (CanbiZ) +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# Source: https://hanko.io/ source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" color diff --git a/install/itsmng-install.sh b/install/itsmng-install.sh deleted file mode 100644 index 2879d1ca..00000000 --- a/install/itsmng-install.sh +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env bash - -# Copyright (c) 2021-2025 community-scripts ORG -# Author: Florianb63 -# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE -# Source: https://itsm-ng.com/ - -source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" -color -verb_ip6 -catch_errors -setting_up_container -network_check -update_os - -setup_mariadb - -msg_info "Installing Repository" -curl -fsSL http://deb.itsm-ng.org/pubkey.gpg | gpg --dearmor -o /etc/apt/trusted.gpg.d/itsm-ng-keyring.gpg -echo "deb http://deb.itsm-ng.org/$(. /etc/os-release && echo "$ID")/ $(. /etc/os-release && echo "$VERSION_CODENAME") main" > /etc/apt/sources.list.d/itsm-ng.list -$STD apt update -msg_ok "Installed Repository" - -msg_info "Installing ITSM-NG" -$STD apt install -y itsm-ng -msg_ok "Installed ITSM-NG" - -msg_info "Setting up database" -DB_NAME=itsmng_db -DB_USER=itsmng -DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13) -mariadb-tzinfo-to-sql /usr/share/zoneinfo | mysql mysql -mariadb -u root -e "CREATE DATABASE $DB_NAME;" -mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';" -mariadb -u root -e "GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost';" -mariadb -u root -e "GRANT SELECT ON \`mysql\`.\`time_zone_name\` TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;" -{ - echo "ITSM-NG Database Credentials" - echo "Database: $DB_NAME" - echo "Username: $DB_USER" - echo "Password: $DB_PASS" -} >>~/itsmng_db.creds -msg_ok "Set up database" - -msg_info "Installing ITSM-NG" -cd /usr/share/itsm-ng -$STD php bin/console db:install --db-name=$DB_NAME --db-user=$DB_USER --db-password=$DB_PASS --no-interaction -msg_ok "Installed ITSM-NG" - -msg_info "Configuring webserver" -$STD a2dissite 000-default.conf -msg_ok "Setup Service" - -msg_info "Setup Cronjob" -echo "* * * * * php /usr/share/itsm-ng/front/cron.php" | crontab - -msg_ok "Setup Cronjob" - -msg_info "Update PHP Params" -PHP_VERSION=$(ls /etc/php/ | grep -E '^[0-9]+\.[0-9]+$' | head -n 1) -PHP_INI="/etc/php/$PHP_VERSION/apache2/php.ini" -sed -i 's/^upload_max_filesize = .*/upload_max_filesize = 20M/' $PHP_INI -sed -i 's/^post_max_size = .*/post_max_size = 20M/' $PHP_INI -sed -i 's/^max_execution_time = .*/max_execution_time = 60/' $PHP_INI -sed -i 's/^max_input_vars = .*/max_input_vars = 5000/' $PHP_INI -sed -i 's/^memory_limit = .*/memory_limit = 256M/' $PHP_INI -sed -i 's/^;\?\s*session.cookie_httponly\s*=.*/session.cookie_httponly = On/' $PHP_INI -systemctl restart apache2 -msg_ok "Update PHP Params" - -motd_ssh -customize - -msg_info "Cleaning up" -rm -rf /usr/share/itsm-ng/install -$STD apt-get -y autoremove -$STD apt-get -y autoclean -msg_ok "Cleaned" diff --git a/install/jellyfin-install.sh b/install/jellyfin-install.sh deleted file mode 100644 index 1c459305..00000000 --- a/install/jellyfin-install.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env bash - -# Copyright (c) 2021-2025 tteck -# Author: tteck (tteckster) -# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE -# Source: https://jellyfin.org/ - -source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" -color -verb_ip6 -catch_errors -setting_up_container -network_check -update_os - -msg_info "Setting Up Hardware Acceleration" -$STD apt-get -y install {va-driver-all,ocl-icd-libopencl1,intel-opencl-icd,vainfo,intel-gpu-tools} -if [[ "$CTTYPE" == "0" ]]; then - chgrp video /dev/dri - chmod 755 /dev/dri - chmod 660 /dev/dri/* - $STD adduser $(id -u -n) video - $STD adduser $(id -u -n) render -fi -msg_ok "Set Up Hardware Acceleration" - -msg_info "Installing Jellyfin" -VERSION="$(awk -F'=' '/^VERSION_CODENAME=/{ print $NF }' /etc/os-release)" -# If the keyring directory is absent, create it -if [[ ! -d /etc/apt/keyrings ]]; then - mkdir -p /etc/apt/keyrings -fi -# Download the repository signing key and install it to the keyring directory -curl -fsSL https://repo.jellyfin.org/jellyfin_team.gpg.key | gpg --dearmor --yes --output /etc/apt/keyrings/jellyfin.gpg -# Install the Deb822 format jellyfin.sources entry -cat </etc/apt/sources.list.d/jellyfin.sources -Types: deb -URIs: https://repo.jellyfin.org/${PCT_OSTYPE} -Suites: ${VERSION} -Components: main -Architectures: amd64 -Signed-By: /etc/apt/keyrings/jellyfin.gpg -EOF -# Install Jellyfin using the metapackage (which will fetch jellyfin-server, jellyfin-web, and jellyfin-ffmpeg5) -$STD apt-get update -$STD apt-get install -y jellyfin -sed -i 's/"MinimumLevel": "Information"/"MinimumLevel": "Error"/g' /etc/jellyfin/logging.json -chown -R jellyfin:adm /etc/jellyfin -sleep 10 -systemctl restart jellyfin -if [[ "$CTTYPE" == "0" ]]; then - sed -i -e 's/^ssl-cert:x:104:$/render:x:104:root,jellyfin/' -e 's/^render:x:108:root,jellyfin$/ssl-cert:x:108:/' /etc/group -else - sed -i -e 's/^ssl-cert:x:104:$/render:x:104:jellyfin/' -e 's/^render:x:108:jellyfin$/ssl-cert:x:108:/' /etc/group -fi -msg_ok "Installed Jellyfin" - -motd_ssh -customize - -msg_info "Cleaning up" -$STD apt-get -y autoremove -$STD apt-get -y autoclean -msg_ok "Cleaned" diff --git a/install/kapowarr-install.sh b/install/kapowarr-install.sh deleted file mode 100644 index c5f29a7b..00000000 --- a/install/kapowarr-install.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env bash - -# Copyright (c) 2021-2025 community-scripts ORG -# Author: Slaviša Arežina (tremor021) -# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE -# Source: https://github.com/Casvt/Kapowarr - -source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" -color -verb_ip6 -catch_errors -setting_up_container -network_check -update_os - -msg_info "Setup Python3" -$STD apt-get install -y python3-pip -msg_ok "Setup Python3" - -setup_uv -fetch_and_deploy_gh_release "kapowarr" "Casvt/Kapowarr" - -msg_info "Setup Kapowarr" -cd /opt/kapowarr -$STD uv venv .venv -$STD source .venv/bin/activate -$STD uv pip install --upgrade pip -$STD uv pip install --no-cache-dir -r requirements.txt -msg_ok "Installed Kapowarr" - -msg_info "Creating Service" -cat </etc/systemd/system/kapowarr.service -[Unit] -Description=Kapowarr Service -After=network.target - -[Service] -WorkingDirectory=/opt/kapowarr/ -ExecStart=/opt/kapowarr/.venv/bin/python3 Kapowarr.py -Restart=always - -[Install] -WantedBy=multi-user.target -EOF -systemctl enable -q --now kapowarr -msg_ok "Created Service" - -motd_ssh -customize - -msg_info "Cleaning up" -$STD apt-get -y autoremove -$STD apt-get -y autoclean -msg_ok "Cleaned" diff --git a/install/scraparr-install.sh b/install/scraparr-install.sh new file mode 100644 index 00000000..4eafe0a6 --- /dev/null +++ b/install/scraparr-install.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2025 community-scripts ORG +# Author: JasonGreenC +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/thecfu/scraparr + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +msg_info "Installing Scraparr" +PYTHON_VERSION="3.12" setup_uv +fetch_and_deploy_gh_release "scrappar" "thecfu/scraparr" "tarball" "latest" "/opt/scraparr" +cd /opt/scraparr || exit +$STD uv venv /opt/scraparr/.venv +$STD /opt/scraparr/.venv/bin/python -m ensurepip --upgrade +$STD /opt/scraparr/.venv/bin/python -m pip install --upgrade pip +$STD /opt/scraparr/.venv/bin/python -m pip install -r /opt/scraparr/src/scraparr/requirements.txt +chmod -R 755 /opt/scraparr +mkdir -p /scraparr/config +mv /opt/scraparr/config.yaml /scraparr/config/config.yaml +chmod -R 755 /scraparr +msg_ok "Installed Scraparr" + +msg_info "Creating Service" +cat </etc/systemd/system/scraparr.service +[Unit] +Description=Scraparr +Wants=network-online.target +After=network.target + +[Service] +Type=simple +WorkingDirectory=/opt/scraparr/src +ExecStart=/opt/scraparr/.venv/bin/python -m scraparr.scraparr +Restart=always + +[Install] +WantedBy=multi-user.target +EOF +systemctl daemon-reload +systemctl enable -q --now scraparr +msg_ok "Configured Service" + +motd_ssh +customize + +msg_info "Cleaning up" +$STD apt-get -y autoremove +$STD apt-get -y autoclean +msg_ok "Cleaned" diff --git a/install/wallabag-install.sh b/install/wallabag-install.sh index b9f1c5d7..351e8537 100644 --- a/install/wallabag-install.sh +++ b/install/wallabag-install.sh @@ -14,52 +14,46 @@ update_os msg_info "Installing Dependencies (Patience)" $STD apt-get install -y \ - curl \ - git \ - unzip \ - sudo \ - make \ - php8.2 \ - php8.2-{cli,common,bcmath,intl,fpm,tidy,xml,mysql,mbstring,zip,gd,curl} \ - composer \ - apache2 \ - libapache2-mod-php \ - redis \ - mariadb-server + make \ + apache2 \ + libapache2-mod-php \ + redis msg_ok "Installed Dependencies" +setup_mariadb +PHP_VERSION="8.3" PHP_APACHE="YES" PHP_FPM="YES" PHP_MODULE="bcmath,bz2,cli,exif,common,curl,tidy,fpm,gd,intl,mbstring,xml,mysql,zip" setup_php +setup_composer + msg_info "Setting up Database" DB_NAME=wallabag_db DB_USER=wallabag DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13) SECRET_KEY="$(openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | cut -c1-32)" -$STD mysql -u root -e "CREATE DATABASE $DB_NAME;" -$STD mysql -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';" -$STD mysql -u root -e "GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;" +$STD mariadb -u root -e "CREATE DATABASE $DB_NAME;" +$STD mariadb -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';" +$STD mariadb -u root -e "GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;" { - echo "Wallabag Credentials" - echo "Database User: $DB_USER" - echo "Database Password: $DB_PASS" - echo "Database Name: $DB_NAME" -} >> ~/wallabag.creds + echo "Wallabag Credentials" + echo "Database User: $DB_USER" + echo "Database Password: $DB_PASS" + echo "Database Name: $DB_NAME" +} >>~/wallabag.creds msg_ok "Set up Database" +fetch_and_deploy_gh_release "wallabag" "wallabag/wallabag" "prebuild" "latest" "/opt/wallabag" "wallabag-*.tar.gz" + msg_info "Installing Wallabag (Patience)" -RELEASE=$(curl -s https://api.github.com/repos/wallabag/wallabag/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }') -wget -q "https://github.com/wallabag/wallabag/archive/refs/tags/${RELEASE}.zip" -unzip -q ${RELEASE}.zip -mv wallabag-${RELEASE} /opt/wallabag cd /opt/wallabag useradd -d /opt/wallabag -s /bin/bash -M wallabag chown -R wallabag:wallabag /opt/wallabag mv /opt/wallabag/app/config/parameters.yml.dist /opt/wallabag/app/config/parameters.yml sed -i \ - -e 's|database_name: wallabag|database_name: wallabag_db|' \ - -e 's|database_port: ~|database_port: 3306|' \ - -e 's|database_user: root|database_user: wallabag|' \ - -e 's|database_password: ~|database_password: '"$DB_PASS"'|' \ - -e 's|secret: .*|secret: '"$SECRET_KEY"'|' \ - /opt/wallabag/app/config/parameters.yml + -e 's|database_name: wallabag|database_name: wallabag_db|' \ + -e 's|database_port: ~|database_port: 3306|' \ + -e 's|database_user: root|database_user: wallabag|' \ + -e 's|database_password: ~|database_password: '"$DB_PASS"'|' \ + -e 's|secret: .*|secret: '"$SECRET_KEY"'|' \ + /opt/wallabag/app/config/parameters.yml export COMPOSER_ALLOW_SUPERUSER=1 sudo -u wallabag make install --no-interaction @@ -72,7 +66,7 @@ msg_info "Setting up Virtual Host" cat </etc/nginx/conf.d/wallabag.conf server { root /opt/wallabag/web; - server_name $IPADDRESS; + server_name $IPADDRESS; location / { # try to serve file directly, fallback to app.php diff --git a/misc/api.func.bak b/misc/backup_07052025/api.func.bak similarity index 100% rename from misc/api.func.bak rename to misc/backup_07052025/api.func.bak diff --git a/misc/backup.func b/misc/backup_07052025/backup.func similarity index 100% rename from misc/backup.func rename to misc/backup_07052025/backup.func diff --git a/misc/build.func b/misc/build.func index 136b3de5..730266ae 100644 --- a/misc/build.func +++ b/misc/build.func @@ -186,92 +186,92 @@ ssh_check() { fi } -select_storage() { - local CLASS=$1 CONTENT CONTENT_LABEL - case $CLASS in - container) - CONTENT='rootdir' - CONTENT_LABEL='Container' - ;; - template) - CONTENT='vztmpl' - CONTENT_LABEL='Template' - ;; - iso) - CONTENT='iso' - CONTENT_LABEL='ISO image' - ;; - images) - CONTENT='images' - CONTENT_LABEL='VM Disk image' - ;; - backup) - CONTENT='backup' - CONTENT_LABEL='Backup' - ;; - snippets) - CONTENT='snippets' - CONTENT_LABEL='Snippets' - ;; - *) - msg_error "Invalid storage class '$CLASS'." - exit 201 - ;; - esac +# select_storage() { +# local CLASS=$1 CONTENT CONTENT_LABEL +# case $CLASS in +# container) +# CONTENT='rootdir' +# CONTENT_LABEL='Container' +# ;; +# template) +# CONTENT='vztmpl' +# CONTENT_LABEL='Template' +# ;; +# iso) +# CONTENT='iso' +# CONTENT_LABEL='ISO image' +# ;; +# images) +# CONTENT='images' +# CONTENT_LABEL='VM Disk image' +# ;; +# backup) +# CONTENT='backup' +# CONTENT_LABEL='Backup' +# ;; +# snippets) +# CONTENT='snippets' +# CONTENT_LABEL='Snippets' +# ;; +# *) +# msg_error "Invalid storage class '$CLASS'." +# exit 201 +# ;; +# esac - command -v whiptail >/dev/null || { - msg_error "whiptail missing." - exit 220 - } - command -v numfmt >/dev/null || { - msg_error "numfmt missing." - exit 221 - } +# command -v whiptail >/dev/null || { +# msg_error "whiptail missing." +# exit 220 +# } +# command -v numfmt >/dev/null || { +# msg_error "numfmt missing." +# exit 221 +# } - local -a MENU - while read -r line; do - local TAG=$(echo "$line" | awk '{print $1}') - local TYPE=$(echo "$line" | awk '{printf "%-10s", $2}') - local FREE=$(echo "$line" | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf "%9sB", $6}') - MENU+=("$TAG" "Type: $TYPE Free: $FREE" "OFF") - done < <(pvesm status -content "$CONTENT" | awk 'NR>1') +# local -a MENU +# while read -r line; do +# local TAG=$(echo "$line" | awk '{print $1}') +# local TYPE=$(echo "$line" | awk '{printf "%-10s", $2}') +# local FREE=$(echo "$line" | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf "%9sB", $6}') +# MENU+=("$TAG" "Type: $TYPE Free: $FREE" "OFF") +# done < <(pvesm status -content "$CONTENT" | awk 'NR>1') - if [ ${#MENU[@]} -eq 0 ]; then - msg_error "No storage found for content type '$CONTENT'." - exit 203 - fi +# if [ ${#MENU[@]} -eq 0 ]; then +# msg_error "No storage found for content type '$CONTENT'." +# exit 203 +# fi - if [ $((${#MENU[@]} / 3)) -eq 1 ]; then - echo "${MENU[0]}" - return - fi +# if [ $((${#MENU[@]} / 3)) -eq 1 ]; then +# echo "${MENU[0]}" +# return +# fi - local STORAGE - STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \ - "Which storage pool for ${CONTENT_LABEL,,}?\n(Spacebar to select)" \ - 16 70 6 "${MENU[@]}" 3>&1 1>&2 2>&3) || { - msg_error "Storage selection cancelled by user." - exit 202 - } - echo "$STORAGE" -} +# local STORAGE +# STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \ +# "Which storage pool for ${CONTENT_LABEL,,}?\n(Spacebar to select)" \ +# 16 70 6 "${MENU[@]}" 3>&1 1>&2 2>&3) || { +# msg_error "Storage selection cancelled by user." +# exit 202 +# } +# echo "$STORAGE" +# } -manage_default_storage() { - local file="/usr/local/community-scripts/default_storage" - mkdir -p /usr/local/community-scripts +# manage_default_storage() { +# local file="/usr/local/community-scripts/default_storage" +# mkdir -p /usr/local/community-scripts - local tmpl=$(select_storage template) - local cont=$(select_storage container) +# local tmpl=$(select_storage template) +# local cont=$(select_storage container) - cat <"$file" -TEMPLATE_STORAGE=$tmpl -CONTAINER_STORAGE=$cont -EOF +# cat <"$file" +# TEMPLATE_STORAGE=$tmpl +# CONTAINER_STORAGE=$cont +# EOF - msg_ok "Default Storage set: Template=${BL}$tmpl${CL} ${GN}|${CL} Container=${BL}$cont${CL}" - whiptail --backtitle "[dev] Proxmox VE Helper Scripts" \ - --msgbox "Default Storage set:\n\nTemplate: $tmpl\nContainer: $cont" 10 58 -} +# msg_ok "Default Storage set: Template=${BL}$tmpl${CL} ${GN}|${CL} Container=${BL}$cont${CL}" +# whiptail --backtitle "[dev] Proxmox VE Helper Scripts" \ +# --msgbox "Default Storage set:\n\nTemplate: $tmpl\nContainer: $cont" 10 58 +# } base_settings() { # Default Settings @@ -333,13 +333,13 @@ write_config() { CT_TYPE="${CT_TYPE}" DISK_SIZE="${DISK_SIZE}" -CORE_COUNT="${DISK_SIZE}" +CORE_COUNT="${CORE_COUNT}" RAM_SIZE="${RAM_SIZE}" HN="${HN}" BRG="${BRG}" APT_CACHER_IP="${APT_CACHER_IP:-none}" DISABLEIP6="${DISABLEIP6}" -PW="${PW:-none}" +PW='${PW:-none}' SSH="${SSH}" SSH_AUTHORIZED_KEY="${SSH_AUTHORIZED_KEY}" VERBOSE="${VERBOSE}" @@ -351,6 +351,7 @@ SD="${SD:-none}" MAC="${MAC:-none}" NS="${NS:-none}" NET="${NET}" +FUSE="${ENABLE_FUSE}" EOF echo -e "${INFO}${BOLD}${GN}Writing configuration to ${FILEPATH}${CL}" @@ -364,7 +365,7 @@ EOF CT_TYPE="${CT_TYPE}" DISK_SIZE="${DISK_SIZE}" -CORE_COUNT="${DISK_SIZE}" +CORE_COUNT="${CORE_COUNT}" RAM_SIZE="${RAM_SIZE}" HN="${HN}" BRG="${BRG}" @@ -382,6 +383,7 @@ SD="${SD:-none}" MAC="${MAC:-none}" NS="${NS:-none}" NET="${NET}" +FUSE="${ENABLE_FUSE}" EOF echo -e "${INFO}${BOLD}${GN}Writing configuration to ${FILEPATH}${CL}" @@ -402,9 +404,11 @@ echo_default() { # Output the selected values with icons echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}${CT_ID}${CL}" - echo -e "${OS}${BOLD}${DGN}Operating System: $var_os | Version: $var_version${CL}" + echo -e "${OS}${BOLD}${DGN}Operating System: ${BGN}$var_os ($var_version)${CL}" echo -e "${CONTAINERTYPE}${BOLD}${DGN}Container Type: ${BGN}$CT_TYPE_DESC${CL}" - echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB | ${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}${CORE_COUNT} | ${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}" + echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}" + echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}${CORE_COUNT}${CL}" + echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}" if [ "$VERB" == "yes" ]; then echo -e "${SEARCH}${BOLD}${DGN}Verbose Mode: ${BGN}Enabled${CL}" fi @@ -861,12 +865,12 @@ advanced_settings() { echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}" fi - # if (whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --defaultno --title "FUSE Support" --yesno "Enable FUSE support?\nRequired for tools like rclone, mergerfs, AppImage, etc." 10 58); then - # ENABLE_FUSE="yes" - # else - # ENABLE_FUSE="no" - # fi - # echo -e "${FUSE}${BOLD}${DGN}Enable FUSE Support: ${BGN}$ENABLE_FUSE${CL}" + if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "FUSE Support" --yesno "Enable FUSE support?\nRequired for tools like rclone, mergerfs, AppImage, etc." 10 58); then + ENABLE_FUSE="yes" + else + ENABLE_FUSE="no" + fi + echo -e "${FUSE}${BOLD}${DGN}Enable FUSE Support: ${BGN}$ENABLE_FUSE${CL}" if (whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --defaultno --title "VERBOSE MODE" --yesno "Enable Verbose Mode?" 10 58); then VERBOSE="yes" @@ -1195,12 +1199,10 @@ build_container() { -unprivileged $CT_TYPE $PW " - # This executes create_lxc.sh and creates the container and .conf file - CREATE_CMD="bash -c \"\$(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/create_lxc.sh)\"" - eval "$CREATE_CMD" + bash -c "$(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/create_lxc.sh)" RET=$? if [[ $RET -ne 0 ]]; then - msg_error "in line $LINENO: exit code $RET: while executing command $CREATE_CMD" + msg_error "rny: in line $LINENO: exit code $RET: while executing create_lxc.sh" exit $RET fi @@ -1273,21 +1275,24 @@ EOF' pct exec "$CTID" -- ash -c "apk add bash newt curl openssh nano mc ncurses >/dev/null" else sleep 3 - # Set locale and timezone before update + pct exec "$CTID" -- bash -c "sed -i '/$LANG/ s/^# //' /etc/locale.gen" pct exec "$CTID" -- bash -c "locale_line=\$(grep -v '^#' /etc/locale.gen | grep -E '^[a-zA-Z]' | awk '{print \$1}' | head -n 1) && \ echo LANG=\$locale_line >/etc/default/locale && \ locale-gen >/dev/null && \ export LANG=\$locale_line" - pct exec "$CTID" -- bash -c "echo $tz >/etc/timezone && ln -sf /usr/share/zoneinfo/$tz /etc/localtime" + if pct exec "$CTID" -- test -e "/usr/share/zoneinfo/$tz"; then + pct exec "$CTID" -- bash -c "echo $tz >/etc/timezone && ln -sf /usr/share/zoneinfo/$tz /etc/localtime" + else + msg_info "Skipping timezone setup – zone '$tz' not found in container" + fi - # Install curl pct exec "$CTID" -- bash -c "apt-get update >/dev/null && apt-get install -y sudo curl mc gnupg2 >/dev/null" fi msg_ok "Customized LXC Container" - lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/install/$var_install.sh)" $? + lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/install/"$var_install".sh)" $? } # This function sets the description of the container. diff --git a/misc/core.func b/misc/core.func index b4ad2fa5..6a14a886 100644 --- a/misc/core.func +++ b/misc/core.func @@ -9,21 +9,21 @@ # } # fi -trap 'on_error $? $LINENO' ERR -trap 'on_exit' EXIT -trap 'on_interrupt' INT -trap 'on_terminate' TERM +# trap 'on_error $? $LINENO' ERR +# trap 'on_exit' EXIT +# trap 'on_interrupt' INT +# trap 'on_terminate' TERM -if ! declare -f wait_for >/dev/null; then - wait_for() { - true - } -fi +# if ! declare -f wait_for >/dev/null; then +# wait_for() { +# true +# } +# fi -declare -A MSG_INFO_SHOWN=() -SPINNER_PID="" -SPINNER_ACTIVE=0 -SPINNER_MSG="" +# declare -A MSG_INFO_SHOWN=() +# SPINNER_PID="" +# SPINNER_ACTIVE=0 +# SPINNER_MSG="" # ------------------------------------------------------------------------------ # Loads core utility groups once (colors, formatting, icons, defaults). @@ -47,9 +47,9 @@ load_functions() { # Error & Signal Handling – robust, universal, subshell-safe # ============================================================================ -_stop_spinner_on_error() { - [[ -n "${SPINNER_PID:-}" ]] && kill "$SPINNER_PID" 2>/dev/null && wait "$SPINNER_PID" 2>/dev/null || true -} +# _stop_spinner_on_error() { +# [[ -n "${SPINNER_PID:-}" ]] && kill "$SPINNER_PID" 2>/dev/null && wait "$SPINNER_PID" 2>/dev/null || true +# } _tool_error_hint() { local cmd="$1" @@ -89,44 +89,39 @@ _tool_error_hint() { esac } -on_error() { - local code="$?" - local line="${BASH_LINENO[0]:-unknown}" - local cmd="${BASH_COMMAND:-unknown}" +# on_error() { +# local code="$?" +# local line="${BASH_LINENO[0]:-unknown}" +# local cmd="${BASH_COMMAND:-unknown}" - # Signalcode unterdrücken, falls INT/TERM kommt - [[ "$code" == "130" || "$code" == "143" ]] && return +# # Signalcode unterdrücken, falls INT/TERM kommt +# [[ "$code" == "130" || "$code" == "143" ]] && return - _stop_spinner_on_error - msg_error "Script failed at line $line with exit code $code: $cmd" - exit "$code" -} +# _stop_spinner_on_error +# msg_error "Script failed at line $line with exit code $code: $cmd" +# exit "$code" +# } -on_exit() { - _stop_spinner_on_error - [[ "${VERBOSE:-no}" == "yes" ]] && msg_info "Script exited cleanly" -} +# on_exit() { +# _stop_spinner_on_error +# [[ "${VERBOSE:-no}" == "yes" ]] && msg_info "Script exited cleanly" +# } -on_interrupt() { - _stop_spinner_on_error - msg_error "Interrupted by user (CTRL+C)" - exit 130 -} +# on_interrupt() { +# _stop_spinner_on_error +# msg_error "Interrupted by user (CTRL+C)" +# exit 130 +# } -on_terminate() { - _stop_spinner_on_error - msg_error "Terminated by signal (SIGTERM)" - exit 143 -} +# on_terminate() { +# _stop_spinner_on_error +# msg_error "Terminated by signal (SIGTERM)" +# exit 143 +# } catch_errors() { - trap 'on_error' ERR - trap 'on_exit' EXIT - trap 'on_interrupt' INT - trap 'on_terminate' TERM - set -Eeuo pipefail - shopt -s inherit_errexit + trap 'error_handler $LINENO "$BASH_COMMAND"' ERR } # ------------------------------------------------------------------------------ @@ -143,6 +138,13 @@ color() { CL=$(echo "\033[m") } +# Special for spinner and colorized output via printf +color_spinner() { + CS_YW=$'\033[33m' + CS_YWB=$'\033[93m' + CS_CL=$'\033[m' +} + # ------------------------------------------------------------------------------ # Defines formatting helpers like tab, bold, and line reset sequences. # ------------------------------------------------------------------------------ @@ -363,149 +365,215 @@ fatal() { kill -INT $$ } -# Ensure POSIX compatibility across Alpine and Debian/Ubuntu -# === Spinner Start === -# Trap cleanup on various signals -trap 'cleanup_spinner' EXIT INT TERM HUP +# # Ensure POSIX compatibility across Alpine and Debian/Ubuntu +# # === Spinner Start === +# # Trap cleanup on various signals +# trap 'cleanup_spinner' EXIT INT TERM HUP -spinner_frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏') +# spinner_frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏') -# === Spinner Start === -start_spinner() { - local msg="$1" - local spin_i=0 - local interval=0.1 +# # === Spinner Start === +# start_spinner() { +# local msg="$1" +# local spin_i=0 +# local interval=0.1 - stop_spinner - SPINNER_MSG="$msg" - SPINNER_ACTIVE=1 +# stop_spinner +# SPINNER_MSG="$msg" +# SPINNER_ACTIVE=1 - { - while [[ "$SPINNER_ACTIVE" -eq 1 ]]; do - if [[ -t 2 ]]; then - printf "\r\e[2K%s %b" "${TAB}${spinner_frames[spin_i]}${TAB}" "${YW}${SPINNER_MSG}${CL}" >&2 - else - printf "%s...\n" "$SPINNER_MSG" >&2 - break - fi - spin_i=$(((spin_i + 1) % ${#spinner_frames[@]})) - sleep "$interval" - done - } & +# { +# while [[ "$SPINNER_ACTIVE" -eq 1 ]]; do +# if [[ -t 2 ]]; then +# printf "\r\e[2K%s %b" "${TAB}${spinner_frames[spin_i]}${TAB}" "${YW}${SPINNER_MSG}${CL}" >&2 +# else +# printf "%s...\n" "$SPINNER_MSG" >&2 +# break +# fi +# spin_i=$(((spin_i + 1) % ${#spinner_frames[@]})) +# sleep "$interval" +# done +# } & - local pid=$! - if ps -p "$pid" >/dev/null 2>&1; then - SPINNER_PID="$pid" - else - SPINNER_ACTIVE=0 - SPINNER_PID="" - fi +# local pid=$! +# if ps -p "$pid" >/dev/null 2>&1; then +# SPINNER_PID="$pid" +# else +# SPINNER_ACTIVE=0 +# SPINNER_PID="" +# fi +# } + +# # === Spinner Stop === +# stop_spinner() { +# if [[ "$SPINNER_ACTIVE" -eq 1 && -n "$SPINNER_PID" ]]; then +# SPINNER_ACTIVE=0 + +# if kill -0 "$SPINNER_PID" 2>/dev/null; then +# kill "$SPINNER_PID" 2>/dev/null || true +# for _ in $(seq 1 10); do +# sleep 0.05 +# kill -0 "$SPINNER_PID" 2>/dev/null || break +# done +# fi + +# if [[ "$SPINNER_PID" =~ ^[0-9]+$ ]]; then +# ps -p "$SPINNER_PID" -o pid= >/dev/null 2>&1 && wait "$SPINNER_PID" 2>/dev/null || true +# fi + +# printf "\r\e[2K" >&2 +# SPINNER_PID="" +# fi +# } + +# cleanup_spinner() { +# stop_spinner +# } + +# msg_info() { +# local msg="$1" +# [[ -z "$msg" || -n "${MSG_INFO_SHOWN["$msg"]+x}" ]] && return +# MSG_INFO_SHOWN["$msg"]=1 + +# stop_spinner +# echo -e "OS: ${var_os:-}" +# if [[ "${VERBOSE:-no}" != "no" || "${var_os:-}" == "alpine" || ! -t 2 ]]; then +# printf "\r\e[2K%s %b\n" "$HOURGLASS" "${YW}${msg}${CL}" >&2 +# else +# start_spinner "$msg" +# fi +# } + +spinner() { + local chars=(⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏) + local i=0 + while true; do + local index=$((i++ % ${#chars[@]})) + printf "\r\033[2K%s %b" "${CS_YWB}${chars[$index]}${CS_CL}" "${CS_YWB}${SPINNER_MSG:-}${CS_CL}" + sleep 0.1 + done } -# === Spinner Stop === stop_spinner() { - if [[ "$SPINNER_ACTIVE" -eq 1 && -n "$SPINNER_PID" ]]; then - SPINNER_ACTIVE=0 + local pid="${SPINNER_PID:-}" + [[ -z "$pid" && -f /tmp/.spinner.pid ]] && pid=$(/dev/null; then - kill "$SPINNER_PID" 2>/dev/null || true - for _ in $(seq 1 10); do - sleep 0.05 - kill -0 "$SPINNER_PID" 2>/dev/null || break - done + if [[ -n "$pid" && "$pid" =~ ^[0-9]+$ ]]; then + if kill "$pid" 2>/dev/null; then + sleep 0.05 + kill -9 "$pid" 2>/dev/null || true + wait "$pid" 2>/dev/null || true fi - - if [[ "$SPINNER_PID" =~ ^[0-9]+$ ]]; then - ps -p "$SPINNER_PID" -o pid= >/dev/null 2>&1 && wait "$SPINNER_PID" 2>/dev/null || true - fi - - printf "\r\e[2K" >&2 - SPINNER_PID="" + rm -f /tmp/.spinner.pid + unset SPINNER_PID fi -} -cleanup_spinner() { - stop_spinner + stty sane 2>/dev/null + #printf "\r\033[K\e[?25h\n" } msg_info() { local msg="$1" - [[ -z "$msg" || -n "${MSG_INFO_SHOWN["$msg"]+x}" ]] && return - MSG_INFO_SHOWN["$msg"]=1 - - stop_spinner - - if [[ "${VERBOSE:-no}" != "no" || "${var_os:-}" == "alpine" || ! -t 2 ]]; then - printf "\r\e[2K%s %b\n" "$HOURGLASS" "${YW}${msg}${CL}" >&2 - else - start_spinner "$msg" - fi + SPINNER_MSG="$msg" + color_spinner + spinner & + SPINNER_PID=$! + echo "$SPINNER_PID" >/tmp/.spinner.pid + disown "$SPINNER_PID" 2>/dev/null || true } msg_ok() { - local msg="$1" - [[ -z "$msg" ]] && return stop_spinner - printf "\r\e[2K%s %b\n" "$CM" "${GN}${msg}${CL}" >&2 - if declare -p MSG_INFO_SHOWN &>/dev/null && [[ "$(declare -p MSG_INFO_SHOWN 2>/dev/null)" =~ "declare -A" ]]; then - unset MSG_INFO_SHOWN["$msg"] - fi + local msg="$1" + echo -e "${BFR:-} ${CM:-✔️} ${GN}${msg}${CL}" } msg_error() { - local msg="$1" - [[ -z "$msg" ]] && return stop_spinner - printf "\r\e[2K%s %b\n" "$CROSS" "${RD}${msg}${CL}" >&2 + local msg="$1" + echo -e "${BFR:-} ${CROSS:-✖️} ${RD}${msg}${CL}" } msg_warn() { - local msg="$1" - [[ -z "$msg" ]] && return stop_spinner - printf "\r\e[2K%s %b\n" "$INFO" "${YWB}${msg}${CL}" >&2 - if declare -p MSG_INFO_SHOWN &>/dev/null && [[ "$(declare -p MSG_INFO_SHOWN 2>/dev/null)" =~ "declare -A" ]]; then - unset MSG_INFO_SHOWN["$msg"] - fi + local msg="$1" + echo -e "${BFR:-} ${INFO:-ℹ️} ${YWB}${msg}${CL}" } msg_custom() { local symbol="${1:-"[*]"}" - local color="${2:-"\e[36m"}" # Default: Cyan + local color="${2:-"\e[36m"}" local msg="${3:-}" - [[ -z "$msg" ]] && return - stop_spinner 2>/dev/null || true - printf "\r\e[2K%s %b\n" "$symbol" "${color}${msg}${CL:-\e[0m}" >&2 + stop_spinner + echo -e "${BFR:-} ${symbol} ${color}${msg}${CL:-\e[0m}" + printf "\r\033[K\e[?25h\n" } -msg_progress() { - local current="$1" - local total="$2" - local label="$3" - local width=40 - local filled percent bar empty - local fill_char="#" - local empty_char="-" +# msg_ok() { +# local msg="$1" +# [[ -z "$msg" ]] && return +# stop_spinner +# printf "\r\e[2K%s %b\n" "$CM" "${GN}${msg}${CL}" >&2 +# if declare -p MSG_INFO_SHOWN &>/dev/null && [[ "$(declare -p MSG_INFO_SHOWN 2>/dev/null)" =~ "declare -A" ]]; then +# unset MSG_INFO_SHOWN["$msg"] +# fi +# } - if ! [[ "$current" =~ ^[0-9]+$ ]] || ! [[ "$total" =~ ^[0-9]+$ ]] || [[ "$total" -eq 0 ]]; then - printf "\r\e[2K%s %b\n" "$CROSS" "${RD}Invalid progress input${CL}" >&2 - return - fi +# msg_error() { +# local msg="$1" +# [[ -z "$msg" ]] && return +# stop_spinner +# printf "\r\e[2K%s %b\n" "$CROSS" "${RD}${msg}${CL}" >&2 +# } - percent=$(((current * 100) / total)) - filled=$(((current * width) / total)) - empty=$((width - filled)) +# msg_warn() { +# local msg="$1" +# [[ -z "$msg" ]] && return +# stop_spinner +# printf "\r\e[2K%s %b\n" "$INFO" "${YWB}${msg}${CL}" >&2 +# if declare -p MSG_INFO_SHOWN &>/dev/null && [[ "$(declare -p MSG_INFO_SHOWN 2>/dev/null)" =~ "declare -A" ]]; then +# unset MSG_INFO_SHOWN["$msg"] +# fi +# } - bar=$(printf "%${filled}s" | tr ' ' "$fill_char") - bar+=$(printf "%${empty}s" | tr ' ' "$empty_char") +# msg_custom() { +# local symbol="${1:-"[*]"}" +# local color="${2:-"\e[36m"}" # Default: Cyan +# local msg="${3:-}" - printf "\r\e[2K%s [%s] %3d%% %s" "${TAB}" "$bar" "$percent" "$label" >&2 +# [[ -z "$msg" ]] && return +# stop_spinner 2>/dev/null || true +# printf "\r\e[2K%s %b\n" "$symbol" "${color}${msg}${CL:-\e[0m}" >&2 +# } - if [[ "$current" -eq "$total" ]]; then - printf "\n" >&2 - fi -} +# msg_progress() { +# local current="$1" +# local total="$2" +# local label="$3" +# local width=40 +# local filled percent bar empty +# local fill_char="#" +# local empty_char="-" + +# if ! [[ "$current" =~ ^[0-9]+$ ]] || ! [[ "$total" =~ ^[0-9]+$ ]] || [[ "$total" -eq 0 ]]; then +# printf "\r\e[2K%s %b\n" "$CROSS" "${RD}Invalid progress input${CL}" >&2 +# return +# fi + +# percent=$(((current * 100) / total)) +# filled=$(((current * width) / total)) +# empty=$((width - filled)) + +# bar=$(printf "%${filled}s" | tr ' ' "$fill_char") +# bar+=$(printf "%${empty}s" | tr ' ' "$empty_char") + +# printf "\r\e[2K%s [%s] %3d%% %s" "${TAB}" "$bar" "$percent" "$label" >&2 + +# if [[ "$current" -eq "$total" ]]; then +# printf "\n" >&2 +# fi +# } run_container_safe() { local ct="$1" @@ -555,3 +623,5 @@ check_or_create_swap() { return 1 fi } + +trap 'stop_spinner' EXIT INT TERM diff --git a/misc/create_lxc.sh b/misc/create_lxc.sh index 81520d0a..98b4d68e 100644 --- a/misc/create_lxc.sh +++ b/misc/create_lxc.sh @@ -27,7 +27,7 @@ trap on_terminate TERM function on_exit() { local exit_code="$?" - [[ -n "${lockfile:-}" ]] + [[ -n "${lockfile:-}" && -e "$lockfile" ]] && rm -f "$lockfile" exit "$exit_code" } @@ -50,18 +50,30 @@ function on_terminate() { exit 143 } +function check_storage_support() { + local CONTENT="$1" + local -a VALID_STORAGES=() + + while IFS= read -r line; do + local STORAGE=$(awk '{print $1}' <<<"$line") + [[ "$STORAGE" == "storage" || -z "$STORAGE" ]] && continue + VALID_STORAGES+=("$STORAGE") + done < <(pvesm status -content "$CONTENT" 2>/dev/null | awk 'NR>1') + + [[ ${#VALID_STORAGES[@]} -gt 0 ]] +} + # This checks for the presence of valid Container Storage and Template Storage locations msg_info "Validating Storage" -VALIDCT=$(pvesm status -content rootdir | awk 'NR>1') -if [ -z "$VALIDCT" ]; then - msg_error "Unable to detect a valid Container Storage location." +if ! check_storage_support "rootdir"; then + msg_error "No valid storage found for 'rootdir' (Container)." exit 1 fi -VALIDTMP=$(pvesm status -content vztmpl | awk 'NR>1') -if [ -z "$VALIDTMP" ]; then - msg_error "Unable to detect a valid Template Storage location." +if ! check_storage_support "vztmpl"; then + msg_error "No valid storage found for 'vztmpl' (Template)." exit 1 fi +msg_ok "Storage types rootdir and vztmpl are supported." # This function is used to select the storage class and determine the corresponding storage content type and label. function select_storage() { @@ -107,12 +119,19 @@ function select_storage() { } local -a MENU - while read -r line; do - local TAG=$(echo $line | awk '{print $1}') - local TYPE=$(echo $line | awk '{printf "%-10s", $2}') - local FREE=$(echo $line | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf( "%9sB", $6)}') - MENU+=("$TAG" "Type: $TYPE Free: $FREE " "OFF") - done < <(pvesm status -content $CONTENT | awk 'NR>1') + local -A STORAGE_MAP=() + local COL_WIDTH=0 + + while read -r TAG TYPE _ TOTAL USED FREE _; do + [[ -n "$TAG" && -n "$TYPE" ]] || continue + local DISPLAY="${TAG} (${TYPE})" + local USED_FMT=$(numfmt --to=iec --from-unit=K --format %.1f <<<"$USED") + local FREE_FMT=$(numfmt --to=iec --from-unit=K --format %.1f <<<"$FREE") + local INFO="Free: ${FREE_FMT}B Used: ${USED_FMT}B" + STORAGE_MAP["$DISPLAY"]="$TAG" # Map DISPLAY to actual TAG + MENU+=("$DISPLAY" "$INFO" "OFF") + ((${#DISPLAY} > COL_WIDTH)) && COL_WIDTH=${#DISPLAY} + done < <(pvesm status -content "$CONTENT" | awk 'NR>1') if [ ${#MENU[@]} -eq 0 ]; then msg_error "No storage found for content type '$CONTENT'." @@ -120,18 +139,32 @@ function select_storage() { fi if [ $((${#MENU[@]} / 3)) -eq 1 ]; then - printf "%s" "${MENU[0]}" + echo "${STORAGE_MAP[${MENU[0]}]}" return fi - local STORAGE - STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \ - "Which storage pool for ${CONTENT_LABEL,,}?\n(Spacebar to select)" \ - 16 70 6 "${MENU[@]}" 3>&1 1>&2 2>&3) || { - msg_error "Storage selection cancelled by user." - exit 202 - } - printf "%s" "$STORAGE" + local WIDTH=$((COL_WIDTH + 42)) + local DISPLAY_SELECTED="" + while true; do + DISPLAY_SELECTED=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \ + "Which storage pool for ${CONTENT_LABEL,,}?\n(Spacebar to select)" \ + 16 "$WIDTH" 6 "${MENU[@]}" 3>&1 1>&2 2>&3) || { + msg_error "Storage selection cancelled by user." + exit 202 + } + + # Validierung gegen STORAGE_MAP + if [[ -z "$DISPLAY_SELECTED" || -z "${STORAGE_MAP[$DISPLAY_SELECTED]+_}" ]]; then + whiptail --backtitle "Proxmox VE Helper Scripts" --title "Invalid Selection" \ + --msgbox "No valid storage selected. Please choose a storage pool to continue." 9 60 + continue + fi + + break + done + + echo "${STORAGE_MAP["$DISPLAY_SELECTED"]}" + } # Test if required variables are set @@ -172,10 +205,29 @@ if [[ -f "$DEFAULT_FILE" ]]; then msg_ok "Using ${BL}$CONTAINER_STORAGE${CL} ${GN}for Container Storage." fi else - TEMPLATE_STORAGE=$(select_storage template) + # TEMPLATE STORAGE SELECTION + # Template Storage + if ! TEMPLATE_STORAGE=$(select_storage template); then + [[ $? -eq 202 ]] && { + msg_error "Template Storage selection cancelled by user. Exiting." + kill -INT $$ + } + msg_error "Unexpected error during template storage selection." + exit 1 + fi msg_ok "Using ${BL}$TEMPLATE_STORAGE${CL} ${GN}for Template Storage." - CONTAINER_STORAGE=$(select_storage container) + + # Container Storage + if ! CONTAINER_STORAGE=$(select_storage container); then + [[ $? -eq 202 ]] && { + msg_error "Container Storage selection cancelled by user. Exiting." + kill -INT $$ + } + msg_error "Unexpected error during container storage selection." + exit 1 + fi msg_ok "Using ${BL}$CONTAINER_STORAGE${CL} ${GN}for Container Storage." + fi # Check free space on selected container storage diff --git a/misc/install.func b/misc/install.func index efc77be5..ddb78bc9 100644 --- a/misc/install.func +++ b/misc/install.func @@ -31,7 +31,7 @@ catch_errors() { # This function handles errors error_handler() { - source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) + source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/api.func) printf "\e[?25h" local exit_code="$?" local line_number="$1" @@ -65,7 +65,8 @@ setting_up_container() { rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED systemctl disable -q --now systemd-networkd-wait-online.service msg_ok "Set up Container OS" - msg_custom "${CM}" "${GN}" "Network Connected: ${BL}$(hostname -I)" + #msg_custom "${CM}" "${GN}" "Network Connected: ${BL}$(hostname -I)" + msg_ok "Network Connected: ${BL}$(hostname -I)" } # This function checks the network connection by pinging a known IP address and prompts the user to continue if the internet is not connected @@ -104,24 +105,24 @@ network_check() { fi # DNS resolution checks for GitHub-related domains (IPv4 and/or IPv6) - GITHUB_HOSTS=("github.com" "raw.githubusercontent.com" "api.github.com" "git.community-scripts.org") - GITHUB_STATUS="GitHub DNS:" + GIT_HOSTS=("github.com" "raw.githubusercontent.com" "api.github.com" "git.community-scripts.org") + GIT_STATUS="Git DNS:" DNS_FAILED=false - for HOST in "${GITHUB_HOSTS[@]}"; do + for HOST in "${GIT_HOSTS[@]}"; do RESOLVEDIP=$(getent hosts "$HOST" | awk '{ print $1 }' | grep -E '(^([0-9]{1,3}\.){3}[0-9]{1,3}$)|(^[a-fA-F0-9:]+$)' | head -n1) if [[ -z "$RESOLVEDIP" ]]; then - GITHUB_STATUS+="$HOST:($DNSFAIL)" + GIT_STATUS+="$HOST:($DNSFAIL)" DNS_FAILED=true else - GITHUB_STATUS+=" $HOST:($DNSOK)" + GIT_STATUS+=" $HOST:($DNSOK)" fi done if [[ "$DNS_FAILED" == true ]]; then - fatal "$GITHUB_STATUS" + fatal "$GIT_STATUS" else - msg_ok "$GITHUB_STATUS" + msg_ok "$GIT_STATUS" fi set -e diff --git a/misc/tools.func b/misc/tools.func index 2b4b5769..f9d4e36d 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -238,7 +238,6 @@ setup_mariadb() { msg_info "Setting up MariaDB $MARIADB_VERSION" # grab dynamic latest LTS version if [[ "$MARIADB_VERSION" == "latest" ]]; then - $STD msg_info "Resolving latest GA MariaDB version" MARIADB_VERSION=$(curl -fsSL http://mirror.mariadb.org/repo/ | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+/' | grep -vE 'rc/|rolling/' | @@ -249,7 +248,6 @@ setup_mariadb() { msg_error "Could not determine latest GA MariaDB version" return 1 fi - $STD msg_ok "Latest GA MariaDB version is $MARIADB_VERSION" fi local CURRENT_VERSION="" @@ -274,7 +272,6 @@ setup_mariadb() { $STD msg_info "Setup MariaDB $MARIADB_VERSION" fi - $STD msg_info "Setting up MariaDB Repository" curl -fsSL "https://mariadb.org/mariadb_release_signing_key.asc" | gpg --dearmor -o /etc/apt/trusted.gpg.d/mariadb.gpg @@ -824,19 +821,30 @@ function fetch_and_deploy_gh_release() { elif [[ "$mode" == "binary" ]]; then local arch arch=$(dpkg --print-architecture 2>/dev/null || uname -m) - [[ "$arch" == "x86_64" ]] && arch="x86_64" + [[ "$arch" == "x86_64" ]] && arch="amd64" [[ "$arch" == "aarch64" ]] && arch="arm64" local assets url_match="" assets=$(echo "$json" | jq -r '.assets[].browser_download_url') - for u in $assets; do - if [[ "$u" =~ ($arch|amd64|x86_64|aarch64|arm64).*\.deb$ ]]; then - url_match="$u" - break - fi - done + # If explicit filename pattern is provided (param $6), match that first + if [[ -n "$6" ]]; then + for u in $assets; do + [[ "$u" =~ $6 || "$u" == *"$6" ]] && url_match="$u" && break + done + fi + # If no match via explicit pattern, fall back to architecture heuristic + if [[ -z "$url_match" ]]; then + for u in $assets; do + if [[ "$u" =~ ($arch|amd64|x86_64|aarch64|arm64).*\.deb$ ]]; then + url_match="$u" + break + fi + done + fi + + # Fallback: any .deb file if [[ -z "$url_match" ]]; then for u in $assets; do [[ "$u" =~ \.deb$ ]] && url_match="$u" && break @@ -1611,3 +1619,142 @@ function setup_imagemagick() { ensure_usr_local_bin_persist msg_ok "Setup ImageMagick $VERSION" } + +# ------------------------------------------------------------------------------ +# Installs FFmpeg from source or prebuilt binary (Debian/Ubuntu only). +# +# Description: +# - Downloads and builds FFmpeg from GitHub (https://github.com/FFmpeg/FFmpeg) +# - Supports specific version override via FFMPEG_VERSION (e.g. n7.1.1) +# - Supports build profile via FFMPEG_TYPE: +# - minimal : x264, vpx, mp3 only +# - medium : adds subtitles, fonts, opus, vorbis +# - full : adds dav1d, svt-av1, zlib, numa +# - binary : downloads static build (johnvansickle.com) +# - Defaults to latest stable version and full feature set +# +# Notes: +# - Requires: curl, jq, build-essential, and matching codec libraries +# - Result is installed to /usr/local/bin/ffmpeg +# ------------------------------------------------------------------------------ + +function setup_ffmpeg() { + local TMP_DIR + TMP_DIR=$(mktemp -d) + local GITHUB_REPO="FFmpeg/FFmpeg" + local VERSION="${FFMPEG_VERSION:-}" + local TYPE="${FFMPEG_TYPE:-full}" + local BIN_PATH="/usr/local/bin/ffmpeg" + + # Binary fallback mode + if [[ "$TYPE" == "binary" ]]; then + msg_info "Installing FFmpeg (static binary)" + curl -fsSL https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz -o "$TMP_DIR/ffmpeg.tar.xz" + tar -xf "$TMP_DIR/ffmpeg.tar.xz" -C "$TMP_DIR" + local EXTRACTED_DIR + EXTRACTED_DIR=$(find "$TMP_DIR" -maxdepth 1 -type d -name "ffmpeg-*") + cp "$EXTRACTED_DIR/ffmpeg" "$BIN_PATH" + cp "$EXTRACTED_DIR/ffprobe" /usr/local/bin/ffprobe + chmod +x "$BIN_PATH" /usr/local/bin/ffprobe + rm -rf "$TMP_DIR" + msg_ok "Installed FFmpeg binary ($($BIN_PATH -version | head -n1))" + return + fi + + # Auto-detect latest stable version if none specified + if [[ -z "$VERSION" ]]; then + msg_info "Fetching latest stable FFmpeg tag" + VERSION=$(curl -fsSL "https://api.github.com/repos/${GITHUB_REPO}/tags" | + jq -r '.[].name' | + grep -E '^n[0-9]+\.[0-9]+\.[0-9]+$' | # stable only + sort -V | tail -n1) + fi + + if [[ -z "$VERSION" ]]; then + msg_error "Could not determine FFmpeg version" + rm -rf "$TMP_DIR" + return 1 + fi + + msg_info "Installing FFmpeg ${VERSION} ($TYPE)" + + # Dependency selection + local DEPS=(build-essential yasm nasm pkg-config) + case "$TYPE" in + minimal) + DEPS+=(libx264-dev libvpx-dev libmp3lame-dev) + ;; + medium) + DEPS+=(libx264-dev libvpx-dev libmp3lame-dev libfreetype6-dev libass-dev libopus-dev libvorbis-dev) + ;; + full) + DEPS+=( + libx264-dev libx265-dev libvpx-dev libmp3lame-dev + libfreetype6-dev libass-dev libopus-dev libvorbis-dev + libdav1d-dev libsvtav1-dev zlib1g-dev libnuma-dev + ) + ;; + *) + msg_error "Invalid FFMPEG_TYPE: $TYPE" + rm -rf "$TMP_DIR" + return 1 + ;; + esac + + $STD apt-get update + $STD apt-get install -y "${DEPS[@]}" + + curl -fsSL "https://github.com/${GITHUB_REPO}/archive/refs/tags/${VERSION}.tar.gz" -o "$TMP_DIR/ffmpeg.tar.gz" + tar -xzf "$TMP_DIR/ffmpeg.tar.gz" -C "$TMP_DIR" + cd "$TMP_DIR/FFmpeg-"* || { + msg_error "Source extraction failed" + rm -rf "$TMP_DIR" + return 1 + } + + local args=( + --enable-gpl + --enable-shared + --enable-nonfree + --disable-static + --enable-libx264 + --enable-libvpx + --enable-libmp3lame + ) + + if [[ "$TYPE" != "minimal" ]]; then + args+=(--enable-libfreetype --enable-libass --enable-libopus --enable-libvorbis) + fi + + if [[ "$TYPE" == "full" ]]; then + args+=(--enable-libx265 --enable-libdav1d --enable-zlib) + fi + + if [[ ${#args[@]} -eq 0 ]]; then + msg_error "FFmpeg configure args array is empty – aborting." + rm -rf "$TMP_DIR" + return 1 + fi + + ./configure "${args[@]}" >"$TMP_DIR/configure.log" 2>&1 || { + msg_error "FFmpeg ./configure failed (see $TMP_DIR/configure.log)" + cat "$TMP_DIR/configure.log" | tail -n 20 + rm -rf "$TMP_DIR" + return 1 + } + + $STD make -j"$(nproc)" + $STD make install + + if ! command -v ffmpeg &>/dev/null; then + msg_error "FFmpeg installation failed" + rm -rf "$TMP_DIR" + return 1 + fi + + local FINAL_VERSION + FINAL_VERSION=$(ffmpeg -version | head -n1 | awk '{print $3}') + rm -rf "$TMP_DIR" + ensure_usr_local_bin_persist + msg_ok "Setup FFmpeg $FINAL_VERSION" +} diff --git a/tools/pve/lxc-delete.sh b/tools/pve/lxc-delete.sh index 8cadfda0..85487cd2 100644 --- a/tools/pve/lxc-delete.sh +++ b/tools/pve/lxc-delete.sh @@ -40,53 +40,72 @@ CM="${TAB}✔️${TAB}${CL}" header_info echo "Loading..." -whiptail --backtitle "Proxmox VE Helper Scripts" --title "Proxmox VE LXC Deletion" --yesno "This will delete LXC containers. Proceed?" 10 58 +if ! whiptail --backtitle "Proxmox VE Helper Scripts" --title "Proxmox VE LXC Deletion" --yesno "This will delete LXC containers. Proceed?" 10 58; then + echo -e "${RD}Aborted by user.${CL}" + exit 0 +fi -NODE=$(hostname) -containers=$(pct list | tail -n +2 | awk '{print $0 " " $4}') +mapfile -t containers < <(pct list | tail -n +2) -if [ -z "$containers" ]; then +if [ ${#containers[@]} -eq 0 ]; then whiptail --title "LXC Container Delete" --msgbox "No LXC containers available!" 10 60 exit 1 fi -menu_items=("ALL" "Delete ALL containers" "OFF") # Add as first option -FORMAT="%-10s %-15s %-10s" +menu_items=("ALL" "Delete ALL containers" "OFF") +FORMAT="%-10s %-10s %-10s %-10s" -while read -r container; do - container_id=$(echo $container | awk '{print $1}') - container_name=$(echo $container | awk '{print $2}') - container_status=$(echo $container | awk '{print $3}') - formatted_line=$(printf "$FORMAT" "$container_name" "$container_status") +for line in "${containers[@]}"; do + container_id=$(echo "$line" | awk '{print $1}') + container_name=$(echo "$line" | awk '{print $2}') + container_status=$(echo "$line" | awk '{print $3}') + container_os=$(echo "$line" | awk '{print $4}') + protected=$(pct config "$container_id" | awk '/^protection:/ {print $2}') + is_protected="No" + [[ "$protected" == "1" ]] && is_protected="Yes" + formatted_line=$(printf "$FORMAT" "$container_name" "$container_status" "$container_os" "$is_protected") menu_items+=("$container_id" "$formatted_line" "OFF") -done <<<"$containers" +done CHOICES=$(whiptail --title "LXC Container Delete" \ - --checklist "Select LXC containers to delete:" 25 60 13 \ + --checklist "Select LXC containers to delete:\n\nNAME STATUS OS PROTECTED" 25 70 15 \ "${menu_items[@]}" 3>&2 2>&1 1>&3) if [ -z "$CHOICES" ]; then - whiptail --title "LXC Container Delete" \ - --msgbox "No containers selected!" 10 60 + whiptail --title "LXC Container Delete" --msgbox "No containers selected!" 10 60 exit 1 fi read -p "Delete containers manually or automatically? (Default: manual) m/a: " DELETE_MODE DELETE_MODE=${DELETE_MODE:-m} - selected_ids=$(echo "$CHOICES" | tr -d '"' | tr -s ' ' '\n') -# If "ALL" is selected, override with all container IDs +# ALL ausgewählt if echo "$selected_ids" | grep -q "^ALL$"; then - selected_ids=$(echo "$containers" | awk '{print $1}') + selected_ids=$(printf '%s\n' "${containers[@]}" | awk '{print $1}') fi for container_id in $selected_ids; do - status=$(pct status $container_id) + status=$(pct status "$container_id") + protected=$(pct config "$container_id" | awk '/^protection:/ {print $2}') + is_protected="No" + [[ "$protected" == "1" ]] && is_protected="Yes" - if [ "$status" == "status: running" ]; then + if [[ "$is_protected" == "Yes" && "$DELETE_MODE" == "a" ]]; then + echo -e "${BL}[Info]${RD} Skipping protected container $container_id (auto mode).${CL}" + continue + fi + + if [[ "$status" == "status: running" ]]; then + if [[ "$is_protected" == "Yes" && "$DELETE_MODE" == "m" ]]; then + read -p "⚠️ Container $container_id is PROTECTED. Delete anyway? (y/N): " CONFIRM_PROTECTED + [[ ! "$CONFIRM_PROTECTED" =~ ^[Yy]$ ]] && { + echo -e "${BL}[Info]${RD} Skipping protected container $container_id...${CL}" + continue + } + fi echo -e "${BL}[Info]${GN} Stopping container $container_id...${CL}" - pct stop $container_id & + pct stop "$container_id" & sleep 5 echo -e "${BL}[Info]${GN} Container $container_id stopped.${CL}" fi @@ -96,15 +115,30 @@ for container_id in $selected_ids; do pct destroy "$container_id" -f & pid=$! spinner $pid - [ $? -eq 0 ] && echo "Container $container_id deleted." || whiptail --title "Error" --msgbox "Failed to delete container $container_id." 10 60 + if [ $? -eq 0 ]; then + echo "Container $container_id deleted." + else + whiptail --title "Error" --msgbox "Failed to delete container $container_id." 10 60 + fi else read -p "Delete container $container_id? (y/N): " CONFIRM if [[ "$CONFIRM" =~ ^[Yy]$ ]]; then + if [[ "$is_protected" == "Yes" ]]; then + read -p "⚠️ Container $container_id is PROTECTED. Delete anyway? (y/N): " CONFIRM_PROTECTED + [[ ! "$CONFIRM_PROTECTED" =~ ^[Yy]$ ]] && { + echo -e "${BL}[Info]${RD} Skipping protected container $container_id...${CL}" + continue + } + fi echo -e "${BL}[Info]${GN} Deleting container $container_id...${CL}" pct destroy "$container_id" -f & pid=$! spinner $pid - [ $? -eq 0 ] && echo "Container $container_id deleted." || whiptail --title "Error" --msgbox "Failed to delete container $container_id." 10 60 + if [ $? -eq 0 ]; then + echo "Container $container_id deleted." + else + whiptail --title "Error" --msgbox "Failed to delete container $container_id." 10 60 + fi else echo -e "${BL}[Info]${RD} Skipping container $container_id...${CL}" fi