Compare commits

..

50 Commits

Author SHA1 Message Date
CanbiZ
0453d61e3c Refactor: audiobookshelf
Increase default disk size from 4GB to 5GB and mark audiobookshelf as updateable in JSON. Update install script to explicitly install ffmpeg and set FFMPEG/FFPROBE paths in /etc/default/audiobookshelf. Revise update logic to use /etc/default/audiobookshelf as installation check and perform apt updates/upgrades.
2025-09-10 10:57:37 +02:00
community-scripts-pr-app[bot]
63f6d772ea Update CHANGELOG.md (#7536)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-10 07:44:30 +00:00
CanbiZ
652df1f370 Set updateable to true for all JSON app configs (#7534) 2025-09-10 09:44:09 +02:00
community-scripts-pr-app[bot]
f4b5baf308 Update CHANGELOG.md (#7535)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-10 07:15:02 +00:00
Michel Roegl-Brunner
cc36fd5434 Booklore: Add Bookdrop location to .env (#7533) 2025-09-10 09:14:41 +02:00
CanbiZ
3e182978ad Improve npmplus credential retrieval and messaging (#7532)
* Improve npmplus credential retrieval and messaging

Enhanced the install script to attempt live log monitoring for credentials if not found initially, and updated the info message in npmplus.json to guide users to check docker logs if the credentials file is missing.

* Update npmplus.json

* Change updateable status to true in npmplus.json
2025-09-10 09:14:15 +02:00
community-scripts-pr-app[bot]
e7adf1a9b5 Update CHANGELOG.md (#7529)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-10 00:12:25 +00:00
community-scripts-pr-app[bot]
36fb86eaf8 Update versions.json (#7528)
Co-authored-by: GitHub Actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-10 02:12:00 +02:00
community-scripts-pr-app[bot]
495c47224e Update CHANGELOG.md (#7525)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-09 21:23:22 +00:00
community-scripts-pr-app[bot]
7af71384b4 Update CHANGELOG.md (#7524)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-09 21:18:08 +00:00
dependabot[bot]
e318152ee3 Bump vite from 7.0.0 to 7.1.5 in /frontend (#7522)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 7.0.0 to 7.1.5.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.1.5/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 7.1.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-09 23:17:43 +02:00
community-scripts-pr-app[bot]
17dc7c90a1 Update CHANGELOG.md (#7521)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-09 20:35:29 +00:00
Chris
226a5bce8f Pulse: standardise install/update with Pulse repo script (#7519)
- revert the pulse => pulse-backend service name change
- remove message about older installs
- symlink pulse binary to /usr/local/bin
2025-09-09 22:35:04 +02:00
community-scripts-pr-app[bot]
ffd2ed01b9 Update CHANGELOG.md (#7518)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-09 17:13:00 +00:00
Chris
3348e2fff0 Tududi: v0.81 (#7517) 2025-09-09 19:12:27 +02:00
community-scripts-pr-app[bot]
def41f66f4 Update CHANGELOG.md (#7516)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-09 14:48:50 +00:00
Slaviša Arežina
02a1a732f8 WGDashboard: Revert back to old update method (#7500)
* Revert back to git clone

* Add git to sh
2025-09-09 16:48:12 +02:00
community-scripts-pr-app[bot]
2494af7e1c Update CHANGELOG.md (#7514)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-09 13:39:02 +00:00
CanbiZ
0c4711d99f Change category ID from 15 to 13 in swizzin.json (#7511) 2025-09-09 15:38:33 +02:00
community-scripts-pr-app[bot]
039f73a5ed Update versions.json (#7512)
Co-authored-by: GitHub Actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-09 14:05:31 +02:00
CanbiZ
74b58d5b10 planka: fix copy issue 2025-09-09 11:40:59 +02:00
community-scripts-pr-app[bot]
61044104a2 Update CHANGELOG.md (#7510)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-09 09:25:29 +00:00
CanbiZ
fac612077a AdventureLog: remove folder during update process (#7507) 2025-09-09 11:24:58 +02:00
community-scripts-pr-app[bot]
135b3ff964 Update CHANGELOG.md (#7509)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-09 09:22:02 +00:00
Slaviša Arežina
393b853119 Fix backup and restore (#7505) 2025-09-09 11:21:38 +02:00
community-scripts-pr-app[bot]
6bb2938e34 Update CHANGELOG.md (#7503)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-09 07:52:08 +00:00
Slaviša Arežina
fbf16fd54d Fixes (#7502) 2025-09-09 09:51:38 +02:00
community-scripts-pr-app[bot]
d6d4fd034f Update CHANGELOG.md (#7501)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-09 07:28:55 +00:00
Bram Suurd
aa4999dac6 Refactor GitHubStarsButton to wrap in Link component for external navigation (#7492) 2025-09-09 09:28:32 +02:00
community-scripts-pr-app[bot]
b6c0b50e79 Update CHANGELOG.md (#7495)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-09 00:13:49 +00:00
community-scripts-pr-app[bot]
0f07f1927e Update versions.json (#7494)
Co-authored-by: GitHub Actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-09 02:13:21 +02:00
community-scripts-pr-app[bot]
4493d86e51 Update CHANGELOG.md (#7490)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-08 19:06:13 +00:00
Chris
fbfeeeb88f Immich: bump to version 1.141.1 (#7418) 2025-09-08 21:05:50 +02:00
community-scripts-pr-app[bot]
2366111bba Update CHANGELOG.md (#7486)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-08 12:28:04 +00:00
CanbiZ
5fb42b87f1 CT's: fix missing variable declaration (actualBudget, openziti, umlautadaptarr) (#7483) 2025-09-08 14:27:40 +02:00
community-scripts-pr-app[bot]
500c35c58d Update CHANGELOG.md (#7484)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-08 12:18:24 +00:00
Tobias
ca3446c90e Change ExecStart to use index.js instead of index.mjs (#7482) 2025-09-08 14:18:04 +02:00
CanbiZ
4c3d42d5d1 fix verbose 2025-09-08 14:09:20 +02:00
CanbiZ
299a10efe8 Update build.func 2025-09-08 14:07:25 +02:00
community-scripts-pr-app[bot]
7adac2a342 Update versions.json (#7481)
Co-authored-by: GitHub Actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-08 14:05:54 +02:00
community-scripts-pr-app[bot]
eb58b10d75 Update CHANGELOG.md (#7480)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-08 12:03:58 +00:00
CanbiZ
5e46d81c45 [core]: switch all base_settings to variables (#7479) 2025-09-08 14:03:34 +02:00
community-scripts-pr-app[bot]
2963926c45 Update CHANGELOG.md (#7478)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-08 10:50:01 +00:00
Bram Suurd
d9a0b863a8 Format numerical values in DataFetcher component for better readability (#7477) 2025-09-08 12:49:38 +02:00
community-scripts-pr-app[bot]
db6369f3c6 Update CHANGELOG.md (#7476)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-08 09:58:53 +00:00
Slaviša Arežina
d450e263f0 Update (#7473) 2025-09-08 11:58:29 +02:00
community-scripts-pr-app[bot]
462960d9bf Update CHANGELOG.md (#7472)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-08 06:42:51 +00:00
Bram Suurd
8ea4829e8a feat: enhance github stars button to be better looking and more compact (#7464)
* feat: enhance github stars button to be better looking and more compact to make mobile compatibility easier in the future

* feat: introduce a new Button component
2025-09-08 08:42:31 +02:00
community-scripts-pr-app[bot]
c5d23dc883 Update CHANGELOG.md (#7471)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-08 06:01:46 +00:00
Seb Guy
3dc973e4ac Update searxng-install.sh (#7469) 2025-09-08 08:01:26 +02:00
75 changed files with 1744 additions and 474 deletions

View File

@@ -10,8 +10,83 @@
> [!CAUTION]
Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit the project's popularity for potentially malicious purposes.
## 2025-09-10
### 🚀 Updated Scripts
- #### ✨ New Features
- Booklore: Add Bookdrop location to .env [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#7533](https://github.com/community-scripts/ProxmoxVE/pull/7533))
- #### 🔧 Refactor
- Improve npmplus credential retrieval and messaging [@MickLesk](https://github.com/MickLesk) ([#7532](https://github.com/community-scripts/ProxmoxVE/pull/7532))
### 🌐 Website
- #### 📝 Script Information
- set updateable to true for several lxc JSON-configs [@MickLesk](https://github.com/MickLesk) ([#7534](https://github.com/community-scripts/ProxmoxVE/pull/7534))
## 2025-09-09
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Tududi: v0.81 [@vhsdream](https://github.com/vhsdream) ([#7517](https://github.com/community-scripts/ProxmoxVE/pull/7517))
- WGDashboard: Revert back to old update method [@tremor021](https://github.com/tremor021) ([#7500](https://github.com/community-scripts/ProxmoxVE/pull/7500))
- AdventureLog: remove folder during update process [@MickLesk](https://github.com/MickLesk) ([#7507](https://github.com/community-scripts/ProxmoxVE/pull/7507))
- PLANKA: Fix backup and restore commands [@tremor021](https://github.com/tremor021) ([#7505](https://github.com/community-scripts/ProxmoxVE/pull/7505))
- Recyclarr: Suppress config creation output [@tremor021](https://github.com/tremor021) ([#7502](https://github.com/community-scripts/ProxmoxVE/pull/7502))
- #### 🔧 Refactor
- Pulse: standardise install/update with Pulse repo script [@vhsdream](https://github.com/vhsdream) ([#7519](https://github.com/community-scripts/ProxmoxVE/pull/7519))
### 🌐 Website
- #### 🐞 Bug Fixes
- Refactor GitHubStarsButton to wrap in Link component for external navigation [@BramSuurdje](https://github.com/BramSuurdje) ([#7492](https://github.com/community-scripts/ProxmoxVE/pull/7492))
- #### ✨ New Features
- Bump vite from 7.0.0 to 7.1.5 in /frontend [@dependabot[bot]](https://github.com/dependabot[bot]) ([#7522](https://github.com/community-scripts/ProxmoxVE/pull/7522))
- #### 📝 Script Information
- swizzin: Change category from nvr to media [@MickLesk](https://github.com/MickLesk) ([#7511](https://github.com/community-scripts/ProxmoxVE/pull/7511))
## 2025-09-08
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- CT's: fix missing variable declaration (actualBudget, openziti, umlautadaptarr) [@MickLesk](https://github.com/MickLesk) ([#7483](https://github.com/community-scripts/ProxmoxVE/pull/7483))
- karakeep: fix service file [@CrazyWolf13](https://github.com/CrazyWolf13) ([#7482](https://github.com/community-scripts/ProxmoxVE/pull/7482))
- Update searxng-install.sh [@sebguy](https://github.com/sebguy) ([#7469](https://github.com/community-scripts/ProxmoxVE/pull/7469))
- #### ✨ New Features
- Immich: bump to version 1.141.1 [@vhsdream](https://github.com/vhsdream) ([#7418](https://github.com/community-scripts/ProxmoxVE/pull/7418))
- [core]: switch all base_settings to variables [@MickLesk](https://github.com/MickLesk) ([#7479](https://github.com/community-scripts/ProxmoxVE/pull/7479))
- #### 💥 Breaking Changes
- RustDesk Server: Update the credentials info [@tremor021](https://github.com/tremor021) ([#7473](https://github.com/community-scripts/ProxmoxVE/pull/7473))
### 🌐 Website
- #### 🐞 Bug Fixes
- Format numerical values in DataFetcher component for better readability [@BramSuurdje](https://github.com/BramSuurdje) ([#7477](https://github.com/community-scripts/ProxmoxVE/pull/7477))
- #### ✨ New Features
- feat: enhance github stars button to be better looking and more compact [@BramSuurdje](https://github.com/BramSuurdje) ([#7464](https://github.com/community-scripts/ProxmoxVE/pull/7464))
## 2025-09-07
### 🚀 Updated Scripts

View File

@@ -6,13 +6,13 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
# Source: https://actualbudget.org/
APP="Actual Budget"
var_tags="finance"
var_cpu="2"
var_ram="2048"
var_disk="4"
var_os="debian"
var_version="12"
var_unprivileged="1"
var_tags="${var_tags:-finance}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-4}"
var_os="${var_os:-debian}"
var_version="${var_version:-12}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables

View File

@@ -39,6 +39,7 @@ function update_script() {
msg_info "Backup Old Installation"
cp -r /opt/adventurelog /opt/adventurelog-backup
rm -rf /opt/adventurelog
msg_ok "Backup done"
fetch_and_deploy_gh_release "adventurelog" "seanmorley15/adventurelog"

View File

@@ -9,7 +9,7 @@ APP="audiobookshelf"
var_tags="${var_tags:-podcast;audiobook}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-4}"
var_disk="${var_disk:-5}"
var_os="${var_os:-debian}"
var_version="${var_version:-12}"
var_unprivileged="${var_unprivileged:-1}"
@@ -20,15 +20,19 @@ color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -f /etc/apt/trusted.gpg.d/audiobookshelf-ppa.asc ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
echo "This application receives updates through the APT package manager."
header_info
check_container_storage
check_container_resources
if [[ ! -f /etc/default/audiobookshelf ]]; 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
@@ -38,4 +42,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}:13378${CL}"
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:13378${CL}"

View File

@@ -61,7 +61,7 @@ function update_script() {
done
msg_ok "Image-processing libraries up to date"
fi
RELEASE="1.140.1"
RELEASE="1.141.1"
if check_for_gh_release "immich" "immich-app/immich" "${RELEASE}"; then
msg_info "Stopping Services"
systemctl stop immich-web

View File

@@ -6,13 +6,13 @@ source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVE/m
# Source: https://github.com/openziti/ziti
APP="openziti-controller"
var_tags="network;openziti-controller"
var_cpu="2"
var_ram="1024"
var_disk="8"
var_os="debian"
var_version="12"
var_unprivileged="1"
var_tags="${var_tags:-network;openziti-controller}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-1024}"
var_disk="${var_disk:-8}"
var_os="${var_os:-debian}"
var_version="${var_version:-12}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
@@ -20,18 +20,18 @@ color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -d /opt/openziti ]]; 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
header_info
check_container_storage
check_container_resources
if [[ ! -d /opt/openziti ]]; 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}https://${IP}:<port>/zac${CL}"
echo -e "${TAB}${GATEWAY}${BGN}https://${IP}:<port>/zac${CL}"

View File

@@ -34,12 +34,13 @@ function update_script() {
msg_ok "Stopped $APP"
msg_info "Backing up data"
mkdir -p /opt/planka-backup/{favicons,user-avatars,background-images,attachments}
mv /opt/planka/.env /opt/planka-backup
[ -d /opt/planka/public/favicons ] && find /opt/planka/public/favicons -maxdepth 1 -type f -exec mv -t /opt/planka-backup/favicons {} +
[ -d /opt/planka/public/user-avatars ] && find /opt/planka/public/user-avatars -maxdepth 1 -type f -exec mv -t /opt/planka-backup/user-avatars {} +
[ -d /opt/planka/public/background-images ] && find /opt/planka/public/background-images -maxdepth 1 -type f -exec mv -t /opt/planka-backup/background-images {} +
[ -d /opt/planka/private/attachments ] && find /opt/planka/private/attachments -maxdepth 1 -type f -exec mv -t /opt/planka-backup/attachments {} +
BK="/opt/planka-backup"
mkdir -p "$BK"/{favicons,user-avatars,background-images,attachments}
[ -f /opt/planka/.env ] && mv /opt/planka/.env "$BK"/
[ -d /opt/planka/public/favicons ] && cp -a /opt/planka/public/favicons/. "$BK/favicons/"
[ -d /opt/planka/public/user-avatars ] && cp -a /opt/planka/public/user-avatars/. "$BK/user-avatars/"
[ -d /opt/planka/public/background-images ] && cp -a /opt/planka/public/background-images/. "$BK/background-images/"
[ -d /opt/planka/private/attachments ] && cp -a /opt/planka/private/attachments/. "$BK/attachments/"
rm -rf /opt/planka
msg_ok "Backed up data"
@@ -51,11 +52,13 @@ function update_script() {
msg_ok "Updated Frontend"
msg_info "Restoring data"
mv /opt/planka-backup/.env /opt/planka/
[ -d /opt/planka-backup/favicons ] && find /opt/planka-backup/favicons -maxdepth 1 -type f -exec mv -t /opt/planka/public/favicons {} +
[ -d /opt/planka-backup/user-avatars ] && find /opt/planka-backup/user-avatars -maxdepth 1 -type f -exec mv -t /opt/planka/public/user-avatars {} +
[ -d /opt/planka-backup/background-images ] && find /opt/planka-backup/background-images -maxdepth 1 -type f -exec mv -t /opt/planka/public/background-images {} +
[ -d /opt/planka-backup/attachments ] && find /opt/planka-backup/attachments -maxdepth 1 -type f -exec mv -t /opt/planka/private/attachments {} +
[ -f "$BK/.env" ] && mv "$BK/.env" /opt/planka/.env
mkdir -p /opt/planka/public/{favicons,user-avatars,background-images} /opt/planka/private/attachments
[ -d "$BK/favicons" ] && cp -a "$BK/favicons/." /opt/planka/public/favicons/
[ -d "$BK/user-avatars" ] && cp -a "$BK/user-avatars/." /opt/planka/public/user-avatars/
[ -d "$BK/background-images" ] && cp -a "$BK/background-images/." /opt/planka/public/background-images/
[ -d "$BK/attachments" ] && cp -a "$BK/attachments/." /opt/planka/private/attachments/
rm -rf "$BK"
msg_ok "Restored data"
msg_info "Starting $APP"

View File

@@ -28,10 +28,6 @@ function update_script() {
exit
fi
if [[ ! -f ~/.pulse ]]; then
msg_error "Old Installation Found! Please recreate the container due big changes in the software."
exit 1
fi
if check_for_gh_release "pulse" "rcourtman/Pulse"; then
SERVICE_PATH="/etc/systemd/system"
msg_info "Stopping Services"
@@ -43,19 +39,20 @@ function update_script() {
fi
fetch_and_deploy_gh_release "pulse" "rcourtman/Pulse" "prebuild" "latest" "/opt/pulse" "*-linux-amd64.tar.gz"
ln -sf /opt/pulse/bin/pulse /usr/local/bin/pulse
chown -R pulse:pulse /etc/pulse /opt/pulse
if [[ -f "$SERVICE_PATH"/pulse.service ]]; then
mv "$SERVICE_PATH"/pulse.service "$SERVICE_PATH"/pulse-backend.service
if [[ -f "$SERVICE_PATH"/pulse-backend.service ]]; then
mv "$SERVICE_PATH"/pulse-backend.service "$SERVICE_PATH"/pulse.service
fi
sed -i -e 's|pulse/pulse|pulse/bin/pulse|' \
-e 's/^Environment="API.*$//' "$SERVICE_PATH"/pulse-backend.service
-e 's/^Environment="API.*$//' "$SERVICE_PATH"/pulse.service
systemctl daemon-reload
if grep -q 'pulse-home:/bin/bash' /etc/passwd; then
usermod -s /usr/sbin/nologin pulse
fi
msg_info "Starting Services"
systemctl start pulse-backend
systemctl start pulse
msg_ok "Started Services"
msg_ok "Updated Successfully"
fi

View File

@@ -34,6 +34,7 @@ function update_script() {
msg_ok "Stopped Service"
fetch_and_deploy_gh_release "recyclarr" "recyclarr/recyclarr" "prebuild" "latest" "/usr/local/bin" "recyclarr-linux-x64.tar.xz"
msg_info "Starting Service"
systemctl start recyclarr
msg_ok "Started Service"

View File

@@ -27,17 +27,22 @@ function update_script() {
msg_error "No ${APP} Installation Found!"
exit
fi
NODE_VERSION="22" setup_nodejs
if check_for_gh_release "tududi" "chrisvel/tududi"; then
msg_info "Stopping Service"
systemctl stop tududi
msg_ok "Stopped Service"
msg_info "Remove and backup Files"
DB="$(sed -n '/^DB_FILE/s/[^=]*=//p' /opt/tududi/backend/.env)"
export DB_FILE="$DB"
cp /opt/tududi/backend/.env /opt/tududi.env
rm -rf /opt/tududi/backend/dist
msg_ok "Backup and removed Files"
fetch_and_deploy_gh_release "tududi" "chrisvel/tududi" "tarball" "v0.80" "/opt/tududi"
fetch_and_deploy_gh_release "tududi" "chrisvel/tududi" "tarball" "latest" "/opt/tududi"
msg_info "Updating ${APP}"
cd /opt/tududi
@@ -48,6 +53,10 @@ function update_script() {
mv ./public/locales ./backend/dist
mv ./public/favicon.* ./backend/dist
mv /opt/tududi.env /opt/tududi/.env
sed -i -e 's|/tududi$|/tududi/backend|' \
-e 's|npm run start|bash /opt/tududi/backend/cmd/start.sh|' \
/etc/systemd/system/tududi.service
systemctl daemon-reload
msg_ok "Updated $APP"
msg_info "Starting Service"

View File

@@ -6,13 +6,13 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
# Source: https://github.com/PCJones/UmlautAdaptarr
APP="UmlautAdaptarr"
var_tags="arr"
var_cpu="1"
var_ram="512"
var_disk="4"
var_os="debian"
var_version="12"
var_unprivileged="1"
var_tags="${var_tags:-arr}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}"
var_disk="${var_disk:-4}"
var_os="${var_os:-debian}"
var_version="${var_version:-12}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
@@ -20,33 +20,33 @@ color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -d /opt/UmlautAdaptarr ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
RELEASE=$(curl -fsSL https://api.github.com/repos/PCJones/Umlautadaptarr/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3)}')
if [[ ! -f /opt/UmlautAdaptarr_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/UmlautAdaptarr_version.txt)" ]]; then
msg_info "Stopping Service"
systemctl stop umlautadaptarr
msg_ok "Stopped Service"
msg_info "Updating ${APP}"
temp_file=$(mktemp)
curl -fsSL "https://github.com/PCJones/Umlautadaptarr/releases/download/${RELEASE}/linux-x64.zip" -o $temp_file
$STD unzip -u $temp_file '*/**' -d /opt/UmlautAdaptarr
msg_ok "Updated ${APP}"
msg_info "Starting Service"
systemctl start umlautadaptarr
msg_ok "Started Service"
msg_ok "$APP has been updated to ${RELEASE}."
else
msg_ok "No update required. ${APP} is already at ${RELEASE}"
fi
header_info
check_container_storage
check_container_resources
if [[ ! -d /opt/UmlautAdaptarr ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
RELEASE=$(curl -fsSL https://api.github.com/repos/PCJones/Umlautadaptarr/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3)}')
if [[ ! -f /opt/UmlautAdaptarr_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/UmlautAdaptarr_version.txt)" ]]; then
msg_info "Stopping Service"
systemctl stop umlautadaptarr
msg_ok "Stopped Service"
msg_info "Updating ${APP}"
temp_file=$(mktemp)
curl -fsSL "https://github.com/PCJones/Umlautadaptarr/releases/download/${RELEASE}/linux-x64.zip" -o $temp_file
$STD unzip -u $temp_file '*/**' -d /opt/UmlautAdaptarr
msg_ok "Updated ${APP}"
msg_info "Starting Service"
systemctl start umlautadaptarr
msg_ok "Started Service"
msg_ok "$APP has been updated to ${RELEASE}."
else
msg_ok "No update required. ${APP} is already at ${RELEASE}"
fi
exit
}
start
build_container

View File

@@ -28,6 +28,12 @@ function update_script() {
msg_error "No ${APP} Installation Found!"
exit
fi
if ! dpkg -s git >/dev/null 2>&1; then
msg_info "Installing git"
$STD apt-get update
$STD apt-get install -y git
msg_ok "Installed git"
fi
apt-get update
apt-get -y upgrade
if [[ -d /etc/wgdashboard ]]; then

View File

@@ -13,5 +13,8 @@
"aliases": {
"components": "@/components",
"utils": "@/lib/utils"
},
"registries": {
"@animate-ui": "https://animate-ui.com/r/{name}.json"
}
}

View File

@@ -31,8 +31,9 @@
"date-fns": "^4.1.0",
"framer-motion": "^11.18.2",
"fuse.js": "^7.1.0",
"lucide-react": "^0.453.0",
"lucide-react": "^0.542.0",
"mini-svg-data-uri": "^1.4.4",
"motion": "^12.23.12",
"next": "15.5.2",
"next-themes": "^0.4.4",
"nuqs": "^2.4.1",
@@ -46,6 +47,7 @@
"react-dom": "19.0.0",
"react-icons": "^5.5.0",
"react-simple-typewriter": "^5.0.1",
"react-use-measure": "^2.1.7",
"sharp": "^0.33.5",
"simple-icons": "^13.21.0",
"sonner": "^1.7.4",
@@ -7664,11 +7666,14 @@
}
},
"node_modules/fdir": {
"version": "6.4.6",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
"integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"picomatch": "^3 || ^4"
},
@@ -9293,12 +9298,12 @@
}
},
"node_modules/lucide-react": {
"version": "0.453.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.453.0.tgz",
"integrity": "sha512-kL+RGZCcJi9BvJtzg2kshO192Ddy9hv3ij+cPrVPWSRzgCWCVazoQJxOjAwgK53NomL07HB7GPHW120FimjNhQ==",
"version": "0.542.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.542.0.tgz",
"integrity": "sha512-w3hD8/SQB7+lzU2r4VdFyzzOzKnUjTZIF/MQJGSSvni7Llewni4vuViRppfRAa2guOsY5k4jZyxw/i9DQHv+dw==",
"license": "ISC",
"peerDependencies": {
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc"
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/magic-string": {
@@ -10339,6 +10344,32 @@
"pathe": "^2.0.1"
}
},
"node_modules/motion": {
"version": "12.23.12",
"resolved": "https://registry.npmjs.org/motion/-/motion-12.23.12.tgz",
"integrity": "sha512-8jCD8uW5GD1csOoqh1WhH1A6j5APHVE15nuBkFeRiMzYBdRwyAHmSP/oXSuW0WJPZRXTFdBoG4hY9TFWNhhwng==",
"license": "MIT",
"dependencies": {
"framer-motion": "^12.23.12",
"tslib": "^2.4.0"
},
"peerDependencies": {
"@emotion/is-prop-valid": "*",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/is-prop-valid": {
"optional": true
},
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/motion-dom": {
"version": "11.18.1",
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.18.1.tgz",
@@ -10354,6 +10385,48 @@
"integrity": "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==",
"license": "MIT"
},
"node_modules/motion/node_modules/framer-motion": {
"version": "12.23.12",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.12.tgz",
"integrity": "sha512-6e78rdVtnBvlEVgu6eFEAgG9v3wLnYEboM8I5O5EXvfKC8gxGQB8wXJdhkMy10iVcn05jl6CNw7/HTsTCfwcWg==",
"license": "MIT",
"dependencies": {
"motion-dom": "^12.23.12",
"motion-utils": "^12.23.6",
"tslib": "^2.4.0"
},
"peerDependencies": {
"@emotion/is-prop-valid": "*",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/is-prop-valid": {
"optional": true
},
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/motion/node_modules/motion-dom": {
"version": "12.23.12",
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.12.tgz",
"integrity": "sha512-RcR4fvMCTESQBD/uKQe49D5RUeDOokkGRmz4ceaJKDBgHYtZtntC/s2vLvY38gqGaytinij/yi3hMcWVcEF5Kw==",
"license": "MIT",
"dependencies": {
"motion-utils": "^12.23.6"
}
},
"node_modules/motion/node_modules/motion-utils": {
"version": "12.23.6",
"resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz",
"integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==",
"license": "MIT"
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -11362,9 +11435,9 @@
"license": "ISC"
},
"node_modules/picomatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
"engines": {
@@ -11990,6 +12063,21 @@
"react": ">= 0.14.0"
}
},
"node_modules/react-use-measure": {
"version": "2.1.7",
"resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.7.tgz",
"integrity": "sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==",
"license": "MIT",
"peerDependencies": {
"react": ">=16.13",
"react-dom": ">=16.13"
},
"peerDependenciesMeta": {
"react-dom": {
"optional": true
}
}
},
"node_modules/read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
@@ -13307,14 +13395,14 @@
"license": "MIT"
},
"node_modules/tinyglobby": {
"version": "0.2.14",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",
"integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==",
"version": "0.2.15",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"fdir": "^6.4.4",
"picomatch": "^4.0.2"
"fdir": "^6.5.0",
"picomatch": "^4.0.3"
},
"engines": {
"node": ">=12.0.0"
@@ -13837,19 +13925,19 @@
"license": "MIT"
},
"node_modules/vite": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.0.0.tgz",
"integrity": "sha512-ixXJB1YRgDIw2OszKQS9WxGHKwLdCsbQNkpJN171udl6szi/rIySHL6/Os3s2+oE4P/FLD4dxg4mD7Wust+u5g==",
"version": "7.1.5",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.1.5.tgz",
"integrity": "sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.4.6",
"picomatch": "^4.0.2",
"fdir": "^6.5.0",
"picomatch": "^4.0.3",
"postcss": "^8.5.6",
"rollup": "^4.40.0",
"tinyglobby": "^0.2.14"
"rollup": "^4.43.0",
"tinyglobby": "^0.2.15"
},
"bin": {
"vite": "bin/vite.js"

4
frontend/package.json generated
View File

@@ -38,8 +38,9 @@
"date-fns": "^4.1.0",
"framer-motion": "^11.18.2",
"fuse.js": "^7.1.0",
"lucide-react": "^0.453.0",
"lucide-react": "^0.542.0",
"mini-svg-data-uri": "^1.4.4",
"motion": "^12.23.12",
"next": "15.5.2",
"next-themes": "^0.4.4",
"nuqs": "^2.4.1",
@@ -53,6 +54,7 @@
"react-dom": "19.0.0",
"react-icons": "^5.5.0",
"react-simple-typewriter": "^5.0.1",
"react-use-measure": "^2.1.7",
"sharp": "^0.33.5",
"simple-icons": "^13.21.0",
"sonner": "^1.7.4",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-19",
"type": "addon",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": null,
"documentation": "https://docs.netbird.io/",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-02",
"type": "addon",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": null,
"documentation": "https://tailscale.com/kb/1017/install",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 3142,
"documentation": "https://www.unix-ag.uni-kl.de/~bloch/acng/html/index.html",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 13378,
"documentation": "https://www.audiobookshelf.org/guides/",
@@ -21,7 +21,7 @@
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 4,
"hdd": 5,
"os": "debian",
"version": "12"
}

View File

@@ -6,7 +6,7 @@
],
"date_created": "2025-01-20",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 8090,
"documentation": "https://beszel.dev/guide/what-is-beszel",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2025-05-22",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": null,
"documentation": "https://github.com/favonia/cloudflare-ddns/blob/main/README.markdown",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": null,
"documentation": "https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 4000,
"documentation": "https://dashy.to/docs",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": true,
"interface_port": 80,
"documentation": "https://github.com/dresden-elektronik/deconz-rest-plugin/wiki",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 8112,
"documentation": "https://www.deluge-torrent.org/userguide/",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 8083,
"documentation": "https://fhem.de/#Documentation",

View File

@@ -7,7 +7,7 @@
],
"date_created": "2025-06-18",
"type": "addon",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 8080,
"documentation": "https://github.com/gtsteffaniak/filebrowser/wiki/Getting-Started",

View File

@@ -7,7 +7,7 @@
],
"date_created": "2024-05-02",
"type": "addon",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 8080,
"documentation": null,

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 8581,
"documentation": "https://github.com/homebridge/homebridge/wiki",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": true,
"interface_port": 8090,
"documentation": "https://github.com/awawa-dev/HyperHDR/wiki",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 8086,
"documentation": "https://docs.influxdata.com/",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2025-07-29",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 80,
"documentation": "https://doc.jeedom.com",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-12-26",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 8080,
"documentation": "https://www.jenkins.io/doc/",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 5299,
"documentation": "https://lazylibrarian.gitlab.io/lazylibrarian.gitlab.io/",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-08-06",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 17170,
"documentation": "https://github.com/lldap/lldap/blob/main/README.md",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 3306,
"documentation": "https://github.com/community-scripts/ProxmoxVE/discussions/192",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2025-01-30",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 8065,
"documentation": "https://docs.mattermost.com/",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-18",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 27017,
"documentation": "https://www.mongodb.com/docs/manual/",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": null,
"documentation": "https://mosquitto.org/documentation/",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2025-03-13",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 81,
"documentation": "https://github.com/ZoeyVid/NPMplus/blob/develop/README.md",
@@ -39,7 +39,7 @@
}
],
"default_credentials": {
"username": "root",
"username": "admin@example.org",
"password": null
},
"notes": [
@@ -52,7 +52,7 @@
"type": "info"
},
{
"text": "Application credentials: `cat /opt/.npm_pwd`",
"text": "Application credentials: `cat /opt/.npm_pwd` - if file not exist in LXC check docker logs for password with `docker logs npmplus`",
"type": "info"
}
]

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 80,
"documentation": "https://docs.ntfy.sh/",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 80,
"documentation": "https://docs.openmediavault.org/en/stable/",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 8443,
"documentation": "https://www.openhab.org/docs/",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": null,
"documentation": "https://github.com/leiweibau/Pi.Alert/blob/main/README.md",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2025-02-02",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 5232,
"documentation": "https://radicale.org/master.html#documentation-1",

View File

@@ -48,7 +48,11 @@
"type": "info"
},
{
"text": "Login credentials: `cat ~/rustdesk.creds`",
"text": "To set admin password on Debian, type `cd /var/lib/rustdesk-api && rustdesk-api reset-admin-pwd <yournewpasswordhere>` inside LXC.",
"type": "info"
},
{
"text": "To see admin password on Alpine, type `cat ~/rustdesk.creds` inside LXC.",
"type": "info"
}
]

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": null,
"documentation": "https://oss.oetiker.ch/smokeping/doc/index.en.html",

View File

@@ -2,7 +2,7 @@
"name": "Swizzin",
"slug": "swizzin",
"categories": [
15
13
],
"date_created": "2025-08-19",
"type": "ct",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 8384,
"documentation": "https://docs.syncthing.net/",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 8181,
"documentation": "https://github.com/Tautulli/Tautulli/wiki",

View File

@@ -6,7 +6,7 @@
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 8443,
"documentation": null,

View File

@@ -1,8 +1,218 @@
[
{
"name": "9001/copyparty",
"version": "v1.19.8",
"date": "2025-09-07T23:36:42Z"
"name": "authelia/authelia",
"version": "v4.39.9",
"date": "2025-09-09T22:48:24Z"
},
{
"name": "MediaBrowser/Emby.Releases",
"version": "4.9.1.2",
"date": "2025-06-26T22:08:00Z"
},
{
"name": "jenkinsci/jenkins",
"version": "jenkins-2.527",
"date": "2025-09-09T19:58:28Z"
},
{
"name": "kyantech/Palmr",
"version": "v3.2.1-beta",
"date": "2025-09-09T19:47:13Z"
},
{
"name": "Part-DB/Part-DB-server",
"version": "v2.1.2",
"date": "2025-09-09T19:34:11Z"
},
{
"name": "hargata/lubelog",
"version": "v1.5.1",
"date": "2025-09-09T16:56:49Z"
},
{
"name": "open-webui/open-webui",
"version": "v0.6.27",
"date": "2025-09-09T14:34:27Z"
},
{
"name": "chrisvel/tududi",
"version": "v0.81",
"date": "2025-09-09T14:06:41Z"
},
{
"name": "firefly-iii/firefly-iii",
"version": "v6.3.2",
"date": "2025-08-19T04:08:36Z"
},
{
"name": "element-hq/synapse",
"version": "v1.138.0",
"date": "2025-09-09T11:25:50Z"
},
{
"name": "traefik/traefik",
"version": "v3.5.2",
"date": "2025-09-09T10:28:12Z"
},
{
"name": "docker/compose",
"version": "v2.39.3",
"date": "2025-09-09T08:27:27Z"
},
{
"name": "OctoPrint/OctoPrint",
"version": "1.11.3",
"date": "2025-09-09T08:03:31Z"
},
{
"name": "readeck/readeck",
"version": "0.20.2",
"date": "2025-09-09T06:09:25Z"
},
{
"name": "Jackett/Jackett",
"version": "v0.22.2444",
"date": "2025-09-09T06:00:01Z"
},
{
"name": "TandoorRecipes/recipes",
"version": "2.1.2",
"date": "2025-09-09T05:55:58Z"
},
{
"name": "gotson/komga",
"version": "1.23.4",
"date": "2025-09-09T02:47:05Z"
},
{
"name": "Tautulli/Tautulli",
"version": "v2.16.0",
"date": "2025-09-09T01:05:45Z"
},
{
"name": "jeedom/core",
"version": "4.4.20",
"date": "2025-09-09T00:27:11Z"
},
{
"name": "steveiliop56/tinyauth",
"version": "v3.6.2",
"date": "2025-07-17T12:08:03Z"
},
{
"name": "YunoHost/yunohost",
"version": "debian/12.1.20",
"date": "2025-09-08T23:47:21Z"
},
{
"name": "mongodb/mongo",
"version": "r8.0.14-rc1",
"date": "2025-09-08T22:50:53Z"
},
{
"name": "diced/zipline",
"version": "v4.3.1",
"date": "2025-09-08T22:26:23Z"
},
{
"name": "cross-seed/cross-seed",
"version": "v6.13.3",
"date": "2025-09-08T21:45:15Z"
},
{
"name": "HabitRPG/habitica",
"version": "v5.40.2",
"date": "2025-09-08T20:59:44Z"
},
{
"name": "keycloak/keycloak",
"version": "26.0.15",
"date": "2025-08-27T12:12:03Z"
},
{
"name": "booklore-app/booklore",
"version": "v1.2.1",
"date": "2025-09-08T19:31:07Z"
},
{
"name": "fallenbagel/jellyseerr",
"version": "preview-OIDC",
"date": "2025-09-08T18:08:15Z"
},
{
"name": "mattermost/mattermost",
"version": "server/public/v0.1.18",
"date": "2025-09-08T18:04:10Z"
},
{
"name": "immich-app/immich",
"version": "v1.141.1",
"date": "2025-09-08T17:15:33Z"
},
{
"name": "msgbyte/tianji",
"version": "v1.24.27",
"date": "2025-09-08T16:23:37Z"
},
{
"name": "Paymenter/Paymenter",
"version": "v1.3.1",
"date": "2025-09-08T15:26:01Z"
},
{
"name": "n8n-io/n8n",
"version": "n8n@1.109.2",
"date": "2025-09-03T07:50:21Z"
},
{
"name": "apache/tomcat",
"version": "10.1.46",
"date": "2025-09-08T14:29:54Z"
},
{
"name": "home-assistant/operating-system",
"version": "16.2",
"date": "2025-09-08T14:03:25Z"
},
{
"name": "zitadel/zitadel",
"version": "v4.1.3",
"date": "2025-09-08T13:36:08Z"
},
{
"name": "theonedev/onedev",
"version": "v12.0.10",
"date": "2025-09-08T13:20:16Z"
},
{
"name": "evcc-io/evcc",
"version": "0.207.6",
"date": "2025-09-08T11:52:00Z"
},
{
"name": "autobrr/autobrr",
"version": "v1.66.1",
"date": "2025-09-08T10:49:03Z"
},
{
"name": "meilisearch/meilisearch",
"version": "latest",
"date": "2025-09-08T10:03:11Z"
},
{
"name": "syncthing/syncthing",
"version": "v2.0.8",
"date": "2025-09-08T08:07:18Z"
},
{
"name": "nzbgetcom/nzbget",
"version": "v25.3",
"date": "2025-09-01T09:47:06Z"
},
{
"name": "webmin/webmin",
"version": "2.501",
"date": "2025-09-08T04:50:25Z"
},
{
"name": "paperless-ngx/paperless-ngx",
@@ -10,20 +220,15 @@
"date": "2025-09-07T23:57:32Z"
},
{
"name": "Part-DB/Part-DB-server",
"version": "v2.1.1",
"date": "2025-09-07T21:59:53Z"
"name": "9001/copyparty",
"version": "v1.19.8",
"date": "2025-09-07T23:36:42Z"
},
{
"name": "minio/minio",
"version": "RELEASE.2025-09-07T16-13-09Z",
"date": "2025-09-07T18:53:04Z"
},
{
"name": "MediaBrowser/Emby.Releases",
"version": "4.9.1.2",
"date": "2025-06-26T22:08:00Z"
},
{
"name": "karakeep-app/karakeep",
"version": "sdk/v0.27.0",
@@ -34,31 +239,16 @@
"version": "0.50.12",
"date": "2025-09-07T14:16:07Z"
},
{
"name": "cross-seed/cross-seed",
"version": "v6.13.2",
"date": "2025-08-19T18:18:40Z"
},
{
"name": "firefly-iii/firefly-iii",
"version": "v6.3.2",
"date": "2025-08-19T04:08:36Z"
},
{
"name": "runtipi/runtipi",
"version": "nightly",
"date": "2025-09-07T12:16:33Z"
"version": "v4.4.0",
"date": "2025-09-02T19:26:18Z"
},
{
"name": "semaphoreui/semaphore",
"version": "v2.17.0-beta1",
"date": "2025-09-07T08:56:50Z"
},
{
"name": "Jackett/Jackett",
"version": "v0.22.2438",
"date": "2025-09-07T06:00:21Z"
},
{
"name": "Radarr/Radarr",
"version": "v5.27.5.10198",
@@ -79,16 +269,6 @@
"version": "v2.13.3.4711",
"date": "2025-08-28T20:06:24Z"
},
{
"name": "jeedom/core",
"version": "4.4.19",
"date": "2025-09-07T00:27:07Z"
},
{
"name": "steveiliop56/tinyauth",
"version": "v3.6.2",
"date": "2025-07-17T12:08:03Z"
},
{
"name": "rcourtman/Pulse",
"version": "v4.14.0",
@@ -99,21 +279,11 @@
"version": "v1.6.4",
"date": "2025-08-18T20:22:07Z"
},
{
"name": "autobrr/autobrr",
"version": "v1.66.0",
"date": "2025-09-06T15:07:16Z"
},
{
"name": "fuma-nama/fumadocs",
"version": "create-fumadocs-app@15.7.10",
"date": "2025-09-06T10:13:43Z"
},
{
"name": "Paymenter/Paymenter",
"version": "v1.3.0",
"date": "2025-09-06T09:02:08Z"
},
{
"name": "Luligu/matterbridge",
"version": "3.2.6",
@@ -124,11 +294,6 @@
"version": "v12.0.3",
"date": "2025-09-06T07:01:44Z"
},
{
"name": "theonedev/onedev",
"version": "v12.0.9",
"date": "2025-09-06T00:39:00Z"
},
{
"name": "moghtech/komodo",
"version": "v1.19.3",
@@ -139,16 +304,6 @@
"version": "v1.36.1",
"date": "2025-09-05T21:14:40Z"
},
{
"name": "booklore-app/booklore",
"version": "v1.2.0",
"date": "2025-09-05T20:43:03Z"
},
{
"name": "immich-app/immich",
"version": "v1.141.1",
"date": "2025-09-05T19:44:39Z"
},
{
"name": "gtsteffaniak/filebrowser",
"version": "v0.8.4-beta",
@@ -159,21 +314,11 @@
"version": "v1.3.2",
"date": "2025-09-05T18:44:15Z"
},
{
"name": "diced/zipline",
"version": "v4.3.0",
"date": "2025-09-05T18:43:28Z"
},
{
"name": "henrygd/beszel",
"version": "v0.12.7",
"date": "2025-09-05T18:11:36Z"
},
{
"name": "keycloak/keycloak",
"version": "26.0.15",
"date": "2025-08-27T12:12:03Z"
},
{
"name": "Brandawg93/PeaNUT",
"version": "v5.14.2",
@@ -184,26 +329,11 @@
"version": "2025.9.0",
"date": "2025-09-05T14:21:34Z"
},
{
"name": "chrisvel/tududi",
"version": "v0.80",
"date": "2025-07-24T14:12:39Z"
},
{
"name": "home-assistant/core",
"version": "2025.9.1",
"date": "2025-09-05T11:15:21Z"
},
{
"name": "syncthing/syncthing",
"version": "v2.0.7",
"date": "2025-09-05T10:18:24Z"
},
{
"name": "zitadel/zitadel",
"version": "v4.1.2",
"date": "2025-09-05T08:23:30Z"
},
{
"name": "CrazyWolf13/streamlink-webui",
"version": "0.6",
@@ -234,36 +364,16 @@
"version": "v1.0.0-beta17",
"date": "2025-09-04T21:30:14Z"
},
{
"name": "TandoorRecipes/recipes",
"version": "2.1.0",
"date": "2025-09-04T20:24:47Z"
},
{
"name": "mongodb/mongo",
"version": "r7.0.24",
"date": "2025-09-04T19:50:49Z"
},
{
"name": "Cleanuparr/Cleanuparr",
"version": "v2.2.3",
"date": "2025-09-04T19:24:39Z"
},
{
"name": "HabitRPG/habitica",
"version": "v5.40.1",
"date": "2025-09-04T19:10:45Z"
},
{
"name": "AdguardTeam/AdGuardHome",
"version": "v0.107.65",
"date": "2025-08-20T14:02:28Z"
},
{
"name": "webmin/webmin",
"version": "2.500",
"date": "2025-09-04T17:44:27Z"
},
{
"name": "ollama/ollama",
"version": "v0.11.10",
@@ -339,31 +449,16 @@
"version": "5.26.12",
"date": "2025-09-03T12:03:22Z"
},
{
"name": "n8n-io/n8n",
"version": "n8n@1.109.2",
"date": "2025-09-03T07:50:21Z"
},
{
"name": "Checkmk/checkmk",
"version": "v2.4.0p11",
"date": "2025-09-03T09:58:14Z"
},
{
"name": "mattermost/mattermost",
"version": "server/public/v0.1.17",
"date": "2025-09-02T21:38:40Z"
},
{
"name": "cockpit-project/cockpit",
"version": "346",
"date": "2025-09-03T09:13:05Z"
},
{
"name": "jenkinsci/jenkins",
"version": "jenkins-2.526",
"date": "2025-09-02T18:44:42Z"
},
{
"name": "apache/cassandra",
"version": "cassandra-4.1.10",
@@ -379,21 +474,11 @@
"version": "v4.4.0",
"date": "2025-09-02T17:04:25Z"
},
{
"name": "element-hq/synapse",
"version": "v1.137.0",
"date": "2025-08-26T09:51:47Z"
},
{
"name": "rabbitmq/rabbitmq-server",
"version": "v4.1.4",
"date": "2025-09-02T14:26:24Z"
},
{
"name": "apache/tomcat",
"version": "10.1.45",
"date": "2025-09-02T12:46:34Z"
},
{
"name": "Dolibarr/dolibarr",
"version": "22.0.1",
@@ -409,11 +494,6 @@
"version": "v25.5.0",
"date": "2025-09-02T01:00:11Z"
},
{
"name": "authelia/authelia",
"version": "v4.39.8",
"date": "2025-09-02T00:44:45Z"
},
{
"name": "postgres/postgres",
"version": "REL_18_RC1",
@@ -434,11 +514,6 @@
"version": "v0.87.3",
"date": "2025-09-01T16:25:43Z"
},
{
"name": "home-assistant/operating-system",
"version": "16.1",
"date": "2025-08-13T07:58:10Z"
},
{
"name": "seanmorley15/AdventureLog",
"version": "v0.11.0",
@@ -449,16 +524,6 @@
"version": "rrc_steady_12.2.0-17245430286.patch1",
"date": "2025-09-01T14:19:14Z"
},
{
"name": "fallenbagel/jellyseerr",
"version": "preview-issue-description",
"date": "2025-09-01T12:21:58Z"
},
{
"name": "nzbgetcom/nzbget",
"version": "v25.3",
"date": "2025-09-01T09:47:06Z"
},
{
"name": "grokability/snipe-it",
"version": "v8.3.1",
@@ -469,16 +534,6 @@
"version": "v1.7.0",
"date": "2025-09-01T10:10:34Z"
},
{
"name": "readeck/readeck",
"version": "0.20.1",
"date": "2025-09-01T07:35:48Z"
},
{
"name": "YunoHost/yunohost",
"version": "debian/12.1.17.1",
"date": "2025-08-31T21:38:21Z"
},
{
"name": "LibreTranslate/LibreTranslate",
"version": "v1.7.3",
@@ -489,11 +544,6 @@
"version": "v0.9.91",
"date": "2025-08-30T21:49:57Z"
},
{
"name": "msgbyte/tianji",
"version": "v1.24.26",
"date": "2025-08-29T20:26:08Z"
},
{
"name": "silverbulletmd/silverbullet",
"version": "2.0.0",
@@ -539,21 +589,11 @@
"version": "v3.4.1",
"date": "2025-08-28T13:56:00Z"
},
{
"name": "open-webui/open-webui",
"version": "v0.6.26",
"date": "2025-08-28T10:40:30Z"
},
{
"name": "garethgeorge/backrest",
"version": "v1.9.2",
"date": "2025-08-28T07:06:14Z"
},
{
"name": "gotson/komga",
"version": "1.23.3",
"date": "2025-08-28T02:50:06Z"
},
{
"name": "pocket-id/pocket-id",
"version": "v1.10.0",
@@ -569,21 +609,6 @@
"version": "v11.2.1",
"date": "2025-08-27T15:19:02Z"
},
{
"name": "traefik/traefik",
"version": "v3.5.1",
"date": "2025-08-27T09:21:19Z"
},
{
"name": "meilisearch/meilisearch",
"version": "latest",
"date": "2025-08-26T14:14:42Z"
},
{
"name": "evcc-io/evcc",
"version": "0.207.5",
"date": "2025-08-26T06:57:07Z"
},
{
"name": "documenso/documenso",
"version": "v1.12.2-rc.6",
@@ -684,16 +709,6 @@
"version": "v6.9.1",
"date": "2025-08-22T04:04:12Z"
},
{
"name": "hargata/lubelog",
"version": "v1.5.0",
"date": "2025-08-21T17:33:22Z"
},
{
"name": "kyantech/Palmr",
"version": "v3.2.0-beta",
"date": "2025-08-21T16:51:45Z"
},
{
"name": "cloudflare/cloudflared",
"version": "2025.8.1",
@@ -829,11 +844,6 @@
"version": "2.38.0",
"date": "2025-08-08T21:47:19Z"
},
{
"name": "docker/compose",
"version": "v2.39.2",
"date": "2025-08-08T16:06:06Z"
},
{
"name": "apache/tika",
"version": "3.2.2",
@@ -874,11 +884,6 @@
"version": "v2.0.116",
"date": "2025-08-05T04:45:21Z"
},
{
"name": "Tautulli/Tautulli",
"version": "v2.15.3",
"date": "2025-08-03T17:27:16Z"
},
{
"name": "linuxserver/Heimdall",
"version": "v2.7.4",
@@ -1119,11 +1124,6 @@
"version": "v2.0.0.4645",
"date": "2017-03-07T18:56:06Z"
},
{
"name": "OctoPrint/OctoPrint",
"version": "1.11.2",
"date": "2025-06-10T11:07:14Z"
},
{
"name": "glanceapp/glance",
"version": "v0.8.4",

View File

@@ -38,6 +38,7 @@ const DataFetcher: React.FC = () => {
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(25);
const [sortConfig, setSortConfig] = useState<{ key: string; direction: "ascending" | "descending" } | null>(null);
const nf = new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 });
useEffect(() => {
const fetchSummary = async () => {
@@ -129,19 +130,24 @@ const DataFetcher: React.FC = () => {
<p className="text-lg font-bold mt-4"> </p>
<div className="mb-4 flex justify-between items-center">
<p className="text-lg font-bold">
{summary?.total_entries}
{nf.format(
summary?.total_entries ?? 0,
)}
{" "}
results found
</p>
<p className="text-lg font">
Status Legend: 🔄 installing
{summary?.status_count.installing ?? 0}
{" "}
{nf.format(summary?.status_count.installing ?? 0)}
{" "}
| completed
{summary?.status_count.done ?? 0}
{" "}
{nf.format(summary?.status_count.done ?? 0)}
{" "}
| failed
{summary?.status_count.failed ?? 0}
{" "}
{nf.format(summary?.status_count.failed ?? 0)}
{" "}
| unknown
</p>

View File

@@ -0,0 +1,61 @@
"use client";
import type { VariantProps } from "class-variance-authority";
import { cva } from "class-variance-authority";
import * as React from "react";
import type { ButtonProps as ButtonPrimitiveProps } from "@/components/animate-ui/primitives/buttons/button";
import {
Button as ButtonPrimitive,
} from "@/components/animate-ui/primitives/buttons/button";
import { cn } from "@/lib/utils";
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-[box-shadow,_color,_background-color,_border-color,_outline-color,_text-decoration-color,_fill,_stroke] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
{
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
accent: "bg-accent text-accent-foreground shadow-xs hover:bg-accent/90",
destructive:
"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
outline:
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
secondary:
"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
ghost:
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
"default": "h-9 px-4 py-2 has-[>svg]:px-3",
"sm": "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
"lg": "h-10 rounded-md px-6 has-[>svg]:px-4",
"icon": "size-9",
"icon-sm": "size-8 rounded-md",
"icon-lg": "size-10 rounded-md",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
},
);
type ButtonProps = ButtonPrimitiveProps & VariantProps<typeof buttonVariants>;
function Button({ className, variant, size, ...props }: ButtonProps) {
return (
<ButtonPrimitive
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
);
}
export { Button, type ButtonProps, buttonVariants };

View File

@@ -0,0 +1,109 @@
import type { VariantProps } from "class-variance-authority";
import { cva } from "class-variance-authority";
import { StarIcon } from "lucide-react";
import Link from "next/link";
import type { ButtonProps as ButtonPrimitiveProps } from "@/components/animate-ui/primitives/buttons/button";
import type { GithubStarsProps } from "@/components/animate-ui/primitives/animate/github-stars";
import {
GithubStars,
GithubStarsIcon,
GithubStarsLogo,
GithubStarsNumber,
GithubStarsParticles,
} from "@/components/animate-ui/primitives/animate/github-stars";
import { Button as ButtonPrimitive } from "@/components/animate-ui/primitives/buttons/button";
import { cn } from "@/lib/utils";
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-[box-shadow,_color,_background-color,_border-color,_outline-color,_text-decoration-color,_fill,_stroke] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
accent: "bg-accent text-accent-foreground shadow-xs hover:bg-accent/90",
outline:
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
},
size: {
default: "h-9 px-4 py-2 has-[>svg]:px-3",
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
},
);
const buttonStarVariants = cva("", {
variants: {
variant: {
default: "fill-neutral-700 stroke-neutral-700 dark:fill-neutral-300 dark:stroke-neutral-300",
accent: "fill-neutral-300 stroke-neutral-300 dark:fill-neutral-700 dark:stroke-neutral-700",
outline: "fill-neutral-300 stroke-neutral-300 dark:fill-neutral-700 dark:stroke-neutral-700",
ghost: "fill-neutral-300 stroke-neutral-300 dark:fill-neutral-700 dark:stroke-neutral-700",
},
},
defaultVariants: {
variant: "default",
},
});
type GitHubStarsButtonProps = Omit<ButtonPrimitiveProps & GithubStarsProps, "asChild" | "children">
& VariantProps<typeof buttonVariants>;
function GitHubStarsButton({
className,
username,
repo,
value,
delay,
inView,
inViewMargin,
inViewOnce,
variant,
size,
...props
}: GitHubStarsButtonProps) {
return (
<Link
target="_blank"
rel="noopener noreferrer"
data-umami-event="github-stars"
href={`https://github.com/${username}/${repo}`}
>
<GithubStars
asChild
username={username}
repo={repo}
value={value}
delay={delay}
inView={inView}
inViewMargin={inViewMargin}
inViewOnce={inViewOnce}
>
<ButtonPrimitive className={cn(buttonVariants({ variant, size, className }))} {...props}>
<GithubStarsLogo />
<GithubStarsNumber />
<GithubStarsParticles className="text-yellow-500">
<GithubStarsIcon
icon={StarIcon}
data-variant={variant}
className={cn(buttonStarVariants({ variant }))}
activeClassName="text-yellow-500"
size={18}
/>
</GithubStarsParticles>
</ButtonPrimitive>
</GithubStars>
</Link>
);
}
export { GitHubStarsButton, type GitHubStarsButtonProps };

View File

@@ -0,0 +1,206 @@
"use client";
import type { HTMLMotionProps } from "motion/react";
import { motion } from "motion/react";
import * as React from "react";
import type { SlidingNumberProps } from "@/components/animate-ui/primitives/texts/sliding-number";
import type { ParticlesEffectProps } from "@/components/animate-ui/primitives/effects/particles";
import type { WithAsChild } from "@/components/animate-ui/primitives/animate/slot";
import type { UseIsInViewOptions } from "@/hooks/use-is-in-view";
import { Particles, ParticlesEffect } from "@/components/animate-ui/primitives/effects/particles";
import { SlidingNumber } from "@/components/animate-ui/primitives/texts/sliding-number";
import { Slot } from "@/components/animate-ui/primitives/animate/slot";
import { getStrictContext } from "@/lib/get-strict-context";
import { useIsInView } from "@/hooks/use-is-in-view";
import { cn } from "@/lib/utils";
type GithubStarsContextType = {
stars: number;
setStars: (stars: number) => void;
currentStars: number;
setCurrentStars: (stars: number) => void;
isCompleted: boolean;
isLoading: boolean;
};
const [GithubStarsProvider, useGithubStars] = getStrictContext<GithubStarsContextType>("GithubStarsContext");
type GithubStarsProps = WithAsChild<
{
children: React.ReactNode;
username?: string;
repo?: string;
value?: number;
delay?: number;
} & UseIsInViewOptions
& HTMLMotionProps<"div">
>;
function GithubStars({
ref,
children,
username,
repo,
value,
delay = 0,
inView = false,
inViewMargin = "0px",
inViewOnce = true,
asChild = false,
...props
}: GithubStarsProps) {
const { ref: localRef, isInView } = useIsInView(ref as React.Ref<HTMLDivElement>, {
inView,
inViewOnce,
inViewMargin,
});
const [stars, setStars] = React.useState(value ?? 0);
const [currentStars, setCurrentStars] = React.useState(0);
const [isLoading, setIsLoading] = React.useState(true);
const isCompleted = React.useMemo(() => currentStars === stars, [currentStars, stars]);
const Component = asChild ? Slot : motion.div;
React.useEffect(() => {
if (value !== undefined && username && repo)
return;
if (!isInView) {
setStars(0);
setIsLoading(true);
return;
}
const timeout = setTimeout(() => {
fetch(`https://api.github.com/repos/${username}/${repo}`)
.then(response => response.json())
.then((data) => {
if (data && typeof data.stargazers_count === "number") {
setStars(data.stargazers_count);
}
})
.catch(console.error)
.finally(() => setIsLoading(false));
}, delay);
return () => clearTimeout(timeout);
}, [username, repo, value, isInView, delay]);
return (
<GithubStarsProvider
value={{
stars,
currentStars,
isCompleted,
isLoading,
setStars,
setCurrentStars,
}}
>
{!isLoading && (
<Component ref={localRef} {...props}>
{children}
</Component>
)}
</GithubStarsProvider>
);
}
type GithubStarsNumberProps = Omit<SlidingNumberProps, "number" | "fromNumber">;
function GithubStarsNumber({ padStart = true, ...props }: GithubStarsNumberProps) {
const { stars, setCurrentStars } = useGithubStars();
return (
<SlidingNumber number={stars} fromNumber={0} onNumberChange={setCurrentStars} padStart={padStart} {...props} />
);
}
type GithubStarsIconProps<T extends React.ElementType> = {
icon: React.ReactElement<T>;
color?: string;
activeClassName?: string;
} & React.ComponentProps<T>;
function GithubStarsIcon<T extends React.ElementType>({
icon: Icon,
color = "currentColor",
activeClassName,
className,
...props
}: GithubStarsIconProps<T>) {
const { stars, currentStars, isCompleted } = useGithubStars();
const fillPercentage = (currentStars / stars) * 100;
return (
<div style={{ position: "relative" }}>
<Icon aria-hidden="true" className={cn(className)} {...props} />
<Icon
aria-hidden="true"
style={{
position: "absolute",
top: 0,
left: 0,
fill: color,
stroke: color,
clipPath: `inset(${100 - (isCompleted ? fillPercentage : fillPercentage - 10)}% 0 0 0)`,
}}
className={cn(className, activeClassName)}
{...props}
/>
</div>
);
}
type GithubStarsParticlesProps = ParticlesEffectProps & {
children: React.ReactElement;
size?: number;
};
function GithubStarsParticles({ children, size = 4, style, ...props }: GithubStarsParticlesProps) {
const { isCompleted } = useGithubStars();
return (
<Particles animate={isCompleted}>
{children}
<ParticlesEffect
style={{
backgroundColor: "currentcolor",
borderRadius: "50%",
width: size,
height: size,
...style,
}}
{...props}
/>
</Particles>
);
}
type GithubStarsLogoProps = React.SVGProps<SVGSVGElement>;
function GithubStarsLogo(props: GithubStarsLogoProps) {
return (
<svg role="img" viewBox="0 0 24 24" fill="currentColor" aria-label="GitHub" {...props}>
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"></path>
</svg>
);
}
export {
GithubStars,
type GithubStarsContextType,
GithubStarsIcon,
type GithubStarsIconProps,
GithubStarsLogo,
type GithubStarsLogoProps,
GithubStarsNumber,
type GithubStarsNumberProps,
GithubStarsParticles,
type GithubStarsParticlesProps,
type GithubStarsProps,
useGithubStars,
};

View File

@@ -0,0 +1,101 @@
"use client";
import type { HTMLMotionProps } from "motion/react";
import { isMotionComponent, motion } from "motion/react";
import * as React from "react";
import { cn } from "@/lib/utils";
type AnyProps = Record<string, unknown>;
type DOMMotionProps<T extends HTMLElement = HTMLElement> = Omit<
HTMLMotionProps<keyof HTMLElementTagNameMap>,
"ref"
> & { ref?: React.Ref<T> };
type WithAsChild<Base extends object>
= | (Base & { asChild: true; children: React.ReactElement })
| (Base & { asChild?: false | undefined });
type SlotProps<T extends HTMLElement = HTMLElement> = {
children?: any;
} & DOMMotionProps<T>;
function mergeRefs<T>(
...refs: (React.Ref<T> | undefined)[]
): React.RefCallback<T> {
return (node) => {
refs.forEach((ref) => {
if (!ref)
return;
if (typeof ref === "function") {
ref(node);
}
else {
(ref as React.RefObject<T | null>).current = node;
}
});
};
}
function mergeProps<T extends HTMLElement>(
childProps: AnyProps,
slotProps: DOMMotionProps<T>,
): AnyProps {
const merged: AnyProps = { ...childProps, ...slotProps };
if (childProps.className || slotProps.className) {
merged.className = cn(
childProps.className as string,
slotProps.className as string,
);
}
if (childProps.style || slotProps.style) {
merged.style = {
...(childProps.style as React.CSSProperties),
...(slotProps.style as React.CSSProperties),
};
}
return merged;
}
function Slot<T extends HTMLElement = HTMLElement>({
children,
ref,
...props
}: SlotProps<T>) {
const isAlreadyMotion
= typeof children.type === "object"
&& children.type !== null
&& isMotionComponent(children.type);
const Base = React.useMemo(
() =>
isAlreadyMotion
? (children.type as React.ElementType)
: motion.create(children.type as React.ElementType),
[isAlreadyMotion, children.type],
);
if (!React.isValidElement(children))
return null;
const { ref: childRef, ...childProps } = children.props as AnyProps;
const mergedProps = mergeProps(childProps, props);
return (
<Base {...mergedProps} ref={mergeRefs(childRef as React.Ref<T>, ref)} />
);
}
export {
type AnyProps,
type DOMMotionProps,
Slot,
type SlotProps,
type WithAsChild,
};

View File

@@ -0,0 +1,36 @@
"use client";
import type { HTMLMotionProps } from "motion/react";
import { motion } from "motion/react";
import * as React from "react";
import type { WithAsChild } from "@/components/animate-ui/primitives/animate/slot";
import { Slot } from "@/components/animate-ui/primitives/animate/slot";
type ButtonProps = WithAsChild<
HTMLMotionProps<"button"> & {
hoverScale?: number;
tapScale?: number;
}
>;
function Button({
hoverScale = 1.05,
tapScale = 0.95,
asChild = false,
...props
}: ButtonProps) {
const Component = asChild ? Slot : motion.button;
return (
<Component
whileTap={{ scale: tapScale }}
whileHover={{ scale: hoverScale }}
{...props}
/>
);
}
export { Button, type ButtonProps };

View File

@@ -0,0 +1,160 @@
"use client";
import type { HTMLMotionProps } from "motion/react";
import { AnimatePresence, motion } from "motion/react";
import * as React from "react";
import type { WithAsChild } from "@/components/animate-ui/primitives/animate/slot";
import type { UseIsInViewOptions } from "@/hooks/use-is-in-view";
import { Slot } from "@/components/animate-ui/primitives/animate/slot";
import { getStrictContext } from "@/lib/get-strict-context";
import {
useIsInView,
} from "@/hooks/use-is-in-view";
type Side = "top" | "bottom" | "left" | "right";
type Align = "start" | "center" | "end";
type ParticlesContextType = {
animate: boolean;
isInView: boolean;
};
const [ParticlesProvider, useParticles]
= getStrictContext<ParticlesContextType>("ParticlesContext");
type ParticlesProps = WithAsChild<
Omit<HTMLMotionProps<"div">, "children"> & {
animate?: boolean;
children: React.ReactNode;
} & UseIsInViewOptions
>;
function Particles({
ref,
animate = true,
asChild = false,
inView = false,
inViewMargin = "0px",
inViewOnce = true,
children,
style,
...props
}: ParticlesProps) {
const { ref: localRef, isInView } = useIsInView(
ref as React.Ref<HTMLDivElement>,
{ inView, inViewOnce, inViewMargin },
);
const Component = asChild ? Slot : motion.div;
return (
<ParticlesProvider value={{ animate, isInView }}>
<Component
ref={localRef}
style={{ position: "relative", ...style }}
{...props}
>
{children}
</Component>
</ParticlesProvider>
);
}
type ParticlesEffectProps = Omit<HTMLMotionProps<"div">, "children"> & {
side?: Side;
align?: Align;
count?: number;
radius?: number;
spread?: number;
duration?: number;
holdDelay?: number;
sideOffset?: number;
alignOffset?: number;
delay?: number;
};
function ParticlesEffect({
side = "top",
align = "center",
count = 6,
radius = 30,
spread = 360,
duration = 0.8,
holdDelay = 0.05,
sideOffset = 0,
alignOffset = 0,
delay = 0,
transition,
style,
...props
}: ParticlesEffectProps) {
const { animate, isInView } = useParticles();
const isVertical = side === "top" || side === "bottom";
const alignPct = align === "start" ? "0%" : align === "end" ? "100%" : "50%";
const top = isVertical
? side === "top"
? `calc(0% - ${sideOffset}px)`
: `calc(100% + ${sideOffset}px)`
: `calc(${alignPct} + ${alignOffset}px)`;
const left = isVertical
? `calc(${alignPct} + ${alignOffset}px)`
: side === "left"
? `calc(0% - ${sideOffset}px)`
: `calc(100% + ${sideOffset}px)`;
const containerStyle: React.CSSProperties = {
position: "absolute",
top,
left,
transform: "translate(-50%, -50%)",
};
const angleStep = (spread * (Math.PI / 180)) / Math.max(1, count - 1);
return (
<AnimatePresence>
{animate
&& isInView
&& Array.from({ length: count }).map((_, i) => {
const angle = i * angleStep;
const x = Math.cos(angle) * radius;
const y = Math.sin(angle) * radius;
return (
<motion.div
key={i}
style={{ ...containerStyle, ...style }}
initial={{ scale: 0, opacity: 0 }}
animate={{
x: `${x}px`,
y: `${y}px`,
scale: [0, 1, 0],
opacity: [0, 1, 0],
}}
transition={{
duration,
delay: delay + i * holdDelay,
ease: "easeOut",
...transition,
}}
{...props}
/>
);
})}
</AnimatePresence>
);
}
export {
Particles,
ParticlesEffect,
type ParticlesEffectProps,
type ParticlesProps,
};

View File

@@ -0,0 +1,338 @@
"use client";
import type { MotionValue, SpringOptions } from "motion/react";
import {
motion,
useMotionValue,
useSpring,
useTransform,
} from "motion/react";
import useMeasure from "react-use-measure";
import * as React from "react";
import type { UseIsInViewOptions } from "@/hooks/use-is-in-view";
import {
useIsInView,
} from "@/hooks/use-is-in-view";
type SlidingNumberRollerProps = {
prevValue: number;
value: number;
place: number;
transition: SpringOptions;
delay?: number;
};
function SlidingNumberRoller({
prevValue,
value,
place,
transition,
delay = 0,
}: SlidingNumberRollerProps) {
const startNumber = Math.floor(prevValue / place) % 10;
const targetNumber = Math.floor(value / place) % 10;
const animatedValue = useSpring(startNumber, transition);
React.useEffect(() => {
const timeoutId = setTimeout(() => {
animatedValue.set(targetNumber);
}, delay);
return () => clearTimeout(timeoutId);
}, [targetNumber, animatedValue, delay]);
const [measureRef, { height }] = useMeasure();
return (
<span
ref={measureRef}
data-slot="sliding-number-roller"
style={{
position: "relative",
display: "inline-block",
width: "1ch",
overflowX: "visible",
overflowY: "clip",
lineHeight: 1,
fontVariantNumeric: "tabular-nums",
}}
>
<span style={{ visibility: "hidden" }}>0</span>
{Array.from({ length: 10 }, (_, i) => (
<SlidingNumberDisplay
key={i}
motionValue={animatedValue}
number={i}
height={height}
transition={transition}
/>
))}
</span>
);
}
type SlidingNumberDisplayProps = {
motionValue: MotionValue<number>;
number: number;
height: number;
transition: SpringOptions;
};
function SlidingNumberDisplay({
motionValue,
number,
height,
transition,
}: SlidingNumberDisplayProps) {
const y = useTransform(motionValue, (latest) => {
if (!height)
return 0;
const currentNumber = latest % 10;
const offset = (10 + number - currentNumber) % 10;
let translateY = offset * height;
if (offset > 5)
translateY -= 10 * height;
return translateY;
});
if (!height) {
return (
<span style={{ visibility: "hidden", position: "absolute" }}>
{number}
</span>
);
}
return (
<motion.span
data-slot="sliding-number-display"
style={{
y,
position: "absolute",
inset: 0,
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
transition={{ ...transition, type: "spring" }}
>
{number}
</motion.span>
);
}
type SlidingNumberProps = Omit<React.ComponentProps<"span">, "children"> & {
number: number;
fromNumber?: number;
onNumberChange?: (number: number) => void;
padStart?: boolean;
decimalSeparator?: string;
decimalPlaces?: number;
thousandSeparator?: string;
transition?: SpringOptions;
delay?: number;
} & UseIsInViewOptions;
function SlidingNumber({
ref,
number,
fromNumber,
onNumberChange,
inView = false,
inViewMargin = "0px",
inViewOnce = true,
padStart = false,
decimalSeparator = ".",
decimalPlaces = 0,
thousandSeparator,
transition = { stiffness: 200, damping: 20, mass: 0.4 },
delay = 0,
...props
}: SlidingNumberProps) {
const { ref: localRef, isInView } = useIsInView(
ref as React.Ref<HTMLElement>,
{
inView,
inViewOnce,
inViewMargin,
},
);
const prevNumberRef = React.useRef<number>(0);
const hasAnimated = fromNumber !== undefined;
const motionVal = useMotionValue(fromNumber ?? 0);
const springVal = useSpring(motionVal, { stiffness: 90, damping: 50 });
React.useEffect(() => {
if (!hasAnimated)
return;
const timeoutId = setTimeout(() => {
if (isInView)
motionVal.set(number);
}, delay);
return () => clearTimeout(timeoutId);
}, [hasAnimated, isInView, number, motionVal, delay]);
const [effectiveNumber, setEffectiveNumber] = React.useState(0);
React.useEffect(() => {
if (hasAnimated) {
const inferredDecimals
= typeof decimalPlaces === "number" && decimalPlaces >= 0
? decimalPlaces
: (() => {
const s = String(number);
const idx = s.indexOf(".");
return idx >= 0 ? s.length - idx - 1 : 0;
})();
const factor = 10 ** inferredDecimals;
const unsubscribe = springVal.on("change", (latest: number) => {
const newValue
= inferredDecimals > 0
? Math.round(latest * factor) / factor
: Math.round(latest);
if (effectiveNumber !== newValue) {
setEffectiveNumber(newValue);
onNumberChange?.(newValue);
}
});
return () => unsubscribe();
}
else {
setEffectiveNumber(!isInView ? 0 : Math.abs(Number(number)));
}
}, [
hasAnimated,
springVal,
isInView,
number,
decimalPlaces,
onNumberChange,
effectiveNumber,
]);
const formatNumber = React.useCallback(
(num: number) =>
decimalPlaces != null ? num.toFixed(decimalPlaces) : num.toString(),
[decimalPlaces],
);
const numberStr = formatNumber(effectiveNumber);
const [newIntStrRaw, newDecStrRaw = ""] = numberStr.split(".");
const finalIntLength = padStart
? Math.max(
Math.floor(Math.abs(number)).toString().length,
newIntStrRaw.length,
)
: newIntStrRaw.length;
const newIntStr = padStart
? newIntStrRaw.padStart(finalIntLength, "0")
: newIntStrRaw;
const prevFormatted = formatNumber(prevNumberRef.current);
const [prevIntStrRaw = "", prevDecStrRaw = ""] = prevFormatted.split(".");
const prevIntStr = padStart
? prevIntStrRaw.padStart(finalIntLength, "0")
: prevIntStrRaw;
const adjustedPrevInt = React.useMemo(() => {
return prevIntStr.length > finalIntLength
? prevIntStr.slice(-finalIntLength)
: prevIntStr.padStart(finalIntLength, "0");
}, [prevIntStr, finalIntLength]);
const adjustedPrevDec = React.useMemo(() => {
if (!newDecStrRaw)
return "";
return prevDecStrRaw.length > newDecStrRaw.length
? prevDecStrRaw.slice(0, newDecStrRaw.length)
: prevDecStrRaw.padEnd(newDecStrRaw.length, "0");
}, [prevDecStrRaw, newDecStrRaw]);
React.useEffect(() => {
if (isInView)
prevNumberRef.current = effectiveNumber;
}, [effectiveNumber, isInView]);
const intPlaces = React.useMemo(
() =>
Array.from({ length: finalIntLength }, (_, i) =>
10 ** (finalIntLength - i - 1)),
[finalIntLength],
);
const decPlaces = React.useMemo(
() =>
newDecStrRaw
? Array.from({ length: newDecStrRaw.length }, (_, i) =>
10 ** (newDecStrRaw.length - i - 1))
: [],
[newDecStrRaw],
);
const newDecValue = newDecStrRaw ? Number.parseInt(newDecStrRaw, 10) : 0;
const prevDecValue = adjustedPrevDec ? Number.parseInt(adjustedPrevDec, 10) : 0;
return (
<span
ref={localRef}
data-slot="sliding-number"
style={{
display: "inline-flex",
alignItems: "center",
}}
{...props}
>
{isInView && Number(number) < 0 && (
<span style={{ marginRight: "0.25rem" }}>-</span>
)}
{intPlaces.map((place, idx) => {
const digitsToRight = intPlaces.length - idx - 1;
const isSeparatorPosition
= typeof thousandSeparator !== "undefined"
&& digitsToRight > 0
&& digitsToRight % 3 === 0;
return (
<React.Fragment key={`int-${place}`}>
<SlidingNumberRoller
prevValue={Number.parseInt(adjustedPrevInt, 10)}
value={Number.parseInt(newIntStr ?? "0", 10)}
place={place}
transition={transition}
/>
{isSeparatorPosition && <span>{thousandSeparator}</span>}
</React.Fragment>
);
})}
{newDecStrRaw && (
<>
<span>{decimalSeparator}</span>
{decPlaces.map(place => (
<SlidingNumberRoller
key={`dec-${place}`}
prevValue={prevDecValue}
value={newDecValue}
place={place}
transition={transition}
delay={delay}
/>
))}
</>
)}
</span>
);
}
export { SlidingNumber, type SlidingNumberProps };

View File

@@ -4,10 +4,10 @@ import Image from "next/image";
import Link from "next/link";
import { navbarLinks } from "@/config/site-config";
import { Button } from "@/components/ui/button";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./ui/tooltip";
import StarOnGithubButton from "./ui/star-on-github-button";
import { GitHubStarsButton } from "./animate-ui/components/buttons/github-stars";
import { Button } from "./animate-ui/components/buttons/button";
import { ThemeToggle } from "./ui/theme-toggle";
import CommandMenu from "./command-menu";
@@ -39,31 +39,18 @@ function Navbar() {
href="/"
className="flex cursor-pointer w-full justify-center sm:justify-start flex-row-reverse items-center gap-2 font-semibold sm:flex-row"
>
<Image
height={18}
unoptimized
width={18}
alt="logo"
src="/ProxmoxVE/logo.png"
className=""
/>
<Image height={18} unoptimized width={18} alt="logo" src="/ProxmoxVE/logo.png" className="" />
<span className="hidden md:block">Proxmox VE Helper-Scripts</span>
</Link>
<div className="flex gap-2">
<CommandMenu />
<StarOnGithubButton />
<GitHubStarsButton username="community-scripts" repo="ProxmoxVE" />
{navbarLinks.map(({ href, event, icon, text, mobileHidden }) => (
<TooltipProvider key={event}>
<Tooltip delayDuration={100}>
<TooltipTrigger
className={mobileHidden ? "hidden lg:block" : ""}
>
<TooltipTrigger className={mobileHidden ? "hidden lg:block" : ""}>
<Button variant="ghost" size="icon" asChild>
<Link
target="_blank"
href={href}
data-umami-event={event}
>
<Link target="_blank" href={href} data-umami-event={event}>
{icon}
<span className="sr-only">{text}</span>
</Link>

View File

@@ -0,0 +1,27 @@
import type { UseInViewOptions } from "motion/react";
import { useInView } from "motion/react";
import * as React from "react";
type UseIsInViewOptions = {
inView?: boolean;
inViewOnce?: boolean;
inViewMargin?: UseInViewOptions["margin"];
};
function useIsInView<T extends HTMLElement = HTMLElement>(
ref: React.Ref<T>,
options: UseIsInViewOptions = {},
) {
const { inView, inViewOnce = false, inViewMargin = "0px" } = options;
const localRef = React.useRef<T>(null);
React.useImperativeHandle(ref, () => localRef.current as T);
const inViewResult = useInView(localRef, {
once: inViewOnce,
margin: inViewMargin,
});
const isInView = !inView || inViewResult;
return { ref: localRef, isInView };
}
export { useIsInView, type UseIsInViewOptions };

View File

@@ -0,0 +1,36 @@
import * as React from "react";
function getStrictContext<T>(
name?: string,
): readonly [
({
value,
children,
}: {
value: T;
children?: React.ReactNode;
}) => React.JSX.Element,
() => T,
] {
const Context = React.createContext<T | undefined>(undefined);
const Provider = ({
value,
children,
}: {
value: T;
children?: React.ReactNode;
}) => <Context.Provider value={value}>{children}</Context.Provider>;
const useSafeContext = () => {
const ctx = React.useContext(Context);
if (ctx === undefined) {
throw new Error(`useContext must be used within ${name ?? "a Provider"}`);
}
return ctx;
};
return [Provider, useSafeContext] as const;
}
export { getStrictContext };

View File

@@ -13,12 +13,18 @@ setting_up_container
network_check
update_os
msg_info "Installing audiobookshelf"
msg_info "Installing Dependencies"
$STD apt-get install -y ffmpeg
msg_ok "Installed Dependencies"
msg_info "Setup audiobookshelf"
curl -fsSL https://advplyr.github.io/audiobookshelf-ppa/KEY.gpg >/etc/apt/trusted.gpg.d/audiobookshelf-ppa.asc
echo "deb [signed-by=/etc/apt/trusted.gpg.d/audiobookshelf-ppa.asc] https://advplyr.github.io/audiobookshelf-ppa ./" >/etc/apt/sources.list.d/audiobookshelf.list
$STD apt-get update
$STD apt install audiobookshelf
msg_ok "Installed audiobookshelf"
$STD apt update
$STD apt install -y audiobookshelf
echo "FFMPEG_PATH=/usr/bin/ffmpeg" >>/etc/default/audiobookshelf
echo "FFPROBE_PATH=/usr/bin/ffprobe" >>/etc/default/audiobookshelf
msg_ok "Setup audiobookshelf"
motd_ssh
customize

View File

@@ -46,7 +46,7 @@ $STD npm run build --configuration=production
msg_ok "Built Frontend"
msg_info "Creating Environment"
mkdir -p /opt/booklore_storage{/data,/books}
mkdir -p /opt/booklore_storage{/data,/books,/bookdrop}
cat <<EOF >/opt/booklore_storage/.env
DATABASE_URL=jdbc:mariadb://localhost:3306/$DB_NAME
DATABASE_USERNAME=$DB_USER
@@ -55,6 +55,7 @@ BOOKLORE_PORT=6060
BOOKLORE_DATA_PATH=/opt/booklore_storage/data
BOOKLORE_BOOKS_PATH=/opt/booklore_storage/books
BOOKLORE_BOOKDROP_PATH=/opt/booklore_storage/bookdrop
EOF
msg_ok "Created Environment"

View File

@@ -285,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.1" "$SRC_DIR"
fetch_and_deploy_gh_release "immich" "immich-app/immich" "tarball" "v1.141.1" "$SRC_DIR"
msg_info "Installing ${APPLICATION} (more patience please)"

View File

@@ -158,7 +158,7 @@ Wants=network.target karakeep-browser.service meilisearch.service
After=network.target karakeep-browser.service meilisearch.service
[Service]
ExecStart=/usr/bin/node dist/index.mjs
ExecStart=/usr/bin/node dist/index.js
WorkingDirectory=/opt/karakeep/apps/workers
EnvironmentFile=/etc/karakeep/karakeep.env
Restart=always

View File

@@ -89,19 +89,36 @@ customize
msg_info "Retrieving Default Login (Patience)"
PASSWORD_FOUND=0
for i in {1..60}; do
PASSWORD_LINE=$(docker logs "$CONTAINER_ID" 2>&1 | awk '/Creating a new user:/ { print; exit }')
if [[ -n "$PASSWORD_LINE" ]]; then
PASSWORD=$(echo "$PASSWORD_LINE" | awk -F 'password: ' '{print $2}')
echo -e "username: admin@example.org\npassword: $PASSWORD" >/opt/.npm_pwd
PASSWORD_LINE=$(
{ awk '/Creating a new user:/{print; exit}' < <(docker logs "$CONTAINER_ID" 2>&1); } || true
)
if [[ -n "${PASSWORD_LINE:-}" ]]; then
PASSWORD="${PASSWORD_LINE#*password: }"
printf 'username: admin@example.org\npassword: %s\n' "$PASSWORD" >/opt/.npm_pwd
msg_ok "Saved default login to /opt/.npm_pwd"
PASSWORD_FOUND=1
break
fi
sleep 2
done
if [[ $PASSWORD_FOUND -eq 0 ]]; then
PASSWORD_LINE=$(
timeout 30s bash -c '
docker logs -f --since=0s --tail=0 "$1" 2>&1 | awk "/Creating a new user:/{print; exit}"
' _ "$CONTAINER_ID" || true
)
if [[ -n "${PASSWORD_LINE:-}" ]]; then
PASSWORD="${PASSWORD_LINE#*password: }"
printf 'username: admin@example.org\npassword: %s\n' "$PASSWORD" >/opt/.npm_pwd
msg_ok "Saved default login to /opt/.npm_pwd (live)"
PASSWORD_FOUND=1
fi
fi
if [[ $PASSWORD_FOUND -eq 0 ]]; then
msg_error "Could not retrieve default login after 60 seconds."
msg_error "Could not retrieve default login after 120s."
echo -e "\nYou can manually check the container logs with:\n docker logs $CONTAINER_ID | grep 'Creating a new user:'\n"
fi

View File

@@ -30,11 +30,12 @@ fi
mkdir -p /etc/pulse
fetch_and_deploy_gh_release "pulse" "rcourtman/Pulse" "prebuild" "latest" "/opt/pulse" "*-linux-amd64.tar.gz"
ln -sf /opt/pulse/bin/pulse /usr/local/bin/pulse
chown -R pulse:pulse /etc/pulse /opt/pulse
msg_ok "Installed Pulse"
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/pulse-backend.service
cat <<EOF >/etc/systemd/system/pulse.service
[Unit]
Description=Pulse Monitoring Server
After=network.target
@@ -55,7 +56,7 @@ Environment="PULSE_DATA_DIR=/etc/pulse"
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now pulse-backend
systemctl enable -q --now pulse
msg_ok "Created Service"
motd_ssh

View File

@@ -21,7 +21,7 @@ fetch_and_deploy_gh_release "recyclarr" "recyclarr/recyclarr" "prebuild" "latest
msg_info "Configuring Recyclarr"
mkdir -p /root/.config/recyclarr
recyclarr config create
$STD recyclarr config create
msg_ok "Configured Recyclarr"
motd_ssh

View File

@@ -18,18 +18,6 @@ fetch_and_deploy_gh_release "rustdesk-hbbs" "rustdesk/rustdesk-server" "binary"
fetch_and_deploy_gh_release "rustdesk-utils" "rustdesk/rustdesk-server" "binary" "latest" "/opt/rustdesk" "rustdesk-server-utils*amd64.deb"
fetch_and_deploy_gh_release "rustdesk-api" "lejianwen/rustdesk-api" "binary" "latest" "/opt/rustdesk" "rustdesk-api-server*amd64.deb"
msg_info "Configuring RustDesk Server"
ADMINPASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
cd /var/lib/rustdesk-api
$STD rustdesk-api reset-admin-pwd $ADMINPASS
{
echo "RustDesk WebUI"
echo ""
echo "Username: admin"
echo "Password: $ADMINPASS"
} >>~/rustdesk.creds
msg_ok "Configured RustDesk Server"
motd_ssh
customize

View File

@@ -36,7 +36,7 @@ msg_info "Creating Python virtual environment"
sudo -H -u searxng bash -c '
python3 -m venv /usr/local/searxng/searx-pyenv &&
. /usr/local/searxng/searx-pyenv/bin/activate &&
pip install -U pip setuptools wheel pyyaml &&
pip install -U pip setuptools wheel pyyaml lxml &&
pip install --use-pep517 --no-build-isolation -e /usr/local/searxng/searxng-src
'
msg_ok "Python environment ready"

View File

@@ -19,8 +19,8 @@ $STD apt-get install -y \
yq
msg_ok "Installed Dependencies"
NODE_VERSION="20" setup_nodejs
fetch_and_deploy_gh_release "tududi" "chrisvel/tududi" "tarball" "v0.80" "/opt/tududi"
NODE_VERSION="22" setup_nodejs
fetch_and_deploy_gh_release "tududi" "chrisvel/tududi" "tarball" "latest" "/opt/tududi"
msg_info "Configuring Tududi"
cd /opt/tududi
@@ -37,15 +37,16 @@ DB_LOCATION="/opt/tududi-db"
UPLOAD_DIR="/opt/tududi-uploads"
mkdir -p {"$DB_LOCATION","$UPLOAD_DIR"}
SECRET="$(openssl rand -hex 64)"
sed -e 's/^GOOGLE/# &/' \
-e '/TUDUDI_SESSION/s/^# //' \
-e '/NODE_ENV/s/^# //' \
-e "s/your_session_secret_here/$SECRET/" \
-e 's/development/production/' \
-e "\$a\DB_FILE=$DB_LOCATION/production.sqlite3" \
-e "\$a\TUDUDI_UPLOAD_PATH=$UPLOAD_DIR" \
/opt/tududi/backend/.env.example >/opt/tududi/backend/.env
export DB_FILE="$DB_LOCATION/production.sqlite3"
cat <<EOF >/opt/tududi/backend/.env
TUDUDI_SESSION_SECRET=${SECRET}
TUDUDI_ALLOWED_ORIGINS=<your tududi IP or FQDN>
NODE_ENV=production
DB_FILE=${DB_LOCATION}/production.sqlite3
TUDUDI_UPLOAD_PATH=${UPLOAD_DIR}
DISABLE_TELEGRAM=true
DIABLE_SCHEDULER=false
EOF
export DB_FILE="${DB_LOCATION}/production.sqlite3"
$STD npm run db:init
msg_ok "Created env and database"
@@ -57,9 +58,9 @@ After=network.target
[Service]
Type=simple
WorkingDirectory=/opt/tududi
WorkingDirectory=/opt/tududi/backend
EnvironmentFile=/opt/tududi/backend/.env
ExecStart=/usr/bin/npm run start
ExecStart=/usr/bin/bash /opt/tududi/backend/cmd/start.sh
[Install]
WantedBy=multi-user.target

View File

@@ -13,6 +13,10 @@ setting_up_container
network_check
update_os
msg_info "Installing Dependencies"
$STD apt-get install -y git
msg_ok "Installed Dependencies"
msg_info "Installing WireGuard"
$STD apt-get install -y wireguard wireguard-tools net-tools iptables
DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confnew" install -y iptables-persistent &>/dev/null
@@ -21,7 +25,7 @@ msg_ok "Installed WireGuard"
read -r -p "${TAB3}Would you like to add WGDashboard? <y/N> " prompt
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
fetch_and_deploy_gh_release "wgdashboard" "donaldzou/WGDashboard" "tarball" "latest" "/etc/wgdashboard"
git clone -q https://github.com/donaldzou/WGDashboard.git /etc/wgdashboard
msg_info "Installing WGDashboard"
cd /etc/wgdashboard/src

View File

@@ -26,7 +26,7 @@ elif command -v wget >/dev/null 2>&1; then
fi
# This function enables error handling in the script by setting options and defining a trap for the ERR signal.
catch_errors() {
set -Eeuo pipefail
set -Eeo pipefail
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
}
@@ -200,41 +200,32 @@ ssh_check() {
base_settings() {
# Default Settings
CT_TYPE="1"
DISK_SIZE="4"
CORE_COUNT="1"
RAM_SIZE="1024"
VERBOSE="${1:-no}"
PW=""
CT_ID=$NEXTID
HN=$NSAPP
BRG="vmbr0"
NET="dhcp"
IPV6_METHOD="none"
IPV6_STATIC=""
GATE=""
APT_CACHER=""
APT_CACHER_IP=""
MTU=""
SD=""
NS=""
MAC=""
VLAN=""
SSH="no"
SSH_AUTHORIZED_KEY=""
TAGS="community-script;"
ENABLE_FUSE="${1:-no}"
ENABLE_TUN="${1:-no}"
# Override default settings with variables from ct script
CT_TYPE=${var_unprivileged:-$CT_TYPE}
DISK_SIZE=${var_disk:-$DISK_SIZE}
CORE_COUNT=${var_cpu:-$CORE_COUNT}
RAM_SIZE=${var_ram:-$RAM_SIZE}
VERB=${var_verbose:-$VERBOSE}
TAGS="${TAGS}${var_tags:-}"
ENABLE_FUSE="${var_fuse:-$ENABLE_FUSE}"
ENABLE_TUN="${var_tun:-$ENABLE_TUN}"
CT_TYPE=${var_unprivileged:-"1"}
DISK_SIZE=${var_disk:-"4"}
CORE_COUNT=${var_cpu:-"1"}
RAM_SIZE=${var_ram:-"1024"}
VERBOSE=${var_verbose:-"${1:-no}"}
PW=${var_pw:-""}
CT_ID=${var_ctid:-$NEXTID}
HN=${var_hostname:-$NSAPP}
BRG=${var_brg:-"vmbr0"}
NET=${var_net:-"dhcp"}
IPV6_METHOD=${var_ipv6_method:-"none"}
IPV6_STATIC=${var_ipv6_static:-""}
GATE=${var_gateway:-""}
APT_CACHER=${var_apt_cacher:-""}
APT_CACHER_IP=${var_apt_cacher_ip:-""}
MTU=${var_mtu:-""}
SD=${var_storage:-""}
NS=${var_ns:-""}
MAC=${var_mac:-""}
VLAN=${var_vlan:-""}
SSH=${var_ssh:-"no"}
SSH_AUTHORIZED_KEY=${var_ssh_authorized_key:-""}
UDHCPC_FIX=${var_udhcpc_fix:-""}
TAGS="community-script;${var_tags:-}"
ENABLE_FUSE=${var_fuse:-"${1:-no}"}
ENABLE_TUN=${var_tun:-"${1:-no}"}
# Since these 2 are only defined outside of default_settings function, we add a temporary fallback. TODO: To align everything, we should add these as constant variables (e.g. OSTYPE and OSVERSION), but that would currently require updating the default_settings function for all existing scripts
if [ -z "$var_os" ]; then
@@ -244,6 +235,7 @@ base_settings() {
var_version="12"
fi
}
write_config() {
mkdir -p /opt/community-scripts
# This function writes the configuration to a file.
@@ -354,7 +346,7 @@ echo_default() {
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}"
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}${CORE_COUNT}${CL}"
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}"
if [ "$VERB" == "yes" ]; then
if [ "$VERBOSE" == "yes" ]; then
echo -e "${SEARCH}${BOLD}${DGN}Verbose Mode: ${BGN}Enabled${CL}"
fi
echo -e "${CREATING}${BOLD}${BL}Creating a ${APP} LXC using the above default settings${CL}"