mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2026-02-04 12:23:26 +01:00
Compare commits
25 Commits
CrazyWolf1
...
disable_np
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c40db61464 | ||
|
|
8226360700 | ||
|
|
b706775a4b | ||
|
|
2f907cc4e0 | ||
|
|
b1927d2678 | ||
|
|
a35b0fbd79 | ||
|
|
4418ed4615 | ||
|
|
19d8592104 | ||
|
|
627587c54b | ||
|
|
b36609dfd5 | ||
|
|
98dc00a1a0 | ||
|
|
ff9f0ed21d | ||
|
|
bc83a37124 | ||
|
|
e0593caa02 | ||
|
|
99e19d4422 | ||
|
|
f8d8769a73 | ||
|
|
8a1b05ccac | ||
|
|
0b167e386c | ||
|
|
edef7f179a | ||
|
|
a5bf7d9fdc | ||
|
|
10e5f99965 | ||
|
|
c82d792a79 | ||
|
|
8589afb17e | ||
|
|
2d5e9592d7 | ||
|
|
6f171f29de |
16
CHANGELOG.md
16
CHANGELOG.md
@@ -772,16 +772,30 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
||||
|
||||
</details>
|
||||
|
||||
## 2026-02-02
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- KitchenOwl ([#11453](https://github.com/community-scripts/ProxmoxVE/pull/11453))
|
||||
|
||||
## 2026-02-01
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- fix headers [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11422](https://github.com/community-scripts/ProxmoxVE/pull/11422))
|
||||
|
||||
- #### 🐞 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))
|
||||
- [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))
|
||||
|
||||
- #### ✨ 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))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
@@ -797,6 +811,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
||||
|
||||
### 🌐 Website
|
||||
|
||||
- feat(frontend): implement UX refinements and syntax highlighting [@ls-root](https://github.com/ls-root) ([#11423](https://github.com/community-scripts/ProxmoxVE/pull/11423))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- feat(frontend): add contribution CTA to empty search state [@ls-root](https://github.com/ls-root) ([#11412](https://github.com/community-scripts/ProxmoxVE/pull/11412))
|
||||
|
||||
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: vhsdream
|
||||
# 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"
|
||||
var_tags="${var_tags:-ebooks}"
|
||||
@@ -30,8 +30,8 @@ function update_script() {
|
||||
|
||||
setup_uv
|
||||
|
||||
RELEASE=$(get_latest_github_release "gelbphoenix/autocaliweb")
|
||||
if check_for_gh_release "autocaliweb" "gelbphoenix/autocaliweb"; then
|
||||
RELEASE=$(get_latest_codeberg_release "gelbphoenix/autocaliweb")
|
||||
if check_for_codeberg_release "autocaliweb" "gelbphoenix/autocaliweb"; then
|
||||
msg_info "Stopping Services"
|
||||
systemctl stop autocaliweb metadata-change-detector acw-ingest-service acw-auto-zipper
|
||||
msg_ok "Stopped Services"
|
||||
@@ -39,7 +39,7 @@ function update_script() {
|
||||
INSTALL_DIR="/opt/autocaliweb"
|
||||
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}
|
||||
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"
|
||||
cd "$INSTALL_DIR"
|
||||
|
||||
6
ct/headers/kitchenowl
Normal file
6
ct/headers/kitchenowl
Normal file
@@ -0,0 +1,6 @@
|
||||
__ __ _ __ __ ____ __
|
||||
/ //_/(_) /______/ /_ ___ ____ / __ \_ __/ /
|
||||
/ ,< / / __/ ___/ __ \/ _ \/ __ \/ / / / | /| / / /
|
||||
/ /| |/ / /_/ /__/ / / / __/ / / / /_/ /| |/ |/ / /
|
||||
/_/ |_/_/\__/\___/_/ /_/\___/_/ /_/\____/ |__/|__/_/
|
||||
|
||||
19
ct/immich.sh
19
ct/immich.sh
@@ -253,25 +253,6 @@ EOF
|
||||
fi
|
||||
systemctl restart immich-ml immich-web
|
||||
msg_ok "Updated successfully!"
|
||||
msg_info "Checking health of Immich-web & Immich-ml services"
|
||||
sleep 5
|
||||
web=0
|
||||
until curl -fs localhost:2283/api/server/ping | grep -q "pong" || [[ $web -gt 1 ]]; do
|
||||
msg_warn "Problem detected with Immich-web service, restarting..."
|
||||
systemctl restart immich-web && sleep 5
|
||||
[[ $(curl -fs localhost:2283/api/server/ping | grep "pong") ]] && break
|
||||
((web++))
|
||||
done
|
||||
[[ $web -lt 1 ]] && msg_ok "Immich-web service is reachable!" || msg_error "Please check '/var/log/immich/web.log' for more details"
|
||||
|
||||
ml=0
|
||||
until [[ $(curl -fs localhost:3003/ping) == "pong" ]] || [[ $ml -gt 1 ]]; do
|
||||
msg_warn "Problem detected with Immich-ml service, restarting..."
|
||||
systemctl restart immich-ml && sleep 5
|
||||
[[ $(curl -fs localhost:3003/ping) == "pong" ]] && break
|
||||
((ml++))
|
||||
done
|
||||
[[ $ml -lt 1 ]] && msg_ok "Immich-ml service is reachable!" || msg_error "Please check '/var/log/immich/ml.log' for more details"
|
||||
fi
|
||||
exit
|
||||
}
|
||||
|
||||
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,6 +27,7 @@ function update_script() {
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
ensure_dependencies graphicsmagick
|
||||
if [ ! -f /opt/n8n.env ]; then
|
||||
sed -i 's|^Environment="N8N_SECURE_COOKIE=false"$|EnvironmentFile=/opt/n8n.env|' /etc/systemd/system/n8n.service
|
||||
mkdir -p /opt
|
||||
@@ -37,6 +38,7 @@ N8N_PROTOCOL=http
|
||||
N8N_HOST=$LOCAL_IP
|
||||
EOF
|
||||
fi
|
||||
|
||||
NODE_VERSION="22" setup_nodejs
|
||||
|
||||
msg_info "Updating ${APP} LXC"
|
||||
|
||||
@@ -28,6 +28,12 @@ function update_script() {
|
||||
exit
|
||||
fi
|
||||
|
||||
msg_error "This script is currently disabled due to an external issue with the OpenResty APT repository."
|
||||
msg_error "The repository's GPG key uses SHA-1 signatures, which are no longer accepted by Debian as of February 1, 2026."
|
||||
msg_error "The issue is tracked in openresty/openresty#1097"
|
||||
msg_error "For more details, see: https://github.com/community-scripts/ProxmoxVE/issues/11406"
|
||||
exit 1
|
||||
|
||||
if [[ $(grep -E '^VERSION_ID=' /etc/os-release) == *"12"* ]]; then
|
||||
msg_error "Wrong Debian version detected!"
|
||||
msg_error "Please create a snapshot first. You must upgrade your LXC to Debian Trixie before updating. Visit: https://github.com/community-scripts/ProxmoxVE/discussions/7489"
|
||||
|
||||
@@ -30,6 +30,55 @@ function update_script() {
|
||||
|
||||
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
|
||||
msg_info "Stopping Services"
|
||||
systemctl stop tracearr postgresql redis
|
||||
@@ -74,10 +123,15 @@ function update_script() {
|
||||
chown -R tracearr:tracearr /data/tracearr
|
||||
msg_ok "Configured Tracearr"
|
||||
|
||||
msg_info "Starting Services"
|
||||
msg_info "Starting services"
|
||||
systemctl start postgresql redis tracearr
|
||||
msg_ok "Started Services"
|
||||
msg_ok "Started services"
|
||||
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
|
||||
exit
|
||||
}
|
||||
|
||||
84
frontend/bun.lock
generated
84
frontend/bun.lock
generated
@@ -20,6 +20,7 @@
|
||||
"@radix-ui/react-tabs": "^1.1.13",
|
||||
"@radix-ui/react-tooltip": "^1.2.8",
|
||||
"@tanstack/react-query": "^5.90.12",
|
||||
"@types/react-syntax-highlighter": "^15.5.13",
|
||||
"chart.js": "^4.5.1",
|
||||
"chartjs-plugin-datalabels": "^2.2.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
@@ -41,6 +42,7 @@
|
||||
"react-day-picker": "^9.12.0",
|
||||
"react-dom": "19.2.3",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-syntax-highlighter": "^16.1.0",
|
||||
"react-use-measure": "^2.1.7",
|
||||
"recharts": "3.6.0",
|
||||
"sharp": "^0.34.5",
|
||||
@@ -552,7 +554,7 @@
|
||||
|
||||
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
||||
|
||||
"@types/hast": ["@types/hast@2.3.10", "", { "dependencies": { "@types/unist": "^2" } }, "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw=="],
|
||||
"@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="],
|
||||
|
||||
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
|
||||
|
||||
@@ -564,10 +566,14 @@
|
||||
|
||||
"@types/node": ["@types/node@25.0.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-gWEkeiyYE4vqjON/+Obqcoeffmk0NF15WSBwSs7zwVA2bAbTaE0SJ7P0WNGoJn8uE7fiaV5a7dKYIJriEqOrmA=="],
|
||||
|
||||
"@types/prismjs": ["@types/prismjs@1.26.5", "", {}, "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ=="],
|
||||
|
||||
"@types/react": ["types-react@19.0.0-rc.1", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-RshndUfqTW6K3STLPis8BtAYCGOkMbtvYsi90gmVNDZBXUyUc5juf2PE9LfS/JmOlUIRO8cWTS/1MTnmhjDqyQ=="],
|
||||
|
||||
"@types/react-dom": ["types-react-dom@19.0.0-rc.1", "", { "dependencies": { "@types/react": "*" } }, "sha512-VSLZJl8VXCD0fAWp7DUTFUDCcZ8DVXOQmjhJMD03odgeFmu14ZQJHCXeETm3BEAhJqfgJaFkLnGkQv88sRx0fQ=="],
|
||||
|
||||
"@types/react-syntax-highlighter": ["@types/react-syntax-highlighter@15.5.13", "", { "dependencies": { "@types/react": "*" } }, "sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA=="],
|
||||
|
||||
"@types/stylis": ["@types/stylis@4.2.5", "", {}, "sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw=="],
|
||||
|
||||
"@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
|
||||
@@ -742,9 +748,9 @@
|
||||
|
||||
"character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="],
|
||||
|
||||
"character-entities-legacy": ["character-entities-legacy@1.1.4", "", {}, "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA=="],
|
||||
"character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="],
|
||||
|
||||
"character-reference-invalid": ["character-reference-invalid@1.1.4", "", {}, "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg=="],
|
||||
"character-reference-invalid": ["character-reference-invalid@2.0.1", "", {}, "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="],
|
||||
|
||||
"chart.js": ["chart.js@4.5.1", "", { "dependencies": { "@kurkle/color": "^0.3.0" } }, "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw=="],
|
||||
|
||||
@@ -768,7 +774,7 @@
|
||||
|
||||
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
|
||||
|
||||
"comma-separated-tokens": ["comma-separated-tokens@1.0.8", "", {}, "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw=="],
|
||||
"comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="],
|
||||
|
||||
"commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="],
|
||||
|
||||
@@ -1012,7 +1018,7 @@
|
||||
|
||||
"fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="],
|
||||
|
||||
"fault": ["fault@2.0.1", "", { "dependencies": { "format": "^0.2.0" } }, "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ=="],
|
||||
"fault": ["fault@1.0.4", "", { "dependencies": { "format": "^0.2.0" } }, "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA=="],
|
||||
|
||||
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
|
||||
|
||||
@@ -1088,9 +1094,9 @@
|
||||
|
||||
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
|
||||
|
||||
"hast-util-parse-selector": ["hast-util-parse-selector@2.2.5", "", {}, "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ=="],
|
||||
"hast-util-parse-selector": ["hast-util-parse-selector@4.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A=="],
|
||||
|
||||
"hastscript": ["hastscript@6.0.0", "", { "dependencies": { "@types/hast": "^2.0.0", "comma-separated-tokens": "^1.0.0", "hast-util-parse-selector": "^2.0.0", "property-information": "^5.0.0", "space-separated-tokens": "^1.0.0" } }, "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w=="],
|
||||
"hastscript": ["hastscript@9.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-parse-selector": "^4.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0" } }, "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w=="],
|
||||
|
||||
"hermes-estree": ["hermes-estree@0.25.1", "", {}, "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw=="],
|
||||
|
||||
@@ -1124,9 +1130,9 @@
|
||||
|
||||
"internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="],
|
||||
|
||||
"is-alphabetical": ["is-alphabetical@1.0.4", "", {}, "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg=="],
|
||||
"is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="],
|
||||
|
||||
"is-alphanumerical": ["is-alphanumerical@1.0.4", "", { "dependencies": { "is-alphabetical": "^1.0.0", "is-decimal": "^1.0.0" } }, "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A=="],
|
||||
"is-alphanumerical": ["is-alphanumerical@2.0.1", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw=="],
|
||||
|
||||
"is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="],
|
||||
|
||||
@@ -1150,7 +1156,7 @@
|
||||
|
||||
"is-date-object": ["is-date-object@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg=="],
|
||||
|
||||
"is-decimal": ["is-decimal@1.0.4", "", {}, "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw=="],
|
||||
"is-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="],
|
||||
|
||||
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
|
||||
|
||||
@@ -1160,7 +1166,7 @@
|
||||
|
||||
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
|
||||
|
||||
"is-hexadecimal": ["is-hexadecimal@1.0.4", "", {}, "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw=="],
|
||||
"is-hexadecimal": ["is-hexadecimal@2.0.1", "", {}, "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="],
|
||||
|
||||
"is-immutable-type": ["is-immutable-type@5.0.1", "", { "dependencies": { "@typescript-eslint/type-utils": "^8.0.0", "ts-api-utils": "^2.0.0", "ts-declaration-location": "^1.0.4" }, "peerDependencies": { "eslint": "*", "typescript": ">=4.7.4" } }, "sha512-LkHEOGVZZXxGl8vDs+10k3DvP++SEoYEAJLRk6buTFi6kD7QekThV7xHS0j6gpnUCQ0zpud/gMDGiV4dQneLTg=="],
|
||||
|
||||
@@ -1416,7 +1422,7 @@
|
||||
|
||||
"parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
|
||||
|
||||
"parse-entities": ["parse-entities@2.0.0", "", { "dependencies": { "character-entities": "^1.0.0", "character-entities-legacy": "^1.0.0", "character-reference-invalid": "^1.0.0", "is-alphanumerical": "^1.0.0", "is-decimal": "^1.0.0", "is-hexadecimal": "^1.0.0" } }, "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ=="],
|
||||
"parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="],
|
||||
|
||||
"parse-gitignore": ["parse-gitignore@2.0.0", "", {}, "sha512-RmVuCHWsfu0QPNW+mraxh/xjQVw/lhUCUru8Zni3Ctq3AoMhpDTq0OVdKS6iesd6Kqb7viCV3isAL43dciOSog=="],
|
||||
|
||||
@@ -1474,7 +1480,7 @@
|
||||
|
||||
"prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="],
|
||||
|
||||
"property-information": ["property-information@5.6.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA=="],
|
||||
"property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],
|
||||
|
||||
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
|
||||
|
||||
@@ -1508,7 +1514,7 @@
|
||||
|
||||
"react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="],
|
||||
|
||||
"react-syntax-highlighter": ["react-syntax-highlighter@15.6.6", "", { "dependencies": { "@babel/runtime": "^7.3.1", "highlight.js": "^10.4.1", "highlightjs-vue": "^1.0.0", "lowlight": "^1.17.0", "prismjs": "^1.30.0", "refractor": "^3.6.0" }, "peerDependencies": { "react": ">= 0.14.0" } }, "sha512-DgXrc+AZF47+HvAPEmn7Ua/1p10jNoVZVI/LoPiYdtY+OM+/nG5yefLHKJwdKqY1adMuHFbeyBaG9j64ML7vTw=="],
|
||||
"react-syntax-highlighter": ["react-syntax-highlighter@16.1.0", "", { "dependencies": { "@babel/runtime": "^7.28.4", "highlight.js": "^10.4.1", "highlightjs-vue": "^1.0.0", "lowlight": "^1.17.0", "prismjs": "^1.30.0", "refractor": "^5.0.0" }, "peerDependencies": { "react": ">= 0.14.0" } }, "sha512-E40/hBiP5rCNwkeBN1vRP+xow1X0pndinO+z3h7HLsHyjztbyjfzNWNKuAsJj+7DLam9iT4AaaOZnueCU+Nplg=="],
|
||||
|
||||
"react-use-measure": ["react-use-measure@2.1.7", "", { "peerDependencies": { "react": ">=16.13", "react-dom": ">=16.13" }, "optionalPeers": ["react-dom"] }, "sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg=="],
|
||||
|
||||
@@ -1526,7 +1532,7 @@
|
||||
|
||||
"reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="],
|
||||
|
||||
"refractor": ["refractor@3.6.0", "", { "dependencies": { "hastscript": "^6.0.0", "parse-entities": "^2.0.0", "prismjs": "~1.27.0" } }, "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA=="],
|
||||
"refractor": ["refractor@5.0.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/prismjs": "^1.0.0", "hastscript": "^9.0.0", "parse-entities": "^4.0.0" } }, "sha512-QXOrHQF5jOpjjLfiNk5GFnWhRXvxjUVnlFxkeDmewR5sXkr3iM46Zo+CnRR8B+MDVqkULW4EcLVcRBNOPXHosw=="],
|
||||
|
||||
"regexp-ast-analysis": ["regexp-ast-analysis@0.7.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.8.0", "refa": "^0.12.1" } }, "sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A=="],
|
||||
|
||||
@@ -1598,7 +1604,7 @@
|
||||
|
||||
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
||||
|
||||
"space-separated-tokens": ["space-separated-tokens@1.1.5", "", {}, "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA=="],
|
||||
"space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="],
|
||||
|
||||
"spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="],
|
||||
|
||||
@@ -1836,8 +1842,6 @@
|
||||
|
||||
"@reduxjs/toolkit/immer": ["immer@11.0.1", "", {}, "sha512-naDCyggtcBWANtIrjQEajhhBEuL9b0Zg4zmlWK2CzS6xCWSE39/vvf4LqnMjUAWHBhot4m9MHCM/Z+mfWhUkiA=="],
|
||||
|
||||
"@types/hast/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
|
||||
|
||||
"@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.50.0", "", { "dependencies": { "@typescript-eslint/types": "8.50.0", "@typescript-eslint/visitor-keys": "8.50.0" } }, "sha512-xCwfuCZjhIqy7+HKxBLrDVT5q/iq7XBVBXLn57RTIIpelLtEIZHXAF/Upa3+gaCpeV1NNS5Z9A+ID6jn50VD4A=="],
|
||||
|
||||
"@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.50.0", "", { "dependencies": { "@typescript-eslint/types": "8.50.0", "@typescript-eslint/typescript-estree": "8.50.0", "@typescript-eslint/utils": "8.50.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-7OciHT2lKCewR0mFoBrvZJ4AXTMe/sYOe87289WAViOocEmDjjv8MvIOT2XESuKj9jp8u3SZYUSh89QA4S1kQw=="],
|
||||
@@ -1912,25 +1916,25 @@
|
||||
|
||||
"jsonc-eslint-parser/espree": ["espree@9.6.1", "", { "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" } }, "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ=="],
|
||||
|
||||
"lowlight/fault": ["fault@1.0.4", "", { "dependencies": { "format": "^0.2.0" } }, "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA=="],
|
||||
|
||||
"mdast-util-find-and-replace/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
|
||||
|
||||
"mdast-util-frontmatter/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
|
||||
|
||||
"micromark-extension-frontmatter/fault": ["fault@2.0.1", "", { "dependencies": { "format": "^0.2.0" } }, "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ=="],
|
||||
|
||||
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
|
||||
"mlly/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="],
|
||||
|
||||
"next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="],
|
||||
|
||||
"parse-entities/character-entities": ["character-entities@1.2.4", "", {}, "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw=="],
|
||||
"parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
|
||||
|
||||
"prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
|
||||
|
||||
"readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
"react-code-blocks/react-syntax-highlighter": ["react-syntax-highlighter@15.6.6", "", { "dependencies": { "@babel/runtime": "^7.3.1", "highlight.js": "^10.4.1", "highlightjs-vue": "^1.0.0", "lowlight": "^1.17.0", "prismjs": "^1.30.0", "refractor": "^3.6.0" }, "peerDependencies": { "react": ">= 0.14.0" } }, "sha512-DgXrc+AZF47+HvAPEmn7Ua/1p10jNoVZVI/LoPiYdtY+OM+/nG5yefLHKJwdKqY1adMuHFbeyBaG9j64ML7vTw=="],
|
||||
|
||||
"refractor/prismjs": ["prismjs@1.27.0", "", {}, "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA=="],
|
||||
"readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
|
||||
"styled-components/csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
||||
|
||||
@@ -1984,10 +1988,44 @@
|
||||
|
||||
"mlly/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
|
||||
|
||||
"react-code-blocks/react-syntax-highlighter/refractor": ["refractor@3.6.0", "", { "dependencies": { "hastscript": "^6.0.0", "parse-entities": "^2.0.0", "prismjs": "~1.27.0" } }, "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA=="],
|
||||
|
||||
"tailwindcss/fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||
|
||||
"@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
|
||||
|
||||
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
|
||||
|
||||
"react-code-blocks/react-syntax-highlighter/refractor/hastscript": ["hastscript@6.0.0", "", { "dependencies": { "@types/hast": "^2.0.0", "comma-separated-tokens": "^1.0.0", "hast-util-parse-selector": "^2.0.0", "property-information": "^5.0.0", "space-separated-tokens": "^1.0.0" } }, "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w=="],
|
||||
|
||||
"react-code-blocks/react-syntax-highlighter/refractor/parse-entities": ["parse-entities@2.0.0", "", { "dependencies": { "character-entities": "^1.0.0", "character-entities-legacy": "^1.0.0", "character-reference-invalid": "^1.0.0", "is-alphanumerical": "^1.0.0", "is-decimal": "^1.0.0", "is-hexadecimal": "^1.0.0" } }, "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ=="],
|
||||
|
||||
"react-code-blocks/react-syntax-highlighter/refractor/prismjs": ["prismjs@1.27.0", "", {}, "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA=="],
|
||||
|
||||
"react-code-blocks/react-syntax-highlighter/refractor/hastscript/@types/hast": ["@types/hast@2.3.10", "", { "dependencies": { "@types/unist": "^2" } }, "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw=="],
|
||||
|
||||
"react-code-blocks/react-syntax-highlighter/refractor/hastscript/comma-separated-tokens": ["comma-separated-tokens@1.0.8", "", {}, "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw=="],
|
||||
|
||||
"react-code-blocks/react-syntax-highlighter/refractor/hastscript/hast-util-parse-selector": ["hast-util-parse-selector@2.2.5", "", {}, "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ=="],
|
||||
|
||||
"react-code-blocks/react-syntax-highlighter/refractor/hastscript/property-information": ["property-information@5.6.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA=="],
|
||||
|
||||
"react-code-blocks/react-syntax-highlighter/refractor/hastscript/space-separated-tokens": ["space-separated-tokens@1.1.5", "", {}, "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA=="],
|
||||
|
||||
"react-code-blocks/react-syntax-highlighter/refractor/parse-entities/character-entities": ["character-entities@1.2.4", "", {}, "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw=="],
|
||||
|
||||
"react-code-blocks/react-syntax-highlighter/refractor/parse-entities/character-entities-legacy": ["character-entities-legacy@1.1.4", "", {}, "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA=="],
|
||||
|
||||
"react-code-blocks/react-syntax-highlighter/refractor/parse-entities/character-reference-invalid": ["character-reference-invalid@1.1.4", "", {}, "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg=="],
|
||||
|
||||
"react-code-blocks/react-syntax-highlighter/refractor/parse-entities/is-alphanumerical": ["is-alphanumerical@1.0.4", "", { "dependencies": { "is-alphabetical": "^1.0.0", "is-decimal": "^1.0.0" } }, "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A=="],
|
||||
|
||||
"react-code-blocks/react-syntax-highlighter/refractor/parse-entities/is-decimal": ["is-decimal@1.0.4", "", {}, "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw=="],
|
||||
|
||||
"react-code-blocks/react-syntax-highlighter/refractor/parse-entities/is-hexadecimal": ["is-hexadecimal@1.0.4", "", {}, "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw=="],
|
||||
|
||||
"react-code-blocks/react-syntax-highlighter/refractor/hastscript/@types/hast/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
|
||||
|
||||
"react-code-blocks/react-syntax-highlighter/refractor/parse-entities/is-alphanumerical/is-alphabetical": ["is-alphabetical@1.0.4", "", {}, "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg=="],
|
||||
}
|
||||
}
|
||||
|
||||
2
frontend/package.json
generated
2
frontend/package.json
generated
@@ -31,6 +31,7 @@
|
||||
"@radix-ui/react-tabs": "^1.1.13",
|
||||
"@radix-ui/react-tooltip": "^1.2.8",
|
||||
"@tanstack/react-query": "^5.90.12",
|
||||
"@types/react-syntax-highlighter": "^15.5.13",
|
||||
"chart.js": "^4.5.1",
|
||||
"chartjs-plugin-datalabels": "^2.2.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
@@ -52,6 +53,7 @@
|
||||
"react-day-picker": "^9.12.0",
|
||||
"react-dom": "19.2.3",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-syntax-highlighter": "^16.1.0",
|
||||
"react-use-measure": "^2.1.7",
|
||||
"recharts": "3.6.0",
|
||||
"sharp": "^0.34.5",
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
"updateable": true,
|
||||
"privileged": false,
|
||||
"interface_port": 8083,
|
||||
"documentation": "https://github.com/gelbphoenix/autocaliweb/wiki",
|
||||
"documentation": "https://codeberg.org/gelbphoenix/autocaliweb/wiki",
|
||||
"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",
|
||||
"description": "A modern web management system for eBooks, eComics and PDFs",
|
||||
"install_methods": [
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"generated": "2026-02-01T12:08:49Z",
|
||||
"generated": "2026-02-02T06:25:10Z",
|
||||
"versions": [
|
||||
{
|
||||
"slug": "2fauth",
|
||||
@@ -95,16 +95,16 @@
|
||||
{
|
||||
"slug": "bar-assistant",
|
||||
"repo": "karlomikus/bar-assistant",
|
||||
"version": "v5.12.0",
|
||||
"version": "v5.13.0",
|
||||
"pinned": false,
|
||||
"date": "2026-01-11T09:37:23Z"
|
||||
"date": "2026-02-01T15:49:21Z"
|
||||
},
|
||||
{
|
||||
"slug": "bazarr",
|
||||
"repo": "morpheus65535/bazarr",
|
||||
"version": "v1.5.4",
|
||||
"version": "v1.5.5",
|
||||
"pinned": false,
|
||||
"date": "2026-01-04T22:41:00Z"
|
||||
"date": "2026-02-01T18:00:34Z"
|
||||
},
|
||||
{
|
||||
"slug": "bentopdf",
|
||||
@@ -116,9 +116,9 @@
|
||||
{
|
||||
"slug": "beszel",
|
||||
"repo": "henrygd/beszel",
|
||||
"version": "v0.18.2",
|
||||
"version": "v0.18.3",
|
||||
"pinned": false,
|
||||
"date": "2026-01-12T23:58:00Z"
|
||||
"date": "2026-02-01T19:02:42Z"
|
||||
},
|
||||
{
|
||||
"slug": "bitmagnet",
|
||||
@@ -242,9 +242,9 @@
|
||||
{
|
||||
"slug": "discopanel",
|
||||
"repo": "nickheyer/discopanel",
|
||||
"version": "v1.0.32",
|
||||
"version": "v1.0.35",
|
||||
"pinned": false,
|
||||
"date": "2026-01-31T22:24:53Z"
|
||||
"date": "2026-02-02T05:20:12Z"
|
||||
},
|
||||
{
|
||||
"slug": "dispatcharr",
|
||||
@@ -487,9 +487,9 @@
|
||||
{
|
||||
"slug": "homebox",
|
||||
"repo": "sysadminsmedia/homebox",
|
||||
"version": "v0.23.0",
|
||||
"version": "v0.23.1",
|
||||
"pinned": false,
|
||||
"date": "2026-01-30T17:41:01Z"
|
||||
"date": "2026-02-01T22:53:32Z"
|
||||
},
|
||||
{
|
||||
"slug": "homepage",
|
||||
@@ -515,9 +515,9 @@
|
||||
{
|
||||
"slug": "huntarr",
|
||||
"repo": "plexguide/Huntarr.io",
|
||||
"version": "9.1.5",
|
||||
"version": "9.1.8",
|
||||
"pinned": false,
|
||||
"date": "2026-01-31T22:55:29Z"
|
||||
"date": "2026-02-02T01:29:45Z"
|
||||
},
|
||||
{
|
||||
"slug": "inspircd",
|
||||
@@ -543,9 +543,9 @@
|
||||
{
|
||||
"slug": "jackett",
|
||||
"repo": "Jackett/Jackett",
|
||||
"version": "v0.24.1003",
|
||||
"version": "v0.24.1008",
|
||||
"pinned": false,
|
||||
"date": "2026-02-01T05:55:30Z"
|
||||
"date": "2026-02-02T05:55:21Z"
|
||||
},
|
||||
{
|
||||
"slug": "joplin-server",
|
||||
@@ -1187,9 +1187,9 @@
|
||||
{
|
||||
"slug": "scanopy",
|
||||
"repo": "scanopy/scanopy",
|
||||
"version": "v0.13.6",
|
||||
"version": "v0.14.0",
|
||||
"pinned": false,
|
||||
"date": "2026-01-15T23:34:51Z"
|
||||
"date": "2026-02-01T17:02:37Z"
|
||||
},
|
||||
{
|
||||
"slug": "scraparr",
|
||||
@@ -1299,9 +1299,9 @@
|
||||
{
|
||||
"slug": "tandoor",
|
||||
"repo": "TandoorRecipes/recipes",
|
||||
"version": "2.4.1",
|
||||
"version": "2.4.2",
|
||||
"pinned": false,
|
||||
"date": "2026-01-30T06:52:26Z"
|
||||
"date": "2026-02-01T12:52:37Z"
|
||||
},
|
||||
{
|
||||
"slug": "tasmoadmin",
|
||||
@@ -1558,9 +1558,9 @@
|
||||
{
|
||||
"slug": "zigbee2mqtt",
|
||||
"repo": "Koenkk/zigbee2mqtt",
|
||||
"version": "2.7.2",
|
||||
"version": "2.8.0",
|
||||
"pinned": false,
|
||||
"date": "2026-01-01T13:43:47Z"
|
||||
"date": "2026-02-01T19:27:25Z"
|
||||
},
|
||||
{
|
||||
"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": []
|
||||
}
|
||||
@@ -13,6 +13,8 @@
|
||||
"website": "https://nginxproxymanager.com/",
|
||||
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/nginx-proxy-manager.webp",
|
||||
"config_path": "",
|
||||
"disable": true,
|
||||
"disable_description": "This script is temporarily disabled due to an external issue with the OpenResty APT repository. The repository's GPG key uses SHA-1 signatures, which are no longer accepted by Debian as of February 1, 2026. This causes installation to fail with APT errors. The issue is tracked in openresty/openresty#1097. A workaround exists but requires manual configuration. The script will be re-enabled once OpenResty updates their repository signing key. For more details, see: https://github.com/community-scripts/ProxmoxVE/issues/11406",
|
||||
"description": "Nginx Proxy Manager is a tool that provides a web-based interface to manage Nginx reverse proxies. It enables users to easily and securely expose their services to the internet by providing features such as HTTPS encryption, domain mapping, and access control. It eliminates the need for manual configuration of Nginx reverse proxies, making it easy for users to quickly and securely expose their services to the public.",
|
||||
"install_methods": [
|
||||
{
|
||||
|
||||
@@ -31,8 +31,8 @@ export const ScriptSchema = z.object({
|
||||
privileged: z.boolean(),
|
||||
interface_port: z.number().nullable(),
|
||||
documentation: z.string().nullable(),
|
||||
website: z.string().url().nullable(),
|
||||
logo: z.string().url().nullable(),
|
||||
website: z.url().nullable(),
|
||||
logo: z.url().nullable(),
|
||||
config_path: z.string(),
|
||||
description: z.string().min(1, "Description is required"),
|
||||
disable: z.boolean().optional(),
|
||||
|
||||
@@ -28,11 +28,14 @@ import { ScriptSchema } from "./_schemas/schemas";
|
||||
import Categories from "./_components/categories";
|
||||
import Note from "./_components/note";
|
||||
|
||||
import { nord } from "react-syntax-highlighter/dist/esm/styles/hljs";
|
||||
import SyntaxHighlighter from "react-syntax-highlighter";
|
||||
|
||||
const initialScript: Script = {
|
||||
name: "",
|
||||
slug: "",
|
||||
categories: [],
|
||||
date_created: "",
|
||||
date_created: format(new Date(), "yyyy-MM-dd"),
|
||||
type: "ct",
|
||||
updateable: false,
|
||||
privileged: false,
|
||||
@@ -98,13 +101,18 @@ export default function JSONGenerator() {
|
||||
}, []);
|
||||
|
||||
const handleCopy = useCallback(() => {
|
||||
if (!isValid) toast.warning("JSON schema is invalid. Copying anyway.");
|
||||
navigator.clipboard.writeText(JSON.stringify(script, null, 2));
|
||||
setIsCopied(true);
|
||||
setTimeout(() => setIsCopied(false), 2000);
|
||||
toast.success("Copied metadata to clipboard");
|
||||
if (isValid) toast.success("Copied metadata to clipboard");
|
||||
}, [script]);
|
||||
|
||||
const handleDownload = useCallback(() => {
|
||||
if (isValid === false) {
|
||||
toast.error("Cannot download invalid JSON");
|
||||
return;
|
||||
}
|
||||
const jsonString = JSON.stringify(script, null, 2);
|
||||
const blob = new Blob([jsonString], { type: "application/json" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
@@ -175,7 +183,7 @@ export default function JSONGenerator() {
|
||||
</div>
|
||||
<div>
|
||||
<Label>
|
||||
Logo <span className="text-red-500">*</span>
|
||||
Logo
|
||||
</Label>
|
||||
<Input
|
||||
placeholder="Full logo URL"
|
||||
@@ -204,7 +212,9 @@ export default function JSONGenerator() {
|
||||
<Categories script={script} setScript={setScript} categories={categories} />
|
||||
<div className="flex gap-2">
|
||||
<div className="flex flex-col gap-2 w-full">
|
||||
<Label>Date Created</Label>
|
||||
<Label>
|
||||
Date Created <span className="text-red-500">*</span>
|
||||
</Label>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild className="flex-1">
|
||||
<Button
|
||||
@@ -220,7 +230,7 @@ export default function JSONGenerator() {
|
||||
mode="single"
|
||||
selected={new Date(script.date_created)}
|
||||
onSelect={handleDateSelect}
|
||||
initialFocus
|
||||
autoFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
@@ -324,9 +334,13 @@ export default function JSONGenerator() {
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<pre className="mt-4 p-4 bg-secondary rounded shadow overflow-x-scroll">
|
||||
<SyntaxHighlighter
|
||||
language="json"
|
||||
style={nord}
|
||||
className="mt-4 p-4 bg-secondary rounded shadow overflow-x-scroll"
|
||||
>
|
||||
{JSON.stringify(script, null, 2)}
|
||||
</pre>
|
||||
</SyntaxHighlighter>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -17,7 +17,8 @@ msg_info "Installing Dependencies"
|
||||
$STD apt install -y nginx
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
PHP_VERSION="8.4" PHP_FPM="YES" setup_php
|
||||
export PHP_VERSION="8.4"
|
||||
PHP_FPM="YES" setup_php
|
||||
setup_composer
|
||||
setup_mariadb
|
||||
MARIADB_DB_NAME="2fauth_db" MARIADB_DB_USER="2fauth" setup_mariadb_db
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: vhsdream
|
||||
# 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"
|
||||
color
|
||||
@@ -56,7 +56,7 @@ msg_ok "Installed Calibre"
|
||||
|
||||
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"
|
||||
INSTALL_DIR="/opt/autocaliweb"
|
||||
@@ -111,8 +111,8 @@ msg_info "Initializing databases"
|
||||
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")
|
||||
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://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/metadata.db -o "$CALIBRE_LIB_DIR"/metadata.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
|
||||
UPDATE settings SET
|
||||
config_kepubifypath='$KEPUBIFY_PATH',
|
||||
|
||||
@@ -477,26 +477,6 @@ chown -R immich:immich "$INSTALL_DIR" /var/log/immich
|
||||
systemctl enable -q --now immich-ml.service immich-web.service
|
||||
msg_ok "Modified user, created env file, scripts and services"
|
||||
|
||||
msg_info "Checking health of Immich-web & Immich-ml services"
|
||||
sleep 5
|
||||
web=0
|
||||
until curl -fs localhost:2283/api/server/ping | grep -q "pong" || [[ $web -gt 1 ]]; do
|
||||
msg_warn "Problem detected with Immich-web service, restarting..."
|
||||
systemctl restart immich-web && sleep 5
|
||||
[[ $(curl -fs localhost:2283/api/server/ping | grep "pong") ]] && break
|
||||
((web++))
|
||||
done
|
||||
[[ $web -lt 1 ]] && msg_ok "Immich-web service is reachable!" || msg_error "Please check '/var/log/immich/web.log' for more details"
|
||||
|
||||
ml=0
|
||||
until [[ $(curl -fs localhost:3003/ping) == "pong" ]] || [[ $ml -gt 1 ]]; do
|
||||
msg_warn "Problem detected with Immich-ml service, restarting..."
|
||||
systemctl restart immich-ml && sleep 5
|
||||
[[ $(curl -fs localhost:3003/ping) == "pong" ]] && break
|
||||
((ml++))
|
||||
done
|
||||
[[ $ml -lt 1 ]] && msg_ok "Immich-ml service is reachable!" || msg_error "Please check '/var/log/immich/ml.log' for more details"
|
||||
|
||||
motd_ssh
|
||||
customize
|
||||
cleanup_lxc
|
||||
|
||||
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
|
||||
@@ -18,7 +18,8 @@ $STD apt install -y \
|
||||
ca-certificates \
|
||||
build-essential \
|
||||
python3 \
|
||||
python3-setuptools
|
||||
python3-setuptools \
|
||||
graphicsmagick
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
NODE_VERSION="22" setup_nodejs
|
||||
|
||||
@@ -31,7 +31,7 @@ After=network-online.target
|
||||
User=root
|
||||
Restart=always
|
||||
Type=simple
|
||||
ExecStart=/usr/local/bin/prometheus-paperless-exporter \
|
||||
ExecStart=/usr/bin/prometheus-paperless-exporter \
|
||||
--paperless_url=http://paperless.example.org \
|
||||
--paperless_auth_token_file=/etc/prometheus-paperless-ngx-exporter/paperless_auth_token_file
|
||||
ExecReload=/bin/kill -HUP \$MAINPID
|
||||
|
||||
@@ -109,18 +109,34 @@ if command -v timescaledb-tune &> /dev/null; then
|
||||
|| echo "Warning: timescaledb-tune failed (non-fatal)"
|
||||
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"
|
||||
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 "# 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
|
||||
|
||||
626
misc/tools.func
626
misc/tools.func
@@ -821,6 +821,54 @@ github_api_call() {
|
||||
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() {
|
||||
local current="$1"
|
||||
local target="$2"
|
||||
@@ -1385,6 +1433,37 @@ get_latest_github_release() {
|
||||
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)
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -1559,6 +1638,119 @@ check_for_gh_release() {
|
||||
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.
|
||||
#
|
||||
@@ -1648,6 +1840,440 @@ function ensure_usr_local_bin_persist() {
|
||||
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).
|
||||
#
|
||||
|
||||
Reference in New Issue
Block a user