mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2026-02-04 12:23:26 +01:00
Compare commits
15 Commits
fix/2fauth
...
feature/co
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de0199107b | ||
|
|
8226360700 | ||
|
|
b706775a4b | ||
|
|
2f907cc4e0 | ||
|
|
b1927d2678 | ||
|
|
a35b0fbd79 | ||
|
|
4418ed4615 | ||
|
|
19d8592104 | ||
|
|
627587c54b | ||
|
|
b36609dfd5 | ||
|
|
98dc00a1a0 | ||
|
|
ff9f0ed21d | ||
|
|
bc83a37124 | ||
|
|
e0593caa02 | ||
|
|
99e19d4422 |
10
CHANGELOG.md
10
CHANGELOG.md
@@ -772,6 +772,12 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
## 2026-02-02
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- KitchenOwl ([#11453](https://github.com/community-scripts/ProxmoxVE/pull/11453))
|
||||||
|
|
||||||
## 2026-02-01
|
## 2026-02-01
|
||||||
|
|
||||||
### 🚀 Updated Scripts
|
### 🚀 Updated Scripts
|
||||||
@@ -780,12 +786,16 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
|||||||
|
|
||||||
- #### 🐞 Bug Fixes
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- 2fauth: export PHP_VERSION for nginx config [@MickLesk](https://github.com/MickLesk) ([#11441](https://github.com/community-scripts/ProxmoxVE/pull/11441))
|
||||||
|
- Prometheus Paperless NGX Exporter: Set correct binary path in systemd unit file [@andygrunwald](https://github.com/andygrunwald) ([#11438](https://github.com/community-scripts/ProxmoxVE/pull/11438))
|
||||||
|
- tracearr: install/update new prestart script from upstream [@durzo](https://github.com/durzo) ([#11433](https://github.com/community-scripts/ProxmoxVE/pull/11433))
|
||||||
- n8n: Fix dependencies [@tremor021](https://github.com/tremor021) ([#11429](https://github.com/community-scripts/ProxmoxVE/pull/11429))
|
- n8n: Fix dependencies [@tremor021](https://github.com/tremor021) ([#11429](https://github.com/community-scripts/ProxmoxVE/pull/11429))
|
||||||
- [Hotfix] Bunkerweb update [@vhsdream](https://github.com/vhsdream) ([#11402](https://github.com/community-scripts/ProxmoxVE/pull/11402))
|
- [Hotfix] Bunkerweb update [@vhsdream](https://github.com/vhsdream) ([#11402](https://github.com/community-scripts/ProxmoxVE/pull/11402))
|
||||||
- [Hotfix] Immich: revert healthcheck feature [@vhsdream](https://github.com/vhsdream) ([#11427](https://github.com/community-scripts/ProxmoxVE/pull/11427))
|
- [Hotfix] Immich: revert healthcheck feature [@vhsdream](https://github.com/vhsdream) ([#11427](https://github.com/community-scripts/ProxmoxVE/pull/11427))
|
||||||
|
|
||||||
- #### ✨ New Features
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- tools.func: add codeberg functions & autocaliweb: migrate from GitHub to Codeberg [@MickLesk](https://github.com/MickLesk) ([#11440](https://github.com/community-scripts/ProxmoxVE/pull/11440))
|
||||||
- Immich Refactor #2 [@vhsdream](https://github.com/vhsdream) ([#11375](https://github.com/community-scripts/ProxmoxVE/pull/11375))
|
- Immich Refactor #2 [@vhsdream](https://github.com/vhsdream) ([#11375](https://github.com/community-scripts/ProxmoxVE/pull/11375))
|
||||||
|
|
||||||
- #### 🔧 Refactor
|
- #### 🔧 Refactor
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: vhsdream
|
# Author: vhsdream
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://github.com/gelbphoenix/autocaliweb
|
# Source: https://codeberg.org/gelbphoenix/autocaliweb
|
||||||
|
|
||||||
APP="Autocaliweb"
|
APP="Autocaliweb"
|
||||||
var_tags="${var_tags:-ebooks}"
|
var_tags="${var_tags:-ebooks}"
|
||||||
@@ -30,8 +30,8 @@ function update_script() {
|
|||||||
|
|
||||||
setup_uv
|
setup_uv
|
||||||
|
|
||||||
RELEASE=$(get_latest_github_release "gelbphoenix/autocaliweb")
|
RELEASE=$(get_latest_codeberg_release "gelbphoenix/autocaliweb")
|
||||||
if check_for_gh_release "autocaliweb" "gelbphoenix/autocaliweb"; then
|
if check_for_codeberg_release "autocaliweb" "gelbphoenix/autocaliweb"; then
|
||||||
msg_info "Stopping Services"
|
msg_info "Stopping Services"
|
||||||
systemctl stop autocaliweb metadata-change-detector acw-ingest-service acw-auto-zipper
|
systemctl stop autocaliweb metadata-change-detector acw-ingest-service acw-auto-zipper
|
||||||
msg_ok "Stopped Services"
|
msg_ok "Stopped Services"
|
||||||
@@ -39,7 +39,7 @@ function update_script() {
|
|||||||
INSTALL_DIR="/opt/autocaliweb"
|
INSTALL_DIR="/opt/autocaliweb"
|
||||||
export VIRTUAL_ENV="${INSTALL_DIR}/venv"
|
export VIRTUAL_ENV="${INSTALL_DIR}/venv"
|
||||||
$STD tar -cf ~/autocaliweb_bkp.tar "$INSTALL_DIR"/{metadata_change_logs,dirs.json,.env,scripts/ingest_watcher.sh,scripts/auto_zipper_wrapper.sh,scripts/metadata_change_detector_wrapper.sh}
|
$STD tar -cf ~/autocaliweb_bkp.tar "$INSTALL_DIR"/{metadata_change_logs,dirs.json,.env,scripts/ingest_watcher.sh,scripts/auto_zipper_wrapper.sh,scripts/metadata_change_detector_wrapper.sh}
|
||||||
fetch_and_deploy_gh_release "autocaliweb" "gelbphoenix/autocaliweb" "tarball" "latest" "/opt/autocaliweb"
|
fetch_and_deploy_codeberg_release "autocaliweb" "gelbphoenix/autocaliweb" "tarball" "latest" "/opt/autocaliweb"
|
||||||
|
|
||||||
msg_info "Updating Autocaliweb"
|
msg_info "Updating Autocaliweb"
|
||||||
cd "$INSTALL_DIR"
|
cd "$INSTALL_DIR"
|
||||||
|
|||||||
@@ -27,35 +27,28 @@ function update_script() {
|
|||||||
msg_error "No ${APP} Installation Found!"
|
msg_error "No ${APP} Installation Found!"
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
msg_info "Stopping Service"
|
if check_for_codeberg_release "forgejo" "forgejo/forgejo"; then
|
||||||
systemctl stop forgejo
|
msg_info "Stopping Service"
|
||||||
msg_ok "Stopped Service"
|
systemctl stop forgejo
|
||||||
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
msg_info "Updating ${APP}"
|
fetch_and_deploy_codeberg_release "forgejo" "forgejo/forgejo" "singlefile" "latest" "/opt/forgejo" "forgejo-*-linux-amd64"
|
||||||
RELEASE=$(curl -fsSL https://codeberg.org/api/v1/repos/forgejo/forgejo/releases/latest | grep -oP '"tag_name":\s*"\K[^"]+' | sed 's/^v//')
|
ln -sf /opt/forgejo/forgejo /usr/local/bin/forgejo
|
||||||
curl -fsSL "https://codeberg.org/forgejo/forgejo/releases/download/v${RELEASE}/forgejo-${RELEASE}-linux-amd64" -o "forgejo-$RELEASE-linux-amd64"
|
|
||||||
rm -rf /opt/forgejo/*
|
|
||||||
cp -r forgejo-$RELEASE-linux-amd64 /opt/forgejo/forgejo-$RELEASE-linux-amd64
|
|
||||||
chmod +x /opt/forgejo/forgejo-$RELEASE-linux-amd64
|
|
||||||
ln -sf /opt/forgejo/forgejo-$RELEASE-linux-amd64 /usr/local/bin/forgejo
|
|
||||||
msg_ok "Updated ${APP}"
|
|
||||||
|
|
||||||
msg_info "Cleaning"
|
if grep -q "GITEA_WORK_DIR" /etc/systemd/system/forgejo.service; then
|
||||||
rm -rf forgejo-$RELEASE-linux-amd64
|
msg_info "Updating Service File"
|
||||||
msg_ok "Cleaned"
|
sed -i "s/GITEA_WORK_DIR/FORGEJO_WORK_DIR/g" /etc/systemd/system/forgejo.service
|
||||||
|
systemctl daemon-reload
|
||||||
|
msg_ok "Updated Service File"
|
||||||
|
fi
|
||||||
|
|
||||||
# Fix env var from older version of community script
|
msg_info "Starting Service"
|
||||||
if grep -q "GITEA_WORK_DIR" /etc/systemd/system/forgejo.service; then
|
systemctl start forgejo
|
||||||
msg_info "Updating Service File"
|
msg_ok "Started Service"
|
||||||
sed -i "s/GITEA_WORK_DIR/FORGEJO_WORK_DIR/g" /etc/systemd/system/forgejo.service
|
msg_ok "Updated successfully!"
|
||||||
systemctl daemon-reload
|
else
|
||||||
msg_ok "Updated Service File"
|
msg_ok "No update required. ${APP} is already at the latest version."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
msg_info "Starting Service"
|
|
||||||
systemctl start forgejo
|
|
||||||
msg_ok "Started Service"
|
|
||||||
msg_ok "Updated successfully!"
|
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
6
ct/headers/kitchenowl
Normal file
6
ct/headers/kitchenowl
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
__ __ _ __ __ ____ __
|
||||||
|
/ //_/(_) /______/ /_ ___ ____ / __ \_ __/ /
|
||||||
|
/ ,< / / __/ ___/ __ \/ _ \/ __ \/ / / / | /| / / /
|
||||||
|
/ /| |/ / /_/ /__/ / / / __/ / / / /_/ /| |/ |/ / /
|
||||||
|
/_/ |_/_/\__/\___/_/ /_/\___/_/ /_/\____/ |__/|__/_/
|
||||||
|
|
||||||
79
ct/kitchenowl.sh
Normal file
79
ct/kitchenowl.sh
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||||
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
|
# Author: snazzybean
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://github.com/TomBursch/kitchenowl
|
||||||
|
|
||||||
|
APP="KitchenOwl"
|
||||||
|
var_tags="${var_tags:-food;recipes}"
|
||||||
|
var_cpu="${var_cpu:-1}"
|
||||||
|
var_ram="${var_ram:-2048}"
|
||||||
|
var_disk="${var_disk:-6}"
|
||||||
|
var_os="${var_os:-debian}"
|
||||||
|
var_version="${var_version:-13}"
|
||||||
|
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/kitchenowl ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if check_for_gh_release "kitchenowl" "TomBursch/kitchenowl"; then
|
||||||
|
msg_info "Stopping Service"
|
||||||
|
systemctl stop kitchenowl
|
||||||
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
|
msg_info "Creating Backup"
|
||||||
|
mkdir -p /opt/kitchenowl_backup
|
||||||
|
cp -r /opt/kitchenowl/data /opt/kitchenowl_backup/
|
||||||
|
cp -f /opt/kitchenowl/kitchenowl.env /opt/kitchenowl_backup/
|
||||||
|
msg_ok "Created Backup"
|
||||||
|
|
||||||
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "kitchenowl" "TomBursch/kitchenowl" "tarball" "latest" "/opt/kitchenowl"
|
||||||
|
rm -rf /opt/kitchenowl/web
|
||||||
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "kitchenowl-web" "TomBursch/kitchenowl" "prebuild" "latest" "/opt/kitchenowl/web" "kitchenowl_Web.tar.gz"
|
||||||
|
|
||||||
|
msg_info "Restoring data"
|
||||||
|
sed -i 's/default=True/default=False/' /opt/kitchenowl/backend/wsgi.py
|
||||||
|
cp -r /opt/kitchenowl_backup/data /opt/kitchenowl/
|
||||||
|
cp -f /opt/kitchenowl_backup/kitchenowl.env /opt/kitchenowl/
|
||||||
|
rm -rf /opt/kitchenowl_backup
|
||||||
|
msg_ok "Restored data"
|
||||||
|
|
||||||
|
msg_info "Updating KitchenOwl"
|
||||||
|
cd /opt/kitchenowl/backend
|
||||||
|
$STD uv sync --frozen
|
||||||
|
cd /opt/kitchenowl/backend
|
||||||
|
set -a
|
||||||
|
source /opt/kitchenowl/kitchenowl.env
|
||||||
|
set +a
|
||||||
|
$STD uv run flask db upgrade
|
||||||
|
msg_ok "Updated KitchenOwl"
|
||||||
|
|
||||||
|
msg_info "Starting Service"
|
||||||
|
systemctl start kitchenowl
|
||||||
|
msg_ok "Started Service"
|
||||||
|
msg_ok "Updated successfully!"
|
||||||
|
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}:80${CL}"
|
||||||
@@ -27,22 +27,20 @@ function update_script() {
|
|||||||
msg_error "No ${APP} Installation Found!"
|
msg_error "No ${APP} Installation Found!"
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
msg_info "Stopping Service"
|
if check_for_codeberg_release "readeck" "readeck/readeck"; then
|
||||||
systemctl stop readeck
|
msg_info "Stopping Service"
|
||||||
msg_ok "Stopped Service"
|
systemctl stop readeck
|
||||||
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
msg_info "Updating Readeck"
|
fetch_and_deploy_codeberg_release "readeck" "readeck/readeck" "singlefile" "latest" "/opt/readeck" "readeck-*-linux-amd64"
|
||||||
LATEST=$(curl -fsSL https://codeberg.org/readeck/readeck/releases/ | grep -oP '/releases/tag/\K\d+\.\d+\.\d+' | head -1)
|
|
||||||
rm -rf /opt/readeck/readeck
|
|
||||||
cd /opt/readeck
|
|
||||||
curl -fsSL "https://codeberg.org/readeck/readeck/releases/download/${LATEST}/readeck-${LATEST}-linux-amd64" -o "readeck"
|
|
||||||
chmod a+x readeck
|
|
||||||
msg_ok "Updated Readeck"
|
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start readeck
|
systemctl start readeck
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
|
else
|
||||||
|
msg_ok "No update required. ${APP} is already at the latest version."
|
||||||
|
fi
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,55 @@ function update_script() {
|
|||||||
|
|
||||||
NODE_VERSION="24" setup_nodejs
|
NODE_VERSION="24" setup_nodejs
|
||||||
|
|
||||||
|
msg_info "Updating prestart script"
|
||||||
|
cat <<EOF >/data/tracearr/prestart.sh
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# =============================================================================
|
||||||
|
# Tune PostgreSQL for available resources (runs every startup)
|
||||||
|
# =============================================================================
|
||||||
|
# timescaledb-tune automatically optimizes PostgreSQL settings based on
|
||||||
|
# available RAM and CPU. Safe to run repeatedly - recalculates if resources change.
|
||||||
|
if command -v timescaledb-tune &> /dev/null; then
|
||||||
|
total_ram_kb=\$(grep MemTotal /proc/meminfo | awk '{print \$2}')
|
||||||
|
ram_for_tsdb=\$((total_ram_kb / 1024 / 2))
|
||||||
|
timescaledb-tune -yes -memory "\$ram_for_tsdb"MB --quiet 2>/dev/null \
|
||||||
|
|| echo "Warning: timescaledb-tune failed (non-fatal)"
|
||||||
|
fi
|
||||||
|
# =============================================================================
|
||||||
|
# Ensure required PostgreSQL settings for Tracearr
|
||||||
|
# =============================================================================
|
||||||
|
pg_config_file="/etc/postgresql/18/main/postgresql.conf"
|
||||||
|
if [ -f \$pg_config_file ]; then
|
||||||
|
# Ensure max_tuples_decompressed_per_dml_transaction is set
|
||||||
|
if grep -q "^timescaledb\.max_tuples_decompressed_per_dml_transaction" \$pg_config_file; then
|
||||||
|
# Setting exists (uncommented) - update if not 0
|
||||||
|
current_value=\$(grep "^timescaledb\.max_tuples_decompressed_per_dml_transaction" \$pg_config_file | grep -oE '[0-9]+' | head -1)
|
||||||
|
if [ -n "\$current_value" ] && [ "\$current_value" -ne 0 ]; then
|
||||||
|
sed -i "s/^timescaledb\.max_tuples_decompressed_per_dml_transaction.*/timescaledb.max_tuples_decompressed_per_dml_transaction = 0/" \$pg_config_file
|
||||||
|
fi
|
||||||
|
elif ! grep -q "^timescaledb\.max_tuples_decompressed_per_dml_transaction" \$pg_config_file; then
|
||||||
|
echo "" >> \$pg_config_file
|
||||||
|
echo "# Allow unlimited tuple decompression for migrations on compressed hypertables" >> \$pg_config_file
|
||||||
|
echo "timescaledb.max_tuples_decompressed_per_dml_transaction = 0" >> \$pg_config_file
|
||||||
|
fi
|
||||||
|
# Ensure max_locks_per_transaction is set (for existing databases)
|
||||||
|
if grep -q "^max_locks_per_transaction" \$pg_config_file; then
|
||||||
|
# Setting exists (uncommented) - update if below 4096
|
||||||
|
current_value=\$(grep "^max_locks_per_transaction" \$pg_config_file | grep -oE '[0-9]+' | head -1)
|
||||||
|
if [ -n "\$current_value" ] && [ "\$current_value" -lt 4096 ]; then
|
||||||
|
sed -i "s/^max_locks_per_transaction.*/max_locks_per_transaction = 4096/" \$pg_config_file
|
||||||
|
fi
|
||||||
|
elif ! grep -q "^max_locks_per_transaction" \$pg_config_file; then
|
||||||
|
echo "" >> \$pg_config_file
|
||||||
|
echo "# Increase lock table size for TimescaleDB hypertables with many chunks" >> \$pg_config_file
|
||||||
|
echo "max_locks_per_transaction = 4096" >> \$pg_config_file
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
systemctl restart postgresql
|
||||||
|
EOF
|
||||||
|
chmod +x /data/tracearr/prestart.sh
|
||||||
|
msg_ok "Updated prestart script"
|
||||||
|
|
||||||
if check_for_gh_release "tracearr" "connorgallopo/Tracearr"; then
|
if check_for_gh_release "tracearr" "connorgallopo/Tracearr"; then
|
||||||
msg_info "Stopping Services"
|
msg_info "Stopping Services"
|
||||||
systemctl stop tracearr postgresql redis
|
systemctl stop tracearr postgresql redis
|
||||||
@@ -74,10 +123,15 @@ function update_script() {
|
|||||||
chown -R tracearr:tracearr /data/tracearr
|
chown -R tracearr:tracearr /data/tracearr
|
||||||
msg_ok "Configured Tracearr"
|
msg_ok "Configured Tracearr"
|
||||||
|
|
||||||
msg_info "Starting Services"
|
msg_info "Starting services"
|
||||||
systemctl start postgresql redis tracearr
|
systemctl start postgresql redis tracearr
|
||||||
msg_ok "Started Services"
|
msg_ok "Started services"
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
|
else
|
||||||
|
# no new release, just restart service to apply prestart changes
|
||||||
|
msg_info "Restarting service"
|
||||||
|
systemctl restart tracearr
|
||||||
|
msg_ok "Restarted service"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
"updateable": true,
|
"updateable": true,
|
||||||
"privileged": false,
|
"privileged": false,
|
||||||
"interface_port": 8083,
|
"interface_port": 8083,
|
||||||
"documentation": "https://github.com/gelbphoenix/autocaliweb/wiki",
|
"documentation": "https://codeberg.org/gelbphoenix/autocaliweb/wiki",
|
||||||
"config_path": "/etc/autocaliweb",
|
"config_path": "/etc/autocaliweb",
|
||||||
"website": "https://github.com/gelbphoenix/autocaliweb",
|
"website": "https://codeberg.org/gelbphoenix/autocaliweb",
|
||||||
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/autocaliweb.webp",
|
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/autocaliweb.webp",
|
||||||
"description": "A modern web management system for eBooks, eComics and PDFs",
|
"description": "A modern web management system for eBooks, eComics and PDFs",
|
||||||
"install_methods": [
|
"install_methods": [
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"generated": "2026-02-01T18:07:47Z",
|
"generated": "2026-02-02T06:25:10Z",
|
||||||
"versions": [
|
"versions": [
|
||||||
{
|
{
|
||||||
"slug": "2fauth",
|
"slug": "2fauth",
|
||||||
@@ -116,9 +116,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "beszel",
|
"slug": "beszel",
|
||||||
"repo": "henrygd/beszel",
|
"repo": "henrygd/beszel",
|
||||||
"version": "v0.18.2",
|
"version": "v0.18.3",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-01-12T23:58:00Z"
|
"date": "2026-02-01T19:02:42Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "bitmagnet",
|
"slug": "bitmagnet",
|
||||||
@@ -242,9 +242,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "discopanel",
|
"slug": "discopanel",
|
||||||
"repo": "nickheyer/discopanel",
|
"repo": "nickheyer/discopanel",
|
||||||
"version": "v1.0.32",
|
"version": "v1.0.35",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-01-31T22:24:53Z"
|
"date": "2026-02-02T05:20:12Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "dispatcharr",
|
"slug": "dispatcharr",
|
||||||
@@ -487,9 +487,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "homebox",
|
"slug": "homebox",
|
||||||
"repo": "sysadminsmedia/homebox",
|
"repo": "sysadminsmedia/homebox",
|
||||||
"version": "v0.23.0",
|
"version": "v0.23.1",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-01-30T17:41:01Z"
|
"date": "2026-02-01T22:53:32Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "homepage",
|
"slug": "homepage",
|
||||||
@@ -515,9 +515,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "huntarr",
|
"slug": "huntarr",
|
||||||
"repo": "plexguide/Huntarr.io",
|
"repo": "plexguide/Huntarr.io",
|
||||||
"version": "9.1.5",
|
"version": "9.1.8",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-01-31T22:55:29Z"
|
"date": "2026-02-02T01:29:45Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "inspircd",
|
"slug": "inspircd",
|
||||||
@@ -543,9 +543,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "jackett",
|
"slug": "jackett",
|
||||||
"repo": "Jackett/Jackett",
|
"repo": "Jackett/Jackett",
|
||||||
"version": "v0.24.1003",
|
"version": "v0.24.1008",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-02-01T05:55:30Z"
|
"date": "2026-02-02T05:55:21Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "joplin-server",
|
"slug": "joplin-server",
|
||||||
@@ -1558,9 +1558,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "zigbee2mqtt",
|
"slug": "zigbee2mqtt",
|
||||||
"repo": "Koenkk/zigbee2mqtt",
|
"repo": "Koenkk/zigbee2mqtt",
|
||||||
"version": "2.7.2",
|
"version": "2.8.0",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-01-01T13:43:47Z"
|
"date": "2026-02-01T19:27:25Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "zipline",
|
"slug": "zipline",
|
||||||
|
|||||||
35
frontend/public/json/kitchenowl.json
Normal file
35
frontend/public/json/kitchenowl.json
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"name": "KitchenOwl",
|
||||||
|
"slug": "kitchenowl",
|
||||||
|
"categories": [
|
||||||
|
13
|
||||||
|
],
|
||||||
|
"date_created": "2026-02-02",
|
||||||
|
"type": "ct",
|
||||||
|
"updateable": true,
|
||||||
|
"privileged": false,
|
||||||
|
"interface_port": 80,
|
||||||
|
"documentation": "https://docs.kitchenowl.org/",
|
||||||
|
"website": "https://kitchenowl.org/",
|
||||||
|
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/kitchenowl.webp",
|
||||||
|
"config_path": "/opt/kitchenowl/kitchenowl.env",
|
||||||
|
"description": "KitchenOwl is a smart self-hosted grocery list and recipe manager with real-time synchronization, recipe management, meal planning, and expense tracking.",
|
||||||
|
"install_methods": [
|
||||||
|
{
|
||||||
|
"type": "default",
|
||||||
|
"script": "ct/kitchenowl.sh",
|
||||||
|
"resources": {
|
||||||
|
"cpu": 1,
|
||||||
|
"ram": 2048,
|
||||||
|
"hdd": 6,
|
||||||
|
"os": "Debian",
|
||||||
|
"version": "13"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default_credentials": {
|
||||||
|
"username": null,
|
||||||
|
"password": null
|
||||||
|
},
|
||||||
|
"notes": []
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: vhsdream
|
# Author: vhsdream
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://github.com/gelbphoenix/autocaliweb
|
# Source: https://codeberg.org/gelbphoenix/autocaliweb
|
||||||
|
|
||||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||||
color
|
color
|
||||||
@@ -56,7 +56,7 @@ msg_ok "Installed Calibre"
|
|||||||
|
|
||||||
setup_uv
|
setup_uv
|
||||||
|
|
||||||
fetch_and_deploy_gh_release "autocaliweb" "gelbphoenix/autocaliweb" "tarball" "latest" "/opt/autocaliweb"
|
fetch_and_deploy_codeberg_release "autocaliweb" "gelbphoenix/autocaliweb" "tarball" "latest" "/opt/autocaliweb"
|
||||||
|
|
||||||
msg_info "Configuring Autocaliweb"
|
msg_info "Configuring Autocaliweb"
|
||||||
INSTALL_DIR="/opt/autocaliweb"
|
INSTALL_DIR="/opt/autocaliweb"
|
||||||
@@ -111,8 +111,8 @@ msg_info "Initializing databases"
|
|||||||
KEPUBIFY_PATH=$(command -v kepubify 2>/dev/null || echo "/usr/bin/kepubify")
|
KEPUBIFY_PATH=$(command -v kepubify 2>/dev/null || echo "/usr/bin/kepubify")
|
||||||
EBOOK_CONVERT_PATH=$(command -v ebook-convert 2>/dev/null || echo "/usr/bin/ebook-convert")
|
EBOOK_CONVERT_PATH=$(command -v ebook-convert 2>/dev/null || echo "/usr/bin/ebook-convert")
|
||||||
CALIBRE_BIN_DIR=$(dirname "$EBOOK_CONVERT_PATH")
|
CALIBRE_BIN_DIR=$(dirname "$EBOOK_CONVERT_PATH")
|
||||||
curl -fsSL https://github.com/gelbphoenix/autocaliweb/raw/refs/heads/main/library/metadata.db -o "$CALIBRE_LIB_DIR"/metadata.db
|
curl -fsSL https://codeberg.org/gelbphoenix/autocaliweb/raw/branch/main/library/metadata.db -o "$CALIBRE_LIB_DIR"/metadata.db
|
||||||
curl -fsSL https://github.com/gelbphoenix/autocaliweb/raw/refs/heads/main/library/app.db -o "$CONFIG_DIR"/app.db
|
curl -fsSL https://codeberg.org/gelbphoenix/autocaliweb/raw/branch/main/library/app.db -o "$CONFIG_DIR"/app.db
|
||||||
sqlite3 "$CONFIG_DIR/app.db" <<EOS
|
sqlite3 "$CONFIG_DIR/app.db" <<EOS
|
||||||
UPDATE settings SET
|
UPDATE settings SET
|
||||||
config_kepubifypath='$KEPUBIFY_PATH',
|
config_kepubifypath='$KEPUBIFY_PATH',
|
||||||
|
|||||||
@@ -14,17 +14,13 @@ network_check
|
|||||||
update_os
|
update_os
|
||||||
|
|
||||||
msg_info "Installing Dependencies"
|
msg_info "Installing Dependencies"
|
||||||
$STD apt-get install -y git
|
$STD apt install -y \
|
||||||
$STD apt-get install -y git-lfs
|
git \
|
||||||
|
git-lfs
|
||||||
msg_ok "Installed Dependencies"
|
msg_ok "Installed Dependencies"
|
||||||
|
|
||||||
msg_info "Installing Forgejo"
|
fetch_and_deploy_codeberg_release "forgejo" "forgejo/forgejo" "singlefile" "latest" "/opt/forgejo" "forgejo-*-linux-amd64"
|
||||||
mkdir -p /opt/forgejo
|
ln -sf /opt/forgejo/forgejo /usr/local/bin/forgejo
|
||||||
RELEASE=$(curl -fsSL https://codeberg.org/api/v1/repos/forgejo/forgejo/releases/latest | grep -oP '"tag_name":\s*"\K[^"]+' | sed 's/^v//')
|
|
||||||
curl -fsSL "https://codeberg.org/forgejo/forgejo/releases/download/v${RELEASE}/forgejo-${RELEASE}-linux-amd64" -o "/opt/forgejo/forgejo-$RELEASE-linux-amd64"
|
|
||||||
chmod +x /opt/forgejo/forgejo-$RELEASE-linux-amd64
|
|
||||||
ln -sf /opt/forgejo/forgejo-$RELEASE-linux-amd64 /usr/local/bin/forgejo
|
|
||||||
msg_ok "Installed Forgejo"
|
|
||||||
|
|
||||||
msg_info "Setting up Forgejo"
|
msg_info "Setting up Forgejo"
|
||||||
$STD adduser --system --shell /bin/bash --gecos 'Git Version Control' --group --disabled-password --home /home/git git
|
$STD adduser --system --shell /bin/bash --gecos 'Git Version Control' --group --disabled-password --home /home/git git
|
||||||
|
|||||||
145
install/kitchenowl-install.sh
Normal file
145
install/kitchenowl-install.sh
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright (c) 2021-2025 community-scripts ORG
|
||||||
|
# Author: snazzybean
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://github.com/TomBursch/kitchenowl
|
||||||
|
|
||||||
|
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||||
|
color
|
||||||
|
verb_ip6
|
||||||
|
catch_errors
|
||||||
|
setting_up_container
|
||||||
|
network_check
|
||||||
|
update_os
|
||||||
|
|
||||||
|
msg_info "Installing Dependencies"
|
||||||
|
$STD apt install -y \
|
||||||
|
nginx \
|
||||||
|
build-essential \
|
||||||
|
gfortran \
|
||||||
|
pkg-config \
|
||||||
|
ninja-build \
|
||||||
|
autoconf \
|
||||||
|
automake \
|
||||||
|
libpq-dev \
|
||||||
|
libffi-dev \
|
||||||
|
libssl-dev \
|
||||||
|
libpcre2-dev \
|
||||||
|
libre2-dev \
|
||||||
|
libxml2-dev \
|
||||||
|
libxslt-dev \
|
||||||
|
libopenblas-dev \
|
||||||
|
liblapack-dev \
|
||||||
|
zlib1g-dev \
|
||||||
|
libjpeg62-turbo-dev \
|
||||||
|
libsqlite3-dev \
|
||||||
|
libexpat1-dev \
|
||||||
|
libicu-dev
|
||||||
|
msg_ok "Installed Dependencies"
|
||||||
|
|
||||||
|
PYTHON_VERSION="3.14" setup_uv
|
||||||
|
fetch_and_deploy_gh_release "kitchenowl" "TomBursch/kitchenowl" "tarball" "latest" "/opt/kitchenowl"
|
||||||
|
rm -rf /opt/kitchenowl/web
|
||||||
|
fetch_and_deploy_gh_release "kitchenowl-web" "TomBursch/kitchenowl" "prebuild" "latest" "/opt/kitchenowl/web" "kitchenowl_Web.tar.gz"
|
||||||
|
|
||||||
|
msg_info "Setting up KitchenOwl"
|
||||||
|
cd /opt/kitchenowl/backend
|
||||||
|
$STD uv sync --no-dev
|
||||||
|
sed -i 's/default=True/default=False/' /opt/kitchenowl/backend/wsgi.py
|
||||||
|
mkdir -p /nltk_data
|
||||||
|
$STD uv run python -m nltk.downloader -d /nltk_data averaged_perceptron_tagger_eng
|
||||||
|
JWT_SECRET=$(openssl rand -hex 32)
|
||||||
|
mkdir -p /opt/kitchenowl/data
|
||||||
|
cat <<EOF >/opt/kitchenowl/kitchenowl.env
|
||||||
|
STORAGE_PATH=/opt/kitchenowl/data
|
||||||
|
JWT_SECRET_KEY=${JWT_SECRET}
|
||||||
|
NLTK_DATA=/nltk_data
|
||||||
|
FRONT_URL=http://${LOCAL_IP}
|
||||||
|
FLASK_APP=wsgi.py
|
||||||
|
FLASK_ENV=production
|
||||||
|
EOF
|
||||||
|
set -a
|
||||||
|
source /opt/kitchenowl/kitchenowl.env
|
||||||
|
set +a
|
||||||
|
$STD uv run flask db upgrade
|
||||||
|
msg_ok "Set up KitchenOwl"
|
||||||
|
|
||||||
|
msg_info "Creating Systemd Service"
|
||||||
|
cat <<EOF >/etc/systemd/system/kitchenowl.service
|
||||||
|
[Unit]
|
||||||
|
Description=KitchenOwl Backend
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
WorkingDirectory=/opt/kitchenowl/backend
|
||||||
|
EnvironmentFile=/opt/kitchenowl/kitchenowl.env
|
||||||
|
ExecStart=/usr/local/bin/uv run wsgi.py
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl enable -q --now kitchenowl
|
||||||
|
msg_ok "Created and Started Service"
|
||||||
|
|
||||||
|
msg_info "Configuring Nginx"
|
||||||
|
rm -f /etc/nginx/sites-enabled/default
|
||||||
|
cat <<'EOF' >/etc/nginx/sites-available/kitchenowl.conf
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
root /opt/kitchenowl/web;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
client_max_body_size 100M;
|
||||||
|
|
||||||
|
# Security Headers
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||||
|
add_header X-Content-Type-Options "nosniff" always;
|
||||||
|
add_header X-XSS-Protection "1; mode=block" always;
|
||||||
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api {
|
||||||
|
proxy_pass http://127.0.0.1:5000;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_connect_timeout 60s;
|
||||||
|
proxy_send_timeout 60s;
|
||||||
|
proxy_read_timeout 60s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /socket.io {
|
||||||
|
proxy_pass http://127.0.0.1:5000;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
# WebSocket Timeouts - allow long-lived connections
|
||||||
|
proxy_read_timeout 86400s;
|
||||||
|
proxy_send_timeout 86400s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
ln -sf /etc/nginx/sites-available/kitchenowl.conf /etc/nginx/sites-enabled/
|
||||||
|
rm -f /etc/nginx/sites-enabled/default
|
||||||
|
$STD systemctl reload nginx
|
||||||
|
msg_ok "Configured Nginx"
|
||||||
|
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
cleanup_lxc
|
||||||
@@ -31,7 +31,7 @@ After=network-online.target
|
|||||||
User=root
|
User=root
|
||||||
Restart=always
|
Restart=always
|
||||||
Type=simple
|
Type=simple
|
||||||
ExecStart=/usr/local/bin/prometheus-paperless-exporter \
|
ExecStart=/usr/bin/prometheus-paperless-exporter \
|
||||||
--paperless_url=http://paperless.example.org \
|
--paperless_url=http://paperless.example.org \
|
||||||
--paperless_auth_token_file=/etc/prometheus-paperless-ngx-exporter/paperless_auth_token_file
|
--paperless_auth_token_file=/etc/prometheus-paperless-ngx-exporter/paperless_auth_token_file
|
||||||
ExecReload=/bin/kill -HUP \$MAINPID
|
ExecReload=/bin/kill -HUP \$MAINPID
|
||||||
|
|||||||
@@ -13,13 +13,7 @@ setting_up_container
|
|||||||
network_check
|
network_check
|
||||||
update_os
|
update_os
|
||||||
|
|
||||||
msg_info "Installing Readeck"
|
fetch_and_deploy_codeberg_release "readeck" "readeck/readeck" "singlefile" "latest" "/opt/readeck" "readeck-*-linux-amd64"
|
||||||
LATEST=$(curl -fsSL https://codeberg.org/readeck/readeck/releases/ | grep -oP '/releases/tag/\K\d+\.\d+\.\d+' | head -1)
|
|
||||||
mkdir -p /opt/readeck
|
|
||||||
cd /opt/readeck
|
|
||||||
curl -fsSL "https://codeberg.org/readeck/readeck/releases/download/${LATEST}/readeck-${LATEST}-linux-amd64" -o "readeck"
|
|
||||||
chmod a+x readeck
|
|
||||||
msg_ok "Installed Readeck"
|
|
||||||
|
|
||||||
msg_info "Creating Service"
|
msg_info "Creating Service"
|
||||||
cat <<EOF >/etc/systemd/system/readeck.service
|
cat <<EOF >/etc/systemd/system/readeck.service
|
||||||
|
|||||||
@@ -109,18 +109,34 @@ if command -v timescaledb-tune &> /dev/null; then
|
|||||||
|| echo "Warning: timescaledb-tune failed (non-fatal)"
|
|| echo "Warning: timescaledb-tune failed (non-fatal)"
|
||||||
fi
|
fi
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Ensure TimescaleDB decompression limit is set (for existing databases)
|
# Ensure required PostgreSQL settings for Tracearr
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# This setting allows migrations to modify compressed hypertable data.
|
|
||||||
# Without it, bulk UPDATEs on compressed sessions will fail with
|
|
||||||
# "tuple decompression limit exceeded" errors.
|
|
||||||
pg_config_file="/etc/postgresql/18/main/postgresql.conf"
|
pg_config_file="/etc/postgresql/18/main/postgresql.conf"
|
||||||
if [ -f \$pg_config_file ]; then
|
if [ -f \$pg_config_file ]; then
|
||||||
if ! grep -q "max_tuples_decompressed_per_dml_transaction" \$pg_config_file; then
|
# Ensure max_tuples_decompressed_per_dml_transaction is set
|
||||||
|
if grep -q "^timescaledb\.max_tuples_decompressed_per_dml_transaction" \$pg_config_file; then
|
||||||
|
# Setting exists (uncommented) - update if not 0
|
||||||
|
current_value=\$(grep "^timescaledb\.max_tuples_decompressed_per_dml_transaction" \$pg_config_file | grep -oE '[0-9]+' | head -1)
|
||||||
|
if [ -n "\$current_value" ] && [ "\$current_value" -ne 0 ]; then
|
||||||
|
sed -i "s/^timescaledb\.max_tuples_decompressed_per_dml_transaction.*/timescaledb.max_tuples_decompressed_per_dml_transaction = 0/" \$pg_config_file
|
||||||
|
fi
|
||||||
|
elif ! grep -q "^timescaledb\.max_tuples_decompressed_per_dml_transaction" \$pg_config_file; then
|
||||||
echo "" >> \$pg_config_file
|
echo "" >> \$pg_config_file
|
||||||
echo "# Allow unlimited tuple decompression for migrations on compressed hypertables" >> \$pg_config_file
|
echo "# Allow unlimited tuple decompression for migrations on compressed hypertables" >> \$pg_config_file
|
||||||
echo "timescaledb.max_tuples_decompressed_per_dml_transaction = 0" >> \$pg_config_file
|
echo "timescaledb.max_tuples_decompressed_per_dml_transaction = 0" >> \$pg_config_file
|
||||||
fi
|
fi
|
||||||
|
# Ensure max_locks_per_transaction is set (for existing databases)
|
||||||
|
if grep -q "^max_locks_per_transaction" \$pg_config_file; then
|
||||||
|
# Setting exists (uncommented) - update if below 4096
|
||||||
|
current_value=\$(grep "^max_locks_per_transaction" \$pg_config_file | grep -oE '[0-9]+' | head -1)
|
||||||
|
if [ -n "\$current_value" ] && [ "\$current_value" -lt 4096 ]; then
|
||||||
|
sed -i "s/^max_locks_per_transaction.*/max_locks_per_transaction = 4096/" \$pg_config_file
|
||||||
|
fi
|
||||||
|
elif ! grep -q "^max_locks_per_transaction" \$pg_config_file; then
|
||||||
|
echo "" >> \$pg_config_file
|
||||||
|
echo "# Increase lock table size for TimescaleDB hypertables with many chunks" >> \$pg_config_file
|
||||||
|
echo "max_locks_per_transaction = 4096" >> \$pg_config_file
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
systemctl restart postgresql
|
systemctl restart postgresql
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
626
misc/tools.func
626
misc/tools.func
@@ -821,6 +821,54 @@ github_api_call() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Codeberg API call with retry logic
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
codeberg_api_call() {
|
||||||
|
local url="$1"
|
||||||
|
local output_file="${2:-/dev/stdout}"
|
||||||
|
local max_retries=3
|
||||||
|
local retry_delay=2
|
||||||
|
|
||||||
|
for attempt in $(seq 1 $max_retries); do
|
||||||
|
local http_code
|
||||||
|
http_code=$(curl -fsSL -w "%{http_code}" -o "$output_file" \
|
||||||
|
-H "Accept: application/json" \
|
||||||
|
"$url" 2>/dev/null || echo "000")
|
||||||
|
|
||||||
|
case "$http_code" in
|
||||||
|
200)
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
403)
|
||||||
|
# Rate limit - retry
|
||||||
|
if [[ $attempt -lt $max_retries ]]; then
|
||||||
|
msg_warn "Codeberg API rate limit, waiting ${retry_delay}s... (attempt $attempt/$max_retries)"
|
||||||
|
sleep "$retry_delay"
|
||||||
|
retry_delay=$((retry_delay * 2))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
msg_error "Codeberg API rate limit exceeded."
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
404)
|
||||||
|
msg_error "Codeberg API endpoint not found: $url"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [[ $attempt -lt $max_retries ]]; then
|
||||||
|
sleep "$retry_delay"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
msg_error "Codeberg API call failed with HTTP $http_code"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
should_upgrade() {
|
should_upgrade() {
|
||||||
local current="$1"
|
local current="$1"
|
||||||
local target="$2"
|
local target="$2"
|
||||||
@@ -1385,6 +1433,37 @@ get_latest_github_release() {
|
|||||||
echo "$version"
|
echo "$version"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Get latest Codeberg release version
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
get_latest_codeberg_release() {
|
||||||
|
local repo="$1"
|
||||||
|
local strip_v="${2:-true}"
|
||||||
|
local temp_file=$(mktemp)
|
||||||
|
|
||||||
|
# Codeberg API: get all releases and pick the first non-draft/non-prerelease
|
||||||
|
if ! codeberg_api_call "https://codeberg.org/api/v1/repos/${repo}/releases" "$temp_file"; then
|
||||||
|
rm -f "$temp_file"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local version
|
||||||
|
# Codeberg uses same JSON structure but releases endpoint returns array
|
||||||
|
version=$(jq -r '[.[] | select(.draft==false and .prerelease==false)][0].tag_name // empty' "$temp_file")
|
||||||
|
|
||||||
|
if [[ "$strip_v" == "true" ]]; then
|
||||||
|
version="${version#v}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "$temp_file"
|
||||||
|
|
||||||
|
if [[ -z "$version" ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$version"
|
||||||
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Debug logging (only if DEBUG=1)
|
# Debug logging (only if DEBUG=1)
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
@@ -1559,6 +1638,119 @@ check_for_gh_release() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Checks for new Codeberg release (latest tag).
|
||||||
|
#
|
||||||
|
# Description:
|
||||||
|
# - Queries the Codeberg API for the latest release tag
|
||||||
|
# - Compares it to a local cached version (~/.<app>)
|
||||||
|
# - If newer, sets global CHECK_UPDATE_RELEASE and returns 0
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# if check_for_codeberg_release "autocaliweb" "gelbphoenix/autocaliweb" [optional] "v0.11.3"; then
|
||||||
|
# # trigger update...
|
||||||
|
# fi
|
||||||
|
# exit 0
|
||||||
|
# } (end of update_script not from the function)
|
||||||
|
#
|
||||||
|
# Notes:
|
||||||
|
# - Requires `jq` (auto-installed if missing)
|
||||||
|
# - Does not modify anything, only checks version state
|
||||||
|
# - Does not support pre-releases
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
check_for_codeberg_release() {
|
||||||
|
local app="$1"
|
||||||
|
local source="$2"
|
||||||
|
local pinned_version_in="${3:-}" # optional
|
||||||
|
local app_lc="${app,,}"
|
||||||
|
local current_file="$HOME/.${app_lc}"
|
||||||
|
|
||||||
|
msg_info "Checking for update: ${app}"
|
||||||
|
|
||||||
|
# DNS check
|
||||||
|
if ! getent hosts codeberg.org >/dev/null 2>&1; then
|
||||||
|
msg_error "Network error: cannot resolve codeberg.org"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ensure_dependencies jq
|
||||||
|
|
||||||
|
# Fetch releases from Codeberg API
|
||||||
|
local releases_json=""
|
||||||
|
releases_json=$(curl -fsSL --max-time 20 \
|
||||||
|
-H 'Accept: application/json' \
|
||||||
|
"https://codeberg.org/api/v1/repos/${source}/releases" 2>/dev/null) || {
|
||||||
|
msg_error "Unable to fetch releases for ${app}"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
mapfile -t raw_tags < <(jq -r '.[] | select(.draft==false and .prerelease==false) | .tag_name' <<<"$releases_json")
|
||||||
|
if ((${#raw_tags[@]} == 0)); then
|
||||||
|
msg_error "No stable releases found for ${app}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local clean_tags=()
|
||||||
|
for t in "${raw_tags[@]}"; do
|
||||||
|
clean_tags+=("${t#v}")
|
||||||
|
done
|
||||||
|
|
||||||
|
local latest_raw="${raw_tags[0]}"
|
||||||
|
local latest_clean="${clean_tags[0]}"
|
||||||
|
|
||||||
|
# current installed (stored without v)
|
||||||
|
local current=""
|
||||||
|
if [[ -f "$current_file" ]]; then
|
||||||
|
current="$(<"$current_file")"
|
||||||
|
else
|
||||||
|
# Migration: search for any /opt/*_version.txt
|
||||||
|
local legacy_files
|
||||||
|
mapfile -t legacy_files < <(find /opt -maxdepth 1 -type f -name "*_version.txt" 2>/dev/null)
|
||||||
|
if ((${#legacy_files[@]} == 1)); then
|
||||||
|
current="$(<"${legacy_files[0]}")"
|
||||||
|
echo "${current#v}" >"$current_file"
|
||||||
|
rm -f "${legacy_files[0]}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
current="${current#v}"
|
||||||
|
|
||||||
|
# Pinned version handling
|
||||||
|
if [[ -n "$pinned_version_in" ]]; then
|
||||||
|
local pin_clean="${pinned_version_in#v}"
|
||||||
|
local match_raw=""
|
||||||
|
for i in "${!clean_tags[@]}"; do
|
||||||
|
if [[ "${clean_tags[$i]}" == "$pin_clean" ]]; then
|
||||||
|
match_raw="${raw_tags[$i]}"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -z "$match_raw" ]]; then
|
||||||
|
msg_error "Pinned version ${pinned_version_in} not found upstream"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$current" != "$pin_clean" ]]; then
|
||||||
|
CHECK_UPDATE_RELEASE="$match_raw"
|
||||||
|
msg_ok "Update available: ${app} ${current:-not installed} → ${pin_clean}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_ok "No update available: ${app} is already on pinned version (${current})"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# No pinning → use latest
|
||||||
|
if [[ -z "$current" || "$current" != "$latest_clean" ]]; then
|
||||||
|
CHECK_UPDATE_RELEASE="$latest_raw"
|
||||||
|
msg_ok "Update available: ${app} ${current:-not installed} → ${latest_clean}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_ok "No update available: ${app} (${latest_clean})"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Creates and installs self-signed certificates.
|
# Creates and installs self-signed certificates.
|
||||||
#
|
#
|
||||||
@@ -1648,6 +1840,440 @@ function ensure_usr_local_bin_persist() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Downloads and deploys latest Codeberg release (source, binary, tarball, asset).
|
||||||
|
#
|
||||||
|
# Description:
|
||||||
|
# - Fetches latest release metadata from Codeberg API
|
||||||
|
# - Supports the following modes:
|
||||||
|
# - tarball: Source code tarball (default if omitted)
|
||||||
|
# - source: Alias for tarball (same behavior)
|
||||||
|
# - binary: .deb package install (arch-dependent)
|
||||||
|
# - prebuild: Prebuilt .tar.gz archive (e.g. Go binaries)
|
||||||
|
# - singlefile: Standalone binary (no archive, direct chmod +x install)
|
||||||
|
# - tag: Direct tag download (bypasses Release API)
|
||||||
|
# - Handles download, extraction/installation and version tracking in ~/.<app>
|
||||||
|
#
|
||||||
|
# Parameters:
|
||||||
|
# $1 APP - Application name (used for install path and version file)
|
||||||
|
# $2 REPO - Codeberg repository in form user/repo
|
||||||
|
# $3 MODE - Release type:
|
||||||
|
# tarball → source tarball (.tar.gz)
|
||||||
|
# binary → .deb file (auto-arch matched)
|
||||||
|
# prebuild → prebuilt archive (e.g. tar.gz)
|
||||||
|
# singlefile→ standalone binary (chmod +x)
|
||||||
|
# tag → direct tag (bypasses Release API)
|
||||||
|
# $4 VERSION - Optional release tag (default: latest)
|
||||||
|
# $5 TARGET_DIR - Optional install path (default: /opt/<app>)
|
||||||
|
# $6 ASSET_FILENAME - Required for:
|
||||||
|
# - prebuild → archive filename or pattern
|
||||||
|
# - singlefile→ binary filename or pattern
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
# # 1. Minimal: Fetch and deploy source tarball
|
||||||
|
# fetch_and_deploy_codeberg_release "autocaliweb" "gelbphoenix/autocaliweb"
|
||||||
|
#
|
||||||
|
# # 2. Binary install via .deb asset (architecture auto-detected)
|
||||||
|
# fetch_and_deploy_codeberg_release "myapp" "myuser/myapp" "binary"
|
||||||
|
#
|
||||||
|
# # 3. Prebuilt archive (.tar.gz) with asset filename match
|
||||||
|
# fetch_and_deploy_codeberg_release "myapp" "myuser/myapp" "prebuild" "latest" "/opt/myapp" "myapp_Linux_x86_64.tar.gz"
|
||||||
|
#
|
||||||
|
# # 4. Single binary (chmod +x)
|
||||||
|
# fetch_and_deploy_codeberg_release "myapp" "myuser/myapp" "singlefile" "v1.0.0" "/opt/myapp" "myapp-linux-amd64"
|
||||||
|
#
|
||||||
|
# # 5. Explicit tag version
|
||||||
|
# fetch_and_deploy_codeberg_release "autocaliweb" "gelbphoenix/autocaliweb" "tag" "v0.11.3" "/opt/autocaliweb"
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function fetch_and_deploy_codeberg_release() {
|
||||||
|
local app="$1"
|
||||||
|
local repo="$2"
|
||||||
|
local mode="${3:-tarball}" # tarball | binary | prebuild | singlefile | tag
|
||||||
|
local version="${4:-latest}"
|
||||||
|
local target="${5:-/opt/$app}"
|
||||||
|
local asset_pattern="${6:-}"
|
||||||
|
|
||||||
|
local app_lc=$(echo "${app,,}" | tr -d ' ')
|
||||||
|
local version_file="$HOME/.${app_lc}"
|
||||||
|
|
||||||
|
local api_timeout="--connect-timeout 10 --max-time 60"
|
||||||
|
local download_timeout="--connect-timeout 15 --max-time 900"
|
||||||
|
|
||||||
|
local current_version=""
|
||||||
|
[[ -f "$version_file" ]] && current_version=$(<"$version_file")
|
||||||
|
|
||||||
|
ensure_dependencies jq
|
||||||
|
|
||||||
|
### Tag Mode (bypass Release API) ###
|
||||||
|
if [[ "$mode" == "tag" ]]; then
|
||||||
|
if [[ "$version" == "latest" ]]; then
|
||||||
|
msg_error "Mode 'tag' requires explicit version (not 'latest')"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local tag_name="$version"
|
||||||
|
[[ "$tag_name" =~ ^v ]] && version="${tag_name:1}" || version="$tag_name"
|
||||||
|
|
||||||
|
if [[ "$current_version" == "$version" ]]; then
|
||||||
|
$STD msg_ok "$app is already up-to-date (v$version)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# DNS check
|
||||||
|
if ! getent hosts "codeberg.org" &>/dev/null; then
|
||||||
|
msg_error "DNS resolution failed for codeberg.org – check /etc/resolv.conf or networking"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local tmpdir
|
||||||
|
tmpdir=$(mktemp -d) || return 1
|
||||||
|
|
||||||
|
msg_info "Fetching Codeberg tag: $app ($tag_name)"
|
||||||
|
|
||||||
|
local safe_version="${version//@/_}"
|
||||||
|
safe_version="${safe_version//\//_}"
|
||||||
|
local filename="${app_lc}-${safe_version}.tar.gz"
|
||||||
|
local download_success=false
|
||||||
|
|
||||||
|
# Codeberg archive URL format: https://codeberg.org/{owner}/{repo}/archive/{tag}.tar.gz
|
||||||
|
local archive_url="https://codeberg.org/$repo/archive/${tag_name}.tar.gz"
|
||||||
|
if curl $download_timeout -fsSL -o "$tmpdir/$filename" "$archive_url"; then
|
||||||
|
download_success=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$download_success" != "true" ]]; then
|
||||||
|
msg_error "Download failed for $app ($tag_name)"
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$target"
|
||||||
|
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
|
||||||
|
rm -rf "${target:?}/"*
|
||||||
|
fi
|
||||||
|
|
||||||
|
tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || {
|
||||||
|
msg_error "Failed to extract tarball"
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
local unpack_dir
|
||||||
|
unpack_dir=$(find "$tmpdir" -mindepth 1 -maxdepth 1 -type d | head -n1)
|
||||||
|
|
||||||
|
shopt -s dotglob nullglob
|
||||||
|
cp -r "$unpack_dir"/* "$target/"
|
||||||
|
shopt -u dotglob nullglob
|
||||||
|
|
||||||
|
echo "$version" >"$version_file"
|
||||||
|
msg_ok "Deployed: $app ($version)"
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Codeberg API: https://codeberg.org/api/v1/repos/{owner}/{repo}/releases
|
||||||
|
local api_url="https://codeberg.org/api/v1/repos/$repo/releases"
|
||||||
|
if [[ "$version" != "latest" ]]; then
|
||||||
|
# Get release by tag: /repos/{owner}/{repo}/releases/tags/{tag}
|
||||||
|
api_url="https://codeberg.org/api/v1/repos/$repo/releases/tags/$version"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# dns pre check
|
||||||
|
if ! getent hosts "codeberg.org" &>/dev/null; then
|
||||||
|
msg_error "DNS resolution failed for codeberg.org – check /etc/resolv.conf or networking"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local max_retries=3 retry_delay=2 attempt=1 success=false resp http_code
|
||||||
|
|
||||||
|
while ((attempt <= max_retries)); do
|
||||||
|
resp=$(curl $api_timeout -fsSL -w "%{http_code}" -o /tmp/codeberg_rel.json "$api_url") && success=true && break
|
||||||
|
sleep "$retry_delay"
|
||||||
|
((attempt++))
|
||||||
|
done
|
||||||
|
|
||||||
|
if ! $success; then
|
||||||
|
msg_error "Failed to fetch release metadata from $api_url after $max_retries attempts"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
http_code="${resp:(-3)}"
|
||||||
|
[[ "$http_code" != "200" ]] && {
|
||||||
|
msg_error "Codeberg API returned HTTP $http_code"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
local json tag_name
|
||||||
|
json=$(</tmp/codeberg_rel.json)
|
||||||
|
|
||||||
|
# For "latest", the API returns an array - take the first (most recent) release
|
||||||
|
if [[ "$version" == "latest" ]]; then
|
||||||
|
json=$(echo "$json" | jq '.[0]')
|
||||||
|
fi
|
||||||
|
|
||||||
|
tag_name=$(echo "$json" | jq -r '.tag_name // .name // empty')
|
||||||
|
[[ "$tag_name" =~ ^v ]] && version="${tag_name:1}" || version="$tag_name"
|
||||||
|
|
||||||
|
if [[ "$current_version" == "$version" ]]; then
|
||||||
|
$STD msg_ok "$app is already up-to-date (v$version)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local tmpdir
|
||||||
|
tmpdir=$(mktemp -d) || return 1
|
||||||
|
local filename="" url=""
|
||||||
|
|
||||||
|
msg_info "Fetching Codeberg release: $app ($version)"
|
||||||
|
|
||||||
|
### Tarball Mode ###
|
||||||
|
if [[ "$mode" == "tarball" || "$mode" == "source" ]]; then
|
||||||
|
local safe_version="${version//@/_}"
|
||||||
|
safe_version="${safe_version//\//_}"
|
||||||
|
filename="${app_lc}-${safe_version}.tar.gz"
|
||||||
|
local download_success=false
|
||||||
|
|
||||||
|
# Codeberg archive URL format
|
||||||
|
local archive_url="https://codeberg.org/$repo/archive/${tag_name}.tar.gz"
|
||||||
|
if curl $download_timeout -fsSL -o "$tmpdir/$filename" "$archive_url"; then
|
||||||
|
download_success=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$download_success" != "true" ]]; then
|
||||||
|
msg_error "Download failed for $app ($tag_name)"
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$target"
|
||||||
|
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
|
||||||
|
rm -rf "${target:?}/"*
|
||||||
|
fi
|
||||||
|
|
||||||
|
tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || {
|
||||||
|
msg_error "Failed to extract tarball"
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
local unpack_dir
|
||||||
|
unpack_dir=$(find "$tmpdir" -mindepth 1 -maxdepth 1 -type d | head -n1)
|
||||||
|
|
||||||
|
shopt -s dotglob nullglob
|
||||||
|
cp -r "$unpack_dir"/* "$target/"
|
||||||
|
shopt -u dotglob nullglob
|
||||||
|
|
||||||
|
### Binary Mode ###
|
||||||
|
elif [[ "$mode" == "binary" ]]; then
|
||||||
|
local arch
|
||||||
|
arch=$(dpkg --print-architecture 2>/dev/null || uname -m)
|
||||||
|
[[ "$arch" == "x86_64" ]] && arch="amd64"
|
||||||
|
[[ "$arch" == "aarch64" ]] && arch="arm64"
|
||||||
|
|
||||||
|
local assets url_match=""
|
||||||
|
# Codeberg assets are in .assets[].browser_download_url
|
||||||
|
assets=$(echo "$json" | jq -r '.assets[].browser_download_url')
|
||||||
|
|
||||||
|
# If explicit filename pattern is provided, match that first
|
||||||
|
if [[ -n "$asset_pattern" ]]; then
|
||||||
|
for u in $assets; do
|
||||||
|
case "${u##*/}" in
|
||||||
|
$asset_pattern)
|
||||||
|
url_match="$u"
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 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
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$url_match" ]]; then
|
||||||
|
msg_error "No suitable .deb asset found for $app"
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
filename="${url_match##*/}"
|
||||||
|
curl $download_timeout -fsSL -o "$tmpdir/$filename" "$url_match" || {
|
||||||
|
msg_error "Download failed: $url_match"
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
chmod 644 "$tmpdir/$filename"
|
||||||
|
$STD apt install -y "$tmpdir/$filename" || {
|
||||||
|
$STD dpkg -i "$tmpdir/$filename" || {
|
||||||
|
msg_error "Both apt and dpkg installation failed"
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
### Prebuild Mode ###
|
||||||
|
elif [[ "$mode" == "prebuild" ]]; then
|
||||||
|
local pattern="${6%\"}"
|
||||||
|
pattern="${pattern#\"}"
|
||||||
|
[[ -z "$pattern" ]] && {
|
||||||
|
msg_error "Mode 'prebuild' requires 6th parameter (asset filename pattern)"
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
local asset_url=""
|
||||||
|
for u in $(echo "$json" | jq -r '.assets[].browser_download_url'); do
|
||||||
|
filename_candidate="${u##*/}"
|
||||||
|
case "$filename_candidate" in
|
||||||
|
$pattern)
|
||||||
|
asset_url="$u"
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ -z "$asset_url" ]] && {
|
||||||
|
msg_error "No asset matching '$pattern' found"
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
filename="${asset_url##*/}"
|
||||||
|
curl $download_timeout -fsSL -o "$tmpdir/$filename" "$asset_url" || {
|
||||||
|
msg_error "Download failed: $asset_url"
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
local unpack_tmp
|
||||||
|
unpack_tmp=$(mktemp -d)
|
||||||
|
mkdir -p "$target"
|
||||||
|
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
|
||||||
|
rm -rf "${target:?}/"*
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$filename" == *.zip ]]; then
|
||||||
|
ensure_dependencies unzip
|
||||||
|
unzip -q "$tmpdir/$filename" -d "$unpack_tmp" || {
|
||||||
|
msg_error "Failed to extract ZIP archive"
|
||||||
|
rm -rf "$tmpdir" "$unpack_tmp"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
elif [[ "$filename" == *.tar.* || "$filename" == *.tgz ]]; then
|
||||||
|
tar --no-same-owner -xf "$tmpdir/$filename" -C "$unpack_tmp" || {
|
||||||
|
msg_error "Failed to extract TAR archive"
|
||||||
|
rm -rf "$tmpdir" "$unpack_tmp"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
else
|
||||||
|
msg_error "Unsupported archive format: $filename"
|
||||||
|
rm -rf "$tmpdir" "$unpack_tmp"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local top_dirs
|
||||||
|
top_dirs=$(find "$unpack_tmp" -mindepth 1 -maxdepth 1 -type d | wc -l)
|
||||||
|
local top_entries inner_dir
|
||||||
|
top_entries=$(find "$unpack_tmp" -mindepth 1 -maxdepth 1)
|
||||||
|
if [[ "$(echo "$top_entries" | wc -l)" -eq 1 && -d "$top_entries" ]]; then
|
||||||
|
inner_dir="$top_entries"
|
||||||
|
shopt -s dotglob nullglob
|
||||||
|
if compgen -G "$inner_dir/*" >/dev/null; then
|
||||||
|
cp -r "$inner_dir"/* "$target/" || {
|
||||||
|
msg_error "Failed to copy contents from $inner_dir to $target"
|
||||||
|
rm -rf "$tmpdir" "$unpack_tmp"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
else
|
||||||
|
msg_error "Inner directory is empty: $inner_dir"
|
||||||
|
rm -rf "$tmpdir" "$unpack_tmp"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
shopt -u dotglob nullglob
|
||||||
|
else
|
||||||
|
shopt -s dotglob nullglob
|
||||||
|
if compgen -G "$unpack_tmp/*" >/dev/null; then
|
||||||
|
cp -r "$unpack_tmp"/* "$target/" || {
|
||||||
|
msg_error "Failed to copy contents to $target"
|
||||||
|
rm -rf "$tmpdir" "$unpack_tmp"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
else
|
||||||
|
msg_error "Unpacked archive is empty"
|
||||||
|
rm -rf "$tmpdir" "$unpack_tmp"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
shopt -u dotglob nullglob
|
||||||
|
fi
|
||||||
|
|
||||||
|
### Singlefile Mode ###
|
||||||
|
elif [[ "$mode" == "singlefile" ]]; then
|
||||||
|
local pattern="${6%\"}"
|
||||||
|
pattern="${pattern#\"}"
|
||||||
|
[[ -z "$pattern" ]] && {
|
||||||
|
msg_error "Mode 'singlefile' requires 6th parameter (asset filename pattern)"
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
local asset_url=""
|
||||||
|
for u in $(echo "$json" | jq -r '.assets[].browser_download_url'); do
|
||||||
|
filename_candidate="${u##*/}"
|
||||||
|
case "$filename_candidate" in
|
||||||
|
$pattern)
|
||||||
|
asset_url="$u"
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ -z "$asset_url" ]] && {
|
||||||
|
msg_error "No asset matching '$pattern' found"
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
filename="${asset_url##*/}"
|
||||||
|
mkdir -p "$target"
|
||||||
|
|
||||||
|
local use_filename="${USE_ORIGINAL_FILENAME:-false}"
|
||||||
|
local target_file="$app"
|
||||||
|
[[ "$use_filename" == "true" ]] && target_file="$filename"
|
||||||
|
|
||||||
|
curl $download_timeout -fsSL -o "$target/$target_file" "$asset_url" || {
|
||||||
|
msg_error "Download failed: $asset_url"
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "$target_file" != *.jar && -f "$target/$target_file" ]]; then
|
||||||
|
chmod +x "$target/$target_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
else
|
||||||
|
msg_error "Unknown mode: $mode"
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$version" >"$version_file"
|
||||||
|
msg_ok "Deployed: $app ($version)"
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Downloads and deploys latest GitHub release (source, binary, tarball, asset).
|
# Downloads and deploys latest GitHub release (source, binary, tarball, asset).
|
||||||
#
|
#
|
||||||
|
|||||||
Reference in New Issue
Block a user