Compare commits

...

17 Commits

Author SHA1 Message Date
github-actions[bot]
dcc88e1854 chore: update github-versions.json 2026-02-04 18:17:33 +00:00
community-scripts-pr-app[bot]
3046eb000d Update CHANGELOG.md (#11542)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-04 15:20:23 +00:00
Chris
472439ce6e [ADDON] Immich Public Proxy addon (#11518)
* [ADDON] Immich Public Proxy

* prompt to add Immich IP or domain

* fix path

* fix immich port

* allow localhost

* add JSON

* Update tools/addon/immich-public-proxy.sh

Co-authored-by: Tobias <96661824+CrazyWolf13@users.noreply.github.com>

* NodeJS things

---------

Co-authored-by: Tobias <96661824+CrazyWolf13@users.noreply.github.com>
2026-02-04 16:19:53 +01:00
community-scripts-pr-app[bot]
43044c60f0 Update CHANGELOG.md (#11540)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-04 13:48:50 +00:00
Chris
36bf5cb57e Immich: pin version to 2.5.3 (#11515)
* Immich: pin version to 2.5.3

[FIX] Immich: only show OpenVINO menu if `/dev/dri` detected

* Grab pnpm version from release package.json
2026-02-04 14:48:18 +01:00
CanbiZ (MickLesk)
338c054112 action: prevent duplicate History section in changelog-archive workflow 2026-02-04 14:04:34 +01:00
community-scripts-pr-app[bot]
17ac4f5ae7 Archive old changelog entries (#11537)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-04 13:00:42 +00:00
CanbiZ (MickLesk)
5210d1bb71 fix sorting in changelog-archive.yml 2026-02-04 13:59:57 +01:00
CanbiZ (MickLesk)
c599fd7551 fix github - changelog double history 2026-02-04 13:58:19 +01:00
community-scripts-pr-app[bot]
0644bef572 Update CHANGELOG.md (#11536)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-04 12:28:08 +00:00
ls-root
27ab446926 fix(frontend): implement weighted search scoring for command menu (#11534)
* fix(frontend): implement weighted search scoring for command menu

The previous cmdk search was filtered correctly but then sorted by category
order rather than match strength. This caused "Dokpoly" to appear above
"Traefik", if you searched for Traefik, simply because its category (Containers) comes before Traefik's
category alphabetically.

- Flatten search results into a single "Search Results" group.
- Implement scoring to prioritize name matches over descriptions.
- Revert to category grouping only when the search query is empty.

* perf(frontend): optimize search logic

Limiting the results to 20 helps a lot.
2026-02-04 13:27:42 +01:00
community-scripts-pr-app[bot]
81abf70851 chore: update github-versions.json (#11535)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-04 12:12:03 +00:00
community-scripts-pr-app[bot]
c570cbe0be Update CHANGELOG.md (#11531)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-04 10:16:37 +00:00
CanbiZ (MickLesk)
fa86809863 core: create vm-core.func from dev (#11528) 2026-02-04 11:16:06 +01:00
community-scripts-pr-app[bot]
c6dfa052ee Update .app files (#11529)
Co-authored-by: GitHub Actions <github-actions[bot]@users.noreply.github.com>
2026-02-04 11:01:30 +01:00
community-scripts-pr-app[bot]
2e9624fdfb Update CHANGELOG.md (#11530)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-04 10:00:46 +00:00
push-app-to-main[bot]
e99702977c Wishlist (#11527)
* Add wishlist (ct)

* Update wishlist.sh

* Update wishlist.json

* Update wishlist.json

---------

Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com>
Co-authored-by: Tobias <96661824+CrazyWolf13@users.noreply.github.com>
2026-02-04 11:00:15 +01:00
15 changed files with 1672 additions and 696 deletions

310
.github/changelogs/2026/01.md generated vendored
View File

@@ -1,14 +1,156 @@
## 2026-01-27
## 2026-01-31
### 🆕 New Scripts
- shelfmark ([#11371](https://github.com/community-scripts/ProxmoxVE/pull/11371))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- fix: yubal: add git [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11394](https://github.com/community-scripts/ProxmoxVE/pull/11394))
## 2026-01-30
### 🆕 New Scripts
- languagetool ([#11370](https://github.com/community-scripts/ProxmoxVE/pull/11370))
- Ampache ([#11369](https://github.com/community-scripts/ProxmoxVE/pull/11369))
### 🚀 Updated Scripts
- #### 🔧 Refactor
- Refactor: remove redundant PHP_MODULE entries in several scripts [@MickLesk](https://github.com/MickLesk) ([#11362](https://github.com/community-scripts/ProxmoxVE/pull/11362))
- Refactor: Koillection [@MickLesk](https://github.com/MickLesk) ([#11361](https://github.com/community-scripts/ProxmoxVE/pull/11361))
### 💾 Core
- #### 🐞 Bug Fixes
- core: meilisearch - add data migration for version upgrades [@MickLesk](https://github.com/MickLesk) ([#11356](https://github.com/community-scripts/ProxmoxVE/pull/11356))
- #### ✨ New Features
- [tools] Add `fetch_and_deploy_from_url()` [@tremor021](https://github.com/tremor021) ([#11376](https://github.com/community-scripts/ProxmoxVE/pull/11376))
- core: php - improve module handling and prevent installation failures [@MickLesk](https://github.com/MickLesk) ([#11358](https://github.com/community-scripts/ProxmoxVE/pull/11358))
## 2026-01-29
### 🆕 New Scripts
- Alpine-Valkey [@MickLesk](https://github.com/MickLesk) ([#11320](https://github.com/community-scripts/ProxmoxVE/pull/11320))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Immich: Pin version to 2.5.2 [@vhsdream](https://github.com/vhsdream) ([#11335](https://github.com/community-scripts/ProxmoxVE/pull/11335))
- Kollection: Update to php 8.5 [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#11315](https://github.com/community-scripts/ProxmoxVE/pull/11315))
- Notifiarr: change installation check from apt to systemd service [@MickLesk](https://github.com/MickLesk) ([#11319](https://github.com/community-scripts/ProxmoxVE/pull/11319))
- #### ✨ New Features
- [FEAT] Immich: Enable Maintenance Mode before update [@vhsdream](https://github.com/vhsdream) ([#11342](https://github.com/community-scripts/ProxmoxVE/pull/11342))
- jellyfin: add logrotate instead of reducing log level [@MickLesk](https://github.com/MickLesk) ([#11326](https://github.com/community-scripts/ProxmoxVE/pull/11326))
- core: Add config file handling options | Fix Vikunja update with interactive overwrite [@MickLesk](https://github.com/MickLesk) ([#11317](https://github.com/community-scripts/ProxmoxVE/pull/11317))
- Immich: v2.5.0 [@vhsdream](https://github.com/vhsdream) ([#11240](https://github.com/community-scripts/ProxmoxVE/pull/11240))
- #### 💥 Breaking Changes
- fix: vikunja v1 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11308](https://github.com/community-scripts/ProxmoxVE/pull/11308))
- #### 🔧 Refactor
- Refactor: Byparr [@vhsdream](https://github.com/vhsdream) ([#11338](https://github.com/community-scripts/ProxmoxVE/pull/11338))
- cloudflare: Remove deprecated DNS-over-HTTPS proxy option [@MickLesk](https://github.com/MickLesk) ([#11068](https://github.com/community-scripts/ProxmoxVE/pull/11068))
### 💾 Core
- #### 🐞 Bug Fixes
- build.func: Replace storage variable with searchdomain variable [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#11322](https://github.com/community-scripts/ProxmoxVE/pull/11322))
### 📂 Github
- Add workflow to lock closed issues [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#11316](https://github.com/community-scripts/ProxmoxVE/pull/11316))
## 2026-01-28
### 🆕 New Scripts
- nodecast-tv ([#11287](https://github.com/community-scripts/ProxmoxVE/pull/11287))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Ubuntu 25.04 VM - Change default start from yes to no [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#11292](https://github.com/community-scripts/ProxmoxVE/pull/11292))
- #### ✨ New Features
- various scripts: use setup_meilisearch function [@MickLesk](https://github.com/MickLesk) ([#11259](https://github.com/community-scripts/ProxmoxVE/pull/11259))
- #### 🔧 Refactor
- Refactor: NPMPlus / Default Login [@MickLesk](https://github.com/MickLesk) ([#11262](https://github.com/community-scripts/ProxmoxVE/pull/11262))
### 💾 Core
- #### 🐞 Bug Fixes
- core: sed patch for ram [@lavacano](https://github.com/lavacano) ([#11285](https://github.com/community-scripts/ProxmoxVE/pull/11285))
- Fix installer loop caused by invalid whiptail menu separator [@Mesteriis](https://github.com/Mesteriis) ([#11237](https://github.com/community-scripts/ProxmoxVE/pull/11237))
- core: fix Debian 13 LXC template root ownership bug [@MickLesk](https://github.com/MickLesk) ([#11277](https://github.com/community-scripts/ProxmoxVE/pull/11277))
- tools.func: prevent systemd-tmpfiles failure in unprivileged LXC during deb install [@MickLesk](https://github.com/MickLesk) ([#11271](https://github.com/community-scripts/ProxmoxVE/pull/11271))
- tools.func: fix php "wait_for" hint [@MickLesk](https://github.com/MickLesk) ([#11254](https://github.com/community-scripts/ProxmoxVE/pull/11254))
- #### ✨ New Features
- core: update dynamic values in LXC profile on update_motd_ip [@MickLesk](https://github.com/MickLesk) ([#11268](https://github.com/community-scripts/ProxmoxVE/pull/11268))
- tools.func: add new function - setup_meilisearch [@MickLesk](https://github.com/MickLesk) ([#11258](https://github.com/community-scripts/ProxmoxVE/pull/11258))
### 📂 Github
- github: add GitHub-based versions.json updater [@MickLesk](https://github.com/MickLesk) ([#10021](https://github.com/community-scripts/ProxmoxVE/pull/10021))
### 🌐 Website
- #### ✨ New Features
- Frontend: use github-versions.json for version display [@MickLesk](https://github.com/MickLesk) ([#11281](https://github.com/community-scripts/ProxmoxVE/pull/11281))
- #### 📝 Script Information
- fix: homarr: conf location [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11253](https://github.com/community-scripts/ProxmoxVE/pull/11253))
## 2026-01-27
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- [FIX] Jotty: backup and restore custom config [@vhsdream](https://github.com/vhsdream) ([#11212](https://github.com/community-scripts/ProxmoxVE/pull/11212))
- Immich: update libraw [@vhsdream](https://github.com/vhsdream) ([#11233](https://github.com/community-scripts/ProxmoxVE/pull/11233))
- #### ✨ New Features
- grist: enable optional enterprise features toggle [@MickLesk](https://github.com/MickLesk) ([#11239](https://github.com/community-scripts/ProxmoxVE/pull/11239))
- #### 🔧 Refactor
- Termix: use nginx.conf from upstream repo [@MickLesk](https://github.com/MickLesk) ([#11228](https://github.com/community-scripts/ProxmoxVE/pull/11228))
### 💾 Core
- #### ✨ New Features
- feat: add NVIDIA driver install prompt for GPU-enabled containers [@devdecrux](https://github.com/devdecrux) ([#11184](https://github.com/community-scripts/ProxmoxVE/pull/11184))
### 📚 Documentation
- doc setup_deb822_repo arg order [@chrnie](https://github.com/chrnie) ([#11215](https://github.com/community-scripts/ProxmoxVE/pull/11215))
- changelog: archive old entries to year/month files [@MickLesk](https://github.com/MickLesk) ([#11225](https://github.com/community-scripts/ProxmoxVE/pull/11225))
## 2026-01-26
@@ -100,7 +242,7 @@
### 🆕 New Scripts
- Tracearr ([#11079](https://github.com/community-scripts/ProxmoxVE/pull/11079))
- Dawarich ([#11075](https://github.com/community-scripts/ProxmoxVE/pull/11075))
- Dawarich ([#11075](https://github.com/community-scripts/ProxmoxVE/pull/11075))
### 🚀 Updated Scripts
@@ -250,7 +392,7 @@
### 🆕 New Scripts
- Termix ([#10887](https://github.com/community-scripts/ProxmoxVE/pull/10887))
- ThingsBoard ([#10904](https://github.com/community-scripts/ProxmoxVE/pull/10904))
- ThingsBoard ([#10904](https://github.com/community-scripts/ProxmoxVE/pull/10904))
### 🚀 Updated Scripts
@@ -319,7 +461,7 @@
### 🆕 New Scripts
- Flatnotes ([#10857](https://github.com/community-scripts/ProxmoxVE/pull/10857))
- Unifi OS Server ([#10856](https://github.com/community-scripts/ProxmoxVE/pull/10856))
- Unifi OS Server ([#10856](https://github.com/community-scripts/ProxmoxVE/pull/10856))
### 🚀 Updated Scripts
@@ -385,7 +527,7 @@
### 🆕 New Scripts
- Investbrain ([#10774](https://github.com/community-scripts/ProxmoxVE/pull/10774))
- Fladder ([#10768](https://github.com/community-scripts/ProxmoxVE/pull/10768))
- Fladder ([#10768](https://github.com/community-scripts/ProxmoxVE/pull/10768))
### 🚀 Updated Scripts
@@ -574,7 +716,7 @@
### 📚 Documentation
- [gh] New Script template update [@tremor021](https://github.com/tremor021) ([#10607](https://github.com/community-scripts/ProxmoxVE/pull/10607))
- chore: bump copyright to 2026 - happy new year [@CrazyWolf13](https://github.com/CrazyWolf13) ([#10585](https://github.com/community-scripts/ProxmoxVE/pull/10585))
- chore: bump copyright to 2026 - happy new year [@CrazyWolf13](https://github.com/CrazyWolf13) ([#10585](https://github.com/community-scripts/ProxmoxVE/pull/10585))
### 📂 Github
@@ -655,7 +797,7 @@
### ❔ Uncategorized
- Wireguard: Update WGDashboard notes URL to the new link [@tremor021](https://github.com/tremor021) ([#10496](https://github.com/community-scripts/ProxmoxVE/pull/10496))
- InvoiceNinja: Update database credentias information [@tremor021](https://github.com/tremor021) ([#10497](https://github.com/community-scripts/ProxmoxVE/pull/10497))
- InvoiceNinja: Update database credentias information [@tremor021](https://github.com/tremor021) ([#10497](https://github.com/community-scripts/ProxmoxVE/pull/10497))
## 2026-01-02
@@ -684,157 +826,3 @@
- #### 🐞 Bug Fixes
- Fix MariaDB runtime directory persistence on container reboot [@Copilot](https://github.com/Copilot) ([#10468](https://github.com/community-scripts/ProxmoxVE/pull/10468))
## 2026-01-31
### 🆕 New Scripts
- shelfmark ([#11371](https://github.com/community-scripts/ProxmoxVE/pull/11371))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- fix: yubal: add git [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11394](https://github.com/community-scripts/ProxmoxVE/pull/11394))
## 2026-01-30
### 🆕 New Scripts
- languagetool ([#11370](https://github.com/community-scripts/ProxmoxVE/pull/11370))
- Ampache ([#11369](https://github.com/community-scripts/ProxmoxVE/pull/11369))
### 🚀 Updated Scripts
- #### 🔧 Refactor
- Refactor: remove redundant PHP_MODULE entries in several scripts [@MickLesk](https://github.com/MickLesk) ([#11362](https://github.com/community-scripts/ProxmoxVE/pull/11362))
- Refactor: Koillection [@MickLesk](https://github.com/MickLesk) ([#11361](https://github.com/community-scripts/ProxmoxVE/pull/11361))
### 💾 Core
- #### 🐞 Bug Fixes
- core: meilisearch - add data migration for version upgrades [@MickLesk](https://github.com/MickLesk) ([#11356](https://github.com/community-scripts/ProxmoxVE/pull/11356))
- #### ✨ New Features
- [tools] Add `fetch_and_deploy_from_url()` [@tremor021](https://github.com/tremor021) ([#11376](https://github.com/community-scripts/ProxmoxVE/pull/11376))
- core: php - improve module handling and prevent installation failures [@MickLesk](https://github.com/MickLesk) ([#11358](https://github.com/community-scripts/ProxmoxVE/pull/11358))
## 2026-01-29
### 🆕 New Scripts
- Alpine-Valkey [@MickLesk](https://github.com/MickLesk) ([#11320](https://github.com/community-scripts/ProxmoxVE/pull/11320))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Immich: Pin version to 2.5.2 [@vhsdream](https://github.com/vhsdream) ([#11335](https://github.com/community-scripts/ProxmoxVE/pull/11335))
- Kollection: Update to php 8.5 [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#11315](https://github.com/community-scripts/ProxmoxVE/pull/11315))
- Notifiarr: change installation check from apt to systemd service [@MickLesk](https://github.com/MickLesk) ([#11319](https://github.com/community-scripts/ProxmoxVE/pull/11319))
- #### ✨ New Features
- [FEAT] Immich: Enable Maintenance Mode before update [@vhsdream](https://github.com/vhsdream) ([#11342](https://github.com/community-scripts/ProxmoxVE/pull/11342))
- jellyfin: add logrotate instead of reducing log level [@MickLesk](https://github.com/MickLesk) ([#11326](https://github.com/community-scripts/ProxmoxVE/pull/11326))
- core: Add config file handling options | Fix Vikunja update with interactive overwrite [@MickLesk](https://github.com/MickLesk) ([#11317](https://github.com/community-scripts/ProxmoxVE/pull/11317))
- Immich: v2.5.0 [@vhsdream](https://github.com/vhsdream) ([#11240](https://github.com/community-scripts/ProxmoxVE/pull/11240))
- #### 💥 Breaking Changes
- fix: vikunja v1 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11308](https://github.com/community-scripts/ProxmoxVE/pull/11308))
- #### 🔧 Refactor
- Refactor: Byparr [@vhsdream](https://github.com/vhsdream) ([#11338](https://github.com/community-scripts/ProxmoxVE/pull/11338))
- cloudflare: Remove deprecated DNS-over-HTTPS proxy option [@MickLesk](https://github.com/MickLesk) ([#11068](https://github.com/community-scripts/ProxmoxVE/pull/11068))
### 💾 Core
- #### 🐞 Bug Fixes
- build.func: Replace storage variable with searchdomain variable [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#11322](https://github.com/community-scripts/ProxmoxVE/pull/11322))
### 📂 Github
- Add workflow to lock closed issues [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#11316](https://github.com/community-scripts/ProxmoxVE/pull/11316))
## 2026-01-28
### 🆕 New Scripts
- nodecast-tv ([#11287](https://github.com/community-scripts/ProxmoxVE/pull/11287))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Ubuntu 25.04 VM - Change default start from yes to no [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#11292](https://github.com/community-scripts/ProxmoxVE/pull/11292))
- #### ✨ New Features
- various scripts: use setup_meilisearch function [@MickLesk](https://github.com/MickLesk) ([#11259](https://github.com/community-scripts/ProxmoxVE/pull/11259))
- #### 🔧 Refactor
- Refactor: NPMPlus / Default Login [@MickLesk](https://github.com/MickLesk) ([#11262](https://github.com/community-scripts/ProxmoxVE/pull/11262))
### 💾 Core
- #### 🐞 Bug Fixes
- core: sed patch for ram [@lavacano](https://github.com/lavacano) ([#11285](https://github.com/community-scripts/ProxmoxVE/pull/11285))
- Fix installer loop caused by invalid whiptail menu separator [@Mesteriis](https://github.com/Mesteriis) ([#11237](https://github.com/community-scripts/ProxmoxVE/pull/11237))
- core: fix Debian 13 LXC template root ownership bug [@MickLesk](https://github.com/MickLesk) ([#11277](https://github.com/community-scripts/ProxmoxVE/pull/11277))
- tools.func: prevent systemd-tmpfiles failure in unprivileged LXC during deb install [@MickLesk](https://github.com/MickLesk) ([#11271](https://github.com/community-scripts/ProxmoxVE/pull/11271))
- tools.func: fix php "wait_for" hint [@MickLesk](https://github.com/MickLesk) ([#11254](https://github.com/community-scripts/ProxmoxVE/pull/11254))
- #### ✨ New Features
- core: update dynamic values in LXC profile on update_motd_ip [@MickLesk](https://github.com/MickLesk) ([#11268](https://github.com/community-scripts/ProxmoxVE/pull/11268))
- tools.func: add new function - setup_meilisearch [@MickLesk](https://github.com/MickLesk) ([#11258](https://github.com/community-scripts/ProxmoxVE/pull/11258))
### 📂 Github
- github: add GitHub-based versions.json updater [@MickLesk](https://github.com/MickLesk) ([#10021](https://github.com/community-scripts/ProxmoxVE/pull/10021))
### 🌐 Website
- #### ✨ New Features
- Frontend: use github-versions.json for version display [@MickLesk](https://github.com/MickLesk) ([#11281](https://github.com/community-scripts/ProxmoxVE/pull/11281))
- #### 📝 Script Information
- fix: homarr: conf location [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11253](https://github.com/community-scripts/ProxmoxVE/pull/11253))
## 2026-01-27
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Immich: update libraw [@vhsdream](https://github.com/vhsdream) ([#11233](https://github.com/community-scripts/ProxmoxVE/pull/11233))
- #### ✨ New Features
- grist: enable optional enterprise features toggle [@MickLesk](https://github.com/MickLesk) ([#11239](https://github.com/community-scripts/ProxmoxVE/pull/11239))
- #### 🔧 Refactor
- Termix: use nginx.conf from upstream repo [@MickLesk](https://github.com/MickLesk) ([#11228](https://github.com/community-scripts/ProxmoxVE/pull/11228))
### 💾 Core
- #### ✨ New Features
- feat: add NVIDIA driver install prompt for GPU-enabled containers [@devdecrux](https://github.com/devdecrux) ([#11184](https://github.com/community-scripts/ProxmoxVE/pull/11184))
### 📚 Documentation
- doc setup_deb822_repo arg order [@chrnie](https://github.com/chrnie) ([#11215](https://github.com/community-scripts/ProxmoxVE/pull/11215))
- changelog: archive old entries to year/month files [@MickLesk](https://github.com/MickLesk) ([#11225](https://github.com/community-scripts/ProxmoxVE/pull/11225))

121
.github/changelogs/2026/02.md generated vendored Normal file
View File

@@ -0,0 +1,121 @@
## 2026-02-04
### 🆕 New Scripts
- Wishlist ([#11527](https://github.com/community-scripts/ProxmoxVE/pull/11527))
- WriteFreely ([#11524](https://github.com/community-scripts/ProxmoxVE/pull/11524))
### 💾 Core
- #### ✨ New Features
- core: create vm-core.func from dev [@MickLesk](https://github.com/MickLesk) ([#11528](https://github.com/community-scripts/ProxmoxVE/pull/11528))
### 🌐 Website
- #### 🐞 Bug Fixes
- fix(frontend): implement weighted search scoring for command menu [@ls-root](https://github.com/ls-root) ([#11534](https://github.com/community-scripts/ProxmoxVE/pull/11534))
## 2026-02-03
### 🆕 New Scripts
- Wealthfolio ([#11511](https://github.com/community-scripts/ProxmoxVE/pull/11511))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- [FIX] Shelfmark: unpin Chromium version [@vhsdream](https://github.com/vhsdream) ([#11505](https://github.com/community-scripts/ProxmoxVE/pull/11505))
- #### ✨ New Features
- [FEAT] Scanopy: automatically update integrated daemon [@vhsdream](https://github.com/vhsdream) ([#11506](https://github.com/community-scripts/ProxmoxVE/pull/11506))
### 💾 Core
- #### 🐞 Bug Fixes
- [FIX] tools.func: trim spaces in app_lc when checking for gh release [@vhsdream](https://github.com/vhsdream) ([#11512](https://github.com/community-scripts/ProxmoxVE/pull/11512))
### 🌐 Website
- #### 🐞 Bug Fixes
- fix(frontend): decouple table pagination from summary fetching [@ls-root](https://github.com/ls-root) ([#11495](https://github.com/community-scripts/ProxmoxVE/pull/11495))
## 2026-02-02
### 🆕 New Scripts
- rustypaste | Alpine-rustypaste ([#11457](https://github.com/community-scripts/ProxmoxVE/pull/11457))
- KitchenOwl ([#11453](https://github.com/community-scripts/ProxmoxVE/pull/11453))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Grist: Update dependencies [@tremor021](https://github.com/tremor021) ([#11489](https://github.com/community-scripts/ProxmoxVE/pull/11489))
- Allow "downgrade" of libigdgmm12 [@vhsdream](https://github.com/vhsdream) ([#11478](https://github.com/community-scripts/ProxmoxVE/pull/11478))
- Disable NPM install and update due to OpenResty SHA-1 signature issues [@MickLesk](https://github.com/MickLesk) ([#11471](https://github.com/community-scripts/ProxmoxVE/pull/11471))
- #### ✨ New Features
- Refactor: Forgejo & readeck - migrate to codeberg functions [@MickLesk](https://github.com/MickLesk) ([#11460](https://github.com/community-scripts/ProxmoxVE/pull/11460))
- #### 💥 Breaking Changes
- [FIX] Scanopy: remove daemon build [@vhsdream](https://github.com/vhsdream) ([#11444](https://github.com/community-scripts/ProxmoxVE/pull/11444))
- #### 🔧 Refactor
- Refactor: Vaultwarden [@MickLesk](https://github.com/MickLesk) ([#11445](https://github.com/community-scripts/ProxmoxVE/pull/11445))
- various scripts: use ensure_dependencies instead of apt [@MickLesk](https://github.com/MickLesk) ([#11463](https://github.com/community-scripts/ProxmoxVE/pull/11463))
### 🌐 Website
- cleanup(frontend): remove unused /category-view route [@ls-root](https://github.com/ls-root) ([#11461](https://github.com/community-scripts/ProxmoxVE/pull/11461))
- #### ✨ New Features
- feat(frontend): preview tab [@ls-root](https://github.com/ls-root) ([#11475](https://github.com/community-scripts/ProxmoxVE/pull/11475))
## 2026-02-01
### 🚀 Updated Scripts
- fix headers [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11422](https://github.com/community-scripts/ProxmoxVE/pull/11422))
- #### 🐞 Bug Fixes
- 2fauth: export PHP_VERSION for nginx config [@MickLesk](https://github.com/MickLesk) ([#11441](https://github.com/community-scripts/ProxmoxVE/pull/11441))
- Prometheus Paperless NGX Exporter: Set correct binary path in systemd unit file [@andygrunwald](https://github.com/andygrunwald) ([#11438](https://github.com/community-scripts/ProxmoxVE/pull/11438))
- tracearr: install/update new prestart script from upstream [@durzo](https://github.com/durzo) ([#11433](https://github.com/community-scripts/ProxmoxVE/pull/11433))
- n8n: Fix dependencies [@tremor021](https://github.com/tremor021) ([#11429](https://github.com/community-scripts/ProxmoxVE/pull/11429))
- [Hotfix] Bunkerweb update [@vhsdream](https://github.com/vhsdream) ([#11402](https://github.com/community-scripts/ProxmoxVE/pull/11402))
- [Hotfix] Immich: revert healthcheck feature [@vhsdream](https://github.com/vhsdream) ([#11427](https://github.com/community-scripts/ProxmoxVE/pull/11427))
- #### ✨ New Features
- tools.func: add codeberg functions & autocaliweb: migrate from GitHub to Codeberg [@MickLesk](https://github.com/MickLesk) ([#11440](https://github.com/community-scripts/ProxmoxVE/pull/11440))
- Immich Refactor #2 [@vhsdream](https://github.com/vhsdream) ([#11375](https://github.com/community-scripts/ProxmoxVE/pull/11375))
- #### 🔧 Refactor
- WordPress: Refactor [@tremor021](https://github.com/tremor021) ([#11408](https://github.com/community-scripts/ProxmoxVE/pull/11408))
- Refactor: Whisparr [@tremor021](https://github.com/tremor021) ([#11411](https://github.com/community-scripts/ProxmoxVE/pull/11411))
### 💾 Core
- #### ✨ New Features
- [tools]: Update `fetch_and_deply_from_url()` [@tremor021](https://github.com/tremor021) ([#11410](https://github.com/community-scripts/ProxmoxVE/pull/11410))
### 🌐 Website
- feat(frontend): implement UX refinements and syntax highlighting [@ls-root](https://github.com/ls-root) ([#11423](https://github.com/community-scripts/ProxmoxVE/pull/11423))
- #### ✨ New Features
- feat(frontend): add contribution CTA to empty search state [@ls-root](https://github.com/ls-root) ([#11412](https://github.com/community-scripts/ProxmoxVE/pull/11412))

View File

@@ -54,8 +54,9 @@ jobs:
console.log(`Cutoff date: ${cutoffDate.toISOString().split('T')[0]}`);
// Read changelog
const content = await fs.readFile(CHANGELOG_PATH, 'utf-8');
// Read changelog and normalize line endings
let content = await fs.readFile(CHANGELOG_PATH, 'utf-8');
content = content.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
const lines = content.split('\n');
// Parse entries
@@ -66,9 +67,39 @@ jobs:
let currentDate = null;
let currentContent = [];
let inHeader = true;
let inOldHistory = false;
let historyDetailsDepth = 0;
for (const line of lines) {
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const match = line.match(datePattern);
// Detect the start of History section: <details> followed by line with 📜 History
if (inHeader && !inOldHistory && line.trim() === '<details>') {
// Look ahead to see if this is the History section
const nextLine = lines[i + 1] || '';
if (nextLine.includes('📜 History')) {
inOldHistory = true;
historyDetailsDepth = 1;
continue;
}
}
// Track nested details tags to find the end of History section
if (inOldHistory) {
if (line.trim() === '<details>') {
historyDetailsDepth++;
}
if (line.trim() === '</details>') {
historyDetailsDepth--;
if (historyDetailsDepth === 0) {
// We've closed the main History details tag
inOldHistory = false;
}
}
continue;
}
if (match) {
inHeader = false;
@@ -148,30 +179,55 @@ jobs:
let existingContent = '';
try {
existingContent = await fs.readFile(monthPath, 'utf-8');
// Normalize line endings to prevent regex issues
existingContent = existingContent.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
} catch (e) {
// File doesn't exist
}
// Merge new entries with existing (avoid duplicates)
const existingDates = new Set();
const existingDatePattern = /^## (\d{4}-\d{2}-\d{2})$/gm;
let match;
while ((match = existingDatePattern.exec(existingContent)) !== null) {
existingDates.add(match[1]);
// Parse existing entries into a Map (date -> content) for deduplication
const allEntries = new Map();
// Helper function to parse entries from content
const parseEntries = (content) => {
const entries = new Map();
const parts = content.split(/(?=^## \d{4}-\d{2}-\d{2}$)/m);
for (const part of parts) {
const trimmed = part.trim();
if (!trimmed) continue;
const dateMatch = trimmed.match(/^## (\d{4}-\d{2}-\d{2})/);
if (dateMatch) {
entries.set(dateMatch[1], trimmed);
}
}
return entries;
};
// Parse existing content
if (existingContent) {
const existingEntries = parseEntries(existingContent);
for (const [date, content] of existingEntries) {
allEntries.set(date, content);
}
}
const newEntries = archiveData[year][month].filter(entry => {
// Add new entries (existing entries take precedence to avoid overwriting)
let addedCount = 0;
for (const entry of archiveData[year][month]) {
const dateMatch = entry.match(/^## (\d{4}-\d{2}-\d{2})/);
return dateMatch && !existingDates.has(dateMatch[1]);
});
if (dateMatch && !allEntries.has(dateMatch[1])) {
allEntries.set(dateMatch[1], entry.trim());
addedCount++;
}
}
if (newEntries.length > 0) {
const allContent = existingContent
? existingContent + '\n\n' + newEntries.join('\n\n')
: newEntries.join('\n\n');
await fs.writeFile(monthPath, allContent, 'utf-8');
console.log(`Updated: ${monthPath} (+${newEntries.length} entries)`);
// Sort entries by date (newest first) and write
const sortedDates = [...allEntries.keys()].sort().reverse();
const sortedContent = sortedDates.map(date => allEntries.get(date)).join('\n\n');
if (addedCount > 0 || !existingContent) {
await fs.writeFile(monthPath, sortedContent + '\n', 'utf-8');
console.log(`Updated: ${monthPath} (${allEntries.size} total entries, +${addedCount} new)`);
}
}
}
@@ -218,7 +274,8 @@ jobs:
// Count entries in month file
let entryCount = 0;
try {
const monthContent = await fs.readFile(monthPath, 'utf-8');
let monthContent = await fs.readFile(monthPath, 'utf-8');
monthContent = monthContent.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
entryCount = (monthContent.match(/^## \d{4}-\d{2}-\d{2}$/gm) || []).length;
} catch (e) {
entryCount = (archiveData[year]?.[month] || []).length;

View File

@@ -21,7 +21,14 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
<details>
<summary><h4>January - 27 entries</h4></summary>
<summary><h4>February (4 entries)</h4></summary>
[View February 2026 Changelog](.github/changelogs/2026/02.md)
</details>
<details>
<summary><h4>January (31 entries)</h4></summary>
[View January 2026 Changelog](.github/changelogs/2026/01.md)
@@ -391,392 +398,36 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
</details>
<details>
<summary><h2>📜 History</h2></summary>
<details>
<summary><h3>2026</h3></summary>
<details>
<summary><h4>January (31 entries)</h4></summary>
[View January 2026 Changelog](.github/changelogs/2026/01.md)
</details>
</details>
<details>
<summary><h3>2025</h3></summary>
<details>
<summary><h4>December (31 entries)</h4></summary>
[View December 2025 Changelog](.github/changelogs/2025/12.md)
</details>
<details>
<summary><h4>November (29 entries)</h4></summary>
[View November 2025 Changelog](.github/changelogs/2025/11.md)
</details>
<details>
<summary><h4>October (30 entries)</h4></summary>
[View October 2025 Changelog](.github/changelogs/2025/10.md)
</details>
<details>
<summary><h4>September (29 entries)</h4></summary>
[View September 2025 Changelog](.github/changelogs/2025/09.md)
</details>
<details>
<summary><h4>August (30 entries)</h4></summary>
[View August 2025 Changelog](.github/changelogs/2025/08.md)
</details>
<details>
<summary><h4>July (29 entries)</h4></summary>
[View July 2025 Changelog](.github/changelogs/2025/07.md)
</details>
<details>
<summary><h4>June (29 entries)</h4></summary>
[View June 2025 Changelog](.github/changelogs/2025/06.md)
</details>
<details>
<summary><h4>May (30 entries)</h4></summary>
[View May 2025 Changelog](.github/changelogs/2025/05.md)
</details>
<details>
<summary><h4>April (25 entries)</h4></summary>
[View April 2025 Changelog](.github/changelogs/2025/04.md)
</details>
<details>
<summary><h4>March (30 entries)</h4></summary>
[View March 2025 Changelog](.github/changelogs/2025/03.md)
</details>
<details>
<summary><h4>February (26 entries)</h4></summary>
[View February 2025 Changelog](.github/changelogs/2025/02.md)
</details>
<details>
<summary><h4>January (27 entries)</h4></summary>
[View January 2025 Changelog](.github/changelogs/2025/01.md)
</details>
</details>
<details>
<summary><h3>2024</h3></summary>
<details>
<summary><h4>December (22 entries)</h4></summary>
[View December 2024 Changelog](.github/changelogs/2024/12.md)
</details>
<details>
<summary><h4>November (15 entries)</h4></summary>
[View November 2024 Changelog](.github/changelogs/2024/11.md)
</details>
<details>
<summary><h4>October (9 entries)</h4></summary>
[View October 2024 Changelog](.github/changelogs/2024/10.md)
</details>
<details>
<summary><h4>September (1 entries)</h4></summary>
[View September 2024 Changelog](.github/changelogs/2024/09.md)
</details>
<details>
<summary><h4>August (2 entries)</h4></summary>
[View August 2024 Changelog](.github/changelogs/2024/08.md)
</details>
<details>
<summary><h4>July (0 entries)</h4></summary>
[View July 2024 Changelog](.github/changelogs/2024/07.md)
</details>
<details>
<summary><h4>June (8 entries)</h4></summary>
[View June 2024 Changelog](.github/changelogs/2024/06.md)
</details>
<details>
<summary><h4>May (16 entries)</h4></summary>
[View May 2024 Changelog](.github/changelogs/2024/05.md)
</details>
<details>
<summary><h4>April (14 entries)</h4></summary>
[View April 2024 Changelog](.github/changelogs/2024/04.md)
</details>
<details>
<summary><h4>March (5 entries)</h4></summary>
[View March 2024 Changelog](.github/changelogs/2024/03.md)
</details>
<details>
<summary><h4>February (9 entries)</h4></summary>
[View February 2024 Changelog](.github/changelogs/2024/02.md)
</details>
<details>
<summary><h4>January (9 entries)</h4></summary>
[View January 2024 Changelog](.github/changelogs/2024/01.md)
</details>
</details>
<details>
<summary><h3>2023</h3></summary>
<details>
<summary><h4>December (3 entries)</h4></summary>
[View December 2023 Changelog](.github/changelogs/2023/12.md)
</details>
<details>
<summary><h4>November (3 entries)</h4></summary>
[View November 2023 Changelog](.github/changelogs/2023/11.md)
</details>
<details>
<summary><h4>October (7 entries)</h4></summary>
[View October 2023 Changelog](.github/changelogs/2023/10.md)
</details>
<details>
<summary><h4>September (10 entries)</h4></summary>
[View September 2023 Changelog](.github/changelogs/2023/09.md)
</details>
<details>
<summary><h4>August (7 entries)</h4></summary>
[View August 2023 Changelog](.github/changelogs/2023/08.md)
</details>
<details>
<summary><h4>July (5 entries)</h4></summary>
[View July 2023 Changelog](.github/changelogs/2023/07.md)
</details>
<details>
<summary><h4>June (5 entries)</h4></summary>
[View June 2023 Changelog](.github/changelogs/2023/06.md)
</details>
<details>
<summary><h4>May (8 entries)</h4></summary>
[View May 2023 Changelog](.github/changelogs/2023/05.md)
</details>
<details>
<summary><h4>April (8 entries)</h4></summary>
[View April 2023 Changelog](.github/changelogs/2023/04.md)
</details>
<details>
<summary><h4>March (8 entries)</h4></summary>
[View March 2023 Changelog](.github/changelogs/2023/03.md)
</details>
<details>
<summary><h4>February (6 entries)</h4></summary>
[View February 2023 Changelog](.github/changelogs/2023/02.md)
</details>
<details>
<summary><h4>January (15 entries)</h4></summary>
[View January 2023 Changelog](.github/changelogs/2023/01.md)
</details>
</details>
<details>
<summary><h3>2022</h3></summary>
<details>
<summary><h4>December (7 entries)</h4></summary>
[View December 2022 Changelog](.github/changelogs/2022/12.md)
</details>
<details>
<summary><h4>November (7 entries)</h4></summary>
[View November 2022 Changelog](.github/changelogs/2022/11.md)
</details>
<details>
<summary><h4>October (2 entries)</h4></summary>
[View October 2022 Changelog](.github/changelogs/2022/10.md)
</details>
<details>
<summary><h4>September (9 entries)</h4></summary>
[View September 2022 Changelog](.github/changelogs/2022/09.md)
</details>
<details>
<summary><h4>August (7 entries)</h4></summary>
[View August 2022 Changelog](.github/changelogs/2022/08.md)
</details>
<details>
<summary><h4>July (10 entries)</h4></summary>
[View July 2022 Changelog](.github/changelogs/2022/07.md)
</details>
<details>
<summary><h4>June (1 entries)</h4></summary>
[View June 2022 Changelog](.github/changelogs/2022/06.md)
</details>
<details>
<summary><h4>May (8 entries)</h4></summary>
[View May 2022 Changelog](.github/changelogs/2022/05.md)
</details>
<details>
<summary><h4>April (13 entries)</h4></summary>
[View April 2022 Changelog](.github/changelogs/2022/04.md)
</details>
<details>
<summary><h4>March (20 entries)</h4></summary>
[View March 2022 Changelog](.github/changelogs/2022/03.md)
</details>
<details>
<summary><h4>February (15 entries)</h4></summary>
[View February 2022 Changelog](.github/changelogs/2022/02.md)
</details>
<details>
<summary><h4>January (3 entries)</h4></summary>
[View January 2022 Changelog](.github/changelogs/2022/01.md)
</details>
</details>
</details>
## 2026-02-04
### 🆕 New Scripts
- writefreely ([#11524](https://github.com/community-scripts/ProxmoxVE/pull/11524))
- Wishlist ([#11527](https://github.com/community-scripts/ProxmoxVE/pull/11527))
- WriteFreely ([#11524](https://github.com/community-scripts/ProxmoxVE/pull/11524))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Immich: pin version to 2.5.3 [@vhsdream](https://github.com/vhsdream) ([#11515](https://github.com/community-scripts/ProxmoxVE/pull/11515))
### 💾 Core
- #### ✨ New Features
- core: create vm-core.func from dev [@MickLesk](https://github.com/MickLesk) ([#11528](https://github.com/community-scripts/ProxmoxVE/pull/11528))
### 🧰 Tools
- #### ✨ New Features
- [ADDON] Immich Public Proxy addon [@vhsdream](https://github.com/vhsdream) ([#11518](https://github.com/community-scripts/ProxmoxVE/pull/11518))
### 🌐 Website
- #### 🐞 Bug Fixes
- fix(frontend): implement weighted search scoring for command menu [@ls-root](https://github.com/ls-root) ([#11534](https://github.com/community-scripts/ProxmoxVE/pull/11534))
## 2026-02-03
@@ -1631,64 +1282,3 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
- #### 🔧 Refactor
- Refactor: IP-Tag (Multiple IP / Performance / Execution Time) [@MickLesk](https://github.com/MickLesk) ([#10558](https://github.com/community-scripts/ProxmoxVE/pull/10558))
## 2026-01-04
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- PocketID: Update PocketID for 2.x [@tremor021](https://github.com/tremor021) ([#10506](https://github.com/community-scripts/ProxmoxVE/pull/10506))
- fix: reitti: nginx [@CrazyWolf13](https://github.com/CrazyWolf13) ([#10511](https://github.com/community-scripts/ProxmoxVE/pull/10511))
- MagicMirror: bump to nodejs 24 [@MickLesk](https://github.com/MickLesk) ([#10534](https://github.com/community-scripts/ProxmoxVE/pull/10534))
- #### 🔧 Refactor
- Refactor: SFTPGo [@tremor021](https://github.com/tremor021) ([#10518](https://github.com/community-scripts/ProxmoxVE/pull/10518))
- Refactor: Pelican Wings [@tremor021](https://github.com/tremor021) ([#10517](https://github.com/community-scripts/ProxmoxVE/pull/10517))
- Refactor: Pelican Panel [@tremor021](https://github.com/tremor021) ([#10516](https://github.com/community-scripts/ProxmoxVE/pull/10516))
- Refactor: Audiobookshelf [@tremor021](https://github.com/tremor021) ([#10519](https://github.com/community-scripts/ProxmoxVE/pull/10519))
### 💾 Core
- #### 🐞 Bug Fixes
- Export IPV6_METHOD to trigger verb_ip6() function [@remz1337](https://github.com/remz1337) ([#10538](https://github.com/community-scripts/ProxmoxVE/pull/10538))
### 🌐 Website
- #### 📝 Script Information
- Prowlarr: Update config_path [@tremor021](https://github.com/tremor021) ([#10504](https://github.com/community-scripts/ProxmoxVE/pull/10504))
## 2026-01-03
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Fix ownership and permissions for InvoiceNinja setup [@twinzdragonz](https://github.com/twinzdragonz) ([#10298](https://github.com/community-scripts/ProxmoxVE/pull/10298))
- Fix headscale Caddyfile to pass non-API URLs [@IlyaSemenov](https://github.com/IlyaSemenov) ([#10493](https://github.com/community-scripts/ProxmoxVE/pull/10493))
### 💾 Core
- #### 🔧 Refactor
- [core]: Preserve log files [@tremor021](https://github.com/tremor021) ([#10509](https://github.com/community-scripts/ProxmoxVE/pull/10509))
### ❔ Uncategorized
- Wireguard: Update WGDashboard notes URL to the new link [@tremor021](https://github.com/tremor021) ([#10496](https://github.com/community-scripts/ProxmoxVE/pull/10496))
- InvoiceNinja: Update database credentias information [@tremor021](https://github.com/tremor021) ([#10497](https://github.com/community-scripts/ProxmoxVE/pull/10497))
## 2026-01-02
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Fix Intel Level Zero package conflict on Debian 13 [@Copilot](https://github.com/Copilot) ([#10467](https://github.com/community-scripts/ProxmoxVE/pull/10467))
### ❔ Uncategorized
- Extend guidance for changing the immich upload location for #10447 [@jshprentz](https://github.com/jshprentz) ([#10475](https://github.com/community-scripts/ProxmoxVE/pull/10475))

6
ct/headers/wishlist Normal file
View File

@@ -0,0 +1,6 @@
_ ___ __ ___ __
| | / (_)____/ /_ / (_)____/ /_
| | /| / / / ___/ __ \/ / / ___/ __/
| |/ |/ / (__ ) / / / / (__ ) /_
|__/|__/_/____/_/ /_/_/_/____/\__/

View File

@@ -36,10 +36,6 @@ function update_script() {
exit
fi
setup_uv
PNPM_VERSION="$(curl -fsSL "https://raw.githubusercontent.com/immich-app/immich/refs/heads/main/package.json" | jq -r '.packageManager | split("@")[1]')"
NODE_VERSION="24" NODE_MODULE="pnpm@${PNPM_VERSION}" setup_nodejs
if [[ ! -f /etc/apt/preferences.d/preferences ]]; then
msg_info "Adding Debian Testing repo"
sed -i 's/ trixie-updates/ trixie-updates testing/g' /etc/apt/sources.list.d/debian.sources
@@ -109,7 +105,7 @@ EOF
msg_ok "Image-processing libraries up to date"
fi
RELEASE="2.5.2"
RELEASE="2.5.3"
if check_for_gh_release "immich" "immich-app/immich" "${RELEASE}"; then
if [[ $(cat ~/.immich) > "2.5.1" ]]; then
msg_info "Enabling Maintenance Mode"
@@ -164,7 +160,10 @@ EOF
rm -rf "${APP_DIR:?}"/*
)
setup_uv
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "immich" "immich-app/immich" "tarball" "v${RELEASE}" "$SRC_DIR"
PNPM_VERSION="$(jq -r '.packageManager | split("@")[1]' ${SRC_DIR}/package.json)"
NODE_VERSION="24" NODE_MODULE="pnpm@${PNPM_VERSION}" setup_nodejs
msg_info "Updating Immich web and microservices"
cd "$SRC_DIR"/server

82
ct/wishlist.sh Normal file
View File

@@ -0,0 +1,82 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG
# Author: Dunky13
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/cmintey/wishlist
APP="Wishlist"
var_tags="${var_tags:-sharing}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-5}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -d /opt/wishlist ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "wishlist" "cmintey/wishlist"; then
NODE_VERSION="24" NODE_MODULE="pnpm" setup_nodejs
msg_info "Stopping Service"
systemctl stop wishlist
msg_ok "Stopped Service"
msg_info "Creating Backup"
mkdir -p /opt/wishlist-backup
cp /opt/wishlist/.env /opt/wishlist-backup/.env
cp -a /opt/wishlist/uploads /opt/wishlist-backup
cp -a /opt/wishlist/data /opt/wishlist-backup
msg_ok "Created Backup"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "wishlist" "cmintey/wishlist" "tarball"
LATEST_APP_VERSION=$(get_latest_github_release "cmintey/wishlist")
msg_info "Updating Wishlist"
cd /opt/wishlist
$STD pnpm install
$STD pnpm svelte-kit sync
$STD pnpm prisma generate
sed -i 's|/usr/src/app/|/opt/wishlist/|g' $(grep -rl '/usr/src/app/' /opt/wishlist)
export VERSION="v${LATEST_APP_VERSION}"
export SHA="v${LATEST_APP_VERSION}"
$STD pnpm run build
$STD pnpm prune --prod
chmod +x /opt/wishlist/entrypoint.sh
msg_info "Restoring Backup"
cp /opt/wishlist-backup/.env /opt/wishlist/.env
cp -a /opt/wishlist-backup/uploads /opt/wishlist
cp -a /opt/wishlist-backup/data /opt/wishlist
rm -rf /opt/wishlist-backup
msg_ok "Restored Backup"
msg_ok "Updated Wishlist"
msg_info "Starting Service"
systemctl start wishlist
msg_ok "Started Service"
msg_ok "Updated successfully!"
fi
exit
}
start
build_container
description
msg_ok "Completed successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3280${CL}"

View File

@@ -1,5 +1,5 @@
{
"generated": "2026-02-04T06:18:03Z",
"generated": "2026-02-04T18:17:33Z",
"versions": [
{
"slug": "2fauth",
@@ -256,9 +256,9 @@
{
"slug": "docmost",
"repo": "docmost/docmost",
"version": "v0.25.0",
"version": "v0.25.1",
"pinned": false,
"date": "2026-02-04T00:33:45Z"
"date": "2026-02-04T15:19:51Z"
},
{
"slug": "domain-locker",
@@ -515,9 +515,9 @@
{
"slug": "huntarr",
"repo": "plexguide/Huntarr.io",
"version": "9.1.9.1",
"version": "9.1.12",
"pinned": false,
"date": "2026-02-04T01:08:22Z"
"date": "2026-02-04T14:28:36Z"
},
{
"slug": "inspircd",
@@ -1096,9 +1096,9 @@
{
"slug": "pulse",
"repo": "rcourtman/Pulse",
"version": "v5.0.17",
"version": "v5.1.0",
"pinned": false,
"date": "2026-01-20T19:07:30Z"
"date": "2026-02-04T17:43:59Z"
},
{
"slug": "pve-scripts-local",
@@ -1271,9 +1271,9 @@
{
"slug": "speedtest-tracker",
"repo": "alexjustesen/speedtest-tracker",
"version": "v1.13.6",
"version": "v1.13.7",
"pinned": false,
"date": "2026-02-03T21:20:51Z"
"date": "2026-02-04T16:47:42Z"
},
{
"slug": "spoolman",
@@ -1369,9 +1369,9 @@
{
"slug": "tianji",
"repo": "msgbyte/tianji",
"version": "v1.31.9",
"version": "v1.31.10",
"pinned": false,
"date": "2026-01-31T18:22:40Z"
"date": "2026-02-04T17:21:04Z"
},
{
"slug": "traccar",
@@ -1411,9 +1411,9 @@
{
"slug": "trip",
"repo": "itskovacs/TRIP",
"version": "1.38.0",
"version": "1.38.1",
"pinned": false,
"date": "2026-01-31T15:56:30Z"
"date": "2026-02-04T18:10:15Z"
},
{
"slug": "tududi",
@@ -1562,6 +1562,13 @@
"pinned": false,
"date": "2026-01-08T09:50:00Z"
},
{
"slug": "wishlist",
"repo": "cmintey/wishlist",
"version": "v0.59.0",
"pinned": false,
"date": "2026-01-19T16:42:14Z"
},
{
"slug": "wizarr",
"repo": "wizarrrr/wizarr",
@@ -1569,6 +1576,13 @@
"pinned": false,
"date": "2025-12-09T14:30:23Z"
},
{
"slug": "writefreely",
"repo": "writefreely/writefreely",
"version": "v0.16.0",
"pinned": false,
"date": "2025-08-29T19:30:02Z"
},
{
"slug": "yt-dlp-webui",
"repo": "marcopiovanello/yt-dlp-web-ui",

View File

@@ -0,0 +1,44 @@
{
"name": "Immich Public Proxy",
"slug": "immich-public-proxy",
"categories": [
21
],
"date_created": "2026-02-04",
"type": "addon",
"updateable": true,
"privileged": false,
"interface_port": 3000,
"documentation": "https://github.com/alangrainger/immich-public-proxy/docs",
"website": "https://github.com/alangrainger/immich-public-proxy",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/immich-public-proxy.webp",
"config_path": "/opt/immich-proxy/app/.env",
"description": "Share your Immich photos and albums in a safe way without exposing your Immich instance to the public.",
"install_methods": [
{
"type": "default",
"script": "tools/addon/immich-public-proxy.sh",
"resources": {
"cpu": null,
"ram": null,
"hdd": null,
"os": null,
"version": null
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "Requires Node.js 24+",
"type": "info"
},
{
"text": "Update with: update_immich-public-proxy",
"type": "info"
}
]
}

View File

@@ -0,0 +1,35 @@
{
"name": "Wishlist",
"slug": "wishlist",
"categories": [
12
],
"date_created": "2026-02-04",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 3280,
"documentation": "https://github.com/cmintey/wishlist/blob/main/README.md#getting-started",
"config_path": "/opt/wishlist/.env",
"website": "https://github.com/cmintey/wishlist",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/cmintey-wishlist.webp",
"description": "Wishlist is a self-hosted wishlist application that you can share with your friends and family. You no longer have to wonder what to get your family for the holidays, simply check their wishlist and claim any available item!",
"install_methods": [
{
"type": "default",
"script": "ct/wishlist.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 5,
"os": "Debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -23,6 +23,34 @@ import { Button } from "./ui/button";
import { Badge } from "./ui/badge";
import Link from "next/link";
function search(scripts: Script[], query: string): Script[] {
const queryLower = query.toLowerCase().trim();
const searchWords = queryLower.split(/\s+/).filter(Boolean);
return scripts
.map(script => {
const nameLower = script.name.toLowerCase();
const descriptionLower = (script.description || "").toLowerCase();
let score = 0;
for (const word of searchWords) {
if (nameLower.includes(word)) {
score += 10;
}
if (descriptionLower.includes(word)) {
score += 5;
}
}
return { script, score };
})
.filter(({ score }) => score > 0)
.sort((a, b) => b.score - a.score)
.slice(0, 20)
.map(({ script }) => script);
}
export function formattedBadge(type: string) {
switch (type) {
case "vm":
@@ -51,9 +79,11 @@ function getRandomScript(categories: Category[], previouslySelected: Set<string>
}
function CommandMenu() {
const [query, setQuery] = React.useState("");
const [open, setOpen] = React.useState(false);
const [links, setLinks] = React.useState<Category[]>([]);
const [isLoading, setIsLoading] = React.useState(false);
const [results, setResults] = React.useState<Script[]>([]);
const [selectedScripts, setSelectedScripts] = React.useState<Set<string>>(new Set());
const router = useRouter();
@@ -70,6 +100,27 @@ function CommandMenu() {
});
};
React.useEffect(() => {
if (query.trim() === "") {
fetchSortedCategories();
}
else {
const scriptMap = new Map<string, Script>();
for (const category of links) {
for (const script of category.scripts || []) {
if (!scriptMap.has(script.slug)) {
scriptMap.set(script.slug, script);
}
}
}
const uniqueScripts = Array.from(scriptMap.values());
const filteredResults = search(uniqueScripts, query);
setResults(filteredResults);
}
}, [query]);
React.useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
@@ -197,20 +248,20 @@ function CommandMenu() {
<CommandDialog
open={open}
onOpenChange={setOpen}
filter={(value: string, search: string) => {
const searchLower = search.toLowerCase().trim();
if (!searchLower)
return 1;
const valueLower = value.toLowerCase();
const searchWords = searchLower.split(/\s+/).filter(Boolean);
// All search words must appear somewhere in the value (name + description)
const allWordsMatch = searchWords.every((word: string) => valueLower.includes(word));
return allWordsMatch ? 1 : 0;
onOpenChange={(open) => {
setOpen(open);
if (open) {
setQuery("");
setResults([]);
}
}}
>
<DialogTitle className="sr-only">Search scripts</DialogTitle>
<CommandInput placeholder="Search for a script..." />
<CommandInput
placeholder="Search for a script..."
onValueChange={setQuery}
value={query}
/>
<CommandList>
<CommandEmpty>
{isLoading ? (
@@ -233,9 +284,10 @@ function CommandMenu() {
</div>
)}
</CommandEmpty>
{Object.entries(uniqueScriptsByCategory).map(([categoryName, scripts]) => (
<CommandGroup key={`category:${categoryName}`} heading={categoryName}>
{scripts.map(script => (
{results.length > 0 ? (
<CommandGroup heading="Search Results">
{results.map(script => (
<CommandItem
key={`script:${script.slug}`}
value={`${script.name} ${script.type} ${script.description || ""}`}
@@ -268,7 +320,44 @@ function CommandMenu() {
</CommandItem>
))}
</CommandGroup>
))}
) : ( // When no search results, show all scripts grouped by category
Object.entries(uniqueScriptsByCategory).map(([categoryName, scripts]) => (
<CommandGroup key={`category:${categoryName}`} heading={categoryName}>
{scripts.map(script => (
<CommandItem
key={`script:${script.slug}`}
value={`${script.name} ${script.type} ${script.description || ""}`}
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
src={script.logo || `/${basePath}/logo.png`}
onError={e => ((e.currentTarget as HTMLImageElement).src = `/${basePath}/logo.png`)}
unoptimized
width={16}
height={16}
alt=""
className="h-5 w-5"
/>
<span>{script.name}</span>
<span>{formattedBadge(script.type)}</span>
</div>
</CommandItem>
))}
</CommandGroup>
))
)}
</CommandList>
</CommandDialog>
</>

View File

@@ -13,44 +13,44 @@ setting_up_container
network_check
update_os
echo ""
echo ""
echo -e "🤖 ${BL}Immich Machine Learning Options${CL}"
echo "─────────────────────────────────────────"
echo "Please choose your machine-learning type:"
echo ""
echo " 1) CPU only (default)"
echo " 2) Intel OpenVINO (requires GPU passthrough)"
echo ""
if [ -d /dev/dri ]; then
echo ""
echo ""
echo -e "🤖 ${BL}Immich Machine Learning Options${CL}"
echo "─────────────────────────────────────────"
echo "Please choose your machine-learning type:"
echo ""
echo " 1) CPU only (default)"
echo " 2) Intel OpenVINO (requires GPU passthrough)"
echo ""
read -r -p "${TAB3}Select machine-learning type [1]: " ML_TYPE
ML_TYPE="${ML_TYPE:-1}"
if [[ "$ML_TYPE" == "2" ]]; then
msg_info "Installing OpenVINO dependencies"
touch ~/.openvino
$STD apt install -y --no-install-recommends patchelf
tmp_dir=$(mktemp -d)
$STD pushd "$tmp_dir"
curl -fsSLO https://raw.githubusercontent.com/immich-app/base-images/refs/heads/main/server/Dockerfile
readarray -t INTEL_URLS < <(
sed -n "/intel-[igc|opencl]/p" ./Dockerfile | awk '{print $2}'
sed -n "/libigdgmm12/p" ./Dockerfile | awk '{print $3}'
)
for url in "${INTEL_URLS[@]}"; do
curl -fsSLO "$url"
done
$STD apt install -y ./libigdgmm12*.deb
rm ./libigdgmm12*.deb
$STD apt install -y ./*.deb
$STD apt-mark hold libigdgmm12
$STD popd
rm -rf "$tmp_dir"
dpkg-query -W -f='${Version}\n' intel-opencl-icd >~/.intel_version
msg_ok "Installed OpenVINO dependencies"
read -r -p "${TAB3}Select machine-learning type [1]: " ML_TYPE
ML_TYPE="${ML_TYPE:-1}"
if [[ "$ML_TYPE" == "2" ]]; then
msg_info "Installing OpenVINO dependencies"
touch ~/.openvino
$STD apt install -y --no-install-recommends patchelf
tmp_dir=$(mktemp -d)
$STD pushd "$tmp_dir"
curl -fsSLO https://raw.githubusercontent.com/immich-app/base-images/refs/heads/main/server/Dockerfile
readarray -t INTEL_URLS < <(
sed -n "/intel-[igc|opencl]/p" ./Dockerfile | awk '{print $2}'
sed -n "/libigdgmm12/p" ./Dockerfile | awk '{print $3}'
)
for url in "${INTEL_URLS[@]}"; do
curl -fsSLO "$url"
done
$STD apt install -y ./libigdgmm12*.deb
rm ./libigdgmm12*.deb
$STD apt install -y ./*.deb
$STD apt-mark hold libigdgmm12
$STD popd
rm -rf "$tmp_dir"
dpkg-query -W -f='${Version}\n' intel-opencl-icd >~/.intel_version
msg_ok "Installed OpenVINO dependencies"
fi
fi
setup_uv
msg_info "Installing dependencies"
$STD apt install --no-install-recommends -y \
git \
@@ -144,8 +144,7 @@ msg_info "Installing packages from Debian Testing repo"
$STD apt install -t testing --no-install-recommends -yqq libmimalloc3 libde265-dev
msg_ok "Installed packages from Debian Testing repo"
PNPM_VERSION="$(curl -fsSL "https://raw.githubusercontent.com/immich-app/immich/refs/heads/main/package.json" | jq -r '.packageManager | split("@")[1]')"
NODE_VERSION="24" NODE_MODULE="pnpm@${PNPM_VERSION}" setup_nodejs
setup_uv
PG_VERSION="16" PG_MODULES="pgvector" setup_postgresql
VCHORD_RELEASE="0.5.3"
@@ -290,7 +289,9 @@ ML_DIR="${APP_DIR}/machine-learning"
GEO_DIR="${INSTALL_DIR}/geodata"
mkdir -p {"${APP_DIR}","${UPLOAD_DIR}","${GEO_DIR}","${INSTALL_DIR}"/cache}
fetch_and_deploy_gh_release "immich" "immich-app/immich" "tarball" "v2.5.2" "$SRC_DIR"
fetch_and_deploy_gh_release "immich" "immich-app/immich" "tarball" "v2.5.3" "$SRC_DIR"
PNPM_VERSION="$(jq -r '.packageManager | split("@")[1]' ${SRC_DIR}/package.json)"
NODE_VERSION="24" NODE_MODULE="pnpm@${PNPM_VERSION}" setup_nodejs
msg_info "Installing Immich (patience)"

View File

@@ -0,0 +1,66 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: Dunky13
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/cmintey/wishlist
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Installing dependencies"
$STD apt install -y \
build-essential \
openssl \
caddy
msg_ok "Installed dependencies"
NODE_VERSION="24" NODE_MODULE="pnpm" setup_nodejs
fetch_and_deploy_gh_release "wishlist" "cmintey/wishlist" "tarball"
LATEST_APP_VERSION=$(get_latest_github_release "cmintey/wishlist")
msg_info "Installing Wishlist"
cd /opt/wishlist
cp .env.example .env
sed -i "s|^ORIGIN=.*|ORIGIN=http://${LOCAL_IP}:3280|" /opt/wishlist/.env
echo "" >>/opt/wishlist/.env
echo "NODE_ENV=production" >>/opt/wishlist/.env
$STD pnpm install
$STD pnpm svelte-kit sync
$STD pnpm prisma generate
sed -i 's|/usr/src/app/|/opt/wishlist/|g' $(grep -rl '/usr/src/app/' /opt/wishlist)
export VERSION="v${LATEST_APP_VERSION}"
export SHA="v${LATEST_APP_VERSION}"
$STD pnpm run build
$STD pnpm prune --prod
chmod +x /opt/wishlist/entrypoint.sh
mkdir -p /opt/wishlist/uploads
mkdir -p /opt/wishlist/data
msg_ok "Installed Wishlist"
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/wishlist.service
[Unit]
Description=Wishlist Service
After=network.target
[Service]
WorkingDirectory=/opt/wishlist
EnvironmentFile=/opt/wishlist/.env
ExecStart=/usr/bin/env sh -c './entrypoint.sh'
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now wishlist
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc

620
misc/vm-core.func Normal file
View File

@@ -0,0 +1,620 @@
# Copyright (c) 2021-2026 community-scripts ORG
# License: MIT | https://git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/main/LICENSE
set -euo pipefail
SPINNER_PID=""
SPINNER_ACTIVE=0
SPINNER_MSG=""
declare -A MSG_INFO_SHOWN
# ------------------------------------------------------------------------------
# Loads core utility groups once (colors, formatting, icons, defaults).
# ------------------------------------------------------------------------------
[[ -n "${_CORE_FUNC_LOADED:-}" ]] && return
_CORE_FUNC_LOADED=1
load_functions() {
[[ -n "${__FUNCTIONS_LOADED:-}" ]] && return
__FUNCTIONS_LOADED=1
color
formatting
icons
default_vars
set_std_mode
shell_check
get_valid_nextid
cleanup_vmid
cleanup
check_root
pve_check
arch_check
}
# Function to download & save header files
get_header() {
local app_name=$(echo "${APP,,}" | tr ' ' '-')
local app_type=${APP_TYPE:-vm}
local header_url="https://git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/main/${app_type}/headers/${app_name}"
local local_header_path="/usr/local/community-scripts/headers/${app_type}/${app_name}"
mkdir -p "$(dirname "$local_header_path")"
if [ ! -s "$local_header_path" ]; then
if ! curl -fsSL "$header_url" -o "$local_header_path"; then
return 1
fi
fi
cat "$local_header_path" 2>/dev/null || true
}
header_info() {
local app_name=$(echo "${APP,,}" | tr ' ' '-')
local header_content
header_content=$(get_header "$app_name") || header_content=""
clear
local term_width
term_width=$(tput cols 2>/dev/null || echo 120)
if [ -n "$header_content" ]; then
echo "$header_content"
fi
}
# ------------------------------------------------------------------------------
# Sets ANSI color codes used for styled terminal output.
# ------------------------------------------------------------------------------
color() {
YW=$(echo "\033[33m")
YWB=$(echo "\033[93m")
BL=$(echo "\033[36m")
RD=$(echo "\033[01;31m")
BGN=$(echo "\033[4;92m")
GN=$(echo "\033[1;92m")
DGN=$(echo "\033[32m")
CL=$(echo "\033[m")
}
# ------------------------------------------------------------------------------
# Defines formatting helpers like tab, bold, and line reset sequences.
# ------------------------------------------------------------------------------
formatting() {
BFR="\\r\\033[K"
BOLD=$(echo "\033[1m")
HOLD=" "
TAB=" "
TAB3=" "
}
# ------------------------------------------------------------------------------
# Sets symbolic icons used throughout user feedback and prompts.
# ------------------------------------------------------------------------------
icons() {
CM="${TAB}✔️${TAB}"
CROSS="${TAB}✖️${TAB}"
DNSOK="✔️ "
DNSFAIL="${TAB}✖️${TAB}"
INFO="${TAB}💡${TAB}${CL}"
OS="${TAB}🖥️${TAB}${CL}"
OSVERSION="${TAB}🌟${TAB}${CL}"
CONTAINERTYPE="${TAB}📦${TAB}${CL}"
DISKSIZE="${TAB}💾${TAB}${CL}"
CPUCORE="${TAB}🧠${TAB}${CL}"
RAMSIZE="${TAB}🛠️${TAB}${CL}"
SEARCH="${TAB}🔍${TAB}${CL}"
VERBOSE_CROPPED="🔍${TAB}"
VERIFYPW="${TAB}🔐${TAB}${CL}"
CONTAINERID="${TAB}🆔${TAB}${CL}"
HOSTNAME="${TAB}🏠${TAB}${CL}"
BRIDGE="${TAB}🌉${TAB}${CL}"
NETWORK="${TAB}📡${TAB}${CL}"
GATEWAY="${TAB}🌐${TAB}${CL}"
DISABLEIPV6="${TAB}🚫${TAB}${CL}"
ICON_DISABLEIPV6="${TAB}🚫${TAB}${CL}"
DEFAULT="${TAB}⚙️${TAB}${CL}"
MACADDRESS="${TAB}🔗${TAB}${CL}"
VLANTAG="${TAB}🏷️${TAB}${CL}"
ROOTSSH="${TAB}🔑${TAB}${CL}"
CREATING="${TAB}🚀${TAB}${CL}"
ADVANCED="${TAB}🧩${TAB}${CL}"
FUSE="${TAB}🗂️${TAB}${CL}"
GPU="${TAB}🎮${TAB}${CL}"
HOURGLASS="${TAB}${TAB}"
}
# ------------------------------------------------------------------------------
# Sets default verbose mode for script and os execution.
# ------------------------------------------------------------------------------
set_std_mode() {
if [ "${VERBOSE:-no}" = "yes" ]; then
STD=""
else
STD="silent"
fi
}
# ------------------------------------------------------------------------------
# default_vars()
#
# - Sets default retry and wait variables used for system actions
# - RETRY_NUM: Maximum number of retry attempts (default: 10)
# - RETRY_EVERY: Seconds to wait between retries (default: 3)
# ------------------------------------------------------------------------------
default_vars() {
RETRY_NUM=10
RETRY_EVERY=3
i=$RETRY_NUM
}
# ------------------------------------------------------------------------------
# get_active_logfile()
#
# - Returns the appropriate log file based on execution context
# - BUILD_LOG: Host operations (VM creation)
# - Fallback to /tmp/build-<timestamp>.log if not set
# ------------------------------------------------------------------------------
get_active_logfile() {
if [[ -n "${BUILD_LOG:-}" ]]; then
echo "$BUILD_LOG"
else
# Fallback for legacy scripts
echo "/tmp/build-$(date +%Y%m%d_%H%M%S).log"
fi
}
# ------------------------------------------------------------------------------
# silent()
#
# - Executes command with output redirected to active log file
# - On error: displays last 10 lines of log and exits with original exit code
# - Temporarily disables error trap to capture exit code correctly
# - Sources explain_exit_code() for detailed error messages
# ------------------------------------------------------------------------------
silent() {
local cmd="$*"
local caller_line="${BASH_LINENO[0]:-unknown}"
local logfile="$(get_active_logfile)"
set +Eeuo pipefail
trap - ERR
"$@" >>"$logfile" 2>&1
local rc=$?
set -Eeuo pipefail
trap 'error_handler' ERR
if [[ $rc -ne 0 ]]; then
# Source explain_exit_code if needed
if ! declare -f explain_exit_code >/dev/null 2>&1; then
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/main/misc/error_handler.func) 2>/dev/null || true
fi
local explanation=""
if declare -f explain_exit_code >/dev/null 2>&1; then
explanation="$(explain_exit_code "$rc")"
fi
printf "\e[?25h"
if [[ -n "$explanation" ]]; then
msg_error "in line ${caller_line}: exit code ${rc} (${explanation})"
else
msg_error "in line ${caller_line}: exit code ${rc}"
fi
msg_custom "→" "${YWB}" "${cmd}"
if [[ -s "$logfile" ]]; then
local log_lines=$(wc -l <"$logfile")
echo "--- Last 10 lines of log ---"
tail -n 10 "$logfile"
echo "----------------------------"
# Show how to view full log if there are more lines
if [[ $log_lines -gt 10 ]]; then
msg_custom "📋" "${YW}" "View full log (${log_lines} lines): ${logfile}"
fi
fi
exit "$rc"
fi
}
# ------------------------------------------------------------------------------
# Performs a curl request with retry logic and inline feedback.
# ------------------------------------------------------------------------------
run_curl() {
if [ "$VERB" = "no" ]; then
curl "$@" >/dev/null 2>>/tmp/curl_error.log
else
curl "$@" 2>>/tmp/curl_error.log
fi
}
curl_handler() {
local args=()
local url=""
local max_retries=0 delay=2 attempt=1
local exit_code has_output_file=false
for arg in "$@"; do
if [[ "$arg" != -* && -z "$url" ]]; then
url="$arg"
fi
[[ "$arg" == "-o" || "$arg" == --output ]] && has_output_file=true
args+=("$arg")
done
if [[ -z "$url" ]]; then
msg_error "no valid url or option entered for curl_handler"
exit 1
fi
$STD msg_info "Fetching: $url"
while :; do
if $has_output_file; then
$STD run_curl "${args[@]}"
exit_code=$?
else
$STD result=$(run_curl "${args[@]}")
exit_code=$?
fi
if [[ $exit_code -eq 0 ]]; then
stop_spinner
msg_ok "Fetched: $url"
$has_output_file || printf '%s' "$result"
return 0
fi
if ((attempt >= max_retries)); then
stop_spinner
if [ -s /tmp/curl_error.log ]; then
local curl_stderr
curl_stderr=$(</tmp/curl_error.log)
rm -f /tmp/curl_error.log
fi
__curl_err_handler "$exit_code" "$url" "$curl_stderr"
exit 1 # hard exit if exit_code is not 0
fi
$STD printf "\r\033[K${INFO}${YW}Retry $attempt/$max_retries in ${delay}s...${CL}" >&2
sleep "$delay"
((attempt++))
done
}
# ------------------------------------------------------------------------------
# Handles specific curl error codes and displays descriptive messages.
# ------------------------------------------------------------------------------
__curl_err_handler() {
local exit_code="$1"
local target="$2"
local curl_msg="$3"
case $exit_code in
1) msg_error "Unsupported protocol: $target" ;;
2) msg_error "Curl init failed: $target" ;;
3) msg_error "Malformed URL: $target" ;;
5) msg_error "Proxy resolution failed: $target" ;;
6) msg_error "Host resolution failed: $target" ;;
7) msg_error "Connection failed: $target" ;;
9) msg_error "Access denied: $target" ;;
18) msg_error "Partial file transfer: $target" ;;
22) msg_error "HTTP error (e.g. 400/404): $target" ;;
23) msg_error "Write error on local system: $target" ;;
26) msg_error "Read error from local file: $target" ;;
28) msg_error "Timeout: $target" ;;
35) msg_error "SSL connect error: $target" ;;
47) msg_error "Too many redirects: $target" ;;
51) msg_error "SSL cert verify failed: $target" ;;
52) msg_error "Empty server response: $target" ;;
55) msg_error "Send error: $target" ;;
56) msg_error "Receive error: $target" ;;
60) msg_error "SSL CA not trusted: $target" ;;
67) msg_error "Login denied by server: $target" ;;
78) msg_error "Remote file not found (404): $target" ;;
*) msg_error "Curl failed with code $exit_code: $target" ;;
esac
[[ -n "$curl_msg" ]] && printf "%s\n" "$curl_msg" >&2
exit 1
}
# ------------------------------------------------------------------------------
# shell_check()
#
# - Verifies that the script is running under Bash shell
# - Exits with error message if different shell is detected
# ------------------------------------------------------------------------------
shell_check() {
if [[ "$(ps -p $$ -o comm=)" != "bash" ]]; then
clear
msg_error "Your default shell is currently not set to Bash. To use these scripts, please switch to the Bash shell."
echo -e "\nExiting..."
sleep 2
exit
fi
}
# ------------------------------------------------------------------------------
# clear_line()
#
# - Clears current terminal line using tput or ANSI escape codes
# - Moves cursor to beginning of line (carriage return)
# - Fallback to ANSI codes if tput not available
# ------------------------------------------------------------------------------
clear_line() {
tput cr 2>/dev/null || echo -en "\r"
tput el 2>/dev/null || echo -en "\033[K"
}
# ------------------------------------------------------------------------------
# is_verbose_mode()
#
# - Determines if script should run in verbose mode
# - Checks VERBOSE and var_verbose variables
# - Also returns true if not running in TTY (pipe/redirect scenario)
# ------------------------------------------------------------------------------
is_verbose_mode() {
local verbose="${VERBOSE:-${var_verbose:-no}}"
[[ "$verbose" != "no" || ! -t 2 ]]
}
### dev spinner ###
SPINNER_ACTIVE=0
SPINNER_PID=""
SPINNER_MSG=""
declare -A MSG_INFO_SHOWN=()
# Trap cleanup on various signals
trap 'cleanup_spinner' EXIT INT TERM HUP
# Cleans up spinner process on exit
cleanup_spinner() {
stop_spinner
# Additional cleanup if needed
}
start_spinner() {
local msg="${1:-Processing...}"
local frames=(⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏)
local spin_i=0
local interval=0.1
# Set message and clear current line
SPINNER_MSG="$msg"
printf "\r\e[2K" >&2
# Stop any existing spinner
stop_spinner
# Set active flag
SPINNER_ACTIVE=1
# Start spinner in background
{
while [[ "$SPINNER_ACTIVE" -eq 1 ]]; do
printf "\r\e[2K%s %b" "${TAB}${frames[spin_i]}${TAB}" "${YW}${SPINNER_MSG}${CL}" >&2
spin_i=$(((spin_i + 1) % ${#frames[@]}))
sleep "$interval"
done
} &
SPINNER_PID=$!
# Disown to prevent getting "Terminated" messages
disown "$SPINNER_PID" 2>/dev/null || true
}
stop_spinner() {
# Check if spinner is active and PID exists
if [[ "$SPINNER_ACTIVE" -eq 1 ]] && [[ -n "${SPINNER_PID}" ]]; then
SPINNER_ACTIVE=0
if kill -0 "$SPINNER_PID" 2>/dev/null; then
kill "$SPINNER_PID" 2>/dev/null
# Give it a moment to terminate
sleep 0.1
# Force kill if still running
if kill -0 "$SPINNER_PID" 2>/dev/null; then
kill -9 "$SPINNER_PID" 2>/dev/null
fi
# Wait for process but ignore errors
wait "$SPINNER_PID" 2>/dev/null || true
fi
# Clear spinner line
printf "\r\e[2K" >&2
SPINNER_PID=""
fi
}
spinner_guard() {
# Safely stop spinner if it's running
if [[ "$SPINNER_ACTIVE" -eq 1 ]] && [[ -n "${SPINNER_PID}" ]]; then
stop_spinner
fi
}
msg_info() {
local msg="${1:-Information message}"
# Only show each message once unless reset
if [[ -n "${MSG_INFO_SHOWN["$msg"]+x}" ]]; then
return
fi
MSG_INFO_SHOWN["$msg"]=1
spinner_guard
start_spinner "$msg"
}
msg_ok() {
local msg="${1:-Operation completed successfully}"
stop_spinner
printf "\r\e[2K%s %b\n" "${CM}" "${GN}${msg}${CL}" >&2
# Remove from shown messages to allow it to be shown again
local sanitized_msg
sanitized_msg=$(printf '%s' "$msg" | sed 's/\x1b\[[0-9;]*m//g; s/[^a-zA-Z0-9_]/_/g')
unset 'MSG_INFO_SHOWN['"$sanitized_msg"']' 2>/dev/null || true
}
msg_error() {
local msg="${1:-An error occurred}"
stop_spinner
printf "\r\e[2K%s %b\n" "${CROSS}" "${RD}${msg}${CL}" >&2
}
msg_warn() {
stop_spinner
local msg="$1"
echo -e "${BFR:-}${INFO:-} ${YWB}${msg}${CL}" >&2
}
# Helper function to display a message with custom symbol and color
msg_custom() {
local symbol="${1:-*}"
local color="${2:-$CL}"
local msg="${3:-Custom message}"
[[ -z "$msg" ]] && return
stop_spinner
printf "\r\e[2K%s %b\n" "$symbol" "${color}${msg}${CL}" >&2
}
# ------------------------------------------------------------------------------
# msg_debug()
#
# - Displays debug message with timestamp when var_full_verbose=1
# - Automatically enables var_verbose if not already set
# - Uses bright yellow color for debug output
# ------------------------------------------------------------------------------
msg_debug() {
if [[ "${var_full_verbose:-0}" == "1" ]]; then
[[ "${var_verbose:-0}" != "1" ]] && var_verbose=1
echo -e "${YWB}[$(date '+%F %T')] [DEBUG]${CL} $*"
fi
}
# Displays error message and immediately terminates script
fatal() {
msg_error "$1"
kill -INT $$
}
get_valid_nextid() {
local try_id
try_id=$(pvesh get /cluster/nextid)
while true; do
if [ -f "/etc/pve/qemu-server/${try_id}.conf" ] || [ -f "/etc/pve/lxc/${try_id}.conf" ]; then
try_id=$((try_id + 1))
continue
fi
if lvs --noheadings -o lv_name | grep -qE "(^|[-_])${try_id}($|[-_])"; then
try_id=$((try_id + 1))
continue
fi
break
done
echo "$try_id"
}
cleanup_vmid() {
if [[ -z "${VMID:-}" ]]; then
return
fi
if qm status "$VMID" &>/dev/null; then
qm stop "$VMID" &>/dev/null
qm destroy "$VMID" &>/dev/null
fi
}
cleanup() {
if [[ "$(dirs -p | wc -l)" -gt 1 ]]; then
popd >/dev/null || true
fi
}
check_root() {
if [[ "$(id -u)" -ne 0 || $(ps -o comm= -p $PPID) == "sudo" ]]; then
clear
msg_error "Please run this script as root."
echo -e "\nExiting..."
sleep 2
exit
fi
}
pve_check() {
if ! pveversion | grep -Eq "pve-manager/(8\.[1-4]|9\.[0-1])(\.[0-9]+)*"; then
msg_error "This version of Proxmox Virtual Environment is not supported"
echo -e "Requires Proxmox Virtual Environment Version 8.1 - 8.4 or 9.0 - 9.1."
echo -e "Exiting..."
sleep 2
exit
fi
}
arch_check() {
if [ "$(dpkg --print-architecture)" != "amd64" ]; then
echo -e "\n ${INFO}${YWB}This script will not work with PiMox! \n"
echo -e "\n ${YWB}Visit https://github.com/asylumexp/Proxmox for ARM64 support. \n"
echo -e "Exiting..."
sleep 2
exit
fi
}
exit_script() {
clear
echo -e "\n${CROSS}${RD}User exited script${CL}\n"
exit
}
check_hostname_conflict() {
local hostname="$1"
if qm list | awk '{print $2}' | grep -qx "$hostname"; then
msg_error "Hostname $hostname already in use by another VM."
exit 1
fi
}
set_description() {
DESCRIPTION=$(
cat <<EOF
<div align='center'>
<a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a>
<h2 style='font-size: 24px; margin: 20px 0;'>${NSAPP} VM</h2>
<p style='margin: 16px 0;'>
<a href='https://ko-fi.com/community_scripts' target='_blank' rel='noopener noreferrer'>
<img src='https://img.shields.io/badge/&#x2615;-Buy us a coffee-blue' alt='spend Coffee' />
</a>
</p>
<span style='margin: 0 10px;'>
<i class="fa fa-github fa-fw" style="color: #f5f5f5;"></i>
<a href='https://github.com/community-scripts/ProxmoxVE' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>GitHub</a>
</span>
<span style='margin: 0 10px;'>
<i class="fa fa-comments fa-fw" style="color: #f5f5f5;"></i>
<a href='https://github.com/community-scripts/ProxmoxVE/discussions' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>Discussions</a>
</span>
<span style='margin: 0 10px;'>
<i class="fa fa-exclamation-circle fa-fw" style="color: #f5f5f5;"></i>
<a href='https://github.com/community-scripts/ProxmoxVE/issues' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>Issues</a>
</span>
</div>
EOF
)
qm set "$VMID" -description "$DESCRIPTION" >/dev/null
}

View File

@@ -0,0 +1,264 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: vhsdream
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/alangrainger/immich-public-proxy
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func)
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func)
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func)
# Enable error handling
set -Eeuo pipefail
trap 'error_handler' ERR
# ==============================================================================
# CONFIGURATION
# ==============================================================================
APP="Immich Public Proxy"
APP_TYPE="addon"
INSTALL_PATH="/opt/immich-proxy"
CONFIG_PATH="/opt/immich-proxy/app"
DEFAULT_PORT=3000
# Initialize all core functions (colors, formatting, icons, STD mode)
load_functions
# ==============================================================================
# HEADER
# ==============================================================================
function header_info {
clear
cat <<"EOF"
____ _ __ ____
/ _/___ ___ ____ ___ (_)____/ /_ / __ \_________ _ ____ __
/ // __ `__ \/ __ `__ \/ / ___/ __ \______/ /_/ / ___/ __ \| |/_/ / / /
_/ // / / / / / / / / / / / /__/ / / /_____/ ____/ / / /_/ /> </ /_/ /
/___/_/ /_/ /_/_/ /_/ /_/_/\___/_/ /_/ /_/ /_/ \____/_/|_|\__, /
/____/
EOF
}
# ==============================================================================
# OS DETECTION
# ==============================================================================
if [[ -f "/etc/alpine-release" ]]; then
msg_error "Alpine is not supported for ${APP}. Use Debian."
exit 1
elif [[ -f "/etc/debian_version" ]]; then
OS="Debian"
SERVICE_PATH="/etc/systemd/system/immich-proxy.service"
else
echo -e "${CROSS} Unsupported OS detected. Exiting."
exit 1
fi
# ==============================================================================
# UNINSTALL
# ==============================================================================
function uninstall() {
msg_info "Uninstalling ${APP}"
systemctl disable --now immich-proxy.service &>/dev/null || true
rm -f "$SERVICE_PATH"
rm -rf "$INSTALL_PATH"
rm -f "/usr/local/bin/update_immich-public-proxy"
rm -f "$HOME/.immichpublicproxy"
msg_ok "${APP} has been uninstalled"
}
# ==============================================================================
# UPDATE
# ==============================================================================
function update() {
if check_for_gh_release "Immich Public Proxy" "alangrainger/immich-public-proxy"; then
msg_info "Stopping service"
systemctl stop immich-proxy.service &>/dev/null || true
msg_ok "Stopped service"
msg_info "Backing up configuration"
cp "$CONFIG_PATH"/.env /tmp/ipp.env.bak 2>/dev/null || true
cp "$CONFIG_PATH"/config.json /tmp/ipp.config.json.bak 2>/dev/null || true
msg_ok "Backed up configuration"
NODE_VERSION="24" setup_nodejs
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "Immich Public Proxy" "alangrainger/immich-public-proxy" "tarball" "latest" "$INSTALL_PATH"
msg_info "Restoring configuration"
cp /tmp/ipp.env.bak "$CONFIG_PATH"/.env 2>/dev/null || true
cp /tmp/ipp.config.json.bak "$CONFIG_PATH"/config.json 2>/dev/null || true
rm -f /tmp/ipp.*.bak
msg_ok "Restored configuration"
msg_info "Installing dependencies"
cd "$CONFIG_PATH"
$STD npm install
msg_ok "Installed dependencies"
msg_info "Building ${APP}"
$STD npm run build
msg_ok "Built ${APP}"
msg_info "Starting service"
systemctl start immich-proxy
msg_ok "Started service"
msg_ok "Updated successfully"
exit
fi
}
# ==============================================================================
# INSTALL
# ==============================================================================
function install() {
NODE_VERSION="24" setup_nodejs
# Force fresh download by removing version cache
rm -f "$HOME/.immichpublicproxy"
fetch_and_deploy_gh_release "Immich Public Proxy" "alangrainger/immich-public-proxy" "tarball" "latest" "$INSTALL_PATH"
msg_info "Installing dependencies"
cd "$CONFIG_PATH"
$STD npm install
msg_ok "Installed dependencies"
msg_info "Building ${APP}"
$STD npm run build
msg_ok "Built ${APP}"
MAX_ATTEMPTS=3
attempt=0
while true; do
attempt=$((attempt + 1))
read -rp "${TAB3}Enter your LOCAL Immich IP or domain (ex. 192.168.1.100 or immich.local.lan): " DOMAIN
if [[ -z "$DOMAIN" ]]; then
if ((attempt >= MAX_ATTEMPTS)); then
DOMAIN="${LOCAL_IP:-localhost}"
msg_warn "Using fallback: $DOMAIN"
break
fi
msg_warn "Domain cannot be empty! (Attempt $attempt/$MAX_ATTEMPTS)"
elif [[ "$DOMAIN" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
valid_ip=true
IFS='.' read -ra octets <<<"$DOMAIN"
for octet in "${octets[@]}"; do
if ((octet > 255)); then
valid_ip=false
break
fi
done
if $valid_ip; then
break
else
msg_warn "Invalid IP address!"
fi
elif [[ "$DOMAIN" =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\.[a-zA-Z]{2,}$ || "$DOMAIN" == "localhost" ]]; then
break
else
msg_warn "Invalid domain format!"
fi
done
msg_info "Creating configuration"
cat <<EOF >"$CONFIG_PATH"/.env
NODE_ENV=production
IMMICH_URL=http://${DOMAIN}:2283
EOF
chmod 600 "$CONFIG_PATH"/.env
msg_ok "Created configuration"
msg_info "Creating service"
cat <<EOF >"$SERVICE_PATH"
[Unit]
Description=Immich Public Proxy
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=${INSTALL_PATH}
EnvironmentFile=${CONFIG_PATH}/.env
ExecStart=/usr/bin/node ${INSTALL_PATH}/app/server.js
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now immich-proxy
msg_ok "Created and started service"
# Create update script (simple wrapper that calls this addon with type=update)
msg_info "Creating update script"
cat <<'UPDATEEOF' >/usr/local/bin/update_immich-public-proxy
#!/usr/bin/env bash
# Immich Public Proxy Update Script
type=update bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/immich-public-proxy.sh)"
UPDATEEOF
chmod +x /usr/local/bin/update_immich-public-proxy
msg_ok "Created update script (/usr/local/bin/update_immich-public-proxy)"
echo ""
msg_ok "${APP} is reachable at: ${BL}http://${LOCAL_IP}:${DEFAULT_PORT}${CL}"
echo ""
msg_warn "Additional configuration is available at '/opt/immich-proxy/app/config.json'"
}
# ==============================================================================
# MAIN
# ==============================================================================
# Handle type=update (called from update script)
if [[ "${type:-}" == "update" ]]; then
header_info
if [[ -d "$INSTALL_PATH" && -f "$SERVICE_PATH" ]]; then
update
else
msg_error "${APP} is not installed. Nothing to update."
exit 1
fi
exit 0
fi
header_info
get_lxc_ip
# Check if already installed
if [[ -d "$INSTALL_PATH" && -f "$SERVICE_PATH" ]]; then
msg_warn "${APP} is already installed."
echo ""
echo -n "${TAB}Uninstall ${APP}? (y/N): "
read -r uninstall_prompt
if [[ "${uninstall_prompt,,}" =~ ^(y|yes)$ ]]; then
uninstall
exit 0
fi
echo -n "${TAB}Update ${APP}? (y/N): "
read -r update_prompt
if [[ "${update_prompt,,}" =~ ^(y|yes)$ ]]; then
update
exit 0
fi
msg_warn "No action selected. Exiting."
exit 0
fi
# Fresh installation
msg_warn "${APP} is not installed."
echo ""
echo -e "${TAB}${INFO} This will install:"
echo -e "${TAB} - Node.js 24"
echo -e "${TAB} - Immich Public Proxy"
echo ""
echo -n "${TAB}Install ${APP}? (y/N): "
read -r install_prompt
if [[ "${install_prompt,,}" =~ ^(y|yes)$ ]]; then
install
else
msg_warn "Installation cancelled. Exiting."
exit 0
fi