mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2025-11-04 10:22:50 +00:00
Compare commits
63 Commits
2025-09-01
...
2025-09-06
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54d4d58b15 | ||
|
|
889a58c00e | ||
|
|
e9a5d7587a | ||
|
|
6f84046741 | ||
|
|
ff96351db8 | ||
|
|
1b632199b3 | ||
|
|
9fb02a93b4 | ||
|
|
3aa56651d8 | ||
|
|
17d4c59041 | ||
|
|
2bfb35779b | ||
|
|
83b93390c9 | ||
|
|
7ce47ad414 | ||
|
|
646e0c31f4 | ||
|
|
0c7e200a94 | ||
|
|
a9b02b3e9c | ||
|
|
b62adc2c5c | ||
|
|
3438b046e5 | ||
|
|
cbd6d6d0f3 | ||
|
|
cf6c429c57 | ||
|
|
bbe71cbbb9 | ||
|
|
9b6a736c8c | ||
|
|
c395ccc270 | ||
|
|
3dd72e08e9 | ||
|
|
1d989bea73 | ||
|
|
f881b88344 | ||
|
|
06dbad83ef | ||
|
|
7ff966b042 | ||
|
|
62264f37a6 | ||
|
|
bf05dabc4c | ||
|
|
bc229d9738 | ||
|
|
969b08caa8 | ||
|
|
c1c43ed2cb | ||
|
|
e74767d1a4 | ||
|
|
e9e17f4f51 | ||
|
|
2c1b15a40e | ||
|
|
a4bfaf1646 | ||
|
|
6fa12cc814 | ||
|
|
d314168a37 | ||
|
|
d6ad11c5c2 | ||
|
|
534592b44a | ||
|
|
d9b6b58b36 | ||
|
|
298eb7e83d | ||
|
|
c2dd1e413f | ||
|
|
a4f1766408 | ||
|
|
a24169e9b8 | ||
|
|
45a2163e66 | ||
|
|
2fc3e62d60 | ||
|
|
210b846d61 | ||
|
|
b04cfb65f7 | ||
|
|
6a2fc4083b | ||
|
|
f7f53943c2 | ||
|
|
31f4d9b16c | ||
|
|
cd4cd5eec1 | ||
|
|
8a7eeee727 | ||
|
|
be5d65f421 | ||
|
|
591af3f109 | ||
|
|
a3e0df9de1 | ||
|
|
596699d07e | ||
|
|
b2275b44c2 | ||
|
|
737842fb1e | ||
|
|
646cb2bc30 | ||
|
|
4599bfe052 | ||
|
|
bb85b1d4ac |
90
CHANGELOG.md
90
CHANGELOG.md
@@ -10,8 +10,98 @@
|
||||
> [!CAUTION]
|
||||
Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit the project's popularity for potentially malicious purposes.
|
||||
|
||||
## 2025-09-07
|
||||
|
||||
## 2025-09-06
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- Resilio Sync ([#7442](https://github.com/community-scripts/ProxmoxVE/pull/7442))
|
||||
- leantime ([#7414](https://github.com/community-scripts/ProxmoxVE/pull/7414))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- use debian source for direct installation of MQTT [@EtlamGit](https://github.com/EtlamGit) ([#7423](https://github.com/community-scripts/ProxmoxVE/pull/7423))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- feat: added mobile ui subscription nag removal [@ivan-penchev](https://github.com/ivan-penchev) ([#7164](https://github.com/community-scripts/ProxmoxVE/pull/7164))
|
||||
|
||||
### 🌐 Website
|
||||
|
||||
- #### 📝 Script Information
|
||||
|
||||
- MediaManager Configuration Path [@austinpilz](https://github.com/austinpilz) ([#7408](https://github.com/community-scripts/ProxmoxVE/pull/7408))
|
||||
- Paperless-NGX: Remove default credentials from json [@tremor021](https://github.com/tremor021) ([#7403](https://github.com/community-scripts/ProxmoxVE/pull/7403))
|
||||
|
||||
## 2025-09-05
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- Tududi: Pin version to 0.80 [@vhsdream](https://github.com/vhsdream) ([#7420](https://github.com/community-scripts/ProxmoxVE/pull/7420))
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- AdventureLog: Update dependencies [@tremor021](https://github.com/tremor021) ([#7404](https://github.com/community-scripts/ProxmoxVE/pull/7404))
|
||||
|
||||
### 🌐 Website
|
||||
|
||||
- refactor: Enhance ScriptAccordion and Sidebar components to support selectedCategory state [@BramSuurdje](https://github.com/BramSuurdje) ([#7405](https://github.com/community-scripts/ProxmoxVE/pull/7405))
|
||||
|
||||
## 2025-09-04
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- fix: Syntax error in Immich scripts [@henworth](https://github.com/henworth) ([#7398](https://github.com/community-scripts/ProxmoxVE/pull/7398))
|
||||
- Netdata: Fix pve_check for 8 [@MickLesk](https://github.com/MickLesk) ([#7392](https://github.com/community-scripts/ProxmoxVE/pull/7392))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Immich: pin compiled photo library revisions [@vhsdream](https://github.com/vhsdream) ([#7395](https://github.com/community-scripts/ProxmoxVE/pull/7395))
|
||||
|
||||
## 2025-09-03
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Element-Synapse: Increase HDD size [@tremor021](https://github.com/tremor021) ([#7384](https://github.com/community-scripts/ProxmoxVE/pull/7384))
|
||||
- Wizarr: fix uv lock issue; use correct output suppression [@vhsdream](https://github.com/vhsdream) ([#7378](https://github.com/community-scripts/ProxmoxVE/pull/7378))
|
||||
- Netbox: Fix missing directory [@tremor021](https://github.com/tremor021) ([#7374](https://github.com/community-scripts/ProxmoxVE/pull/7374))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Enhanced IP-Tag installation script with interactive configuration, improved VM IP detection, and better visual indicators [@DesertGamer](https://github.com/DesertGamer) ([#7366](https://github.com/community-scripts/ProxmoxVE/pull/7366))
|
||||
|
||||
### 🌐 Website
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Fix navigation [@BramSuurdje](https://github.com/BramSuurdje) ([#7376](https://github.com/community-scripts/ProxmoxVE/pull/7376))
|
||||
|
||||
## 2025-09-02
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- Increase default disk size for Apt-Cacher-NG [@MickLesk](https://github.com/MickLesk) ([#7352](https://github.com/community-scripts/ProxmoxVE/pull/7352))
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Snipe-IT: Fix Nginx configuration [@tremor021](https://github.com/tremor021) ([#7358](https://github.com/community-scripts/ProxmoxVE/pull/7358))
|
||||
- booklore: remove folder before update [@MickLesk](https://github.com/MickLesk) ([#7351](https://github.com/community-scripts/ProxmoxVE/pull/7351))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- Immich: bump version to 1.140.1 [@vhsdream](https://github.com/vhsdream) ([#7349](https://github.com/community-scripts/ProxmoxVE/pull/7349))
|
||||
|
||||
### 🌐 Website
|
||||
|
||||
- #### 📝 Script Information
|
||||
|
||||
- pbs: increase note on website for ipv6 [@MickLesk](https://github.com/MickLesk) ([#7339](https://github.com/community-scripts/ProxmoxVE/pull/7339))
|
||||
|
||||
## 2025-09-01
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
@@ -27,6 +27,10 @@ function update_script() {
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
if ! command -v memcached >/dev/null 2>&1; then
|
||||
$STD apt-get update
|
||||
$STD apt-get install -y memcached libmemcached-tools
|
||||
fi
|
||||
if check_for_gh_release "adventurelog" "seanmorley15/adventurelog"; then
|
||||
msg_info "Stopping Services"
|
||||
systemctl stop adventurelog-backend
|
||||
|
||||
@@ -9,7 +9,7 @@ APP="Apt-Cacher-NG"
|
||||
var_tags="${var_tags:-caching}"
|
||||
var_cpu="${var_cpu:-1}"
|
||||
var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-2}"
|
||||
var_disk="${var_disk:-10}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-12}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
@@ -20,18 +20,18 @@ color
|
||||
catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
if [[ ! -d /var ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
msg_info "Updating $APP LXC"
|
||||
$STD apt-get update
|
||||
$STD apt-get -y upgrade
|
||||
msg_ok "Updated $APP LXC"
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
if [[ ! -d /var ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
msg_info "Updating $APP LXC"
|
||||
$STD apt-get update
|
||||
$STD apt-get -y upgrade
|
||||
msg_ok "Updated $APP LXC"
|
||||
exit
|
||||
}
|
||||
|
||||
start
|
||||
@@ -41,4 +41,4 @@ 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}:3142/acng-report.html${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3142/acng-report.html${CL}"
|
||||
|
||||
@@ -33,6 +33,10 @@ function update_script() {
|
||||
systemctl stop booklore
|
||||
msg_ok "Stopped $APP"
|
||||
|
||||
msg_info "backup old install"
|
||||
mv /opt/booklore /opt/booklore_bak
|
||||
msg_ok "backup done"
|
||||
|
||||
fetch_and_deploy_gh_release "booklore" "booklore-app/BookLore"
|
||||
|
||||
msg_info "Building Frontend"
|
||||
@@ -58,6 +62,7 @@ function update_script() {
|
||||
msg_info "Starting $APP"
|
||||
systemctl start booklore
|
||||
systemctl reload nginx
|
||||
rm -rf /opt/booklore_bak
|
||||
msg_ok "Started $APP"
|
||||
msg_ok "Updated Successfully"
|
||||
fi
|
||||
|
||||
@@ -9,7 +9,7 @@ APP="Element Synapse"
|
||||
var_tags="${var_tags:-server}"
|
||||
var_cpu="${var_cpu:-1}"
|
||||
var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-4}"
|
||||
var_disk="${var_disk:-8}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-12}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
6
ct/headers/leantime
Normal file
6
ct/headers/leantime
Normal file
@@ -0,0 +1,6 @@
|
||||
__ __ _
|
||||
/ / ___ ____ _____ / /_(_)___ ___ ___
|
||||
/ / / _ \/ __ `/ __ \/ __/ / __ `__ \/ _ \
|
||||
/ /___/ __/ /_/ / / / / /_/ / / / / / / __/
|
||||
/_____/\___/\__,_/_/ /_/\__/_/_/ /_/ /_/\___/
|
||||
|
||||
6
ct/headers/resiliosync
Normal file
6
ct/headers/resiliosync
Normal file
@@ -0,0 +1,6 @@
|
||||
____ _ ___ _____
|
||||
/ __ \___ _____(_) (_)___ / ___/__ ______ _____
|
||||
/ /_/ / _ \/ ___/ / / / __ \ \__ \/ / / / __ \/ ___/
|
||||
/ _, _/ __(__ ) / / / /_/ / ___/ / /_/ / / / / /__
|
||||
/_/ |_|\___/____/_/_/_/\____/ /____/\__, /_/ /_/\___/
|
||||
/____/
|
||||
17
ct/immich.sh
17
ct/immich.sh
@@ -61,7 +61,7 @@ function update_script() {
|
||||
done
|
||||
msg_ok "Image-processing libraries up to date"
|
||||
fi
|
||||
RELEASE="1.140.0"
|
||||
RELEASE="1.140.1"
|
||||
if check_for_gh_release "immich" "immich-app/immich" "${RELEASE}"; then
|
||||
msg_info "Stopping Services"
|
||||
systemctl stop immich-web
|
||||
@@ -206,7 +206,8 @@ function compile_libjxl() {
|
||||
SOURCE=${SOURCE_DIR}/libjxl
|
||||
JPEGLI_LIBJPEG_LIBRARY_SOVERSION="62"
|
||||
JPEGLI_LIBJPEG_LIBRARY_VERSION="62.3.0"
|
||||
: "${LIBJXL_REVISION:=$(jq -cr '.revision' "$BASE_DIR"/server/sources/libjxl.json)}"
|
||||
# : "${LIBJXL_REVISION:=$(jq -cr '.revision' "$BASE_DIR"/server/sources/libjxl.json)}"
|
||||
: "${LIBJXL_REVISION:=794a5dcf0d54f9f0b20d288a12e87afb91d20dfc}"
|
||||
if [[ "${update:-}" ]] || [[ "$LIBJXL_REVISION" != "$(grep 'libjxl' ~/.immich_library_revisions | awk '{print $2}')" ]]; then
|
||||
msg_info "Recompiling libjxl"
|
||||
if [[ -d "$SOURCE" ]]; then rm -rf "$SOURCE"; fi
|
||||
@@ -253,7 +254,8 @@ function compile_libheif() {
|
||||
$STD apt-get install -y libaom-dev
|
||||
local update="required"
|
||||
fi
|
||||
: "${LIBHEIF_REVISION:=$(jq -cr '.revision' "$BASE_DIR"/server/sources/libheif.json)}"
|
||||
# : "${LIBHEIF_REVISION:=$(jq -cr '.revision' "$BASE_DIR"/server/sources/libheif.json)}"
|
||||
: "${LIBHEIF_REVISION:=35dad50a9145332a7bfdf1ff6aef6801fb613d68}"
|
||||
if [[ "${update:-}" ]] || [[ "$LIBHEIF_REVISION" != "$(grep 'libheif' ~/.immich_library_revisions | awk '{print $2}')" ]]; then
|
||||
msg_info "Recompiling libheif"
|
||||
if [[ -d "$SOURCE" ]]; then rm -rf "$SOURCE"; fi
|
||||
@@ -285,7 +287,8 @@ function compile_libheif() {
|
||||
function compile_libraw() {
|
||||
SOURCE=${SOURCE_DIR}/libraw
|
||||
local update
|
||||
: "${LIBRAW_REVISION:=$(jq -cr '.revision' "$BASE_DIR"/server/sources/libraw.json)}"
|
||||
# : "${LIBRAW_REVISION:=$(jq -cr '.revision' "$BASE_DIR"/server/sources/libraw.json)}"
|
||||
: "${LIBRAW_REVISION:=09bea31181b43e97959ee5452d91e5bc66365f1f}"
|
||||
if [[ "${update:-}" ]] || [[ "$LIBRAW_REVISION" != "$(grep 'libraw' ~/.immich_library_revisions | awk '{print $2}')" ]]; then
|
||||
msg_info "Recompiling libraw"
|
||||
if [[ -d "$SOURCE" ]]; then rm -rf "$SOURCE"; fi
|
||||
@@ -306,7 +309,8 @@ function compile_libraw() {
|
||||
|
||||
function compile_imagemagick() {
|
||||
SOURCE=$SOURCE_DIR/imagemagick
|
||||
: "${IMAGEMAGICK_REVISION:=$(jq -cr '.revision' "$BASE_DIR"/server/sources/imagemagick.json)}"
|
||||
# : "${IMAGEMAGICK_REVISION:=$(jq -cr '.revision' "$BASE_DIR"/server/sources/imagemagick.json)}"
|
||||
: "${IMAGEMAGICK_REVISION:=8289a3388a085ad5ae81aa6812f21554bdfd54f2}"
|
||||
if [[ "${update:-}" ]] || [[ "$IMAGEMAGICK_REVISION" != "$(grep 'imagemagick' ~/.immich_library_revisions | awk '{print $2}')" ]]; then
|
||||
msg_info "Recompiling ImageMagick"
|
||||
if [[ -d "$SOURCE" ]]; then rm -rf "$SOURCE"; fi
|
||||
@@ -326,7 +330,8 @@ function compile_imagemagick() {
|
||||
|
||||
function compile_libvips() {
|
||||
SOURCE=$SOURCE_DIR/libvips
|
||||
: "${LIBVIPS_REVISION:=$(jq -cr '.revision' "$BASE_DIR"/server/sources/libvips.json)}"
|
||||
# : "${LIBVIPS_REVISION:=$(jq -cr '.revision' "$BASE_DIR"/server/sources/libvips.json)}"
|
||||
: "${LIBVIPS_REVISION:=8fa37a64547e392d3808eed8d72adab7e02b3d00}"
|
||||
if [[ "${update:-}" ]] || [[ "$LIBVIPS_REVISION" != "$(grep 'libvips' ~/.immich_library_revisions | awk '{print $2}')" ]]; then
|
||||
msg_info "Recompiling libvips"
|
||||
if [[ -d "$SOURCE" ]]; then rm -rf "$SOURCE"; fi
|
||||
|
||||
62
ct/leantime.sh
Normal file
62
ct/leantime.sh
Normal file
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||
# Copyright (c) 2021-2025 community-scripts ORG
|
||||
# Author: Stroopwafe1
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://leantime.io
|
||||
|
||||
APP="Leantime"
|
||||
var_tags="${var_tags:-productivity}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-20}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-12}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
variables
|
||||
color
|
||||
catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
|
||||
if [[ ! -d /opt/leantime ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
if check_for_gh_release "leantime" "Leantime/leantime"; then
|
||||
msg_info "Creating Backup"
|
||||
mariadb-dump leantime >"/opt/${APP}_db_backup_$(date +%F).sql"
|
||||
tar -czf "/opt/${APP}_backup_$(date +%F).tar.gz" "/opt/${APP}"
|
||||
mv /opt/leantime /opt/leantime_bak
|
||||
msg_ok "Backup Created"
|
||||
|
||||
fetch_and_deploy_gh_release "leantime" "Leantime/leantime" "prebuild" "latest" "/opt/leantime" Leantime*.tar.gz
|
||||
|
||||
msg_info "Restoring Config & Permissions"
|
||||
mv /opt/leantime_bak/config/.env /opt/leantime/config/.env
|
||||
chown -R www-data:www-data "/opt/leantime"
|
||||
chmod -R 750 "/opt/leantime"
|
||||
msg_ok "Restored Config & Permissions"
|
||||
|
||||
msg_info "Removing Backup"
|
||||
rm -rf /opt/leantime_bak
|
||||
msg_ok "Removed Backup"
|
||||
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}/install${CL}"
|
||||
44
ct/resiliosync.sh
Normal file
44
ct/resiliosync.sh
Normal file
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||
# Copyright (c) 2021-2025 community-scripts ORG
|
||||
# Author: David Bennett (dbinit)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://www.resilio.com/sync
|
||||
|
||||
APP="Resilio Sync"
|
||||
var_tags="${var_tags:-sync}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-8}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-12}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
variables
|
||||
color
|
||||
catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
if [[ ! -d /var/lib/resilio-sync ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
msg_info "Updating ${APP} LXC"
|
||||
$STD apt-get update
|
||||
$STD apt-get -y upgrade
|
||||
msg_ok "Updated Successfully"
|
||||
exit
|
||||
}
|
||||
|
||||
start
|
||||
build_container
|
||||
description
|
||||
|
||||
msg_ok "Completed Successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}https://${IP}:8888${CL}"
|
||||
@@ -27,6 +27,9 @@ function update_script() {
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
if ! grep -q "client_max_body_size[[:space:]]\+100M;" /etc/nginx/conf.d/snipeit.conf; then
|
||||
sed -i '/index index.php;/i \ client_max_body_size 100M;' /etc/nginx/conf.d/snipeit.conf
|
||||
fi
|
||||
|
||||
if check_for_gh_release "snipe-it" "snipe/snipe-it"; then
|
||||
msg_info "Stopping Services"
|
||||
|
||||
@@ -37,7 +37,7 @@ function update_script() {
|
||||
rm -rf /opt/tududi/backend/dist
|
||||
msg_ok "Backup and removed Files"
|
||||
|
||||
fetch_and_deploy_gh_release "tududi" "chrisvel/tududi"
|
||||
fetch_and_deploy_gh_release "tududi" "chrisvel/tududi" "tarball" "v0.80" "/opt/tududi"
|
||||
|
||||
msg_info "Updating ${APP}"
|
||||
cd /opt/tududi
|
||||
|
||||
@@ -45,13 +45,14 @@ function update_script() {
|
||||
|
||||
msg_info "Updating $APP"
|
||||
cd /opt/wizarr
|
||||
/usr/local/bin/uv -q sync --locked
|
||||
$STD /usr/local/bin/uv -q run pybabel compile -d app/translations
|
||||
$STD /usr/local/bin/uv lock
|
||||
$STD /usr/local/bin/uv sync --locked
|
||||
$STD /usr/local/bin/uv run pybabel compile -d app/translations
|
||||
$STD npm --prefix app/static install
|
||||
$STD npm --prefix app/static run build:css
|
||||
mkdir -p ./.cache
|
||||
$STD tar -xf "$BACKUP_FILE" --directory=/
|
||||
$STD /usr/local/bin/uv -q run flask db upgrade
|
||||
$STD /usr/local/bin/uv run flask db upgrade
|
||||
msg_ok "Updated $APP"
|
||||
|
||||
msg_info "Starting $APP"
|
||||
@@ -61,7 +62,7 @@ function update_script() {
|
||||
msg_info "Cleaning Up"
|
||||
rm -rf "$BACKUP_FILE"
|
||||
msg_ok "Cleanup Completed"
|
||||
msg_ok "Update Successfully"
|
||||
msg_ok "Updated Successfully"
|
||||
fi
|
||||
exit
|
||||
}
|
||||
|
||||
@@ -18,6 +18,10 @@ const nextConfig = {
|
||||
BASE_PATH: "ProxmoxVE",
|
||||
},
|
||||
|
||||
eslint: {
|
||||
ignoreDuringBuilds: true,
|
||||
},
|
||||
|
||||
output: "export",
|
||||
basePath: `/ProxmoxVE`,
|
||||
};
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"resources": {
|
||||
"cpu": 1,
|
||||
"ram": 512,
|
||||
"hdd": 2,
|
||||
"hdd": 10,
|
||||
"os": "debian",
|
||||
"version": "12"
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"resources": {
|
||||
"cpu": 1,
|
||||
"ram": 2048,
|
||||
"hdd": 4,
|
||||
"hdd": 8,
|
||||
"os": "debian",
|
||||
"version": "12"
|
||||
}
|
||||
|
||||
@@ -32,6 +32,10 @@
|
||||
"password": null
|
||||
},
|
||||
"notes": [
|
||||
{
|
||||
"text": "Please be aware that Immich releases are pinned to specific versions until compatibility has been confirmed by the Community Scripts maintainers; as a result, the version installed by the helper script may not be the most current version of Immich",
|
||||
"type": "info"
|
||||
},
|
||||
{
|
||||
"text": "During installation, you will be prompted with the option to install Intel OpenVINO for hardware-accelerated machine-learning. If you opt in, increase your LXC RAM after installation, as OpenVINO is memory-intensive",
|
||||
"type": "info"
|
||||
|
||||
35
frontend/public/json/leantime.json
Normal file
35
frontend/public/json/leantime.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "Leantime",
|
||||
"slug": "leantime",
|
||||
"categories": [
|
||||
12
|
||||
],
|
||||
"date_created": "2025-09-06",
|
||||
"type": "ct",
|
||||
"updateable": true,
|
||||
"privileged": false,
|
||||
"interface_port": 80,
|
||||
"documentation": "https://docs.leantime.io/",
|
||||
"config_path": "/opt/Leantime/config/.env",
|
||||
"website": "https://leantime.io",
|
||||
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/leantime.webp",
|
||||
"description": "Leantime is a goals focused project management system for non-project managers. Building with ADHD, Autism, and dyslexia in mind. ",
|
||||
"install_methods": [
|
||||
{
|
||||
"type": "default",
|
||||
"script": "ct/leantime.sh",
|
||||
"resources": {
|
||||
"cpu": 2,
|
||||
"ram": 2048,
|
||||
"hdd": 20,
|
||||
"os": "Debian",
|
||||
"version": "12"
|
||||
}
|
||||
}
|
||||
],
|
||||
"default_credentials": {
|
||||
"username": null,
|
||||
"password": null
|
||||
},
|
||||
"notes": []
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
"privileged": false,
|
||||
"interface_port": 8000,
|
||||
"documentation": "https://maxdorninger.github.io/MediaManager/introduction.html",
|
||||
"config_path": "/opt/mm_data/config.toml",
|
||||
"config_path": "/opt/mm/config/config.toml",
|
||||
"website": "https://github.com/maxdorninger/MediaManager",
|
||||
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/mediamanager.webp",
|
||||
"description": "A modern selfhosted media management system for your media library",
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
{
|
||||
"name": "Paperless-ngx",
|
||||
"slug": "paperless-ngx",
|
||||
"categories": [
|
||||
12
|
||||
],
|
||||
"date_created": "2024-05-02",
|
||||
"type": "ct",
|
||||
"updateable": true,
|
||||
"privileged": false,
|
||||
"interface_port": 8000,
|
||||
"documentation": "https://docs.paperless-ngx.com/",
|
||||
"website": "https://docs.paperless-ngx.com/",
|
||||
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/paperless-ngx.webp",
|
||||
"config_path": "/opt/paperless/paperless.conf",
|
||||
"description": "Paperless-ngx is a software tool designed for digitizing and organizing paper documents. It provides a web-based interface for scanning, uploading, and organizing paper documents, making it easier to manage, search, and access important information. Paperless-ngx uses the OCR (Optical Character Recognition) technology to extract text from scanned images and makes it searchable, thus increasing the efficiency of document management.",
|
||||
"install_methods": [
|
||||
{
|
||||
"type": "default",
|
||||
"script": "ct/paperless-ngx.sh",
|
||||
"resources": {
|
||||
"cpu": 2,
|
||||
"ram": 2048,
|
||||
"hdd": 12,
|
||||
"os": "debian",
|
||||
"version": "12"
|
||||
}
|
||||
}
|
||||
],
|
||||
"default_credentials": {
|
||||
"username": "admin",
|
||||
"password": null
|
||||
"name": "Paperless-ngx",
|
||||
"slug": "paperless-ngx",
|
||||
"categories": [
|
||||
12
|
||||
],
|
||||
"date_created": "2024-05-02",
|
||||
"type": "ct",
|
||||
"updateable": true,
|
||||
"privileged": false,
|
||||
"interface_port": 8000,
|
||||
"documentation": "https://docs.paperless-ngx.com/",
|
||||
"website": "https://docs.paperless-ngx.com/",
|
||||
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/paperless-ngx.webp",
|
||||
"config_path": "/opt/paperless/paperless.conf",
|
||||
"description": "Paperless-ngx is a software tool designed for digitizing and organizing paper documents. It provides a web-based interface for scanning, uploading, and organizing paper documents, making it easier to manage, search, and access important information. Paperless-ngx uses the OCR (Optical Character Recognition) technology to extract text from scanned images and makes it searchable, thus increasing the efficiency of document management.",
|
||||
"install_methods": [
|
||||
{
|
||||
"type": "default",
|
||||
"script": "ct/paperless-ngx.sh",
|
||||
"resources": {
|
||||
"cpu": 2,
|
||||
"ram": 2048,
|
||||
"hdd": 12,
|
||||
"os": "debian",
|
||||
"version": "12"
|
||||
}
|
||||
}
|
||||
],
|
||||
"default_credentials": {
|
||||
"username": null,
|
||||
"password": null
|
||||
},
|
||||
"notes": [
|
||||
{
|
||||
"text": "Show Login Credentials, type `cat ~/paperless-ngx.creds` in the LXC console",
|
||||
"type": "info"
|
||||
},
|
||||
"notes": [
|
||||
{
|
||||
"text": "Show Login Credentials, type `cat ~/paperless-ngx.creds` in the LXC console",
|
||||
"type": "info"
|
||||
},
|
||||
{
|
||||
"text": "Script installs English as default OCR language. To install additional languages, use `apt-get install tesseract-ocr-[lang]`, where [lang] is the language code (e.g. `apt-get install tesseract-ocr-deu`).",
|
||||
"type": "info"
|
||||
}
|
||||
]
|
||||
{
|
||||
"text": "Script installs English as default OCR language. To install additional languages, use `apt-get install tesseract-ocr-[lang]`, where [lang] is the language code (e.g. `apt-get install tesseract-ocr-deu`).",
|
||||
"type": "info"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
"type": "warning"
|
||||
},
|
||||
{
|
||||
"text": "Advanced Install is only possible without root password and root SSH access, you can configure this after installation.",
|
||||
"text": "Advanced Install is only possible with disabled IPV6! Otherwise the installation sometimes stuck.",
|
||||
"type": "warning"
|
||||
}
|
||||
]
|
||||
|
||||
40
frontend/public/json/resiliosync.json
Normal file
40
frontend/public/json/resiliosync.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "Resilio Sync",
|
||||
"slug": "resiliosync",
|
||||
"categories": [
|
||||
11
|
||||
],
|
||||
"date_created": "2025-09-06",
|
||||
"type": "ct",
|
||||
"updateable": true,
|
||||
"privileged": false,
|
||||
"config_path": "/etc/resilio-sync/config.json",
|
||||
"interface_port": 8888,
|
||||
"documentation": "https://help.resilio.com/",
|
||||
"website": "https://www.resilio.com/sync",
|
||||
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/resilio-sync.webp",
|
||||
"description": "Fast, reliable, and simple file sync and share solution, powered by P2P technology. Sync files across all your devices without storing them in the cloud.",
|
||||
"install_methods": [
|
||||
{
|
||||
"type": "default",
|
||||
"script": "ct/resilio-sync.sh",
|
||||
"resources": {
|
||||
"cpu": 2,
|
||||
"ram": 2048,
|
||||
"hdd": 8,
|
||||
"os": "debian",
|
||||
"version": "12"
|
||||
}
|
||||
}
|
||||
],
|
||||
"default_credentials": {
|
||||
"username": null,
|
||||
"password": null
|
||||
},
|
||||
"notes": [
|
||||
{
|
||||
"text": "After free registration, you will receive a license keyfile to your email address. Upload it into any LXC directory and select on first run.",
|
||||
"type": "info"
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -73,7 +73,13 @@ function CategoryView() {
|
||||
};
|
||||
|
||||
const handleScriptClick = (scriptSlug: string) => {
|
||||
router.push(`/scripts?id=${scriptSlug}`);
|
||||
// Include category context when navigating to scripts
|
||||
const categoryName = selectedCategoryIndex !== null ? categories[selectedCategoryIndex]?.name : null;
|
||||
const queryParams = new URLSearchParams({ id: scriptSlug });
|
||||
if (categoryName) {
|
||||
queryParams.append("category", categoryName);
|
||||
}
|
||||
router.push(`/scripts?${queryParams.toString()}`);
|
||||
};
|
||||
|
||||
const navigateCategory = (direction: "prev" | "next") => {
|
||||
|
||||
@@ -4,12 +4,7 @@ import Link from "next/link";
|
||||
|
||||
import type { Category } from "@/lib/types";
|
||||
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/components/ui/accordion";
|
||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";
|
||||
import { formattedBadge } from "@/components/command-menu";
|
||||
import { basePath } from "@/config/site-config";
|
||||
import { cn } from "@/lib/utils";
|
||||
@@ -18,14 +13,16 @@ export default function ScriptAccordion({
|
||||
items,
|
||||
selectedScript,
|
||||
setSelectedScript,
|
||||
selectedCategory,
|
||||
setSelectedCategory,
|
||||
}: {
|
||||
items: Category[];
|
||||
selectedScript: string | null;
|
||||
setSelectedScript: (script: string | null) => void;
|
||||
selectedCategory: string | null;
|
||||
setSelectedCategory: (category: string | null) => void;
|
||||
}) {
|
||||
const [expandedItem, setExpandedItem] = useState<string | undefined>(
|
||||
undefined,
|
||||
);
|
||||
const [expandedItem, setExpandedItem] = useState<string | undefined>(undefined);
|
||||
const linkRefs = useRef<{ [key: string]: HTMLAnchorElement | null }>({});
|
||||
|
||||
const handleAccordionChange = (value: string | undefined) => {
|
||||
@@ -41,15 +38,27 @@ export default function ScriptAccordion({
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedScript) {
|
||||
const category = items.find(category =>
|
||||
category.scripts.some(script => script.slug === selectedScript),
|
||||
);
|
||||
let category;
|
||||
|
||||
// If we have a selected category, try to find the script in that specific category
|
||||
if (selectedCategory) {
|
||||
category = items.find(
|
||||
cat => cat.name === selectedCategory && cat.scripts.some(script => script.slug === selectedScript),
|
||||
);
|
||||
}
|
||||
|
||||
// Fallback: if no category is selected or script not found in selected category,
|
||||
// use the first category containing the script (backward compatibility)
|
||||
if (!category) {
|
||||
category = items.find(category => category.scripts.some(script => script.slug === selectedScript));
|
||||
}
|
||||
|
||||
if (category) {
|
||||
setExpandedItem(category.name);
|
||||
handleSelected(selectedScript);
|
||||
}
|
||||
}
|
||||
}, [selectedScript, items, handleSelected]);
|
||||
}, [selectedScript, selectedCategory, items, handleSelected]);
|
||||
return (
|
||||
<Accordion
|
||||
type="single"
|
||||
@@ -82,10 +91,7 @@ export default function ScriptAccordion({
|
||||
</div>
|
||||
{" "}
|
||||
</AccordionTrigger>
|
||||
<AccordionContent
|
||||
data-state={expandedItem === category.name ? "open" : "closed"}
|
||||
className="pt-0"
|
||||
>
|
||||
<AccordionContent data-state={expandedItem === category.name ? "open" : "closed"} className="pt-0">
|
||||
{category.scripts
|
||||
.slice()
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
@@ -94,7 +100,7 @@ export default function ScriptAccordion({
|
||||
<Link
|
||||
href={{
|
||||
pathname: "/scripts",
|
||||
query: { id: script.slug },
|
||||
query: { id: script.slug, category: category.name },
|
||||
}}
|
||||
prefetch={false}
|
||||
className={`flex cursor-pointer items-center justify-between gap-1 px-1 py-1 text-muted-foreground hover:rounded-lg hover:bg-accent/60 hover:dark:bg-accent/20 ${
|
||||
@@ -102,7 +108,10 @@ export default function ScriptAccordion({
|
||||
? "rounded-lg bg-accent font-semibold dark:bg-accent/30 dark:text-white"
|
||||
: ""
|
||||
}`}
|
||||
onClick={() => handleSelected(script.slug)}
|
||||
onClick={() => {
|
||||
handleSelected(script.slug);
|
||||
setSelectedCategory(category.name);
|
||||
}}
|
||||
ref={(el) => {
|
||||
linkRefs.current[script.slug] = el;
|
||||
}}
|
||||
@@ -113,15 +122,11 @@ export default function ScriptAccordion({
|
||||
height={16}
|
||||
width={16}
|
||||
unoptimized
|
||||
onError={e =>
|
||||
((e.currentTarget as HTMLImageElement).src
|
||||
= `/${basePath}/logo.png`)}
|
||||
onError={e => ((e.currentTarget as HTMLImageElement).src = `/${basePath}/logo.png`)}
|
||||
alt={script.name}
|
||||
className="mr-1 w-4 h-4 rounded-full"
|
||||
/>
|
||||
<span className="flex items-center gap-2">
|
||||
{script.name}
|
||||
</span>
|
||||
<span className="flex items-center gap-2">{script.name}</span>
|
||||
</div>
|
||||
{formattedBadge(script.type)}
|
||||
</Link>
|
||||
|
||||
@@ -8,10 +8,14 @@ function Sidebar({
|
||||
items,
|
||||
selectedScript,
|
||||
setSelectedScript,
|
||||
selectedCategory,
|
||||
setSelectedCategory,
|
||||
}: {
|
||||
items: Category[];
|
||||
selectedScript: string | null;
|
||||
setSelectedScript: (script: string | null) => void;
|
||||
selectedCategory: string | null;
|
||||
setSelectedCategory: (category: string | null) => void;
|
||||
}) {
|
||||
const uniqueScripts = items.reduce((acc, category) => {
|
||||
for (const script of category.scripts) {
|
||||
@@ -37,6 +41,8 @@ function Sidebar({
|
||||
items={items}
|
||||
selectedScript={selectedScript}
|
||||
setSelectedScript={setSelectedScript}
|
||||
selectedCategory={selectedCategory}
|
||||
setSelectedCategory={setSelectedCategory}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,16 +8,14 @@ import type { Category, Script } from "@/lib/types";
|
||||
import { ScriptItem } from "@/app/scripts/_components/script-item";
|
||||
import { fetchCategories } from "@/lib/data";
|
||||
|
||||
import {
|
||||
LatestScripts,
|
||||
MostViewedScripts,
|
||||
} from "./_components/script-info-blocks";
|
||||
import { LatestScripts, MostViewedScripts } from "./_components/script-info-blocks";
|
||||
import Sidebar from "./_components/sidebar";
|
||||
|
||||
export const dynamic = "force-static";
|
||||
|
||||
function ScriptContent() {
|
||||
const [selectedScript, setSelectedScript] = useQueryState("id");
|
||||
const [selectedCategory, setSelectedCategory] = useQueryState("category");
|
||||
const [links, setLinks] = useState<Category[]>([]);
|
||||
const [item, setItem] = useState<Script>();
|
||||
|
||||
@@ -47,6 +45,8 @@ function ScriptContent() {
|
||||
items={links}
|
||||
selectedScript={selectedScript}
|
||||
setSelectedScript={setSelectedScript}
|
||||
selectedCategory={selectedCategory}
|
||||
setSelectedCategory={setSelectedCategory}
|
||||
/>
|
||||
</div>
|
||||
<div className="mx-4 w-full sm:mx-0 sm:ml-4">
|
||||
|
||||
@@ -36,19 +36,24 @@ export function formattedBadge(type: string) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// random Script
|
||||
function getRandomScript(categories: Category[]): Script | null {
|
||||
function getRandomScript(categories: Category[], previouslySelected: Set<string> = new Set()): Script | null {
|
||||
const allScripts = categories.flatMap(cat => cat.scripts || []);
|
||||
if (allScripts.length === 0)
|
||||
return null;
|
||||
const idx = Math.floor(Math.random() * allScripts.length);
|
||||
return allScripts[idx];
|
||||
|
||||
const availableScripts = allScripts.filter(script => !previouslySelected.has(script.slug));
|
||||
if (availableScripts.length === 0) {
|
||||
return allScripts[Math.floor(Math.random() * allScripts.length)];
|
||||
}
|
||||
const idx = Math.floor(Math.random() * availableScripts.length);
|
||||
return availableScripts[idx];
|
||||
}
|
||||
|
||||
export default function CommandMenu() {
|
||||
function CommandMenu() {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [links, setLinks] = React.useState<Category[]>([]);
|
||||
const [isLoading, setIsLoading] = React.useState(false);
|
||||
const [selectedScripts, setSelectedScripts] = React.useState<Set<string>>(new Set());
|
||||
const router = useRouter();
|
||||
|
||||
const fetchSortedCategories = () => {
|
||||
@@ -65,25 +70,26 @@ export default function CommandMenu() {
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
const down = (e: KeyboardEvent) => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
|
||||
e.preventDefault();
|
||||
fetchSortedCategories();
|
||||
setOpen(open => !open);
|
||||
}
|
||||
};
|
||||
document.addEventListener("keydown", down);
|
||||
return () => document.removeEventListener("keydown", down);
|
||||
document.addEventListener("keydown", handleKeyDown);
|
||||
return () => document.removeEventListener("keydown", handleKeyDown);
|
||||
}, []);
|
||||
|
||||
const openRandomScript = async () => {
|
||||
const handleOpenRandomScript = async () => {
|
||||
if (links.length === 0) {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const categories = await fetchCategories();
|
||||
setLinks(categories);
|
||||
const randomScript = getRandomScript(categories);
|
||||
const randomScript = getRandomScript(categories, selectedScripts);
|
||||
if (randomScript) {
|
||||
setSelectedScripts(prev => new Set([...prev, randomScript.slug]));
|
||||
router.push(`/scripts?id=${randomScript.slug}`);
|
||||
}
|
||||
}
|
||||
@@ -92,13 +98,54 @@ export default function CommandMenu() {
|
||||
}
|
||||
}
|
||||
else {
|
||||
const randomScript = getRandomScript(links);
|
||||
const randomScript = getRandomScript(links, selectedScripts);
|
||||
if (randomScript) {
|
||||
setSelectedScripts(prev => new Set([...prev, randomScript.slug]));
|
||||
router.push(`/scripts?id=${randomScript.slug}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getUniqueScriptsMap = React.useCallback(() => {
|
||||
const scriptMap = new Map<string, { script: Script; categoryName: string }>();
|
||||
for (const category of links) {
|
||||
for (const script of category.scripts) {
|
||||
if (!scriptMap.has(script.slug)) {
|
||||
scriptMap.set(script.slug, { script, categoryName: category.name });
|
||||
}
|
||||
}
|
||||
}
|
||||
return scriptMap;
|
||||
}, [links]);
|
||||
|
||||
const getUniqueScriptsByCategory = React.useCallback(() => {
|
||||
const scriptMap = getUniqueScriptsMap();
|
||||
const categoryOrder = links.map(cat => cat.name);
|
||||
const grouped: Record<string, Script[]> = {};
|
||||
|
||||
for (const name of categoryOrder) {
|
||||
grouped[name] = [];
|
||||
}
|
||||
|
||||
for (const { script, categoryName } of scriptMap.values()) {
|
||||
if (grouped[categoryName]) {
|
||||
grouped[categoryName].push(script);
|
||||
}
|
||||
else {
|
||||
grouped[categoryName] = [script];
|
||||
}
|
||||
}
|
||||
|
||||
Object.keys(grouped).forEach((cat) => {
|
||||
if (grouped[cat].length === 0)
|
||||
delete grouped[cat];
|
||||
});
|
||||
|
||||
return grouped;
|
||||
}, [getUniqueScriptsMap, links]);
|
||||
|
||||
const uniqueScriptsByCategory = getUniqueScriptsByCategory();
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex gap-2">
|
||||
@@ -122,7 +169,20 @@ export default function CommandMenu() {
|
||||
<TooltipProvider>
|
||||
<Tooltip delayDuration={100}>
|
||||
<TooltipTrigger asChild>
|
||||
<Button variant="outline" size="icon" onClick={openRandomScript} disabled={isLoading} className="hidden lg:flex">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={handleOpenRandomScript}
|
||||
disabled={isLoading}
|
||||
className="hidden lg:flex"
|
||||
aria-label="Open Random Script"
|
||||
tabIndex={0}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
handleOpenRandomScript();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Sparkles className="size-4" />
|
||||
<span className="sr-only">Open Random Script</span>
|
||||
</Button>
|
||||
@@ -139,16 +199,24 @@ export default function CommandMenu() {
|
||||
<CommandInput placeholder="Search for a script..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>{isLoading ? "Loading..." : "No scripts found."}</CommandEmpty>
|
||||
{links.map(category => (
|
||||
<CommandGroup key={`category:${category.name}`} heading={category.name}>
|
||||
{category.scripts.map(script => (
|
||||
{Object.entries(uniqueScriptsByCategory).map(([categoryName, scripts]) => (
|
||||
<CommandGroup key={`category:${categoryName}`} heading={categoryName}>
|
||||
{scripts.map(script => (
|
||||
<CommandItem
|
||||
key={`script:${script.slug}`}
|
||||
value={`${script.slug}-${script.name}`}
|
||||
value={`${script.name}-${script.type}`}
|
||||
onSelect={() => {
|
||||
setOpen(false);
|
||||
router.push(`/scripts?id=${script.slug}`);
|
||||
}}
|
||||
tabIndex={0}
|
||||
aria-label={`Open script ${script.name}`}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
setOpen(false);
|
||||
router.push(`/scripts?id=${script.slug}`);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="flex gap-2" onClick={() => setOpen(false)}>
|
||||
<Image
|
||||
@@ -172,3 +240,5 @@ export default function CommandMenu() {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default CommandMenu;
|
||||
|
||||
@@ -17,7 +17,9 @@ msg_info "Installing Dependencies"
|
||||
$STD apt-get install -y \
|
||||
gdal-bin \
|
||||
libgdal-dev \
|
||||
git
|
||||
git \
|
||||
memcached \
|
||||
libmemcached-tools
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
PYTHON_VERSION="3.12" setup_uv
|
||||
|
||||
@@ -169,7 +169,8 @@ cd "$STAGING_DIR"
|
||||
SOURCE=${SOURCE_DIR}/libjxl
|
||||
JPEGLI_LIBJPEG_LIBRARY_SOVERSION="62"
|
||||
JPEGLI_LIBJPEG_LIBRARY_VERSION="62.3.0"
|
||||
: "${LIBJXL_REVISION:=$(jq -cr '.revision' $BASE_DIR/server/sources/libjxl.json)}"
|
||||
# : "${LIBJXL_REVISION:=$(jq -cr '.revision' $BASE_DIR/server/sources/libjxl.json)}"
|
||||
: "${LIBJXL_REVISION:=794a5dcf0d54f9f0b20d288a12e87afb91d20dfc}"
|
||||
$STD git clone https://github.com/libjxl/libjxl.git "$SOURCE"
|
||||
cd "$SOURCE"
|
||||
$STD git reset --hard "$LIBJXL_REVISION"
|
||||
@@ -204,7 +205,8 @@ cd "$STAGING_DIR"
|
||||
rm -rf "$SOURCE"/{build,third_party}
|
||||
|
||||
SOURCE=${SOURCE_DIR}/libheif
|
||||
: "${LIBHEIF_REVISION:=$(jq -cr '.revision' $BASE_DIR/server/sources/libheif.json)}"
|
||||
# : "${LIBHEIF_REVISION:=$(jq -cr '.revision' $BASE_DIR/server/sources/libheif.json)}"
|
||||
: "${LIBHEIF_REVISION:=35dad50a9145332a7bfdf1ff6aef6801fb613d68}"
|
||||
$STD git clone https://github.com/strukturag/libheif.git "$SOURCE"
|
||||
cd "$SOURCE"
|
||||
$STD git reset --hard "$LIBHEIF_REVISION"
|
||||
@@ -227,7 +229,8 @@ cd "$STAGING_DIR"
|
||||
rm -rf "$SOURCE"/build
|
||||
|
||||
SOURCE=${SOURCE_DIR}/libraw
|
||||
: "${LIBRAW_REVISION:=$(jq -cr '.revision' $BASE_DIR/server/sources/libraw.json)}"
|
||||
# : "${LIBRAW_REVISION:=$(jq -cr '.revision' $BASE_DIR/server/sources/libraw.json)}"
|
||||
: "${LIBRAW_REVISION:=09bea31181b43e97959ee5452d91e5bc66365f1f}"
|
||||
$STD git clone https://github.com/libraw/libraw.git "$SOURCE"
|
||||
cd "$SOURCE"
|
||||
$STD git reset --hard "$LIBRAW_REVISION"
|
||||
@@ -240,7 +243,8 @@ $STD make clean
|
||||
cd "$STAGING_DIR"
|
||||
|
||||
SOURCE=$SOURCE_DIR/imagemagick
|
||||
: "${IMAGEMAGICK_REVISION:=$(jq -cr '.revision' $BASE_DIR/server/sources/imagemagick.json)}"
|
||||
# : "${IMAGEMAGICK_REVISION:=$(jq -cr '.revision' $BASE_DIR/server/sources/imagemagick.json)}"
|
||||
: "${IMAGEMAGICK_REVISION:=8289a3388a085ad5ae81aa6812f21554bdfd54f2}"
|
||||
$STD git clone https://github.com/ImageMagick/ImageMagick.git "$SOURCE"
|
||||
cd "$SOURCE"
|
||||
$STD git reset --hard "$IMAGEMAGICK_REVISION"
|
||||
@@ -252,7 +256,8 @@ $STD make clean
|
||||
cd "$STAGING_DIR"
|
||||
|
||||
SOURCE=$SOURCE_DIR/libvips
|
||||
: "${LIBVIPS_REVISION:=$(jq -cr '.revision' $BASE_DIR/server/sources/libvips.json)}"
|
||||
# : "${LIBVIPS_REVISION:=$(jq -cr '.revision' $BASE_DIR/server/sources/libvips.json)}"
|
||||
: "${LIBVIPS_REVISION:=8fa37a64547e392d3808eed8d72adab7e02b3d00}"
|
||||
$STD git clone https://github.com/libvips/libvips.git "$SOURCE"
|
||||
cd "$SOURCE"
|
||||
$STD git reset --hard "$LIBVIPS_REVISION"
|
||||
@@ -280,7 +285,7 @@ GEO_DIR="${INSTALL_DIR}/geodata"
|
||||
mkdir -p "$INSTALL_DIR"
|
||||
mkdir -p {"${APP_DIR}","${UPLOAD_DIR}","${GEO_DIR}","${INSTALL_DIR}"/cache}
|
||||
|
||||
fetch_and_deploy_gh_release "immich" "immich-app/immich" "tarball" "v1.140.0" "$SRC_DIR"
|
||||
fetch_and_deploy_gh_release "immich" "immich-app/immich" "tarball" "v1.140.1" "$SRC_DIR"
|
||||
|
||||
msg_info "Installing ${APPLICATION} (more patience please)"
|
||||
|
||||
|
||||
78
install/leantime-install.sh
Normal file
78
install/leantime-install.sh
Normal file
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (c) 2021-2025 community-scripts ORG
|
||||
# Author: Stroopwafe1
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://leantime.io
|
||||
|
||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||
color
|
||||
verb_ip6
|
||||
catch_errors
|
||||
setting_up_container
|
||||
network_check
|
||||
update_os
|
||||
|
||||
PHP_VERSION="8.4" PHP_MODULE="mysql" PHP_APACHE="YES" PHP_FPM="YES" setup_php
|
||||
setup_mariadb
|
||||
|
||||
msg_info "Setting up Database"
|
||||
DB_NAME=leantime
|
||||
DB_USER=leantime
|
||||
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
|
||||
$STD mysql -u root -e "CREATE DATABASE $DB_NAME;"
|
||||
$STD mysql -u root -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED WITH mysql_native_password AS PASSWORD('$DB_PASS');"
|
||||
$STD mysql -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
|
||||
{
|
||||
echo "Leantime Credentials"
|
||||
echo "Database User: $DB_USER"
|
||||
echo "Database Password: $DB_PASS"
|
||||
echo "Database Name: $DB_NAME"
|
||||
} >>~/leantime.creds
|
||||
msg_ok "Set up Database"
|
||||
|
||||
fetch_and_deploy_gh_release "leantime" "Leantime/leantime" "prebuild" "latest" "/opt/leantime" Leantime*.tar.gz
|
||||
|
||||
msg_info "Setup Leantime"
|
||||
chown -R www-data:www-data "/opt/leantime"
|
||||
chmod -R 750 "/opt/leantime"
|
||||
cat <<EOF >/etc/apache2/sites-enabled/000-default.conf
|
||||
<VirtualHost *:80>
|
||||
ServerAdmin webmaster@localhost
|
||||
DocumentRoot /opt/leantime/public
|
||||
DirectoryIndex index.php index.html index.cgi index.pl index.xhtml
|
||||
Options +ExecCGI
|
||||
|
||||
<Directory /opt/leantime/>
|
||||
Options FollowSymLinks
|
||||
Require all granted
|
||||
AllowOverride All
|
||||
</Directory>
|
||||
|
||||
<Location />
|
||||
Require all granted
|
||||
</Location>
|
||||
|
||||
ErrorLog /var/log/apache2/error.log
|
||||
CustomLog /var/log/apache2/access.log combined
|
||||
</VirtualHost>
|
||||
EOF
|
||||
mv "/opt/leantime/config/sample.env" "/opt/leantime/config/.env"
|
||||
sed -i -e "s|^LEAN_DB_DATABASE.*|LEAN_DB_DATABASE = '$DB_NAME'|" \
|
||||
-e "s|^LEAN_DB_USER.*|LEAN_DB_USER = '$DB_USER'|" \
|
||||
-e "s|^LEAN_DB_PASSWORD.*|LEAN_DB_PASSWORD = '$DB_PASS'|" \
|
||||
-e "s|^LEAN_SESSION_PASSWORD.*|LEAN_SESSION_PASSWORD = '$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)'|" \
|
||||
"/opt/leantime/config/.env"
|
||||
$STD a2enmod -q proxy_fcgi setenvif rewrite
|
||||
$STD a2enconf -q "php8.4-fpm"
|
||||
sed -i -e "s/^;extension.\(curl\|fileinfo\|gd\|intl\|ldap\|mbstring\|exif\|mysqli\|odbc\|openssl\|pdo_mysql\)/extension=\1/g" "/etc/php/8.4/apache2/php.ini"
|
||||
systemctl restart apache2
|
||||
msg_ok "Setup leantime"
|
||||
|
||||
motd_ssh
|
||||
customize
|
||||
|
||||
msg_info "Cleaning up"
|
||||
$STD apt-get -y autoremove
|
||||
$STD apt-get -y autoclean
|
||||
msg_ok "Cleaned"
|
||||
@@ -15,12 +15,10 @@ update_os
|
||||
|
||||
msg_info "Installing Mosquitto MQTT Broker"
|
||||
source /etc/os-release
|
||||
curl -fsSL http://repo.mosquitto.org/debian/mosquitto-repo.gpg >/usr/share/keyrings/mosquitto-repo.gpg.key
|
||||
chmod go+r /usr/share/keyrings/mosquitto-repo.gpg.key
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/mosquitto-repo.gpg.key] http://repo.mosquitto.org/debian ${VERSION_CODENAME} main" >/etc/apt/sources.list.d/mosquitto.list
|
||||
$STD apt-get update
|
||||
$STD apt-get -y install mosquitto
|
||||
$STD apt-get -y install mosquitto-clients
|
||||
|
||||
cat <<EOF >/etc/mosquitto/conf.d/default.conf
|
||||
allow_anonymous false
|
||||
persistence true
|
||||
|
||||
@@ -56,6 +56,7 @@ RELEASE=$(curl -fsSL https://api.github.com/repos/netbox-community/netbox/releas
|
||||
curl -fsSL "https://github.com/netbox-community/netbox/archive/refs/tags/v${RELEASE}.zip" -o "v${RELEASE}.zip"
|
||||
$STD unzip "v${RELEASE}.zip"
|
||||
mv /opt/netbox-"${RELEASE}"/ /opt/netbox
|
||||
mkdir -p /opt/netbox/netbox/media
|
||||
|
||||
$STD adduser --system --group netbox
|
||||
chown --recursive netbox /opt/netbox/netbox/media/
|
||||
|
||||
35
install/resiliosync-install.sh
Normal file
35
install/resiliosync-install.sh
Normal file
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (c) 2021-2025 community-scripts ORG
|
||||
# Author: David Bennett (dbinit)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://www.resilio.com/sync
|
||||
|
||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||
color
|
||||
verb_ip6
|
||||
catch_errors
|
||||
setting_up_container
|
||||
network_check
|
||||
update_os
|
||||
|
||||
msg_info "Setting up Resilio Sync Repository"
|
||||
curl -fsSL "https://linux-packages.resilio.com/resilio-sync/key.asc" >/etc/apt/trusted.gpg.d/resilio-sync.asc
|
||||
echo "deb [signed-by=/etc/apt/trusted.gpg.d/resilio-sync.asc] http://linux-packages.resilio.com/resilio-sync/deb resilio-sync non-free" >/etc/apt/sources.list.d/resilio-sync.list
|
||||
$STD apt-get update
|
||||
msg_ok "Resilio Sync Repository Setup"
|
||||
|
||||
msg_info "Installing Resilio Sync"
|
||||
$STD apt-get install -y resilio-sync
|
||||
sed -i "s/127.0.0.1:8888/0.0.0.0:8888/g" /etc/resilio-sync/config.json
|
||||
systemctl enable -q resilio-sync
|
||||
systemctl restart resilio-sync
|
||||
msg_ok "Installed Resilio Sync"
|
||||
|
||||
motd_ssh
|
||||
customize
|
||||
|
||||
msg_info "Cleaning up"
|
||||
$STD apt-get -y autoremove
|
||||
$STD apt-get -y autoclean
|
||||
msg_ok "Cleaned"
|
||||
@@ -62,6 +62,7 @@ server {
|
||||
listen 80;
|
||||
root /opt/snipe-it/public;
|
||||
server_name $IPADDRESS;
|
||||
client_max_body_size 100M;
|
||||
index index.php;
|
||||
|
||||
location / {
|
||||
|
||||
@@ -20,7 +20,7 @@ $STD apt-get install -y \
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
NODE_VERSION="20" setup_nodejs
|
||||
fetch_and_deploy_gh_release "tududi" "chrisvel/tududi"
|
||||
fetch_and_deploy_gh_release "tududi" "chrisvel/tududi" "tarball" "v0.80" "/opt/tududi"
|
||||
|
||||
msg_info "Configuring Tududi"
|
||||
cd /opt/tududi
|
||||
|
||||
@@ -23,12 +23,13 @@ fetch_and_deploy_gh_release "wizarr" "wizarrrr/wizarr"
|
||||
|
||||
msg_info "Configure ${APPLICATION}"
|
||||
cd /opt/wizarr
|
||||
/usr/local/bin/uv -q sync --locked
|
||||
$STD /usr/local/bin/uv -q run pybabel compile -d app/translations
|
||||
$STD /usr/local/bin/uv lock
|
||||
$STD /usr/local/bin/uv sync --locked
|
||||
$STD /usr/local/bin/uv run pybabel compile -d app/translations
|
||||
$STD npm --prefix app/static install
|
||||
$STD npm --prefix app/static run build:css
|
||||
mkdir -p ./.cache
|
||||
$STD /usr/local/bin/uv -q run flask db upgrade
|
||||
$STD /usr/local/bin/uv run flask db upgrade
|
||||
msg_ok "Configure ${APPLICATION}"
|
||||
|
||||
msg_info "Creating env, start script and service"
|
||||
|
||||
@@ -41,39 +41,37 @@ function msg_ok() {
|
||||
|
||||
function msg_error() { echo -e "${RD}✗ $1${CL}"; }
|
||||
|
||||
# This function checks the version of Proxmox Virtual Environment (PVE) and exits if the version is not supported.
|
||||
# Supported: Proxmox VE 8.0.x – 8.9.x and 9.0 (NOT 9.1+)
|
||||
pve_check() {
|
||||
if ! command -v pveversion >/dev/null 2>&1; then
|
||||
msg_error "This script can only be run on a Proxmox VE host."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local PVE_VER
|
||||
PVE_VER="$(pveversion | awk -F'/' '{print $2}' | awk -F'-' '{print $1}')"
|
||||
|
||||
# Proxmox VE 8.x: allow 8.0 – 8.9
|
||||
if [[ "$PVE_VER" =~ ^9\.([0-9]+)(\.[0-9]+)?$ ]]; then
|
||||
# Check for Proxmox VE 8.x: allow 8.0–8.9
|
||||
if [[ "$PVE_VER" =~ ^8\.([0-9]+) ]]; then
|
||||
local MINOR="${BASH_REMATCH[1]}"
|
||||
if ((MINOR != 0)); then
|
||||
msg_error "Unsupported Proxmox VE version: $PVE_VER"
|
||||
msg_error "Supported versions: 8.0 – 8.9 or 9.0.x"
|
||||
if ((MINOR < 0 || MINOR > 9)); then
|
||||
msg_error "This version of Proxmox VE is not supported."
|
||||
msg_error "Supported: Proxmox VE version 8.0 – 8.9"
|
||||
exit 1
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Proxmox VE 9.x: allow only 9.0
|
||||
if [[ "$PVE_VER" =~ ^9\.([0-9]+)$ ]]; then
|
||||
# Check for Proxmox VE 9.x: allow ONLY 9.0
|
||||
if [[ "$PVE_VER" =~ ^9\.([0-9]+) ]]; then
|
||||
local MINOR="${BASH_REMATCH[1]}"
|
||||
if ((MINOR != 0)); then
|
||||
msg_error "Unsupported Proxmox VE version: $PVE_VER"
|
||||
msg_error "Supported versions: 8.0 – 8.9 or 9.0"
|
||||
msg_error "This version of Proxmox VE is not yet supported."
|
||||
msg_error "Supported: Proxmox VE version 9.0"
|
||||
exit 1
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
msg_error "Unsupported Proxmox VE version: $PVE_VER"
|
||||
msg_error "Supported versions: 8.0 – 8.9 or 9.0"
|
||||
# All other unsupported versions
|
||||
msg_error "This version of Proxmox VE is not supported."
|
||||
msg_error "Supported versions: Proxmox VE 8.0 – 8.x or 9.0"
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -514,7 +514,42 @@ post_routines_common() {
|
||||
yes)
|
||||
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox --title "Support Subscriptions" "Supporting the software's development team is essential. Check their official website's Support Subscriptions for pricing. Without their dedicated work, we wouldn't have this exceptional software." 10 58
|
||||
msg_info "Disabling subscription nag"
|
||||
echo "DPkg::Post-Invoke { \"if [ -s /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js ] && ! grep -q -F 'NoMoreNagging' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js; then echo 'Removing subscription nag from UI...'; sed -i '/data\.status/{s/\\!//;s/active/NoMoreNagging/}' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js; fi\" };" >/etc/apt/apt.conf.d/no-nag-script
|
||||
# Create external script, this is needed because DPkg::Post-Invoke is fidly with quote interpretation
|
||||
cat >/usr/local/bin/pve-remove-nag.sh <<'EOF'
|
||||
#!/bin/sh
|
||||
WEB_JS=/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js
|
||||
if [ -s "$WEB_JS" ] && ! grep -q NoMoreNagging "$WEB_JS"; then
|
||||
echo "Patching Web UI nag..."
|
||||
sed -i -e "/data\.status/ s/!//" -e "/data\.status/ s/active/NoMoreNagging/" "$WEB_JS"
|
||||
fi
|
||||
|
||||
MOBILE_TPL=/usr/share/pve-yew-mobile-gui/index.html.tpl
|
||||
MARKER="<!-- MANAGED BLOCK FOR MOBILE NAG -->"
|
||||
if [ -f "$MOBILE_TPL" ] && ! grep -q "$MARKER" "$MOBILE_TPL"; then
|
||||
echo "Patching Mobile UI nag..."
|
||||
printf "%s\n" \
|
||||
"$MARKER" \
|
||||
"<script>" \
|
||||
" function watchAndRemoveDialog() {" \
|
||||
" const observer = new MutationObserver(() => {" \
|
||||
" const dialog = document.querySelector('dialog[aria-label=\"No valid subscription\"]');" \
|
||||
" if (dialog) { dialog.remove(); console.log('Removed dialog: No valid subscription'); observer.disconnect(); }" \
|
||||
" });" \
|
||||
" observer.observe(document.body, { childList: true, subtree: true });" \
|
||||
" }" \
|
||||
" setTimeout(watchAndRemoveDialog, 100);" \
|
||||
"</script>" \
|
||||
"" >> "$MOBILE_TPL"
|
||||
fi
|
||||
EOF
|
||||
|
||||
chmod 755 /usr/local/bin/pve-remove-nag.sh
|
||||
|
||||
cat >/etc/apt/apt.conf.d/no-nag-script <<'EOF'
|
||||
DPkg::Post-Invoke { "/usr/local/bin/pve-remove-nag.sh"; };
|
||||
EOF
|
||||
chmod 644 /etc/apt/apt.conf.d/no-nag-script
|
||||
|
||||
msg_ok "Disabled subscription nag (Delete browser cache)"
|
||||
;;
|
||||
no)
|
||||
|
||||
Reference in New Issue
Block a user